galaxy 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. data/.document +5 -0
  2. data/.gitignore +21 -0
  3. data/.idea/.rakeTasks +7 -0
  4. data/.idea/encodings.xml +5 -0
  5. data/.idea/galaxy.iml +10 -0
  6. data/.idea/misc.xml +14 -0
  7. data/.idea/modules.xml +9 -0
  8. data/.idea/vcs.xml +8 -0
  9. data/.idea/workspace.xml +486 -0
  10. data/LICENSE +20 -0
  11. data/README.rdoc +36 -0
  12. data/Rakefile +62 -0
  13. data/VERSION +1 -0
  14. data/doc/plan.txt +5 -0
  15. data/doc/pseudo.txt +43 -0
  16. data/features/galaxy.feature +9 -0
  17. data/features/step_definitions/galaxy_steps.rb +0 -0
  18. data/features/support/env.rb +4 -0
  19. data/galaxy.gemspec +95 -0
  20. data/galaxy/.loadpath +5 -0
  21. data/galaxy/.project +17 -0
  22. data/galaxy/.settings/org.eclipse.mylyn.tasks.ui.prefs +4 -0
  23. data/galaxy/.settings/org.eclipse.wst.sse.core.prefs +5 -0
  24. data/galaxy/experiments.rb +26 -0
  25. data/lib/galaxy.rb +8 -0
  26. data/lib/galaxy/models/bombing.rb +64 -0
  27. data/lib/galaxy/models/fleet.rb +62 -0
  28. data/lib/galaxy/models/group.rb +178 -0
  29. data/lib/galaxy/models/models.rb +16 -0
  30. data/lib/galaxy/models/planet.rb +181 -0
  31. data/lib/galaxy/models/product.rb +84 -0
  32. data/lib/galaxy/models/race.rb +112 -0
  33. data/lib/galaxy/models/route.rb +60 -0
  34. data/lib/galaxy/order.rb +24 -0
  35. data/lib/galaxy/report.rb +176 -0
  36. data/lib/galaxy/section.rb +226 -0
  37. data/lib/galaxy/utils.rb +109 -0
  38. data/lib/galaxy/virtual_base.rb +165 -0
  39. data/spec/spec_helper.rb +9 -0
  40. data/test/test_helper.rb +4 -0
  41. data/test/unit/models_test.rb +1469 -0
  42. data/test/unit/report_test.rb +187 -0
  43. data/test/unit/utils_test.rb +421 -0
  44. data/test/unit/virtual_base_test.rb +224 -0
  45. metadata +123 -0
