galaxy 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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