UG_RRobots 1.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.
- data/bin/rrobots +202 -0
- data/bin/tournament +413 -0
- data/config/rrobots.yml +15 -0
- data/contribs/allbots.rb +0 -0
- data/doc/manual.rdoc +126 -0
- data/doc/manual_fr.rdoc +129 -0
- data/images/explosion00.gif +0 -0
- data/images/explosion01.gif +0 -0
- data/images/explosion02.gif +0 -0
- data/images/explosion03.gif +0 -0
- data/images/explosion04.gif +0 -0
- data/images/explosion05.gif +0 -0
- data/images/explosion06.gif +0 -0
- data/images/explosion07.gif +0 -0
- data/images/explosion08.gif +0 -0
- data/images/explosion09.gif +0 -0
- data/images/explosion10.gif +0 -0
- data/images/explosion11.gif +0 -0
- data/images/explosion12.gif +0 -0
- data/images/explosion13.gif +0 -0
- data/images/explosion14.gif +0 -0
- data/images/red_body000.gif +0 -0
- data/images/red_body010.gif +0 -0
- data/images/red_body020.gif +0 -0
- data/images/red_body030.gif +0 -0
- data/images/red_body040.gif +0 -0
- data/images/red_body050.gif +0 -0
- data/images/red_body060.gif +0 -0
- data/images/red_body070.gif +0 -0
- data/images/red_body080.gif +0 -0
- data/images/red_body090.gif +0 -0
- data/images/red_body100.gif +0 -0
- data/images/red_body110.gif +0 -0
- data/images/red_body120.gif +0 -0
- data/images/red_body130.gif +0 -0
- data/images/red_body140.gif +0 -0
- data/images/red_body150.gif +0 -0
- data/images/red_body160.gif +0 -0
- data/images/red_body170.gif +0 -0
- data/images/red_body180.gif +0 -0
- data/images/red_body190.gif +0 -0
- data/images/red_body200.gif +0 -0
- data/images/red_body210.gif +0 -0
- data/images/red_body220.gif +0 -0
- data/images/red_body230.gif +0 -0
- data/images/red_body240.gif +0 -0
- data/images/red_body250.gif +0 -0
- data/images/red_body260.gif +0 -0
- data/images/red_body270.gif +0 -0
- data/images/red_body280.gif +0 -0
- data/images/red_body290.gif +0 -0
- data/images/red_body300.gif +0 -0
- data/images/red_body310.gif +0 -0
- data/images/red_body320.gif +0 -0
- data/images/red_body330.gif +0 -0
- data/images/red_body340.gif +0 -0
- data/images/red_body350.gif +0 -0
- data/images/red_radar000.gif +0 -0
- data/images/red_radar010.gif +0 -0
- data/images/red_radar020.gif +0 -0
- data/images/red_radar030.gif +0 -0
- data/images/red_radar040.gif +0 -0
- data/images/red_radar050.gif +0 -0
- data/images/red_radar060.gif +0 -0
- data/images/red_radar070.gif +0 -0
- data/images/red_radar080.gif +0 -0
- data/images/red_radar090.gif +0 -0
- data/images/red_radar100.gif +0 -0
- data/images/red_radar110.gif +0 -0
- data/images/red_radar120.gif +0 -0
- data/images/red_radar130.gif +0 -0
- data/images/red_radar140.gif +0 -0
- data/images/red_radar150.gif +0 -0
- data/images/red_radar160.gif +0 -0
- data/images/red_radar170.gif +0 -0
- data/images/red_radar180.gif +0 -0
- data/images/red_radar190.gif +0 -0
- data/images/red_radar200.gif +0 -0
- data/images/red_radar210.gif +0 -0
- data/images/red_radar220.gif +0 -0
- data/images/red_radar230.gif +0 -0
- data/images/red_radar240.gif +0 -0
- data/images/red_radar250.gif +0 -0
- data/images/red_radar260.gif +0 -0
- data/images/red_radar270.gif +0 -0
- data/images/red_radar280.gif +0 -0
- data/images/red_radar290.gif +0 -0
- data/images/red_radar300.gif +0 -0
- data/images/red_radar310.gif +0 -0
- data/images/red_radar320.gif +0 -0
- data/images/red_radar330.gif +0 -0
- data/images/red_radar340.gif +0 -0
- data/images/red_radar350.gif +0 -0
- data/images/red_turret000.gif +0 -0
- data/images/red_turret010.gif +0 -0
- data/images/red_turret020.gif +0 -0
- data/images/red_turret030.gif +0 -0
- data/images/red_turret040.gif +0 -0
- data/images/red_turret050.gif +0 -0
- data/images/red_turret060.gif +0 -0
- data/images/red_turret070.gif +0 -0
- data/images/red_turret080.gif +0 -0
- data/images/red_turret090.gif +0 -0
- data/images/red_turret100.gif +0 -0
- data/images/red_turret110.gif +0 -0
- data/images/red_turret120.gif +0 -0
- data/images/red_turret130.gif +0 -0
- data/images/red_turret140.gif +0 -0
- data/images/red_turret150.gif +0 -0
- data/images/red_turret160.gif +0 -0
- data/images/red_turret170.gif +0 -0
- data/images/red_turret180.gif +0 -0
- data/images/red_turret190.gif +0 -0
- data/images/red_turret200.gif +0 -0
- data/images/red_turret210.gif +0 -0
- data/images/red_turret220.gif +0 -0
- data/images/red_turret230.gif +0 -0
- data/images/red_turret240.gif +0 -0
- data/images/red_turret250.gif +0 -0
- data/images/red_turret260.gif +0 -0
- data/images/red_turret270.gif +0 -0
- data/images/red_turret280.gif +0 -0
- data/images/red_turret290.gif +0 -0
- data/images/red_turret300.gif +0 -0
- data/images/red_turret310.gif +0 -0
- data/images/red_turret320.gif +0 -0
- data/images/red_turret330.gif +0 -0
- data/images/red_turret340.gif +0 -0
- data/images/red_turret350.gif +0 -0
- data/images/toolbox.gif +0 -0
- data/lib/battlefield.rb +102 -0
- data/lib/bullets.rb +39 -0
- data/lib/configuration.rb +26 -0
- data/lib/explosions.rb +20 -0
- data/lib/overloads.rb +10 -0
- data/lib/robot.rb +122 -0
- data/lib/robotrunner.rb +260 -0
- data/lib/tkarena.rb +197 -0
- data/lib/toolboxes.rb +28 -0
- data/robots/BillDuck.rb +92 -0
- data/robots/BotOne.rb +39 -0
- data/robots/DuckBill.rb +384 -0
- data/robots/DuckBill04.rb +330 -0
- data/robots/DuckToEndAllDucks.rb +140 -0
- data/robots/EdgeBot.rb +203 -0
- data/robots/HuntingDuck.rb +74 -0
- data/robots/HyperactiveDuck.rb +15 -0
- data/robots/Killer.rb +58 -0
- data/robots/Kite.rb +193 -0
- data/robots/KoDuck.rb +57 -0
- data/robots/LinearShooter.rb +279 -0
- data/robots/LuckyDuck.rb +83 -0
- data/robots/MoxonoM.rb +85 -0
- data/robots/MsgBot.rb +13 -0
- data/robots/NervousDuck.rb +13 -0
- data/robots/Polisher.rb +15 -0
- data/robots/RomBot.rb +514 -0
- data/robots/RoomPainter.rb +205 -0
- data/robots/Rrrkele.rb +48 -0
- data/robots/Seeker.rb +57 -0
- data/robots/ShootingStation.rb +15 -0
- data/robots/SittingDuck.rb +18 -0
- data/robots/SniperDuck.rb +277 -0
- data/robots/WallPainter.rb +224 -0
- metadata +220 -0
data/lib/tkarena.rb
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
require 'tk'
|
|
2
|
+
require 'base64'
|
|
3
|
+
|
|
4
|
+
TkRobot = Struct.new(:body, :gun, :radar, :speech, :info, :status)
|
|
5
|
+
|
|
6
|
+
class TkArena
|
|
7
|
+
|
|
8
|
+
attr_reader :battlefield, :xres, :yres
|
|
9
|
+
attr_accessor :speed_multiplier, :on_game_over_handlers
|
|
10
|
+
attr_accessor :canvas, :boom, :robots, :bullets, :explosions, :colors, :toolboxes, :toolbox_img
|
|
11
|
+
attr_accessor :default_skin_prefix, :path_prefix
|
|
12
|
+
|
|
13
|
+
def initialize battlefield, xres, yres, speed_multiplier
|
|
14
|
+
@battlefield = battlefield
|
|
15
|
+
@xres, @yres = xres, yres
|
|
16
|
+
@speed_multiplier = speed_multiplier
|
|
17
|
+
@text_colors = ['#ff0000', '#00ff00', '#0000ff', '#ffff00', '#00ffff', '#ff00ff', '#ffffff', '#777777']
|
|
18
|
+
|
|
19
|
+
# TODO : Perhaps a better way to do it ...
|
|
20
|
+
# regarder Rubygems pour avoir le path direct ..
|
|
21
|
+
table_map = Gem.location_of_caller.first.split('/')
|
|
22
|
+
2.times do
|
|
23
|
+
table_map.pop
|
|
24
|
+
end
|
|
25
|
+
@path_prefix = table_map.join('/')
|
|
26
|
+
|
|
27
|
+
@default_skin_prefix = "images/red_"
|
|
28
|
+
@on_game_over_handlers = []
|
|
29
|
+
init_canvas
|
|
30
|
+
init_simulation
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def on_game_over(&block)
|
|
34
|
+
@on_game_over_handlers << block
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def read_gif name, c1, c2, c3
|
|
38
|
+
data = nil
|
|
39
|
+
open(name, 'rb') do |f|
|
|
40
|
+
data = f.read()
|
|
41
|
+
ncolors = 2**(1 + data[10][0] + data[10][1] * 2 + data[10][2] * 4)
|
|
42
|
+
ncolors.times do |j|
|
|
43
|
+
data[13 + j * 3 + 0], data[13 + j * 3 + 1], data[13 + j * 3 + 2] =
|
|
44
|
+
data[13 + j * 3 + c1], data[13 + j * 3 + c2], data[13 + j * 3 + c3]
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
TkPhotoImage.new(:data => Base64.encode64(data))
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def usage
|
|
51
|
+
puts "usage: rrobots.rb <FirstRobotClassName[.rb]> <SecondRobotClassName[.rb]> <...>"
|
|
52
|
+
puts "\tthe names of the rb files have to match the class names of the robots"
|
|
53
|
+
puts "\t(up to 8 robots)"
|
|
54
|
+
puts "\te.g. 'ruby rrobots.rb SittingDuck NervousDuck'"
|
|
55
|
+
exit
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def init_canvas
|
|
59
|
+
@canvas = TkCanvas.new(:height=>yres, :width=>xres, :scrollregion=>[0, 0, xres, yres], :background => '#000000').pack
|
|
60
|
+
@colors = []
|
|
61
|
+
[[0,1,1],[1,0,1],[1,1,0],[0,0,1],[1,0,0],[0,1,0],[0,0,0],[1,1,1]][0...@battlefield.robots.length].zip(@battlefield.robots) do |color, robot|
|
|
62
|
+
bodies, guns, radars = [], [], []
|
|
63
|
+
image_path = robot.skin_prefix || @default_skin_prefix
|
|
64
|
+
image_path = "#{@path_prefix}/#{image_path}"
|
|
65
|
+
reader = robot.skin_prefix ? lambda{|fn| TkPhotoImage.new(:file => fn) } : lambda{|fn| read_gif(fn, *color)}
|
|
66
|
+
36.times do |i|
|
|
67
|
+
bodies << reader["#{image_path}body#{(i*10).to_s.rjust(3, '0')}.gif"]
|
|
68
|
+
guns << reader["#{image_path}turret#{(i*10).to_s.rjust(3, '0')}.gif"]
|
|
69
|
+
radars << reader["#{image_path}radar#{(i*10).to_s.rjust(3, '0')}.gif"]
|
|
70
|
+
end
|
|
71
|
+
@colors << TkRobot.new(bodies << bodies[0], guns << guns[0], radars << radars[0])
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
@boom = (0..14).map do |i|
|
|
75
|
+
TkPhotoImage.new(:file => "#{path_prefix}/images/explosion#{i.to_s.rjust(2, '0')}.gif")
|
|
76
|
+
end
|
|
77
|
+
@toolbox_img = TkPhotoImage.new(:file => "#{path_prefix}/images/toolbox.gif")
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def init_simulation
|
|
81
|
+
@robots, @bullets, @explosions, @toolboxes = {}, {}, {}, {}
|
|
82
|
+
TkTimer.new(20, -1, Proc.new{
|
|
83
|
+
begin
|
|
84
|
+
draw_frame
|
|
85
|
+
rescue => err
|
|
86
|
+
puts err.class, err, err.backtrace
|
|
87
|
+
raise
|
|
88
|
+
end
|
|
89
|
+
}).start
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def draw_frame
|
|
93
|
+
simulate(@speed_multiplier)
|
|
94
|
+
draw_battlefield
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def simulate(ticks=1)
|
|
98
|
+
@explosions.reject!{|e,tko| @canvas.delete(tko) if e.dead; e.dead }
|
|
99
|
+
@bullets.reject!{|b,tko| @canvas.delete(tko) if b.dead; b.dead }
|
|
100
|
+
@toolboxes.reject!{|t,tko| @canvas.delete(tko) if t.dead; t.dead }
|
|
101
|
+
@robots.reject! do |ai,tko|
|
|
102
|
+
if ai.dead
|
|
103
|
+
tko.status.configure(:text => "#{ai.name.ljust(20)} dead")
|
|
104
|
+
tko.each{|part| @canvas.delete(part) if part != tko.status}
|
|
105
|
+
true
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
ticks.times do
|
|
109
|
+
if @battlefield.game_over
|
|
110
|
+
@on_game_over_handlers.each{|h| h.call(@battlefield) }
|
|
111
|
+
unless @game_over
|
|
112
|
+
winner = @robots.keys.first
|
|
113
|
+
whohaswon = if winner.nil?
|
|
114
|
+
"Draw!"
|
|
115
|
+
elsif @battlefield.teams.all?{|k,t|t.size<2}
|
|
116
|
+
"#{winner.name} won!"
|
|
117
|
+
else
|
|
118
|
+
"Team #{winner.team} won!"
|
|
119
|
+
end
|
|
120
|
+
text_color = winner ? winner.team : 7
|
|
121
|
+
@game_over = TkcText.new(canvas,
|
|
122
|
+
:fill => @text_colors[text_color],
|
|
123
|
+
:anchor => 'c', :coords => [400,400], :font=>'courier 36', :justify => 'center',
|
|
124
|
+
:text => "GAME OVER\n#{whohaswon}")
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
@battlefield.tick
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def draw_battlefield
|
|
132
|
+
draw_toolboxes
|
|
133
|
+
draw_robots
|
|
134
|
+
draw_bullets
|
|
135
|
+
draw_explosions
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def draw_robots
|
|
139
|
+
@battlefield.robots.each_with_index do |ai, i|
|
|
140
|
+
next if ai.dead
|
|
141
|
+
@robots[ai] ||= TkRobot.new(
|
|
142
|
+
TkcImage.new(@canvas, 0, 0),
|
|
143
|
+
TkcImage.new(@canvas, 0, 0),
|
|
144
|
+
TkcImage.new(@canvas, 0, 0),
|
|
145
|
+
TkcText.new(@canvas,
|
|
146
|
+
:fill => @text_colors[ai.team],
|
|
147
|
+
:anchor => 's', :justify => 'center', :coords => [ai.x / 2, ai.y / 2 - ai.size / 2]),
|
|
148
|
+
TkcText.new(@canvas,
|
|
149
|
+
:fill => @text_colors[ai.team],
|
|
150
|
+
:anchor => 'n', :justify => 'center', :coords => [ai.x / 2, ai.y / 2 + ai.size / 2]),
|
|
151
|
+
TkcText.new(@canvas,
|
|
152
|
+
:fill => @text_colors[ai.team],
|
|
153
|
+
:anchor => 'nw', :coords => [10, 15 * i + 10], :font => TkFont.new("courier 9")))
|
|
154
|
+
@robots[ai].body.configure( :image => @colors[ai.team].body[(ai.heading+5) / 10],
|
|
155
|
+
:coords => [ai.x / 2, ai.y / 2])
|
|
156
|
+
@robots[ai].gun.configure( :image => @colors[ai.team].gun[(ai.gun_heading+5) / 10],
|
|
157
|
+
:coords => [ai.x / 2, ai.y / 2])
|
|
158
|
+
@robots[ai].radar.configure(:image => @colors[ai.team].radar[(ai.radar_heading+5) / 10],
|
|
159
|
+
:coords => [ai.x / 2, ai.y / 2])
|
|
160
|
+
@robots[ai].speech.configure(:text => "#{ai.speech}",
|
|
161
|
+
:coords => [ai.x / 2, ai.y / 2 - ai.size / 2])
|
|
162
|
+
@robots[ai].info.configure(:text => "#{ai.name}\n#{'|' * (ai.energy / 5)}",
|
|
163
|
+
:coords => [ai.x / 2, ai.y / 2 + ai.size / 2])
|
|
164
|
+
@robots[ai].status.configure(:text => "#{ai.name.ljust(20)} #{'%.1f' % ai.energy}")
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def draw_bullets
|
|
169
|
+
@battlefield.bullets.each do |bullet|
|
|
170
|
+
@bullets[bullet] ||= TkcOval.new(
|
|
171
|
+
@canvas, [-2, -2], [3, 3],
|
|
172
|
+
:fill=>'#'+("%02x" % (128+bullet.energy*14).to_i)*3)
|
|
173
|
+
@bullets[bullet].coords(
|
|
174
|
+
bullet.x / 2 - 2, bullet.y / 2 - 2,
|
|
175
|
+
bullet.x / 2 + 3, bullet.y / 2 + 3)
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def draw_explosions
|
|
180
|
+
@battlefield.explosions.each do |explosion|
|
|
181
|
+
@explosions[explosion] ||= TkcImage.new(@canvas, explosion.x / 2, explosion.y / 2)
|
|
182
|
+
@explosions[explosion].image(boom[explosion.t])
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def draw_toolboxes
|
|
187
|
+
@battlefield.toolboxes.each do |toolbox|
|
|
188
|
+
@toolboxes[toolbox] ||= TkcImage.new(@canvas, toolbox.x / 2, toolbox.y / 2)
|
|
189
|
+
@toolboxes[toolbox].image(toolbox_img)
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
def run
|
|
194
|
+
Tk.mainloop
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
end
|
data/lib/toolboxes.rb
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
class Toolbox
|
|
2
|
+
attr_accessor :x
|
|
3
|
+
attr_accessor :y
|
|
4
|
+
attr_accessor :t
|
|
5
|
+
attr_accessor :dead
|
|
6
|
+
attr_accessor :energy
|
|
7
|
+
|
|
8
|
+
def initialize bf, x, y, t, energy
|
|
9
|
+
@x, @y, @t = x, y, t
|
|
10
|
+
@battlefield, @energy, @dead = bf, energy, false
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def state
|
|
14
|
+
{:x=>x, :y=>y, :energy=>energy}
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def tick
|
|
18
|
+
@t += 1
|
|
19
|
+
@dead ||= t > @battlefield.config.toolboxes[:life_time]
|
|
20
|
+
@battlefield.robots.each do |robot|
|
|
21
|
+
if Math.hypot(@y - robot.y, robot.x - @x) < 20 && (!robot.dead)
|
|
22
|
+
healing = robot.heal(self)
|
|
23
|
+
@dead = true
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
end
|
data/robots/BillDuck.rb
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
require 'robot'
|
|
2
|
+
|
|
3
|
+
class BillDuck
|
|
4
|
+
include Robot
|
|
5
|
+
def min(a,b)
|
|
6
|
+
(a < b)? a : b
|
|
7
|
+
end
|
|
8
|
+
def aimtank(angle,rate)
|
|
9
|
+
error = (360 + angle - heading) % 360
|
|
10
|
+
if error > 180
|
|
11
|
+
turn -min(360-error,rate)
|
|
12
|
+
else
|
|
13
|
+
turn min(error,rate)
|
|
14
|
+
end
|
|
15
|
+
error == 0
|
|
16
|
+
end
|
|
17
|
+
def aimgun(angle,rate)
|
|
18
|
+
error = (360 + angle - gun_heading) % 360
|
|
19
|
+
if error > 180
|
|
20
|
+
turn_gun -min(360-error,rate)
|
|
21
|
+
else
|
|
22
|
+
turn_gun min(error,rate)
|
|
23
|
+
end
|
|
24
|
+
error == 0
|
|
25
|
+
end
|
|
26
|
+
def aimrad(angle,rate)
|
|
27
|
+
error = (360 + angle - radar_heading) % 360
|
|
28
|
+
if error > 180
|
|
29
|
+
turn_radar -min(360-error,rate)
|
|
30
|
+
else
|
|
31
|
+
turn_radar min(error,rate)
|
|
32
|
+
end
|
|
33
|
+
error == 0
|
|
34
|
+
end
|
|
35
|
+
def tick events
|
|
36
|
+
#mode nil is startup and initialize variables
|
|
37
|
+
if @mode == nil
|
|
38
|
+
@mode = 0
|
|
39
|
+
@stage = 0
|
|
40
|
+
@dir = 0
|
|
41
|
+
@firecnt = 0
|
|
42
|
+
@timer = 0
|
|
43
|
+
@sincehit = 100
|
|
44
|
+
@sinceblip = 100
|
|
45
|
+
#mode 0 is turn to new heading
|
|
46
|
+
elsif @mode == 0
|
|
47
|
+
a,b,c = aimtank(@dir*90,10),aimgun(@dir*90,30),aimrad(@dir*90,60)
|
|
48
|
+
@stage = 0
|
|
49
|
+
@mode = 1 if a and b and c
|
|
50
|
+
#mode 1 is look forward down the wall
|
|
51
|
+
elsif @mode == 1
|
|
52
|
+
(@stage%2==0)? aimrad(@dir*90 + 5,60) : aimrad(@dir*90-5,60)
|
|
53
|
+
if @stage > 2 and @sinceblip > 2
|
|
54
|
+
@mode,@stage = 2,0
|
|
55
|
+
else
|
|
56
|
+
@stage += 1
|
|
57
|
+
end
|
|
58
|
+
#mode 2 is look backward down the wall
|
|
59
|
+
elsif @mode == 2
|
|
60
|
+
if @stage == 0
|
|
61
|
+
a,b = aimgun(@dir*90 + 180,30), aimrad(@dir*90 + 180,60)
|
|
62
|
+
@stage += 1 if a and b
|
|
63
|
+
else
|
|
64
|
+
(@stage%2==0)? aimrad(@dir*90 + 185,10) : aimrad(@dir*90 +175,10)
|
|
65
|
+
@stage += 1
|
|
66
|
+
end
|
|
67
|
+
if @stage > 2 and @sinceblip > 2
|
|
68
|
+
@mode,@stage = 3,0
|
|
69
|
+
end
|
|
70
|
+
#mode 3 is scan towards the center of the arena and run down the wall
|
|
71
|
+
elsif @mode == 3
|
|
72
|
+
if @stage == 0
|
|
73
|
+
a,b = aimgun(@dir*90 + 90,30), aimrad(@dir*90 + 80,60)
|
|
74
|
+
@stage += 1 if a and b
|
|
75
|
+
else
|
|
76
|
+
@stage += 1
|
|
77
|
+
(@stage%2 == 0)? aimrad(@dir*90 + 90,10) : aimrad(@dir*90 + 80,10)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
walls = [battlefield_width - x,y,x,battlefield_height - y]
|
|
81
|
+
if walls[@dir] < 100
|
|
82
|
+
@mode,@stage,@dir = 0,0,(@dir+1)%4
|
|
83
|
+
end
|
|
84
|
+
accelerate 1
|
|
85
|
+
@sincehit += 1
|
|
86
|
+
@sincehit = 0 if not events['got_hit'].empty?
|
|
87
|
+
@sinceblip += 1
|
|
88
|
+
@sinceblip = 0 if not events['robot_scanned'].empty?
|
|
89
|
+
fire 0.1
|
|
90
|
+
STDOUT.flush
|
|
91
|
+
end
|
|
92
|
+
end
|
data/robots/BotOne.rb
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require 'robot'
|
|
2
|
+
|
|
3
|
+
class BotOne
|
|
4
|
+
include Robot
|
|
5
|
+
def tick events
|
|
6
|
+
@rapid_fire = 0 if @rapid_fire.nil?
|
|
7
|
+
@last_seen = 0 if @last_seen.nil?
|
|
8
|
+
@turn_speed = 3 if @turn_speed.nil?
|
|
9
|
+
|
|
10
|
+
if time - @last_seen > 200
|
|
11
|
+
@turn_speed *= -1
|
|
12
|
+
@last_seen = time
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
turn @turn_speed
|
|
16
|
+
|
|
17
|
+
if( @rapid_fire > 0 )
|
|
18
|
+
fire 0.84
|
|
19
|
+
turn_gun -(@turn_speed / @turn_speed) *2
|
|
20
|
+
@rapid_fire = @rapid_fire - 1
|
|
21
|
+
else
|
|
22
|
+
turn_gun @turn_speed * 1.25
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
if( !events['robot_scanned'].empty? )
|
|
26
|
+
@turn_speed *= -1
|
|
27
|
+
@last_seen = time
|
|
28
|
+
@rapid_fire = 20
|
|
29
|
+
end
|
|
30
|
+
@last_hit = time unless events['got_hit'].empty?
|
|
31
|
+
if @last_hit && time - @last_hit < 20
|
|
32
|
+
accelerate(-1)
|
|
33
|
+
else
|
|
34
|
+
accelerate 1
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
|
data/robots/DuckBill.rb
ADDED
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
require 'robot'
|
|
2
|
+
class Tracking
|
|
3
|
+
def debug(a)
|
|
4
|
+
print a if @trkdbg
|
|
5
|
+
STDOUT.flush if @trkdbg
|
|
6
|
+
end
|
|
7
|
+
def initialize(width,height)
|
|
8
|
+
@trkdbg = false
|
|
9
|
+
@tracking = []
|
|
10
|
+
@width = width
|
|
11
|
+
@height = height
|
|
12
|
+
end
|
|
13
|
+
def add(x,y,angle,dist,time)
|
|
14
|
+
@tracking << [x + Math::cos(angle.to_rad)*dist,y + Math::sin(angle.to_rad)*dist,time]
|
|
15
|
+
debug "added track angle=#{angle},dist=#{dist},#{@tracking.last.inspect}\n"
|
|
16
|
+
end
|
|
17
|
+
def trim(time)
|
|
18
|
+
#delete really old samples
|
|
19
|
+
@tracking.delete_if{|e| time - e[2] > 30}
|
|
20
|
+
#limit to 10 samples
|
|
21
|
+
@tracking.shift while @tracking.size>10
|
|
22
|
+
#eliminate samples if they came from a different robot. we can tell this because they have max speed of 8
|
|
23
|
+
gap = 0
|
|
24
|
+
(@tracking.size- 1).times{|i|
|
|
25
|
+
if v=velocity(@tracking[i],@tracking[i+1]) > 25
|
|
26
|
+
gap = i+1
|
|
27
|
+
debug "traking gap #{@tracking[i].inspect},#{@tracking[i+1].inspect},v\n"
|
|
28
|
+
end
|
|
29
|
+
}
|
|
30
|
+
gap.times{@tracking.shift}
|
|
31
|
+
#normalize the time
|
|
32
|
+
#@tracking.size.times{|i| @tracking[@tracking.size-1-i][2] -=@tracking[0][2]}
|
|
33
|
+
end
|
|
34
|
+
def velocity (e1,e2)
|
|
35
|
+
distance(e1[0],e1[1],e2[0],e2[1])/(e1[2]-e2[2]).abs
|
|
36
|
+
end
|
|
37
|
+
def distance (x1,y1,x2,y2)
|
|
38
|
+
((x1-x2)**2 + (y1-y2)**2)**(0.5)
|
|
39
|
+
end
|
|
40
|
+
def findline
|
|
41
|
+
sx=sy=st=sxt=syt=stt=0.0
|
|
42
|
+
@tracking.each{|e|
|
|
43
|
+
debug " findline element = #{e.inspect}\n"
|
|
44
|
+
sx += e[0]
|
|
45
|
+
sxt += e[2]*e[0]
|
|
46
|
+
sy += e[1]
|
|
47
|
+
syt += e[2]*e[1]
|
|
48
|
+
st += e[2]
|
|
49
|
+
stt += e[2]*e[2]
|
|
50
|
+
}
|
|
51
|
+
n=@tracking.size
|
|
52
|
+
c2 = (sxt/st-sx/n)/(stt/st-st/n)
|
|
53
|
+
c1 = sx/n-(st/n)*c2
|
|
54
|
+
f2 = (syt/st-sy/n)/(stt/st-st/n)
|
|
55
|
+
f1 = sy/n-(st/n)*f2
|
|
56
|
+
debug "x = #{c2}t + #{c1}\n"
|
|
57
|
+
debug "y = #{f2}t + #{f1}\n"
|
|
58
|
+
[c2,c1,f2,f1]
|
|
59
|
+
end
|
|
60
|
+
def predict(x,y,time)
|
|
61
|
+
trim(time)
|
|
62
|
+
if @tracking.size < 1
|
|
63
|
+
return false
|
|
64
|
+
elsif @tracking.size == 1
|
|
65
|
+
interceptx,intercepty = @tracking[0][0],@tracking[0][1]
|
|
66
|
+
else
|
|
67
|
+
a,b,c,d = findline
|
|
68
|
+
intercepttime = time + distance(a*time+b,c*time+d,x,y)/60.0
|
|
69
|
+
#interceptx,intercepty = limitcoord(intercepttime*a + b, intercepttime*c+d)
|
|
70
|
+
interceptx,intercepty = intercepttime*a + b, intercepttime*c+d
|
|
71
|
+
end
|
|
72
|
+
debug"intercept at (#{interceptx},#{intercepty},#{intercepttime})\n"
|
|
73
|
+
angle = (Math.atan2(intercepty - y,interceptx - x) * 180 / Math::PI)%360
|
|
74
|
+
debug "firing angle is #{angle}\n"
|
|
75
|
+
angle
|
|
76
|
+
end
|
|
77
|
+
def limitcoord(x,y)
|
|
78
|
+
nx=[x,0.0].max
|
|
79
|
+
nx = [nx,@width.to_f].min
|
|
80
|
+
ny = [ny,@height.to_f].min
|
|
81
|
+
[nx,ny]
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
class DuckBill
|
|
86
|
+
include Robot
|
|
87
|
+
@@ScanRes = [1,2,4,8,16,32,60]
|
|
88
|
+
# ###########
|
|
89
|
+
# # Initialize
|
|
90
|
+
# ###########
|
|
91
|
+
def initialize *bf
|
|
92
|
+
if bf.size != 0
|
|
93
|
+
super(bf[0])
|
|
94
|
+
@tourney = false
|
|
95
|
+
else
|
|
96
|
+
super
|
|
97
|
+
@tourney = true
|
|
98
|
+
end
|
|
99
|
+
@mode = 0 # mode of high level logic
|
|
100
|
+
@stage = 0 # sequences within mode
|
|
101
|
+
@dir = 0 # direction we are going
|
|
102
|
+
@walldir = 1 # dirrection we travel around perimeter in, 1 = ccw,-1=cw
|
|
103
|
+
@hit_filter = 0 #low pass filter tells how much damage we are taking
|
|
104
|
+
@sincehit = 100 #how long since we were hit
|
|
105
|
+
@sinceblip = 100 #how long since we saw someone in our radar
|
|
106
|
+
@since_evade = 0 #time since we took evasive action
|
|
107
|
+
@closest = 0 #distance to closest robot scanned since last tick
|
|
108
|
+
@range = 10000 #distance of closest robot
|
|
109
|
+
@mytrack = Tracking.new(battlefield_width,battlefield_height)
|
|
110
|
+
@turns = [0,0,0,0,0,0,0,0,0,0,0,0] # holds data for turn/aim calculations
|
|
111
|
+
end
|
|
112
|
+
# ###########
|
|
113
|
+
# # Controls
|
|
114
|
+
# ###########
|
|
115
|
+
def min(a,b)
|
|
116
|
+
(a < b)? a : b
|
|
117
|
+
end
|
|
118
|
+
def max(a,b)
|
|
119
|
+
(a > b)? a : b
|
|
120
|
+
end
|
|
121
|
+
#dir is 1 for ccw, -1 for cw, and 0 for whichever is quickest
|
|
122
|
+
def aimtank(angle,rate=10,dir=0)
|
|
123
|
+
@turns[0,3] = angle%360,rate,dir
|
|
124
|
+
angle%360 == heading
|
|
125
|
+
end
|
|
126
|
+
def aimgun(angle,rate=30,dir=0)
|
|
127
|
+
@turns[4,3] = angle%360,rate,dir
|
|
128
|
+
angle%360 == gun_heading
|
|
129
|
+
end
|
|
130
|
+
def aimrad(angle,rate=60,dir=0)
|
|
131
|
+
@turns[8,3] = angle%360,rate,dir
|
|
132
|
+
angle%360 == radar_heading
|
|
133
|
+
end
|
|
134
|
+
def doturns
|
|
135
|
+
#this translates directional commands from robot into motor actions
|
|
136
|
+
#turns: 0=desired heading, 1=max speed,2=dir[1=ccw,-1=cw,0=fastest],
|
|
137
|
+
# 3=computed turn, 0-3 for tank, 4-7 for gun, 8-11 for radar
|
|
138
|
+
#compute turns for tank, gun, and radar headings
|
|
139
|
+
#print "computed turns = #{@turns.inspect}\n"
|
|
140
|
+
ccw = (@turns[0] - heading) % 360
|
|
141
|
+
cw = 360 - ccw
|
|
142
|
+
dir = (@turns[2] == 0)? ((ccw<cw)? 1 : -1) : @turns[2]
|
|
143
|
+
@turns[3] = dir * min((dir==1)? ccw : cw,@turns[1])
|
|
144
|
+
ccw = (@turns[4] - @turns[3] - gun_heading) % 360
|
|
145
|
+
cw = 360 - ccw
|
|
146
|
+
dir = (@turns[6] == 0)? ((ccw<cw)? 1 : -1) : @turns[6]
|
|
147
|
+
@turns[7] = dir * min((dir==1)? ccw : cw,@turns[5])
|
|
148
|
+
ccw = (@turns[8] - @turns[7] - @turns[3] - radar_heading) % 360
|
|
149
|
+
cw = 360 - ccw
|
|
150
|
+
dir = (@turns[10] == 0)? ((ccw<cw)? 1 : -1) : @turns[10]
|
|
151
|
+
@turns[11] = dir * min(((dir==1)? ccw : cw),@turns[9])
|
|
152
|
+
#print "computed turns = #{@turns.inspect}\n"
|
|
153
|
+
turn @turns[3]
|
|
154
|
+
turn_gun @turns[7]
|
|
155
|
+
turn_radar @turns[11]
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# ###########
|
|
159
|
+
# # TICK, the Robot code
|
|
160
|
+
# ###########
|
|
161
|
+
def tick events
|
|
162
|
+
@outerlimit = (battlefield_width + battlefield_height) * 3
|
|
163
|
+
#print "mode=#{@mode},stage=#{@stage},dir=#{@dir},walldir=#{@walldir}\n"
|
|
164
|
+
#print "at (#{x},#{y}) at time #{time},res=#{@trk_res}\n"
|
|
165
|
+
#mode nil is startup and initialize variables
|
|
166
|
+
#STDOUT.flush
|
|
167
|
+
# ###########
|
|
168
|
+
# # Sensors
|
|
169
|
+
# ###########
|
|
170
|
+
@since_evade += 1
|
|
171
|
+
@sincehit += 1
|
|
172
|
+
@sincehit = 0 if not events['got_hit'].empty?
|
|
173
|
+
events['got_hit'].each{|e| @hit_filter += e.first}
|
|
174
|
+
@hit_filter *= 0.99
|
|
175
|
+
if events['robot_scanned'].empty?
|
|
176
|
+
@sinceblip += 1
|
|
177
|
+
@closest = @outerlimit
|
|
178
|
+
#print"\n"
|
|
179
|
+
else
|
|
180
|
+
@closest = events['robot_scanned'].collect{|e| e.first}.sort.first
|
|
181
|
+
@sinceblip = 0
|
|
182
|
+
#print ",blip=#{@closest}\n"
|
|
183
|
+
end
|
|
184
|
+
# ###########
|
|
185
|
+
# # High level logic - state machine
|
|
186
|
+
# ###########
|
|
187
|
+
#print "sincehit=#{@sincehit},closest=#{@closest},range=#{@range}\n"
|
|
188
|
+
#mode 0 is orient tank
|
|
189
|
+
if @mode == 0
|
|
190
|
+
@stage = 0
|
|
191
|
+
@range = @outerlimit
|
|
192
|
+
@mode = 1 if aimrad(@dir*90)
|
|
193
|
+
#mode 1 find range of nearest target
|
|
194
|
+
elsif @mode == 1
|
|
195
|
+
#setup radar for a scan
|
|
196
|
+
if @stage==0
|
|
197
|
+
aimrad(@dir*90 + 180,60,1)
|
|
198
|
+
@range = min(@range,@closest)
|
|
199
|
+
@stage +=1
|
|
200
|
+
#continue around for full circle
|
|
201
|
+
elsif @stage == 1
|
|
202
|
+
@range = min(@range,@closest)
|
|
203
|
+
if aimrad(@dir*90,60,1)
|
|
204
|
+
#did we see a bot?
|
|
205
|
+
if @range == @outerlimit
|
|
206
|
+
@stage = 0
|
|
207
|
+
else
|
|
208
|
+
@mode = 2
|
|
209
|
+
@stage = 0
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
#mode 2: find the nearestbot
|
|
214
|
+
elsif @mode == 2
|
|
215
|
+
#start next circle to re find the closest bot
|
|
216
|
+
if @stage == 0
|
|
217
|
+
#print "range is #{@range}\n"
|
|
218
|
+
aimrad(@dir*90 + 180,60,1)
|
|
219
|
+
@stage +=1
|
|
220
|
+
#continue scan for the closest bot
|
|
221
|
+
elsif @stage == 1
|
|
222
|
+
#print "dir=#{@dir},angle=#{radar_heading}, closest=#{@closest}\n"
|
|
223
|
+
if @closest < @range * 1.25
|
|
224
|
+
@range = @closest
|
|
225
|
+
@mode = 3
|
|
226
|
+
@stage = 0
|
|
227
|
+
@tangle = radar_heading
|
|
228
|
+
#print "found target at angle #{@tangle}\n"
|
|
229
|
+
#if we finished the scan, and didn't find close target, recompute range
|
|
230
|
+
elsif aimrad(@dir*90,60,1)
|
|
231
|
+
@mode = 0
|
|
232
|
+
@stage =0
|
|
233
|
+
end
|
|
234
|
+
end
|
|
235
|
+
#mode 3 is tracking bot
|
|
236
|
+
elsif @mode == 3
|
|
237
|
+
#entry from previous mode, determine whether to scan ccw or cw
|
|
238
|
+
if @stage == 0
|
|
239
|
+
@trk_dir,@trk_res,@stage = -1,4,2
|
|
240
|
+
#first scan in this direction
|
|
241
|
+
elsif @stage == 1
|
|
242
|
+
if @closest < @range * 1.25
|
|
243
|
+
@range = @closest
|
|
244
|
+
@trk_dir = -@trk_dir
|
|
245
|
+
@trk_res = max(@trk_res - 1,0)
|
|
246
|
+
@mytrack.add(x,y,@radar_heading, @range , time) if @trk_res < 3
|
|
247
|
+
else
|
|
248
|
+
@stage = 2
|
|
249
|
+
end
|
|
250
|
+
#second scan in this direction
|
|
251
|
+
elsif @stage == 2
|
|
252
|
+
if @closest < @range * 1.25
|
|
253
|
+
@range = @closest
|
|
254
|
+
@trk_dir = -@trk_dir
|
|
255
|
+
@trk_res = max(@trk_res - 1,0)
|
|
256
|
+
@mytrack.add(x,y,@radar_heading, @range , time) if @trk_res < 3
|
|
257
|
+
@stage = 1
|
|
258
|
+
else
|
|
259
|
+
@trk_dir = -@trk_dir
|
|
260
|
+
@trk_res = min(@trk_res + 2,4)
|
|
261
|
+
@stage = 3
|
|
262
|
+
end
|
|
263
|
+
#the target bot has moved out of our window, expand the window
|
|
264
|
+
elsif @stage == 3
|
|
265
|
+
if @closest < @range * 1.25
|
|
266
|
+
@range = @closest
|
|
267
|
+
@trk_dir = - @trk_dir
|
|
268
|
+
@trk_res = max(@trk_res - 2,0)
|
|
269
|
+
@mytrack.add(x,y,@radar_heading, @range , time) if @trk_res < 3
|
|
270
|
+
@stage = 1
|
|
271
|
+
elsif @trk_res < 6
|
|
272
|
+
@trk_dir = - @trk_dir
|
|
273
|
+
@trk_res = @trk_res +1
|
|
274
|
+
else
|
|
275
|
+
#we lost our target, reaquire from scratch
|
|
276
|
+
@mode = 0
|
|
277
|
+
@stage = 0
|
|
278
|
+
end
|
|
279
|
+
end
|
|
280
|
+
@tangle += @@ScanRes[@trk_res] * @trk_dir
|
|
281
|
+
aimrad(@tangle)
|
|
282
|
+
#print"tangle=#{@tangle}, res=#{@@ScanRes[@trk_res]}, rot=#{@trk_dir}\n"
|
|
283
|
+
elsif @mode == 4
|
|
284
|
+
#determine which corner to go to from a corner
|
|
285
|
+
if @stage == 0
|
|
286
|
+
@stage += 1 if aimrad(@dir*90 + 95*@walldir)
|
|
287
|
+
#first scan in direction of prev corner
|
|
288
|
+
elsif @stage == 1
|
|
289
|
+
aimrad(@dir*90 + 60*@walldir)
|
|
290
|
+
@stage += 1
|
|
291
|
+
#save count of robots in next corner, and swing radar to previous corner
|
|
292
|
+
elsif @stage == 2
|
|
293
|
+
@prevCorner = events['robot_scanned'].size
|
|
294
|
+
aimrad(@dir*90 + 30*@walldir)
|
|
295
|
+
@stage += 1
|
|
296
|
+
elsif @stage == 3
|
|
297
|
+
aimrad(@dir*90 -5*@walldir)
|
|
298
|
+
@stage += 1
|
|
299
|
+
elsif @stage == 4
|
|
300
|
+
@nextCorner = events['robot_scanned'].size
|
|
301
|
+
#print "next corner=#{@nextCorner}, prev corner=#{@prevCorner}\n"
|
|
302
|
+
if @nextCorner > @prevCorner
|
|
303
|
+
@dir = (@dir + @walldir)%4
|
|
304
|
+
@walldir *= -1
|
|
305
|
+
end
|
|
306
|
+
@stage = 0
|
|
307
|
+
@mode = 0
|
|
308
|
+
end
|
|
309
|
+
elsif @mode == 5
|
|
310
|
+
#determine which corner to go to from middle of wall
|
|
311
|
+
if @stage == 0
|
|
312
|
+
@stage += 1 if aimrad(@dir*90 - 5*@walldir)
|
|
313
|
+
#first scan in direction of prev corner
|
|
314
|
+
elsif @stage == 1
|
|
315
|
+
aimrad(@dir*90 + 30*@walldir)
|
|
316
|
+
@stage += 1
|
|
317
|
+
#save count of robots in next corner, and swing radar to previous corner
|
|
318
|
+
elsif @stage == 2
|
|
319
|
+
@nextCorner = events['robot_scanned'].size
|
|
320
|
+
aimrad(@dir*90 + 150*@walldir)
|
|
321
|
+
@stage += 1
|
|
322
|
+
elsif @stage == 3
|
|
323
|
+
@stage += 1
|
|
324
|
+
aimrad(@dir*90 -150*@walldir)
|
|
325
|
+
elsif @stage == 4
|
|
326
|
+
aimrad(@dir*90 -185*@walldir)
|
|
327
|
+
@stage += 1
|
|
328
|
+
elsif @stage == 5
|
|
329
|
+
@prevCorner = events['robot_scanned'].size
|
|
330
|
+
#print "next corner=#{@nextCorner}, prev corner=#{@prevCorner}\n"
|
|
331
|
+
if @nextCorner > @prevCorner
|
|
332
|
+
@dir = (@dir + 2)%4
|
|
333
|
+
@walldir *= -1
|
|
334
|
+
end
|
|
335
|
+
@stage = 0
|
|
336
|
+
@mode = 0
|
|
337
|
+
end
|
|
338
|
+
end
|
|
339
|
+
#compute the distances to the four walls
|
|
340
|
+
walls = [battlefield_width - x,y,x,battlefield_height - y]
|
|
341
|
+
#hug the wall, if we are slightly off the wall, than move back to the wall
|
|
342
|
+
toleftwall,torightwall = walls[(@dir+1)%4],walls[(@dir-1)%4]
|
|
343
|
+
#print "wallroom left=#{toleftwall}, right=#{torightwall}\n"
|
|
344
|
+
if toleftwall > 80 and toleftwall < 200
|
|
345
|
+
aimtank(@dir * 90 + 20)
|
|
346
|
+
elsif torightwall > 80 and torightwall < 200
|
|
347
|
+
aimtank(@dir * 90 - 20)
|
|
348
|
+
else
|
|
349
|
+
aimtank(@dir * 90)
|
|
350
|
+
end
|
|
351
|
+
#If we reach a corner or wall, turn towards farthest corner on this wall
|
|
352
|
+
if walls[@dir] < 100
|
|
353
|
+
if toleftwall > torightwall
|
|
354
|
+
@walldir = 1 #we are now going ccw
|
|
355
|
+
@dir = (@dir+1)%4 # turn ccw
|
|
356
|
+
#print "turn left\n"
|
|
357
|
+
else
|
|
358
|
+
@walldir = -1 #we are now going cw
|
|
359
|
+
@dir = (@dir-1)%4 #turn cw
|
|
360
|
+
#print "turn right\n"
|
|
361
|
+
end
|
|
362
|
+
#don't check corners at T junction
|
|
363
|
+
if toleftwall > 100 and torightwall > 100
|
|
364
|
+
@mode = 5 # determin weather it is safer ahead or behind
|
|
365
|
+
@stage = 0
|
|
366
|
+
else
|
|
367
|
+
@mode = 4 # determin if previous corner was safer
|
|
368
|
+
@stage = 0
|
|
369
|
+
end
|
|
370
|
+
#If we are getting hammered, turn now to evade damage
|
|
371
|
+
# once we evade, avoid making another evasive manuver or we will turn in circles
|
|
372
|
+
elsif @hit_filter > 400 and @since_evade > 100
|
|
373
|
+
@dir = (@dir+@walldir)%4
|
|
374
|
+
@hit_filter = 0
|
|
375
|
+
@since_evade = 0
|
|
376
|
+
end
|
|
377
|
+
accelerate 1
|
|
378
|
+
aim = @mytrack.predict(x,y,time) || (@dir * 90)%360
|
|
379
|
+
aimgun(aim)
|
|
380
|
+
fire 0.1
|
|
381
|
+
doturns #we already computed our turns, now execute them
|
|
382
|
+
STDOUT.flush
|
|
383
|
+
end
|
|
384
|
+
end
|