@@ -0,0 +1,178 @@
1
+ require 'galaxy/models/models'
2
+
3
+ class Group < ActiveRecord::Base
4
+ virtual
5
+ tableless :columns => [
6
+ [:num, :integer],
7
+ [:xx, :float],
8
+ [:yy, :float],
9
+ [:num_ships, :integer ],
10
+ [:num_before, :integer], # Number of ships BEFORE battle (for Battle Groups only)
11
+ [:drive, :float],
12
+ [:weapons, :float],
13
+ [:shields, :float],
14
+ [:cargo, :float],
15
+ [:cargo_type, :string],
16
+ [:qty, :float],
17
+ [:range, :float],
18
+ [:speed, :float],
19
+ [:mass, :float],
20
+ [:status, :string] # May cause problems with AR?
21
+ ]
22
+ belongs_to :race
23
+ belongs_to :product
24
+ belongs_to :planet
25
+ belongs_to :fleet
26
+ belongs_to :from, :class_name => 'Planet'
27
+
28
+ attr_accessor :battles
29
+
30
+ def initialize match, state
31
+ super()
32
+ update_group match, state
33
+ end
34
+
35
+ # Update information on this Group (based on match size and state hash given)
36
+ def update_group match, state
37
+ race = product = planet = from = fleet = nil
38
+ # Make attributes hash based on match size (many constructors)
39
+ hash = case match.size
40
+ when 16 # Your Group
41
+ race = state[:race]
42
+ p 'No planet!', match, state unless planet = Planet.lookup(match[9])
43
+ p 'No from!', match, state unless from = Planet.lookup(match[10]) unless match[10] == '-'
44
+ p 'No fleet!', match, state unless fleet = Fleet.lookup(race.name + '.' + match[14]) unless match[14] == '-'
45
+ product = Product.lookup(race.name + '.' + match[2])
46
+ product = Product.lookup(race.name + '.' + match[2])
47
+ {:num=>match[0].to_i, :num_ships=>match[1].to_i, :drive=>match[3].to_f, :weapons=>match[4].to_f,
48
+ :shields=>match[5].to_f, :cargo=>match[6].to_f, :cargo_type=>match[7], :qty=>match[8].to_f,
49
+ :range=>match[11].to_f, :speed=>match[12].to_f, :mass=>match[13].to_f, :status=>match[15]}
50
+
51
+ when 11 # (known) * Group
52
+ race = state[:race]
53
+ p 'No planet!', match, state unless planet = Planet.lookup(match[8])
54
+ p 'No product!', match, state unless product = Product.lookup(race.name + '.' + match[1])
55
+ {:num_ships=>match[0].to_i, :drive=>match[2].to_f, :weapons=>match[3].to_f, :shields=>match[4].to_f,
56
+ :cargo=>match[5].to_f, :cargo_type=>match[6], :qty=>match[7].to_f, :speed=>match[9].to_f, :mass=>match[10].to_f}
57
+
58
+ when 10 # Battle Group
59
+ race = state[:race]
60
+ planet = state[:planet]
61
+ product = Product.lookup(race.name + '.' + match[1])
62
+ @battles = state[:battles]
63
+ {:num_before=>match[0].to_i, :drive=>match[2].to_f, :weapons=>match[3].to_f,
64
+ :shields=>match[4].to_f, :cargo=>match[5].to_f, :cargo_type=>match[6], :qty=>match[7].to_f,
65
+ :num_ships=>match[8].to_i, :status=>match[9]}
66
+
67
+ when 5 # Incoming Group
68
+ planet = Planet.new [match[1]], state.merge({:race=>nil,:product=>nil,:created_by=>self}) unless planet = Planet.lookup(match[1])
69
+ from = Planet.new [match[0]], state.merge({:race=>nil,:product=>nil,:created_by=>self}) unless from = Planet.lookup(match[0])
70
+ {:range=>match[2].to_f, :speed=>match[3].to_f, :mass=>match[4].to_f}
71
+
72
+ when 2 # Unidentified Group - TODO implement track calculation
73
+ {:xx=>match[0].to_f, :yy=>match[1].to_f}
74
+
75
+ when 0 # All init data given in a state hash
76
+ state
77
+ else {}
78
+ end
79
+ # Set all the attributes given in hash
80
+ hash.each do |key, value|
81
+ setter = key.to_s.concat('=').to_sym
82
+ if self.respond_to? setter then self.send setter, value else raise ArgumentError end
83
+ end
84
+ # Add this Group to appropriate collections it belongs to
85
+ # auto-delete from previous collection should be handled by Owner class through collection callbacks
86
+ race.groups << self if race
87
+ product.groups << self if product
88
+ planet.groups << self if planet
89
+ fleet.groups << self if fleet
90
+ from.sent_groups << self if from
91
+ add if self.class.dataset # Add instantiated model to dataset if it is established
92
+ end
93
+
94
+ # Accessor methods
95
+ def eta ; from ? range/speed : 0 end
96
+
97
+ def x
98
+ return xx if xx
99
+ return planet.x if planet and !from
100
+ return 0 if planet and from # game.geometry.group_pos(self)[0]
101
+ nil
102
+ end
103
+
104
+ def y
105
+ return yy if yy
106
+ return planet.y if planet and !from
107
+ return 0 if planet and from # game.geometry.group_pos(self)[0]
108
+ nil
109
+ end
110
+
111
+ def destination ; planet end
112
+
113
+ def origin ; from end
114
+ alias source origin
115
+
116
+ def key
117
+ if num # Your Group or other known race from additional reports
118
+ race.name + '.' + num.to_s
119
+ else # Impossible to define primary key (no combination of parameters is unique)
120
+ nil
121
+ end
122
+ end
123
+
124
+ def distance planet
125
+ #game.geometry.distance (self, planet2)
126
+ 0
127
+ end
128
+
129
+ # Boolean tests on Groups
130
+ def from_battle? ; @battles and @battles > 0 end # This Group is known from Battle
131
+
132
+ def incoming? ; !your? and from and planet and planet.your? end
133
+
134
+ def unidentified? ; !race end
135
+ alias unknown? unidentified?
136
+
137
+ def active?
138
+ return true unless from_battle? # All Groups are "real", unless they are known only from Battle
139
+ !your? and num_ships > 0 and planet.unknown? and planet.battles == self.battles # Not killed Groups from LAST Battle on UNKNOWN PLanet are "real" too
140
+ end
141
+ alias real? active?
142
+
143
+ def your_active? ; active? and your? end # Only includes your "active" (NOT from_battle) groups
144
+
145
+ def drone? ; (product and product.drone?) or (incoming? and mass == 1) end
146
+
147
+ def <=>(other) # Default comparable is num_ships
148
+ case other
149
+ when nil then 1
150
+ when Group then # key <=> other.key
151
+ return 0 if key and self.key == other.key
152
+ if num_ships and other.num_ships then num_ships <=> other.num_ships else -1 end
153
+ # Meaningful comparison only possible for groups with known num_ships
154
+ when Race then race ? race <=> other : -1
155
+ when Planet then
156
+ return 0 if from and from == other
157
+ planet ? planet <=> other : -1
158
+ when Product then product ? product <=> other : -1
159
+ when Fleet then fleet ? fleet <=> other : -1
160
+ when Integer then num_ships ? num_ships <=> other : -1
161
+ when String then self <=> other.downcase.to_sym
162
+ when Symbol then
163
+ return active? ? 0 : 1 if other == :active or other == :real or other == :alive
164
+ return from_battle? ? 0 : 1 if other == :from_battle or other == :battle
165
+ return incoming? ? 0 : 1 if other == :incoming
166
+ return unidentified? ? 0 : 1 if other == :unidentified or other == :unknown
167
+ return 0 if race and race == other
168
+ return 0 if product and product == other
169
+ return 0 if planet and planet == other
170
+ return 0 if from and from == other
171
+ return 0 if fleet and fleet == other
172
+ return 0 if status and status.downcase.include? other.to_s
173
+ return 0 if key and key.downcase.include? other.to_s
174
+ -1
175
+ else raise ArgumentError, 'Comparison with a wrong type'
176
+ end
177
+ end
178
+ end #Group
@@ -0,0 +1,16 @@
1
+ # First, 'models.rb' serves as 'super-class-equivalent' for Models, activating all the
2
+ # VirtualBase enhancements that can be used in Model classes (macros, class methods, instance methods)
3
+ require 'rubygems'
4
+ require 'active_record'
5
+ require 'galaxy/virtual_base.rb'
6
+ ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => ":memory:", :timeout => 500)
7
+ ActiveRecord::Base.send(:include, ActiveRecord::VirtualBase)
8
+
9
+ # Second, 'models.rb' serves as collector, allowing clients to require 'models.rb' instead of individual Model files
10
+ require 'galaxy/models/race'
11
+ require 'galaxy/models/product'
12
+ require 'galaxy/models/planet'
13
+ require 'galaxy/models/bombing'
14
+ require 'galaxy/models/route'
15
+ require 'galaxy/models/fleet'
16
+ require 'galaxy/models/group'
@@ -0,0 +1,181 @@
1
+ require 'galaxy/models/models'
2
+
3
+ class Planet < ActiveRecord::Base
4
+ virtual
5
+ tableless :columns => [
6
+ [ :num, :integer],
7
+ [ :x, :float ],
8
+ [ :y, :float ],
9
+ [ :name, :string ],
10
+ [ :size, :float ],
11
+ [ :pop, :float ],
12
+ [ :ind, :float ],
13
+ [ :res, :float ],
14
+ [ :cap, :float ],
15
+ [ :mat, :float ],
16
+ [ :col, :float ],
17
+ [ :l, :float ]
18
+ ]
19
+ belongs_to :race
20
+ belongs_to :product
21
+ has_many_linked :bombings
22
+ has_many_linked :fleets
23
+ has_many_linked :groups
24
+ has_many_linked :sent_fleets, :class_name => 'Fleet', :foreign_key => 'from_id'
25
+ has_many_linked :sent_groups, :class_name => 'Group', :foreign_key => 'from_id'
26
+ has_many_linked :routes, :before_add => :add_route, :after_remove => :remove_route #, after_remove => :remove_hmt
27
+ has_many_linked :incoming_routes, :foreign_key => 'target_id', :class_name => 'Route', :after_remove => :remove_route #, :after_remove => :remove_hmt
28
+
29
+ attr_accessor :battles, :progress, :created_by
30
+
31
+ def add_route(route)
32
+ # Find if target Route of this cargo type already exist, remove previous Route if found
33
+ routes.each do |r|
34
+ remove_route r if r == route.cargo
35
+ end
36
+ end
37
+
38
+ def remove_route(route)
39
+ route.kill
40
+ end
41
+
42
+ def targets
43
+ routes.map {|r| r.target}
44
+ end
45
+
46
+ def suppliers
47
+ incoming_routes.map {|r| r.planet}
48
+ end
49
+
50
+ def Planet.new_or_update match, state
51
+ # Lookup by both num and name is necessary since Routes/Fleets/Bombings create planets by name only
52
+ num = match[0][0,1] == '#' ? match[0] : '#' + match[0].to_s
53
+ name = match[3]
54
+ planet = Planet.lookup(num)
55
+ planet ||= Planet.lookup(name) if name
56
+ if planet
57
+ planet.update_planet match, state
58
+ else
59
+ new match, state
60
+ end
61
+ end
62
+
63
+ def initialize match, state
64
+ super()
65
+ update_planet match, state
66
+ end
67
+
68
+ # Update information on Planet (based on match size and state hash given)
69
+ def update_planet match, state
70
+ # Make attributes hash based on match size (4 possible constructors
71
+ hash = case match.size
72
+ when 13 # Your Planet/ * Planet
73
+ prod_name = match[8]
74
+ prod_key = state[:race] ? state[:race].name + '.' + prod_name : nil
75
+ product = Product.lookup(prod_name)
76
+ product ||= Product.lookup(prod_key) if prod_key
77
+ product.planets << self if product
78
+ {:num=>match[0].to_i, :x=>match[1].to_f, :y=>match[2].to_f, :name=>match[3], :size=>match[4].to_f,
79
+ :pop=>match[5].to_f, :ind=>match[6].to_f, :res=>match[7].to_f, :cap=>match[9].to_f,
80
+ :mat=>match[10].to_f, :col=>match[11].to_f, :l=>match[12].to_f}
81
+
82
+ when 8 # Uninhabited Planet
83
+ {:num=>match[0].to_i, :x=>match[1].to_f, :y=>match[2].to_f, :name=>match[3], :size=>match[4].to_f,
84
+ :res=>match[5].to_f, :cap=>match[6].to_f, :mat=>match[7].to_f}
85
+
86
+ when 6 # Ships In Production
87
+ total_mass = match[3].to_f / 10 # Mass values given in "Material units", divide by 10
88
+ produced_mass = match[4].to_f / 10
89
+ percentage = produced_mass/total_mass # Calculate ship production progress
90
+ {:progress=>percentage}
91
+
92
+ when 3 # Unidentified Planet
93
+ {:num=>match[0].to_i, :x=>match[1].to_f, :y=>match[2].to_f}
94
+
95
+ when 2 # Battle/Bombing generated Planet (known num and name)
96
+ if state[:section] = 'Battle_planets'
97
+ self.battles = state[:battles] = self.battles ? self.battles + 1 : 1
98
+ state[:planet] = self
99
+ end
100
+ {:num=>match[0].to_i, :name=>match[1]}
101
+
102
+ when 1 # Route/Fleet/Bombing generated Planet (given EITHER #num or name)
103
+ match[0][0,1] == '#' ?
104
+ {:num=>match[0][1..-1].to_s} :
105
+ {:name=>match[0]}
106
+
107
+ when 0 # All init data given in a state hash
108
+ state
109
+ else {}
110
+ end
111
+ # Set all the attributes given in hash
112
+ hash.each do |key, value|
113
+ setter = key.to_s.concat('=').to_sym
114
+ if self.respond_to? setter then self.send setter, value else raise ArgumentError end
115
+ end
116
+ state[:race].planets << self if state[:race]
117
+ num ? add(numkey) : add if self.class.dataset # Add instantiated/updated model to dataset if dataset established
118
+ @created_by = state[:created_by]
119
+ self
120
+ end
121
+
122
+ def key ; name ? name : numkey end
123
+ def numkey ; num ? '#' + num.to_s : nil end
124
+
125
+ def distance planet
126
+ #game.geometry.distance (planet1, planet2)
127
+ 0
128
+ end
129
+
130
+ def produced_full_mat
131
+ @progress end
132
+
133
+ def produced_by_mat
134
+ return nil unless self.product and self.product.ship?
135
+ produced_mass = @progress*self.product.mass
136
+ available_mass = self.mat/10
137
+ missing_mass = self.product.mass - produced_mass - available_mass
138
+ if missing_mass < 0
139
+ @progress
140
+ else
141
+ missing_l = (1/self.res+10)*missing_mass #
142
+ return 1-(available_mass + missing_l/10)/(produced_mass+available_mass+missing_l/10)
143
+ end
144
+ end
145
+ alias produced produced_by_mat
146
+
147
+ # Boolean tests on Planets
148
+ def aster? ; size and size < 1 end
149
+
150
+ def max_size? ; size and size == 2500 end
151
+
152
+ def uninhabited? ; !race and size end
153
+ alias free? uninhabited?
154
+
155
+ def unidentified? ; !race and !size end
156
+ alias unknown? unidentified?
157
+
158
+ def <=>(other)
159
+ case other
160
+ when nil then 1
161
+ when Planet then num <=> other.num
162
+ when Race then race ? race <=> other : -1
163
+ when Product then product ? product <=> other : -1
164
+ when Bombing then bombings.any? {|r| r == other} ? 0 : 1 #Planet is bigger than Bombing
165
+ when Fleet then fleets.any? {|r| r == other} ? 0 : sent_fleets.any? {|r| r == other} ? 0 : 1 #Planet is bigger than Fleet
166
+ when Route then routes.any? {|r| r == other} ? 0 : incoming_routes.any? {|r| r == other}? 0 : 1 #Planet is bigger than Route
167
+ when Integer then num <=> other
168
+ when String then self <=> other.downcase.to_sym
169
+ when Symbol then
170
+ return aster? ? 0 : 1 if other == :aster or other == :asteroid or other == :min
171
+ return max_size? ? 0 : 1 if other == :max_size or other == :max
172
+ return uninhabited? ? 0 : 1 if other == :uninhabited or other == :free or other == :empty
173
+ return unidentified? ? 0 : 1 if other == :unidentified or other == :unid or other == :unknown
174
+ return 0 if name and name.downcase.to_sym == other
175
+ return 0 if race and race == other
176
+ return 0 if product and product == other
177
+ key <=> other.to_s
178
+ else raise ArgumentError, 'Comparison with a wrong type'
179
+ end
180
+ end
181
+ end #Planet
@@ -0,0 +1,84 @@
1
+ require 'galaxy/models/models'
2
+
3
+ class Product < ActiveRecord::Base
4
+ virtual
5
+ tableless :columns => [
6
+ [:name, :string],
7
+ [:drive, :float],
8
+ [:weapons, :float],
9
+ [:shields, :float],
10
+ [:cargo, :float],
11
+ [:guns, :integer],
12
+ [:mass, :float],
13
+ [:prod_type, :string]
14
+ ]
15
+ belongs_to :race
16
+ has_many_linked :bombings
17
+ has_many_linked :groups
18
+ has_many_linked :planets
19
+
20
+ def initialize match, state
21
+ case match.size
22
+ when 7 then # This is a ship design
23
+ super({:name=>match[0], :drive=>match[1].to_f, :guns=>match[2].to_i, :weapons=>match[3].to_f,
24
+ :shields=>match[4].to_f, :cargo=>match[5].to_f, :mass=>match[6].to_f, :prod_type=>'ship'})
25
+
26
+ when 5 then # This is a science
27
+ super({:name=>match[0], :drive=>match[1].to_f, :weapons=>match[2].to_f, :shields=>match[3].to_f,
28
+ :cargo=>match[4].to_f, :prod_type=>'research'})
29
+
30
+ when 0 then # This is Cap/Mat/Col/Drive/Weapon/Shields/Cargo init, all init data given in a hash
31
+ super state # :name=>state[:name], :prod_type=>state[:prod_type]
32
+ end
33
+ # Add this Product to appropriate Race collections it belongs to
34
+ # auto-delete from previous collection should be handled by Race class through collection callbacks
35
+ state[:race].products << self if state[:race]
36
+ add if self.class.dataset # Add instantiated model to dataset if it is defined
37
+ end
38
+
39
+ def key
40
+ full_name = research? ? name + '_Research' : name
41
+ full_name = race.name + '.' + full_name if race
42
+ full_name
43
+ end
44
+
45
+ # Boolean tests on Products
46
+ def cap? ; prod_type == 'cap' end
47
+
48
+ def mat? ; prod_type == 'mat' end
49
+
50
+ def terraforming? ; research? and name == '_TerraForming' end
51
+
52
+ def moving? ; name[0..3].downcase == 'move' end
53
+
54
+ def ship? ; mass != nil end
55
+
56
+ def drone? ; drive == 1 and mass == 1 end
57
+
58
+ def research? ; prod_type == 'research' end
59
+
60
+ def in_use? ; !bombings.empty? or !planets.empty? or !groups.empty? end
61
+ alias science? research?
62
+
63
+ def <=>(other)
64
+ case other
65
+ when nil then 1
66
+ when Race then race ? race <=> other : -1
67
+ when Product then (ship? and mass != other.mass) ? mass <=> other.mass : key <=> other.key
68
+ when Bombing then bombings.any? {|r| r == other} ? 0 : 1 #Product is bigger than Bombing
69
+ when Planet then planets.any? {|r| r == other} ? 0 : 1 #Product is bigger than Planet
70
+ when Integer then ship? ? mass <=> other : 1 #Science is bigger than anything
71
+ when Float then ship? ? mass <=> other : 1 #Science is bigger than anything
72
+ when String then self <=> other.downcase.to_sym
73
+ when Symbol then
74
+ return drone? ? 0 : 1 if other == :drone or other == :dron
75
+ return research? ? 0 : 1 if other == :research or other == :science or other == :tech
76
+ return moving? ? 0 : 1 if other == :move or other == :moving
77
+ return terraforming? ? 0 : 1 if other == :terraform or other == :terraforming
78
+ return 0 if prod_type.downcase.to_sym == other
79
+ return 0 if key.downcase.include? other.to_s
80
+ key <=> other.to_s
81
+ else raise ArgumentError, 'Comparison with a wrong type'
82
+ end
83
+ end
84
+ end