UG_RRobots 1.3 → 2.0

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.
data/lib/bullets.rb CHANGED
@@ -35,5 +35,16 @@ class Bullet
35
35
  @dead = true
36
36
  end
37
37
  end
38
+
39
+ @battlefield.mines.each do |mine|
40
+ if (Math.hypot(@y - mine.y, mine.x - @x) < 10) && (!mine.dead) && (mine.origin != origin) then
41
+ explosion = Explosion.new(@battlefield, mine.x, mine.y)
42
+ @battlefield << explosion
43
+ mine.destroy if self.energy > @battlefield.config.mines[:bullet_energy_resistance]
44
+ origin.destroyed_mines += 1
45
+ @dead = true
46
+ end
47
+ end
48
+
38
49
  end
39
50
  end
data/lib/configuration.rb CHANGED
@@ -4,6 +4,7 @@ module Configuration_accessors
4
4
  attr_accessor :robots
5
5
  attr_accessor :bullets
6
6
  attr_accessor :battlefield
7
+ attr_accessor :mines
7
8
  end
8
9
 
9
10
  class Configuration
@@ -20,9 +21,10 @@ class Configuration
20
21
  @filename = filename
21
22
  @game = { :timeout => 50000 }
22
23
  @toolboxes = { :with_toolboxes => false, :life_time => 200, :spawning_chances => 100, :energy_heal_points => 20 }
23
- @robots = { :energy_max => 100 }
24
+ @robots = { :energy_max => 100, :nb_mines => 3, :radar_mine_scanning_performance => 500 }
24
25
  @bullets = { :speed => 30 }
25
26
  @battlefield = { :height => 800, :width => 800 }
27
+ @mines = { :with_mines => false, :energy_hit_points => 20, :bullet_energy_resistance => 2 }
26
28
  end
27
29
 
28
30
  end
data/lib/misc.rb ADDED
@@ -0,0 +1,29 @@
1
+
2
+ def gem_path(path='')
3
+ # TODO : Perhaps a better way to do it ...
4
+ # regarder Rubygems pour avoir le path direct ..
5
+ table_map = Gem.location_of_caller.first.split('/')
6
+ 2.times do
7
+ table_map.pop
8
+ end
9
+ table_map.push path unless path.empty?
10
+ path_prefix = table_map.join('/')
11
+ return false unless File::exist?(path_prefix)
12
+ return path_prefix
13
+ end
14
+
15
+ def init_I18n(locales)
16
+ I18n.default_locale = locales
17
+ locales_path = gem_path('config').concat("/locales")
18
+ I18n.load_path << Dir["#{locales_path}/*.yml"]
19
+ end
20
+
21
+ def get_locale_from_env
22
+ if not ENV['LANGUAGE'].empty? then
23
+ locale = ENV['LANGUAGE'].split('_').first
24
+ elsif not ENV['LANG'].empty? then
25
+ locale = ENV['LANG'].split('_').first
26
+ else
27
+ locale = 'en'
28
+ end
29
+ end
data/lib/overloads.rb CHANGED
@@ -7,4 +7,28 @@ class Numeric
7
7
  def to_deg
8
8
  self * TO_DEG
9
9
  end
10
- end
10
+ end
11
+
12
+ module RDoc
13
+ # File lib/rdoc/usage.rb, line 98
14
+ def RDoc.file_no_exit(filename,*args)
15
+ content = IO.readlines(filename).join
16
+ markup = SM::SimpleMarkup.new
17
+ flow_convertor = SM::ToFlow.new
18
+ flow = markup.convert(content, flow_convertor)
19
+
20
+ format = "plain"
21
+
22
+ unless args.empty?
23
+ flow = extract_sections(flow, args)
24
+ end
25
+
26
+ options = RI::Options.instance
27
+ if args = ENV["RI"]
28
+ options.parse(args.split)
29
+ end
30
+ formatter = options.formatter.new(options, "")
31
+ formatter.display_flow(flow)
32
+ end
33
+ end
34
+
data/lib/robot.rb CHANGED
@@ -14,13 +14,22 @@ module Robot
14
14
  define_method(n){|param| @actions[n] = param }
