lomic 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Gilbert B Garza
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Manifest ADDED
@@ -0,0 +1,22 @@
1
+ LICENSE
2
+ Manifest
3
+ README.rdoc
4
+ Rakefile
5
+ TODO
6
+ examples/nomic_initial_rules.rb
7
+ examples/priority.rb
8
+ examples/simple.rb
9
+ features/event_engine.feature
10
+ features/resource.feature
11
+ features/step_definitions/steps.rb
12
+ features/support/env.rb
13
+ features/var_init.feature
14
+ lib/lomic.rb
15
+ lib/lomic/Event.rb
16
+ lib/lomic/EventEngine.rb
17
+ lib/lomic/GameState.rb
18
+ lib/lomic/Lomic.rb
19
+ lib/lomic/LomicParser.rb
20
+ lib/lomic/Rule.rb
21
+ lomic.gemspec
22
+ parse.rb
data/README.rdoc ADDED
@@ -0,0 +1,55 @@
1
+ = Lomic
2
+
3
+ Lomic is a Domain Specific Language (DSL) intended to be used for Pomic, a programming version of the game Nomic.
4
+
5
+ == What does Lomic look like?
6
+
7
+ Lomic is designed to be expressive in declaring rules for the game Nomic:
8
+
9
+ class Globals < Lomic
10
+ var :players => []
11
+ var :currentPlayer
12
+ end
13
+
14
+ class Player < Lomic
15
+ resource :hp => 15 # resources have a max and min value
16
+ end
17
+
18
+ rule 101 do |g| # g refers to globals
19
+ ### The game begins with 4 players.
20
+ ### Each player is assigned a unique number.
21
+ event "game:start" do
22
+ Player.new_var :number => 0
23
+ 4.times do |i|
24
+ p = Player.new
25
+ p.number = i
26
+ g.players.push(p)
27
+ end
28
+ end
29
+ end
30
+
31
+ rule 102 do |g|
32
+ ### At the beginning of each player's turn,
33
+ ### that player takes 3 damage
34
+ event "turn:start" do
35
+ currentPlayer.hp -= 3
36
+ end
37
+ end
38
+
39
+ == Getting Started
40
+
41
+ Download the source and run an example:
42
+
43
+ $ git clone git://github.com/mindeavor/Lomic.git
44
+ $ cd Lomic
45
+ $ ruby parse.rb examples/simple.rb
46
+
47
+ Check out the `examples/` folder to see what Lomic is supposed to look like, and `parse.rb` to see how to use Lomic (in its current, underdeveloped state)
48
+
49
+ == Contributing
50
+
51
+ Lomic is currently in the concept and development stage. To discuss contributing, syntax, goals, or implementation, join us at #lomic on irc.freenode, or email me at gilbertbgarza aT gmail
52
+
53
+ == Copyright
54
+
55
+ Copyright (c) 2010 Gilbert B Garza. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,65 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "lomic"
8
+ gem.summary = %Q{A Ruby DSL for the game Nomic}
9
+ gem.description = %Q{Lomic is a Domain Specific Language (DSL) intended to be used for Pomic, a programming version of the game Nomic.}
10
+ gem.email = "gilbertbgarza@gmail.com"
11
+ gem.homepage = "http://github.com/mindeavor/lomic"
12
+ gem.authors = ["Gilbert B Garza"]
13
+ gem.add_development_dependency "thoughtbot-shoulda", ">= 0"
14
+ gem.add_development_dependency "cucumber", ">= 0.8.0"
15
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
16
+ end
17
+ Jeweler::GemcutterTasks.new
18
+ rescue LoadError
19
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
20
+ end
21
+
22
+ require 'rake/testtask'
23
+ Rake::TestTask.new(:test) do |test|
24
+ test.libs << 'lib' << 'test'
25
+ test.pattern = 'test/**/test_*.rb'
26
+ test.verbose = true
27
+ end
28
+
29
+ begin
30
+ require 'rcov/rcovtask'
31
+ Rcov::RcovTask.new do |test|
32
+ test.libs << 'test'
33
+ test.pattern = 'test/**/test_*.rb'
34
+ test.verbose = true
35
+ end
36
+ rescue LoadError
37
+ task :rcov do
38
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
39
+ end
40
+ end
41
+
42
+ task :test => :check_dependencies
43
+
44
+ begin
45
+ require 'cucumber/rake/task'
46
+ Cucumber::Rake::Task.new(:features)
47
+
48
+ task :features => :check_dependencies
49
+ rescue LoadError
50
+ task :features do
51
+ abort "Cucumber is not available. In order to run features, you must: sudo gem install cucumber"
52
+ end
53
+ end
54
+
55
+ task :default => :test
56
+
57
+ require 'rake/rdoctask'
58
+ Rake::RDocTask.new do |rdoc|
59
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
60
+
61
+ rdoc.rdoc_dir = 'rdoc'
62
+ rdoc.title = "lomic #{version}"
63
+ rdoc.rdoc_files.include('README*')
64
+ rdoc.rdoc_files.include('lib/**/*.rb')
65
+ end
data/TODO ADDED
@@ -0,0 +1,2 @@
1
+ * Network communication via send and listen
2
+ * Rule source code reloading to support rule changing
data/VERSION.yml ADDED
@@ -0,0 +1,5 @@
1
+ ---
2
+ :major: 0
3
+ :minor: 0
4
+ :patch: 1
5
+ :build:
@@ -0,0 +1,184 @@
1
+ class Player < Lomic
2
+ var :number
3
+ end
4
+
5
+ # global data: all lomic functions search exclusively in this class for global variables
6
+ class Globals < Lomic
7
+ var :currentRule # Rule is a built-in class type
8
+ var :ruleChangeType => ""
9
+
10
+ var :players => []
11
+ var :currentPlayer
12
+
13
+ var :num => 99
14
+
15
+ var :turnCounter => 0, :ruleCounter => 301
16
+
17
+ var :playersVoted => Set.new
18
+ var :votesUnanimous => false # since this is a boolean, it's accessed with: votesUnanimous?
19
+ end
20
+
21
+ # Rules
22
+
23
+ # Rules recieve events in the order of their priority *for that event* (standard is 5)
24
+ # If two rules have the same priority, the lowest rule number goes first
25
+
26
+ # A failed cond will cause the rule to ignore the event
27
+ # A failed assert will cause the rule to kill the event entirely and
28
+ # set the next event to "assert:fail" with failed_event containing
29
+ # the name of the failed event
30
+
31
+ # Both cond and assert failures will cause the rule to stop executing.
32
+
33
+ rule 102 do |g|
34
+ ### Initially the rules in the 100's are immutable and rules in
35
+ ### the 200's are mutable. Rules subsequently enacted or transmuted
36
+ ### (that is, changed from immutable to mutable or vice versa) may be
37
+ ### immutable or mutable regardless of their numbers, and rules in the
38
+ ### Initial Set may be transmuted regardless of their numbers
39
+ event "game:start" do
40
+ # create a new accessible variable in the Rule class initialized to false
41
+ Rule.new_var :immutable => false
42
+ # rules is a reserved global array
43
+ g.rules.each do |r|
44
+ r.immutable = true if r.number >= 100 and r.number < 200
45
+ end
46
+ end
47
+
48
+ event "rule:change", :priority => 1 do
49
+ cond g.ruleChangeType == "transmute"
50
+ assert g.currentRule.immutable == false
51
+ end
52
+ end
53
+
54
+ rule 103 do |g|
55
+ ### A rule change is any of the following:
56
+ ### (1) the enactment, repeal, or amendment of a mutable rule;
57
+ ### (2) the enactment, repeal, or amendment of an amendment of a mutable rule;
58
+ ### or (3) the transmutation of an immutable rule into a mutable rule or vice versa.
59
+ event "rule:change" do
60
+ assert g.ruleChangeType.isEither ["repeal","amendment","transmute"]
61
+ end
62
+ end
63
+
64
+ rule 104 do |g|
65
+ ### All rule-changes proposed in the proper way shall be voted on.
66
+ event "rule:change" do
67
+ set_next "players:vote"
68
+ end
69
+
70
+ ### They will be adopted if and only if they receive the required number of votes.
71
+ event "rule:voted" do
72
+ set_next "vote:unanimous?"
73
+ end
74
+ end
75
+
76
+ rule 105 do |g|
77
+ ### Every player is an eligible voter.
78
+ event "game:start" do
79
+ Player.new_var 'voter' => true
80
+ Player.new_var 'votedYes' => false
81
+ end
82
+
83
+ ### Every eligible voter must participate in every vote on rule-changes.
84
+ event "players:vote" do
85
+ # This will send JSON data over the network to the external manager
86
+ # that is managing this instance of Lomic
87
+ send "request:votes"
88
+ # This will listen for a message from the external manager and treat it an event
89
+ listen "player:vote"
90
+ end
91
+
92
+ event "player:vote" do
93
+ # start listening before the assertions in case one of them fails
94
+ # listening, like next_event, takes place after the code block is done executing
95
+ listen "player:vote"
96
+
97
+ assert g.currentPlayer.voter? == true
98
+ assert g.playersVoted.include? currentPlayer == false
99
+ playersVoted.add(currentPlayer)
100
+
101
+ allVoted = true
102
+ g.players.each do |p|
103
+ allVoted = false if p.voter? and g.playersVoted.include? p == false
104
+ end
105
+
106
+ if allVoted
107
+ listen :cancel # necessary because listening has higher priority over next_event
108
+ set_next "rule:voted"
109
+ end
110
+ end
111
+ end
112
+
113
+ rule 108 do |g|
114
+ ### Each proposed rule-change shall be given a number for reference.
115
+ ### The numbers shall begin with 301, and each rule-change proposed
116
+ ### in the proper way shall receive the next successive integer,
117
+ ### whether or not the proposal is adopted.
118
+ event "rule:passed" do
119
+ # store global data
120
+ # modify source code for rule currentRule.number
121
+ # reload source code
122
+ # reload global data
123
+ # set_next "rule:complete" on load
124
+ end
125
+ end
126
+
127
+ rule 201 do |g|
128
+ ### Players shall alternate in clockwise order, taking one whole turn apiece.
129
+ ### Turns may not be skipped or passed, and parts of turns may not be omitted.
130
+ ### All players begin with zero points.
131
+ event "game:start" do
132
+ Player.new_var 'points', 0
133
+ g.turnCounter = 0
134
+ g.currentPlayer = players[0]
135
+ set_next "turn:start"
136
+ end
137
+
138
+ event "turn:end" do
139
+ g.turnCounter += 1
140
+ g.currentPlayer = g.players[g.turnCounter % g.players.size]
141
+ set_next "turn:start"
142
+ end
143
+ end
144
+
145
+ rule 202 do |g|
146
+ ### One turn consists of two parts in this order:
147
+ ### (1) proposing one rule-change and having it voted on, and
148
+ event "turn:start" do
149
+ # prompt external manager for action
150
+ send :event => "request:action", :player => g.currentPlayer.number
151
+ g.ruleChangeType = listen "response:action"
152
+
153
+ set_next "rule:change"
154
+ end
155
+
156
+ ### (2) throwing one die once and adding the number of points on its face to one's score.
157
+ event "rule:complete" do
158
+ set_next "player:dice roll"
159
+ end
160
+
161
+ event "player:dice roll" do
162
+ g.currentPlayer.points += ran(6)
163
+ end
164
+ end
165
+
166
+ rule 203 do |g|
167
+ ### A rule-change is adopted if and only if the vote is unanimous among the eligible voters.
168
+ event "vote:unanimous?" do
169
+ g.votesUnanimous = true
170
+ g.votedPlayers.each { |p| g.votesUnanimous = false if p.votedYes? == false }
171
+ assert g.votesUnanimous?
172
+ end
173
+ end
174
+
175
+ rule 208 do |g|
176
+ ### The winner is the first player to achieve 100 (positive) points.
177
+ event "player:dice roll", :priority => 1 do
178
+ if g.currentPlayer.points >= 100
179
+ set_next "player:win by points"
180
+ else
181
+ set_next "turn:end"
182
+ end
183
+ end
184
+ end
@@ -0,0 +1,35 @@
1
+ class Globals < Lomic
2
+ var :number => 100
3
+ end
4
+
5
+ rule 101 do |g| # g refers to globals
6
+ event "game:start" do
7
+ puts '[Example: priority.rb]'
8
+ g.number = 99
9
+ set_next "route:right"
10
+ end
11
+
12
+ # A lower priority number means it runs closer to the end.
13
+ # The default priority is 5, thus this event block
14
+ # runs last, having the last effect on set_next and g.number
15
+ event "game:start", :priority => 1 do
16
+ g.number = 77
17
+ set_next "route:left"
18
+ end
19
+
20
+ event "game:start" do
21
+ g.number = 55
22
+ set_next "route:right"
23
+ end
24
+
25
+ event "route:left" do
26
+ puts "The number is: #{g.number}"
27
+ puts "You went left!"
28
+ end
29
+
30
+ event "route:right" do
31
+ puts "The number is: #{g.number}"
32
+ puts "You went right!"
33
+ end
34
+ end
35
+
@@ -0,0 +1,15 @@
1
+ class Globals < Lomic
2
+ var :didiwin => 'No...'
3
+ end
4
+
5
+ rule 101 do |g| # g refers to globals
6
+ event "game:start" do
7
+ puts '[Example: simple.rb]'
8
+ g.didiwin = 'Yes!'
9
+ set_next "game:test1"
10
+ end
11
+
12
+ event "game:test1" do
13
+ puts "Did I win? #{g.didiwin}"
14
+ end
15
+ end
@@ -0,0 +1,41 @@
1
+ Feature: resources in class declarations
2
+ In order to remove boiler plate code
3
+ Resources auto generate convenience methods
4
+ Geared towards game resources
5
+ Such as hit points and energy
6
+
7
+ Scenario: Declaring a resource should generate additional variables
8
+ Given the Lomic inherited class MyClass
9
+ And the resource declaration HP with value 17
10
+ When I create a new MyClass object named foo
11
+ Then the result of foo.HP should be 17
12
+ And the result of foo.HPmax should be 17
13
+ And the result of foo.HPmin should be 0
14
+
15
+ Scenario: A resources should automatically be kept within its defined limits
16
+ Given the Lomic inherited class MyClass
17
+ And the resource declaration HP with value 17
18
+ And the resource declaration MP with value 5
19
+ When I create a new MyClass object named foo
20
+ And I add 33 to foo.HP
21
+ And I subtract 99 from foo.MP
22
+ Then the result of foo.HP should be 17
23
+ And the result of foo.MP should be 0
24
+
25
+ Scenario: Resource limits can be explicitly defined
26
+ Given the Lomic inherited class MyClass
27
+ And the resource declaration EXP with value [0,15,0]
28
+ And the resource declaration STR with value [1,5]
29
+ And the resource declaration HP with value [17]
30
+ When I create a new MyClass object named foo
31
+ Then the results of each <var> should be <val>:
32
+ | var | val |
33
+ | foo.EXP | 0 |
34
+ | foo.EXPmin | 0 |
35
+ | foo.EXPmax | 15 |
36
+ | foo.STR | 5 |
37
+ | foo.STRmin | 1 |
38
+ | foo.STRmax | 5 |
39
+ | foo.HP | 17 |
40
+ | foo.HPmin | 0 |
41
+ | foo.HPmax | 17 |
@@ -0,0 +1,39 @@
1
+ Given /^the Lomic inherited class (\w*)/ do |klass|
2
+ eval "class #{klass} < Lomic\nend"
3
+ @class = Kernel.const_get(klass)
4
+ end
5
+
6
+ When /^I create a new (\w*) object named (\w*)/ do |klass,obj_name|
7
+ eval "$#{obj_name} = #{klass}.new"
8
+ end
9
+
10
+ Then /^the result of (\w+)\.(\w+) should be (\w+)/ do |obj_name,var_name,result|
11
+ result == (eval "$#{obj_name}.#{var_name}")
12
+ end
13
+
14
+ Then /^the results of each <var> should be <val>/ do |table|
15
+ @alltrue = true
16
+ table.hashes.each do |h|
17
+ @alltrue = @alltrue and h[:val] == (eval "$#{h[:var]}")
18
+ end
19
+ @alltrue
20
+ end
21
+
22
+ ### general variables
23
+
24
+ When /^I (add|subtract) (\d+) (?:to|from) (.*)/ do |type,amt,var|
25
+ op = (type=='add') ? '+' : '-'
26
+ eval "$#{var} #{op}= #{amt}"
27
+ end
28
+
29
+ ### var declaration
30
+
31
+ Given /^the following var declarations:/ do |vars|
32
+ vars.hashes.each { |h| @class.class_eval h[:var_decl] }
33
+ end
34
+
35
+ ### resources
36
+
37
+ Given /^the resource declaration (\w+) with value (\[.*\]|\d+)/ do |name,val|
38
+ @class.class_eval "resource :#{name} => #{val}"
39
+ end
@@ -0,0 +1,2 @@
1
+ lomic_file = File.join(File.dirname(__FILE__), *%w[.. .. lib Lomic.rb])
2
+ require lomic_file
@@ -0,0 +1,14 @@
1
+ Feature: variable declaration and initialization on new objects
2
+ In order to keep variable declarations consistent
3
+ With other Lomic features
4
+ Such as resources
5
+
6
+ Scenario: Use of var after new object initializes
7
+ Given the Lomic inherited class MyClass
8
+ And the following var declarations:
9
+ | var_decl |
10
+ | var :example => 9 |
11
+ | var :another => 3 |
12
+ When I create a new MyClass object named foo
13
+ Then the result of foo.example should be 9
14
+ And the result of foo.another should be 3
data/lib/Lomic.rb ADDED
@@ -0,0 +1,16 @@
1
+ $:.push File.expand_path(File.dirname(__FILE__) + '/lib')
2
+ require 'lomic/Event'
3
+ require 'lomic/EventEngine'
4
+ require 'lomic/GameState'
5
+ require 'lomic/Lomic'
6
+ require 'lomic/Rule'
7
+ require 'lomic/LomicParser'
8
+
9
+ module Lomic
10
+ VERSION = '0.0.1'
11
+
12
+ def self.parse(filename, start_event="game:start")
13
+ gstate = LomicParser.load_source(filename)
14
+ gstate.emit start_event
15
+ end
16
+ end
@@ -0,0 +1,12 @@
1
+ module Lomic
2
+
3
+ class Event
4
+ attr_accessor :name, :priority, :rule_number
5
+ attr_accessor :block
6
+
7
+ def initialize(attrs)
8
+ attrs.each {|key,val| instance_variable_set "@#{key}", val }
9
+ end
10
+ end
11
+
12
+ end # module
@@ -0,0 +1,78 @@
1
+ module Lomic
2
+
3
+ class EventEngine
4
+
5
+ def initialize
6
+ @stack = []
7
+ @counter = 0 # the number of event code blocks executed
8
+ end
9
+
10
+ def run(event_name, rules)
11
+ add_sort_events rules
12
+ @next_event = event_name
13
+
14
+ begin
15
+ event_name = @next_event
16
+ @next_event = nil
17
+ for event in @events[event_name]
18
+ # event code blocks can set @next_event through set_next
19
+ instance_eval &event.block
20
+ end
21
+ end while @next_event.nil? == false
22
+ end
23
+
24
+ def set_next(event_name)
25
+ @next_event = event_name
26
+ end
27
+
28
+ def next_event
29
+ @next_event
30
+ end
31
+
32
+ def counter
33
+ @counter
34
+ end
35
+
36
+ private
37
+
38
+ def add_sort_events(rules)
39
+ # "event_name" => [Event]
40
+ @events = {}
41
+ rules.each do |r|
42
+ r.event_bag.each do |name, event_arr|
43
+ for e in event_arr do
44
+ if @events[name].nil?
45
+ @events[name] = [e]
46
+ next
47
+ end
48
+ # insert into sorted spot
49
+ arr = @events[name]
50
+ i = 0
51
+ arr.each do |arr_e|
52
+ if e.priority > arr_e.priority
53
+ arr.insert(i,e)
54
+ break
55
+ elsif i == arr.size-1
56
+ arr.insert(i+1,e)
57
+ break
58
+ end
59
+ i += 1
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+
66
+ def push(event)
67
+ # pushes a state onto the stack
68
+ state = {
69
+ :event_name => event.name,
70
+ :priority => event.priority,
71
+ :rule_number => event.rule_number
72
+ }
73
+ @stack.push(state)
74
+ end
75
+
76
+ end
77
+
78
+ end # module
@@ -0,0 +1,35 @@
1
+ module Lomic
2
+
3
+ require 'Set'
4
+
5
+ class GameState
6
+ def initialize
7
+ super
8
+ @globals
9
+ @rules = []
10
+ @em = EventEngine.new
11
+ end
12
+
13
+ def globals
14
+ @globals
15
+ end
16
+
17
+ def globals=(globals_obj)
18
+ return if @globals.nil? == false
19
+ @globals = globals_obj
20
+ klass = @globals.class
21
+
22
+ klass.new_var :rules => []
23
+ @globals.rules = @rules
24
+ end
25
+
26
+ def addRule(rule)
27
+ @rules.push(rule)
28
+ end
29
+
30
+ def emit(event_name)
31
+ @em.run(event_name,@globals.rules)
32
+ end
33
+ end
34
+
35
+ end # module
@@ -0,0 +1,104 @@
1
+ module Lomic
2
+
3
+ ### This class helps clean up in-game class definitions
4
+ class Lomic
5
+ class << self
6
+ public :define_method, :remove_method
7
+ end
8
+
9
+ def self.var(symbols)
10
+ if symbols.instance_of? Symbol
11
+ self.new_var({symbols.to_sym => nil})
12
+ else
13
+ symbols.each { |name,init_val|
14
+ self.new_var(name => init_val)
15
+ }
16
+ end
17
+ end
18
+
19
+ def self.new_var(symbol)
20
+ name = symbol.keys[0]
21
+ init_val = symbol[name]
22
+
23
+ self.define_method name do
24
+ getter = "@#{name}"
25
+ getter += '?' if init_val.instance_of? TrueClass or init_val.instance_of? FalseClass
26
+ val = instance_variable_get getter
27
+
28
+ if val.nil? and @init_used[name].nil?
29
+ inits = self.class.class_eval "@@__#{className}_inits__"
30
+ val = inits[name]
31
+ instance_variable_set("@#{name}", val)
32
+ @init_used[name] = true
33
+ end
34
+
35
+ return val
36
+ end
37
+
38
+ self.define_method "#{name}=" do |new_val|
39
+ instance_variable_set("@#{name}", new_val)
40
+ @init_used[name] = true
41
+ end
42
+
43
+ class_eval "@@__#{self.className}_inits__ ||= {}"
44
+ inits = class_eval "@@__#{self.className}_inits__"
45
+ inits[name] = init_val
46
+ end
47
+
48
+ def self.resource(symbols)
49
+ symbols.each { |name,init_val|
50
+ self.new_resource(name => init_val)
51
+ }
52
+ end
53
+
54
+ def self.new_resource(symbol)
55
+ name = symbol.keys[0]
56
+ init_val = symbol[name]
57
+
58
+ if init_val.instance_of? Array
59
+ min,max,init = case init_val.size
60
+ when 1 then [0,init_val[0],init_val[0]]
61
+ when 2 then [init_val[0],init_val[1],init_val[1]]
62
+ else [init_val[0],init_val[1],init_val[2]]
63
+ end
64
+ else
65
+ min,max,init = [0,init_val,init_val]
66
+ end
67
+ self.new_var(name => init)
68
+ self.new_var("#{name}min" => min)
69
+ self.new_var("#{name}max" => max)
70
+
71
+ # redefine the set method to enforce resource limits
72
+ self.remove_method "#{name}="
73
+ self.define_method "#{name}=" do |new_val|
74
+ min = instance_variable_get "@#{name}min"
75
+ max = instance_variable_get "@#{name}max"
76
+ new_val = new_val < min ? min : (new_val > max ? max : new_val)
77
+
78
+ instance_variable_set("@#{name}", new_val)
79
+ end
80
+ end
81
+
82
+ def initialize
83
+ @init_used = {}
84
+ inits = self.class.class_eval "@@__#{className}_inits__"
85
+ inits.each do |var,val|
86
+ instance_variable_set "@#{var}", val
87
+ @init_used[var] = true
88
+ end
89
+ end
90
+
91
+ def self.className
92
+ if self.name.include? '::'
93
+ self.name.split('::')[1]
94
+ else
95
+ self.name
96
+ end
97
+ end
98
+
99
+ def className
100
+ self.class.className
101
+ end
102
+ end
103
+
104
+ end # module
@@ -0,0 +1,43 @@
1
+ module Lomic
2
+
3
+ class LomicParser
4
+
5
+ def initialize
6
+ # points to the Rule that is currently being parsed
7
+ @currentRule = nil
8
+ # The entire state of the game
9
+ @state = GameState.new
10
+ @first_rule = true
11
+ end
12
+
13
+ def rule(number)
14
+ # TODO: ensure number is int
15
+ @currentRule = Rule.new(number)
16
+ if @first_rule
17
+ @state.globals = instance_eval 'Globals.new'
18
+ @first_rule = false
19
+ end
20
+
21
+ yield @state.globals
22
+ ensure
23
+ @state.addRule(@currentRule)
24
+ @currentRule = nil
25
+ end
26
+
27
+ def event(event_name, options={}, &block)
28
+ @currentRule.event(event_name, options, &block)
29
+ end
30
+
31
+ def gamestate
32
+ @state
33
+ end
34
+
35
+ def self.load_source(filename)
36
+ dsl = new
37
+ dsl.instance_eval(File.read(filename),filename)
38
+ # dsl.gamestate.globals = (dsl.instance_eval 'Globals.new')
39
+ dsl.gamestate
40
+ end
41
+ end
42
+
43
+ end # module
data/lib/lomic/Rule.rb ADDED
@@ -0,0 +1,44 @@
1
+ module Lomic
2
+
3
+ class Rule < Lomic
4
+ def initialize(number)
5
+ @number = number
6
+ @event_bag = {} # "event_name" => [Event]
7
+ end
8
+
9
+
10
+ def event(event_name, options={}, &block)
11
+ options[:priority] ||= 5
12
+ options[:name] = event_name
13
+ options[:block] = block
14
+
15
+ event = Event.new(options)
16
+ if @event_bag[event_name].nil?
17
+ @event_bag[event_name] = [event]
18
+ else
19
+ # insert into sorted spot
20
+ arr = @event_bag[event_name]
21
+ i = 0
22
+ arr.each do |e|
23
+ if event.priority > e.priority
24
+ arr.insert(i,event)
25
+ break
26
+ elsif i == arr.size-1
27
+ arr.insert(i+1,event)
28
+ break
29
+ end
30
+ i += 1
31
+ end
32
+ end
33
+ end
34
+
35
+ def event_bag
36
+ @event_bag
37
+ end
38
+
39
+ def inspect
40
+ "Rule #{@number}: #{@event_bag.inspect}"
41
+ end
42
+ end
43
+
44
+ end # module
metadata ADDED
@@ -0,0 +1,119 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lomic
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Gilbert B Garza
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-06-12 00:00:00 -05:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: thoughtbot-shoulda
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ type: :development
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: cucumber
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ hash: 63
44
+ segments:
45
+ - 0
46
+ - 8
47
+ - 0
48
+ version: 0.8.0
49
+ type: :development
50
+ version_requirements: *id002
51
+ description: Lomic is a Domain Specific Language (DSL) intended to be used for Pomic, a programming version of the game Nomic.
52
+ email: gilbertbgarza@gmail.com
53
+ executables: []
54
+
55
+ extensions: []
56
+
57
+ extra_rdoc_files:
58
+ - LICENSE
59
+ - README.rdoc
60
+ - TODO
61
+ files:
62
+ - LICENSE
63
+ - Manifest
64
+ - README.rdoc
65
+ - Rakefile
66
+ - TODO
67
+ - VERSION.yml
68
+ - examples/nomic_initial_rules.rb
69
+ - examples/priority.rb
70
+ - examples/simple.rb
71
+ - features/resource.feature
72
+ - features/step_definitions/steps.rb
73
+ - features/support/env.rb
74
+ - features/var_init.feature
75
+ - lib/Lomic.rb
76
+ - lib/lomic/Event.rb
77
+ - lib/lomic/EventEngine.rb
78
+ - lib/lomic/GameState.rb
79
+ - lib/lomic/Lomic.rb
80
+ - lib/lomic/LomicParser.rb
81
+ - lib/lomic/Rule.rb
82
+ has_rdoc: true
83
+ homepage: http://github.com/mindeavor/lomic
84
+ licenses: []
85
+
86
+ post_install_message:
87
+ rdoc_options:
88
+ - --charset=UTF-8
89
+ require_paths:
90
+ - lib
91
+ required_ruby_version: !ruby/object:Gem::Requirement
92
+ none: false
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ hash: 3
97
+ segments:
98
+ - 0
99
+ version: "0"
100
+ required_rubygems_version: !ruby/object:Gem::Requirement
101
+ none: false
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ hash: 3
106
+ segments:
107
+ - 0
108
+ version: "0"
109
+ requirements: []
110
+
111
+ rubyforge_project:
112
+ rubygems_version: 1.3.7
113
+ signing_key:
114
+ specification_version: 3
115
+ summary: A Ruby DSL for the game Nomic
116
+ test_files:
117
+ - examples/nomic_initial_rules.rb
118
+ - examples/priority.rb
119
+ - examples/simple.rb