15
15
  }
16
16
  end
17
-
17
+
18
+ def self.attr_order(*names)
19
+ names.each{|n|
20
+ n = n.to_sym
21
+ define_method(n){ @orders[n] = true }
22
+ }
23
+ end
24
+
18
25
  def self.attr_event(*names)
19
26
  names.each{|n|
20
27
  n = n.to_sym
21
28
  define_method(n){ @events[n] }
22
29
  }
23
30
  end
31
+
32
+
24
33
 
25
34
  #the state hash of your robot. also accessible through the attr_state methods
26
35
  attr_accessor :state
@@ -30,6 +39,8 @@ module Robot
30
39
 
31
40
  #the event hash of your robot
32
41
  attr_accessor :events
42
+
43
+ attr_accessor :orders
33
44
 
34
45
  #path to where your robot's optional skin images are
35
46
  attr_accessor :skin_prefix
@@ -87,6 +98,8 @@ module Robot
87
98
 
88
99
  #fires a bullet in the direction of your gun, power is 0.1 - 3, this power is taken from your energy
89
100
  attr_action :fire
101
+
102
+ attr_order :drop_mine
90
103
 
91
104
  #turns the robot (and the gun and the radar), max 10 degrees per tick
92
105
  attr_action :turn
@@ -99,6 +112,9 @@ module Robot
99
112
 
100
113
  #broadcast message to other robots
101
114
  attr_action :broadcast
115
+
116
+ #team_broadcast message to other robots
117
+ attr_action :team_broadcast
102
118
 
103
119
  #say something to the spectators
104
120
  attr_action :say
@@ -109,12 +125,18 @@ module Robot
109
125
  #distances to robots your radar swept over during last tick
110
126
  attr_event :robot_scanned
111
127
 
112
- #distances to robots your radar swept over during last tick
128
+ #distances to toolboxes your radar swept over during last tick
113
129
  attr_event :toolbox_scanned
130
+
131
+ #distances to mines your radar swept over during last tick
132
+ attr_event :mine_scanned
114
133
 
115
134
  #broadcasts received last turn
116
135
  attr_event :broadcasts
117
136
 
137
+ #Team broadcasts received last turn
138
+ attr_event :team_broadcasts
139
+
118
140
  end
119
141
 
120
142
  require 'robotrunner'
data/lib/robotrunner.rb CHANGED
@@ -2,7 +2,9 @@ class RobotRunner
2
2
 
3
3
  STATE_IVARS = [ :x, :y, :gun_heat, :heading, :gun_heading, :radar_heading, :time, :size, :speed, :energy, :team ]
4
4
  NUMERIC_ACTIONS = [ :fire, :turn, :turn_gun, :turn_radar, :accelerate ]
5
- STRING_ACTIONS = [ :say, :broadcast ]
5
+ STRING_ACTIONS = [ :say, :broadcast, :team_broadcast ]
6
+ ORDERS = [ :drop_mine ]
7
+
6
8
 
7
9
  STATE_IVARS.each{|iv|
8
10
  attr_accessor iv
@@ -14,6 +16,10 @@ class RobotRunner
14
16
  attr_accessor "#{iv}_max"
15
17
  }
16
18
 
19
+ ORDERS.each{|iv|
20
+ attr_accessor "#{iv}_max"
21
+ }
22
+
17
23
  #AI of this robot
18
24
  attr_accessor :robot
19
25
 
@@ -26,10 +32,14 @@ class RobotRunner
26
32
  #keeps track of the kills
27
33
  attr_accessor :kills
28
34
 
35
+ attr_accessor :destroyed_mines
36
+ attr_accessor :trigged_mines
37
+ attr_accessor :dropped_mines
38
+
29
39
  #keeps track of the catched toolboxes
30
40
  attr_accessor :catched_toolboxes
31
41
 
32
- attr_reader :actions, :speech
42
+ attr_reader :actions, :speech, :orders
33
43
 
34
44
  def initialize robot, bf, team=0
35
45
  @robot = robot
@@ -39,6 +49,7 @@ class RobotRunner
39
49
  set_initial_state
40
50
  @events = Hash.new{|h, k| h[k]=[]}
41
51
  @actions = Hash.new(0)
52
+ @orders = Hash.new(0)
42
53
  end
43
54
 
44
55
  def skin_prefix
@@ -57,7 +68,10 @@ class RobotRunner
57
68
  @energy = @battlefield.config.robots[:energy_max]
58
69
  @damage_given = 0
59
70
  @kills = 0
71
+ @destroyed_mines = 0
60
72
  @catched_toolboxes = 0
73
+ @dropped_mines = 0
74
+ @trigged_mines = 0
61
75
  teleport
62
76
  end
63
77
 
@@ -79,6 +93,8 @@ class RobotRunner
79
93
  @teleport_min, @teleport_max = 0, 100
80
94
  @say_max = 256
81
95
  @broadcast_max = 16
96
+ @team_broadcast_max = 16
97
+ @drop_mine_max = @battlefield.config.robots[:nb_mines]
82
98
  end
83
99
 
84
100
  def hit bullet
@@ -115,15 +131,28 @@ class RobotRunner
115
131
  update_state
116
132
  robot_tick
117
133
  parse_actions
134
+ parse_orders
118
135
  fire
136
+ drop_mine if @battlefield.with_mines
119
137
  turn
120
138
  move
121
139
  scan
122
140
  speak
123
141
  broadcast
142
+ team_broadcast
124
143
  @time += 1
125
144
  end
126
145
 
146
+ def parse_orders
147
+ @orders.clear
148
+ ORDERS.each{|on|
149
+ if @robot.orders[on] = true
150
+ @orders[on] = true
151
+ end
152
+ }
153
+ @orders
154
+ end
155
+
127
156
  def parse_actions
128
157
  @actions.clear
129
158
  NUMERIC_ACTIONS.each{|an|
@@ -155,7 +184,10 @@ class RobotRunner
155
184
  @robot.send("#{k}=", v)
156
185
  }
157
186
  @robot.events = @events.dup
187
+ @robot.orders ||= Hash.new(0)
158
188
  @robot.actions ||= Hash.new(0)
189
+ @robot.orders.clear
190
+ @robot.orders[:drop_mine] = false
159
191
  @robot.actions.clear
160
192
  end
161
193
 
@@ -165,7 +197,7 @@ class RobotRunner
165
197
  end
166
198
 
167
199
  def fire
168
- if (@actions[:fire] > 0) && (@gun_heat == 0)
200
+ if (@actions[:fire] > 0) && (@gun_heat == 0)
169
201
  bullet = Bullet.new(@battlefield, @x, @y, @gun_heading, @battlefield.config.bullets[:speed] , @actions[:fire]*3.0, self)
170
202
  3.times{bullet.tick}
171
203
  @battlefield << bullet
@@ -174,6 +206,15 @@ class RobotRunner
174
206
  @gun_heat -= 0.1
175
207
  @gun_heat = 0 if @gun_heat < 0
176
208
  end
209
+
210
+ def drop_mine
211
+ if (@orders[:drop_mine] == true) && (@actions[:fire] == 0) && (@dropped_mines < @drop_mine_max) then
212
+ energy = @battlefield.config.mines[:energy_hit_points]
213
+ mine = Mine.new(@battlefield, @x, @y, energy , self)
214
+ @battlefield << mine
215
+ @dropped_mines += 1
216
+ end
217
+ end
177
218
 
178
219
  def turn
179
220
  @old_radar_heading = @radar_heading
@@ -222,6 +263,17 @@ class RobotRunner
222
263
  end
223
264
  end
224
265
  end
266
+ @battlefield.mines.each do |mine|
267
+ if (!mine.dead)
268
+ a = Math.atan2(@y - mine.y, mine.x - @x) / Math::PI * 180 % 360
269
+ if (@old_radar_heading <= a && a <= @new_radar_heading) || (@old_radar_heading >= a && a >= @new_radar_heading) ||
270
+ (@old_radar_heading <= a+360 && a+360 <= @new_radar_heading) || (@old_radar_heading >= a+360 && a+360 >= new_radar_heading) ||
271
+ (@old_radar_heading <= a-360 && a-360 <= @new_radar_heading) || (@old_radar_heading >= a-360 && a-360 >= @new_radar_heading)
272
+ dist = Math.hypot(@y - mine.y, mine.x - @x)
273
+ @events['mine_scanned'] << [dist] if (dist < @battlefield.config.robots[:radar_mine_scanning_performance]) and (self != mine.origin)
274
+ end
275
+ end
276
+ end
225
277
  end
226
278
 
227
279
  def speak
@@ -233,6 +285,22 @@ class RobotRunner
233
285
  end
234
286
  end
235
287
 
288
+ def team_broadcast
289
+ @battlefield.teams[self.team].each do |other|
290
+ if (other != self) && (!other.dead)
291
+ msg = other.actions[:team_broadcast]
292
+ if msg != 0
293
+ a = Math.atan2(@y - other.y, other.x - @x) / Math::PI * 180 % 360
294
+ dir = 'east'
295
+ dir = 'north' if a.between? 45,135
296
+ dir = 'west' if a.between? 135,225
297
+ dir = 'south' if a.between? 225,315
298
+ @events['team_broadcasts'] << [msg, dir]
299
+ end
300
+ end
301
+ end
302
+ end
303
+
236
304
  def broadcast
237
305
  @battlefield.robots.each do |other|
238
306
  if (other != self) && (!other.dead)
data/lib/tkarena.rb CHANGED
@@ -7,7 +7,7 @@ class TkArena
7
7
 
8
8
  attr_reader :battlefield, :xres, :yres
9
9
  attr_accessor :speed_multiplier, :on_game_over_handlers
10
- attr_accessor :canvas, :boom, :robots, :bullets, :explosions, :colors, :toolboxes, :toolbox_img
10
+ attr_accessor :canvas, :boom, :robots, :bullets, :explosions, :colors, :toolboxes, :toolbox_img, :mines, :mine_img
11
11
  attr_accessor :default_skin_prefix, :path_prefix
12
12
 
13
13
  def initialize battlefield, xres, yres, speed_multiplier
@@ -42,14 +42,6 @@ class TkArena
42
42
  TkPhotoImage.new(:data => Base64.encode64(data))
43
43
  end
44
44
 
45
- def usage
46
- puts "usage: rrobots.rb <FirstRobotClassName[.rb]> <SecondRobotClassName[.rb]> <...>"
47
- puts "\tthe names of the rb files have to match the class names of the robots"
48
- puts "\t(up to 8 robots)"
49
- puts "\te.g. 'ruby rrobots.rb SittingDuck NervousDuck'"
50
- exit
51
- end
52
-
53
45
  def init_canvas
54
46
  @canvas = TkCanvas.new(:height=>yres, :width=>xres, :scrollregion=>[0, 0, xres, yres], :background => '#000000').pack
55
47
  @colors = []
@@ -70,10 +62,11 @@ class TkArena
70
62
  TkPhotoImage.new(:file => "#{path_prefix}/images/explosion#{i.to_s.rjust(2, '0')}.gif")
71
63
  end
72
64
  @toolbox_img = TkPhotoImage.new(:file => "#{path_prefix}/images/toolbox.gif")
65
+ @mine_img = TkPhotoImage.new(:file => "#{path_prefix}/images/mine.gif")
73
66
  end
74
67
 
75
68
  def init_simulation
76
- @robots, @bullets, @explosions, @toolboxes = {}, {}, {}, {}
69
+ @robots, @bullets, @explosions, @toolboxes, @mines = {}, {}, {}, {}, {}
77
70
  TkTimer.new(20, -1, Proc.new{
78
71
  begin
79
72
  draw_frame
@@ -93,9 +86,10 @@ class TkArena
93
86
  @explosions.reject!{|e,tko| @canvas.delete(tko) if e.dead; e.dead }
94
87
  @bullets.reject!{|b,tko| @canvas.delete(tko) if b.dead; b.dead }
95
88
  @toolboxes.reject!{|t,tko| @canvas.delete(tko) if t.dead; t.dead }
89
+ @mines.reject!{|m,tko| @canvas.delete(tko) if m.dead; m.dead }
96
90
  @robots.reject! do |ai,tko|
97
91
  if ai.dead
98
- tko.status.configure(:text => "#{ai.name.ljust(20)} dead")
92
+ tko.status.configure(:text => I18n.t('tkarena.ai_name_dead', :ai_name => ai.name.ljust(20)))
99
93
  tko.each{|part| @canvas.delete(part) if part != tko.status}
100
94
  true
101
95
  end
@@ -106,17 +100,17 @@ class TkArena
106
100
  unless @game_over
107
101
  winner = @robots.keys.first
108
102
  whohaswon = if winner.nil?
109
- "Draw!"
103
+ I18n.t('tkarena.draw')
110
104
  elsif @battlefield.teams.all?{|k,t|t.size<2}
111
- "#{winner.name} won!"
105
+ I18n.t('tkarena.no_team_won', :winner_name => winner.name)
112
106
  else
113
- "Team #{winner.team} won!"
107
+ I18n.t('tkarena.team_won', :winner_team => winner.team)
114
108
  end
115
109
  text_color = winner ? winner.team : 7
116
110
  @game_over = TkcText.new(canvas,
117
111
  :fill => @text_colors[text_color],
118
112
  :anchor => 'c', :coords => [400,400], :font=>'courier 36', :justify => 'center',
119
- :text => "GAME OVER\n#{whohaswon}")
113
+ :text => I18n.t('tkarena.game_over').concat("\n#{whohaswon}"))
120
114
  end
121
115
  end
122
116
  @battlefield.tick
@@ -125,6 +119,7 @@ class TkArena
125
119
 
126
120
  def draw_battlefield
127
121
  draw_toolboxes
122
+ draw_mines
128
123
  draw_robots
129
124
  draw_bullets
130
125
  draw_explosions
@@ -170,6 +165,13 @@ class TkArena
170
165
  bullet.x / 2 + 3, bullet.y / 2 + 3)
171
166
  end
172
167
  end
168
+
169
+ def draw_mines
170
+ @battlefield.mines.each do |mine|
171
+ @mines[mine] ||= TkcImage.new(@canvas, mine.x / 2, mine.y / 2)
172
+ @mines[mine].image(mine_img)
173
+ end
174
+ end
173
175
 
174
176
  def draw_explosions
175
177
  @battlefield.explosions.each do |explosion|
data/robots/Killer.rb CHANGED
@@ -36,7 +36,7 @@ class Killer
36
36
  else
37
37
  @radar_range *= -2 if (@radar_range.abs < 60)
38
38
  end
39
-
39
+ drop_mine if rand(100) == 50
40
40
  fire 3
41
41
 
42
42
  if ((x < 100) || (x > 1500) || (y < 100) || (y > 1500)) && (@escape.nil? || @escape.zero?)
data/robots/MsgBot.rb CHANGED
@@ -4,10 +4,18 @@ class MsgBot
4
4
  include Robot
5
5
 
6
6
  def tick events
7
- events['broadcasts'].each{|msg,dir|
8
- say "Got message #{msg.inspect} from #{dir}!"
9
- }
10
- broadcast "Hello! Team #{team}!" if rand < 0.01
7
+ priv = true
8
+ unless priv then
9
+ events['broadcasts'].each{|msg,dir|
10
+ say "Got message #{msg.inspect} from #{dir}!"
11
+ }
12
+ broadcast "Hello! Team #{team}!" if rand < 0.01
13
+ else
14
+ events['team_broadcasts'].each{|msg,dir|
15
+ say "Got priv message #{msg.inspect} from #{dir}!"
16
+ }
17
+ team_broadcast "Hello! Team #{team}!" if rand < 0.01
18
+ end
11
19
  end
12
20
 
13
21
  end