UG_RRobots 1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (165) hide show
  1. data/bin/rrobots +202 -0
  2. data/bin/tournament +413 -0
  3. data/config/rrobots.yml +15 -0
  4. data/contribs/allbots.rb +0 -0
  5. data/doc/manual.rdoc +126 -0
  6. data/doc/manual_fr.rdoc +129 -0
  7. data/images/explosion00.gif +0 -0
  8. data/images/explosion01.gif +0 -0
  9. data/images/explosion02.gif +0 -0
  10. data/images/explosion03.gif +0 -0
  11. data/images/explosion04.gif +0 -0
  12. data/images/explosion05.gif +0 -0
  13. data/images/explosion06.gif +0 -0
  14. data/images/explosion07.gif +0 -0
  15. data/images/explosion08.gif +0 -0
  16. data/images/explosion09.gif +0 -0
  17. data/images/explosion10.gif +0 -0
  18. data/images/explosion11.gif +0 -0
  19. data/images/explosion12.gif +0 -0
  20. data/images/explosion13.gif +0 -0
  21. data/images/explosion14.gif +0 -0
  22. data/images/red_body000.gif +0 -0
  23. data/images/red_body010.gif +0 -0
  24. data/images/red_body020.gif +0 -0
  25. data/images/red_body030.gif +0 -0
  26. data/images/red_body040.gif +0 -0
  27. data/images/red_body050.gif +0 -0
  28. data/images/red_body060.gif +0 -0
  29. data/images/red_body070.gif +0 -0
  30. data/images/red_body080.gif +0 -0
  31. data/images/red_body090.gif +0 -0
  32. data/images/red_body100.gif +0 -0
  33. data/images/red_body110.gif +0 -0
  34. data/images/red_body120.gif +0 -0
  35. data/images/red_body130.gif +0 -0
  36. data/images/red_body140.gif +0 -0
  37. data/images/red_body150.gif +0 -0
  38. data/images/red_body160.gif +0 -0
  39. data/images/red_body170.gif +0 -0
  40. data/images/red_body180.gif +0 -0
  41. data/images/red_body190.gif +0 -0
  42. data/images/red_body200.gif +0 -0
  43. data/images/red_body210.gif +0 -0
  44. data/images/red_body220.gif +0 -0
  45. data/images/red_body230.gif +0 -0
  46. data/images/red_body240.gif +0 -0
  47. data/images/red_body250.gif +0 -0
  48. data/images/red_body260.gif +0 -0
  49. data/images/red_body270.gif +0 -0
  50. data/images/red_body280.gif +0 -0
  51. data/images/red_body290.gif +0 -0
  52. data/images/red_body300.gif +0 -0
  53. data/images/red_body310.gif +0 -0
  54. data/images/red_body320.gif +0 -0
  55. data/images/red_body330.gif +0 -0
  56. data/images/red_body340.gif +0 -0
  57. data/images/red_body350.gif +0 -0
  58. data/images/red_radar000.gif +0 -0
  59. data/images/red_radar010.gif +0 -0
  60. data/images/red_radar020.gif +0 -0
  61. data/images/red_radar030.gif +0 -0
  62. data/images/red_radar040.gif +0 -0
  63. data/images/red_radar050.gif +0 -0
  64. data/images/red_radar060.gif +0 -0
  65. data/images/red_radar070.gif +0 -0
  66. data/images/red_radar080.gif +0 -0
  67. data/images/red_radar090.gif +0 -0
  68. data/images/red_radar100.gif +0 -0
  69. data/images/red_radar110.gif +0 -0
  70. data/images/red_radar120.gif +0 -0
  71. data/images/red_radar130.gif +0 -0
  72. data/images/red_radar140.gif +0 -0
  73. data/images/red_radar150.gif +0 -0
  74. data/images/red_radar160.gif +0 -0
  75. data/images/red_radar170.gif +0 -0
  76. data/images/red_radar180.gif +0 -0
  77. data/images/red_radar190.gif +0 -0
  78. data/images/red_radar200.gif +0 -0
  79. data/images/red_radar210.gif +0 -0
  80. data/images/red_radar220.gif +0 -0
  81. data/images/red_radar230.gif +0 -0
  82. data/images/red_radar240.gif +0 -0
  83. data/images/red_radar250.gif +0 -0
  84. data/images/red_radar260.gif +0 -0
  85. data/images/red_radar270.gif +0 -0
  86. data/images/red_radar280.gif +0 -0
  87. data/images/red_radar290.gif +0 -0
  88. data/images/red_radar300.gif +0 -0
  89. data/images/red_radar310.gif +0 -0
  90. data/images/red_radar320.gif +0 -0
  91. data/images/red_radar330.gif +0 -0
  92. data/images/red_radar340.gif +0 -0
  93. data/images/red_radar350.gif +0 -0
  94. data/images/red_turret000.gif +0 -0
  95. data/images/red_turret010.gif +0 -0
  96. data/images/red_turret020.gif +0 -0
  97. data/images/red_turret030.gif +0 -0
  98. data/images/red_turret040.gif +0 -0
  99. data/images/red_turret050.gif +0 -0
  100. data/images/red_turret060.gif +0 -0
  101. data/images/red_turret070.gif +0 -0
  102. data/images/red_turret080.gif +0 -0
  103. data/images/red_turret090.gif +0 -0
  104. data/images/red_turret100.gif +0 -0
  105. data/images/red_turret110.gif +0 -0
  106. data/images/red_turret120.gif +0 -0
  107. data/images/red_turret130.gif +0 -0
  108. data/images/red_turret140.gif +0 -0
  109. data/images/red_turret150.gif +0 -0
  110. data/images/red_turret160.gif +0 -0
  111. data/images/red_turret170.gif +0 -0
  112. data/images/red_turret180.gif +0 -0
  113. data/images/red_turret190.gif +0 -0
  114. data/images/red_turret200.gif +0 -0
  115. data/images/red_turret210.gif +0 -0
  116. data/images/red_turret220.gif +0 -0
  117. data/images/red_turret230.gif +0 -0
  118. data/images/red_turret240.gif +0 -0
  119. data/images/red_turret250.gif +0 -0
  120. data/images/red_turret260.gif +0 -0
  121. data/images/red_turret270.gif +0 -0
  122. data/images/red_turret280.gif +0 -0
  123. data/images/red_turret290.gif +0 -0
  124. data/images/red_turret300.gif +0 -0
  125. data/images/red_turret310.gif +0 -0
  126. data/images/red_turret320.gif +0 -0
  127. data/images/red_turret330.gif +0 -0
  128. data/images/red_turret340.gif +0 -0
  129. data/images/red_turret350.gif +0 -0
  130. data/images/toolbox.gif +0 -0
  131. data/lib/battlefield.rb +102 -0
  132. data/lib/bullets.rb +39 -0
  133. data/lib/configuration.rb +26 -0
  134. data/lib/explosions.rb +20 -0
  135. data/lib/overloads.rb +10 -0
  136. data/lib/robot.rb +122 -0
  137. data/lib/robotrunner.rb +260 -0
  138. data/lib/tkarena.rb +197 -0
  139. data/lib/toolboxes.rb +28 -0
  140. data/robots/BillDuck.rb +92 -0
  141. data/robots/BotOne.rb +39 -0
  142. data/robots/DuckBill.rb +384 -0
  143. data/robots/DuckBill04.rb +330 -0
  144. data/robots/DuckToEndAllDucks.rb +140 -0
  145. data/robots/EdgeBot.rb +203 -0
  146. data/robots/HuntingDuck.rb +74 -0
  147. data/robots/HyperactiveDuck.rb +15 -0
  148. data/robots/Killer.rb +58 -0
  149. data/robots/Kite.rb +193 -0
  150. data/robots/KoDuck.rb +57 -0
  151. data/robots/LinearShooter.rb +279 -0
  152. data/robots/LuckyDuck.rb +83 -0
  153. data/robots/MoxonoM.rb +85 -0
  154. data/robots/MsgBot.rb +13 -0
  155. data/robots/NervousDuck.rb +13 -0
  156. data/robots/Polisher.rb +15 -0
  157. data/robots/RomBot.rb +514 -0
  158. data/robots/RoomPainter.rb +205 -0
  159. data/robots/Rrrkele.rb +48 -0
  160. data/robots/Seeker.rb +57 -0
  161. data/robots/ShootingStation.rb +15 -0
  162. data/robots/SittingDuck.rb +18 -0
  163. data/robots/SniperDuck.rb +277 -0
  164. data/robots/WallPainter.rb +224 -0
  165. metadata +220 -0
@@ -0,0 +1,330 @@
1
+ require 'robot'
2
+
3
+ class DuckBill04
4
+ include Robot
5
+ # ###########
6
+ # # Initialize
7
+ # ###########
8
+ def initialize *bf
9
+ super(bf[0]) if bf.size != 0
10
+ super if bf.size == 0
11
+ @ScanRes = [1,2,4,8,16,32,60]
12
+ @mode = 0 # mode of high level logic
13
+ @stage = 0 # sequences within mode
14
+ @dir = 0 # direction we are going
15
+ @walldir = 1 # dirrection we travel around perimeter in, 1 = ccw,-1=cw
16
+ @hit_filter = 0 #low pass filter tells how much damage we are taking
17
+ @sincehit = 100 #how long since we were hit
18
+ @sinceblip = 100 #how long since we saw someone in our radar
19
+ @time_sync = 0 #time since we took evasive action
20
+ @sinceturn = 0
21
+ @closest = 0 #distance to closest robot scanned since last tick
22
+ @range = 10000 #distance of closest robot
23
+ @tangle = 0
24
+ @radar_old = 0
25
+ @mytrack = Tracking.new(battlefield_width,battlefield_height)
26
+ @turns = [0,0,0,0,0,0,0,0,0,0,0,0] # holds data for turn/aim calculations
27
+ @duckdbg = false
28
+ end
29
+ def debug(a)
30
+ print a if @duckdbg
31
+ STDOUT.flush if @duckdbg
32
+ end
33
+ # ###########
34
+ # # Controls
35
+ # ###########
36
+ def min(a,b)
37
+ (a < b)? a : b
38
+ end
39
+ def max(a,b)
40
+ (a > b)? a : b
41
+ end
42
+ #dir is 1 for ccw, -1 for cw, and 0 for whichever is quickest
43
+ def aimtank(angle,rate=10,dir=0)
44
+ @turns[0,3] = angle%360,rate,dir
45
+ angle%360 == heading
46
+ end
47
+ def aimgun(angle,rate=30,dir=0)
48
+ @turns[4,3] = angle%360,rate,dir
49
+ angle%360 == gun_heading
50
+ end
51
+ def aimrad(angle,rate=60,dir=0)
52
+ @turns[8,3] = angle%360,rate,dir
53
+ angle%360 == radar_heading
54
+ end
55
+ def doturns
56
+ #this translates directional commands from robot into motor actions
57
+ #turns: 0=desired heading, 1=max speed,2=dir[1=ccw,-1=cw,0=fastest],
58
+ # 3=computed turn, 0-3 for tank, 4-7 for gun, 8-11 for radar
59
+ #compute turns for tank, gun, and radar headings
60
+ #print "computed turns = #{@turns.inspect}\n"
61
+ ccw = (@turns[0] - heading) % 360
62
+ cw = 360 - ccw
63
+ dir = (@turns[2] == 0)? ((ccw<cw)? 1 : -1) : @turns[2]
64
+ @turns[3] = dir * min((dir==1)? ccw : cw,@turns[1])
65
+ ccw = (@turns[4] - @turns[3] - gun_heading) % 360
66
+ cw = 360 - ccw
67
+ dir = (@turns[6] == 0)? ((ccw<cw)? 1 : -1) : @turns[6]
68
+ @turns[7] = dir * min((dir==1)? ccw : cw,@turns[5])
69
+ ccw = (@turns[8] - @turns[7] - @turns[3] - radar_heading) % 360
70
+ cw = 360 - ccw
71
+ dir = (@turns[10] == 0)? ((ccw<cw)? 1 : -1) : @turns[10]
72
+ @turns[11] = dir * min(((dir==1)? ccw : cw),@turns[9])
73
+ #print "computed turns = #{@turns.inspect}\n"
74
+ turn @turns[3]
75
+ turn_gun @turns[7]
76
+ turn_radar @turns[11]
77
+ end
78
+
79
+ # ###########
80
+ # # TICK, the Robot code
81
+ # ###########
82
+ def tick events
83
+ @outerlimit = (battlefield_width + battlefield_height)*2
84
+ debug "\nmode=#{@mode},stage=#{@stage},dir=#{@dir},walldir=#{@walldir}\n"
85
+ debug "at (#{x},#{y}) at #{time}, radar=#{radar_heading}, gun=#{gun_heading}\n"
86
+ debug "trk_dir=#{@trk_dir}, trk_res=#{@trk_res},range=#{@range}\n"
87
+ #mode nil is startup and initialize variables
88
+ #STDOUT.flush
89
+ # ###########
90
+ # # Sensors
91
+ # ###########
92
+ raddif = (radar_heading - @radar_old)%360
93
+ raddif = 360 -raddif if raddif >= 180
94
+ @radave = (radar_heading + raddif/2.0)%360
95
+ @sincehit += 1
96
+ @sinceturn += 1
97
+ @sincehit = 0 if not events['got_hit'].empty?
98
+ events['got_hit'].each{|e| @hit_filter += e.first}
99
+ @hit_filter *= 0.99
100
+ if events['robot_scanned'].empty?
101
+ @sinceblip += 1
102
+ @closest = @outerlimit
103
+ #print"\n"
104
+ else
105
+ @closest = events['robot_scanned'].collect{|e| e.first}.sort.first
106
+ @sinceblip = 0
107
+ debug ",blip=#{@closest} sweep=(#{@radar_old},#{radar_heading})\n"
108
+ end
109
+ # ###########
110
+ # # High level logic - state machine
111
+ # ###########
112
+ #print "sincehit=#{@sincehit},closest=#{@closest},range=#{@range}\n"
113
+ #mode 0 is orient tank
114
+ if @mode == 0
115
+ @stage = 0
116
+ @range = @outerlimit
117
+ @mode = 1 if aimrad(@dir*90)
118
+ #mode 1 find range of nearest target
119
+ elsif @mode == 1
120
+ #setup radar for a scan
121
+ if @stage==0
122
+ aimrad(@dir*90 + 180,60,@walldir)
123
+ @range = min(@range,@closest)
124
+ @stage +=1
125
+ #continue around for full circle
126
+ elsif @stage == 1
127
+ @range = min(@range,@closest)
128
+ if aimrad(@dir*90,60,@walldir)
129
+ #did we see a bot?
130
+ if @range == @outerlimit
131
+ @stage = 0
132
+ else
133
+ @mode = 2
134
+ @stage = 0
135
+ end
136
+ end
137
+ end
138
+ #mode 2: find the nearestbot
139
+ elsif @mode == 2
140
+ #start next circle to re find the closest bot
141
+ if @stage == 0
142
+ #print "range is #{@range}\n"
143
+ aimrad(@dir*90 + 180,60,@walldir)
144
+ @stage +=1
145
+ #continue scan for the closest bot
146
+ elsif @stage == 1
147
+ #print "dir=#{@dir},angle=#{radar_heading}, closest=#{@closest}\n"
148
+ if @closest < @range * 1.25
149
+ @range = @closest
150
+ @mode = 3
151
+ @stage = 1
152
+ @tangle = radar_heading
153
+ @trk_dir,@trk_res = -@walldir,5
154
+ @tangle += @ScanRes[@trk_res] * @trk_dir
155
+ aimrad(@tangle)
156
+ debug "found target at angle #{@tangle}\n"
157
+ #if we finished the scan, and didn't find close target, recompute range
158
+ elsif aimrad(@dir*90,60,@walldir)
159
+ @mode = 0
160
+ @stage =0
161
+ end
162
+ end
163
+ #mode 3 is tracking bot
164
+ elsif @mode == 3
165
+ #entry from previous mode, determine whether to scan ccw or cw
166
+ if @stage == 0
167
+ @trk_dir,@trk_res,@stage = -1,4,2
168
+ #first scan in this direction
169
+ elsif @stage == 1
170
+ if @closest < @range * 1.25
171
+ @range = @closest
172
+ @trk_dir = -@trk_dir
173
+ @trk_res = max(@trk_res - 1,0)
174
+ @mytrack.add(x,y,@radave, @range , time) if @trk_res < 3
175
+ else
176
+ @stage = 2
177
+ end
178
+ #second scan in this direction
179
+ elsif @stage == 2
180
+ if @closest < @range * 1.25
181
+ @range = @closest
182
+ @trk_dir = -@trk_dir
183
+ @trk_res = max(@trk_res - 1,0)
184
+ @mytrack.add(x,y,@radave, @range , time) if @trk_res < 3
185
+ @stage = 1
186
+ else
187
+ @trk_dir = -@trk_dir
188
+ @trk_res = min(@trk_res + 2,4)
189
+ @stage = 3
190
+ end
191
+ #the target bot has moved out of our window, expand the window
192
+ elsif @stage == 3
193
+ if @closest < @range * 1.25
194
+ @range = @closest
195
+ @trk_dir = - @trk_dir
196
+ @trk_res = max(@trk_res - 2,0)
197
+ @mytrack.add(x,y,@radave, @range , time) if @trk_res < 3
198
+ @stage = 1
199
+ elsif @trk_res < 6
200
+ @trk_dir = - @trk_dir
201
+ @trk_res = @trk_res +1
202
+ else
203
+ #we lost our target, reaquire from scratch
204
+ @mode = 0
205
+ @stage = 0
206
+ end
207
+ end
208
+ @tangle += @ScanRes[@trk_res] * @trk_dir
209
+ aimrad(@tangle)
210
+ #print"tangle=#{@tangle}, res=#{@ScanRes[@trk_res]}, rot=#{@trk_dir}\n"
211
+ end
212
+ #compute the distances to the four walls
213
+ walls = [battlefield_width - x,y,x,battlefield_height - y]
214
+ toleftwall,torightwall = walls[(@dir+1)%4],walls[(@dir-1)%4]
215
+ #debug "wallroom left=#{toleftwall}, right=#{torightwall}\n"
216
+ if walls.sort.first < 100 and @sinceturn > 30
217
+ if walls.sort[1] < 300
218
+ @dir = walls.index(walls.sort.first)
219
+ aimtank((@dir * 90 + 180)%360)
220
+ else
221
+ aimtank((heading + 180)%360)
222
+ end
223
+ @walldir *= -1
224
+ @sinceturn = 0
225
+ else
226
+ if @range > 800
227
+ aimtank((@tangle + @walldir* 70)%360)
228
+ elsif @range <600
229
+ aimtank((@tangle + @walldir* 110)%360)
230
+ else
231
+ aimtank((@tangle + @walldir* 90)%360)
232
+ end
233
+ end
234
+ debug "time=#{time}, time_sync=#{@time_sync},mod=#{(time+@time_sync)%20}\n"
235
+ if (time+@time_sync) % 20 < 10
236
+ stop
237
+ else
238
+ accelerate 1
239
+ end
240
+ @time_sync = 25 - time%20 if @sincehit == 0
241
+ aim = @mytrack.predict(x,y,time) || (@dir * 90)%360
242
+ aimgun(aim)
243
+ fire 0.1
244
+ doturns #we already computed our turns, now execute them
245
+ @radar_old = radar_heading
246
+ STDOUT.flush
247
+ end
248
+ end
249
+ class Tracking
250
+ def debug(a)
251
+ print a if @trkdbg
252
+ STDOUT.flush if @trkdbg
253
+ end
254
+ def initialize(width,height)
255
+ @trkdbg = false
256
+ @tracking = []
257
+ @width = width
258
+ @height = height
259
+ end
260
+ def add(x,y,angle,dist,time)
261
+ @tracking << [x + Math::cos(angle.to_rad)*dist,y - Math::sin(angle.to_rad)*dist,time]
262
+ debug "added track angle=#{angle},dist=#{dist},#{@tracking.last.inspect}\n"
263
+ end
264
+ def trim(time)
265
+ #delete really old samples
266
+ @tracking.delete_if{|e| time - e[2] > 30}
267
+ #limit to 10 samples
268
+ @tracking.shift while @tracking.size>10
269
+ #eliminate samples if they came from a different robot. we can tell this because they have max speed of 8
270
+ gap = 0
271
+ (@tracking.size- 1).times{|i|
272
+ if (v=velocity(@tracking[i],@tracking[i+1])) > 40
273
+ gap = i+1
274
+ debug "traking gap #{@tracking[i].inspect},#{@tracking[i+1].inspect},v=#{v}\n"
275
+ end
276
+ }
277
+ gap.times{@tracking.shift}
278
+ #normalize the time
279
+ #@tracking.size.times{|i| @tracking[@tracking.size-1-i][2] -=@tracking[0][2]}
280
+ end
281
+ def velocity (e1,e2)
282
+ distance(e1[0],e1[1],e2[0],e2[1])/(e1[2]-e2[2]).abs
283
+ end
284
+ def distance (x1,y1,x2,y2)
285
+ ((x1-x2)**2 + (y1-y2)**2)**(0.5)
286
+ end
287
+ def findline
288
+ sx=sy=st=sxt=syt=stt=0.0
289
+ @tracking.each{|e|
290
+ debug " findline element = #{e.inspect}\n"
291
+ sx += e[0]
292
+ sxt += e[2]*e[0]
293
+ sy += e[1]
294
+ syt += e[2]*e[1]
295
+ st += e[2]
296
+ stt += e[2]*e[2]
297
+ }
298
+ n=@tracking.size
299
+ c2 = (sxt/st-sx/n)/(stt/st-st/n)
300
+ c1 = sx/n-(st/n)*c2
301
+ f2 = (syt/st-sy/n)/(stt/st-st/n)
302
+ f1 = sy/n-(st/n)*f2
303
+ debug "x = #{c2}t + #{c1}\n"
304
+ debug "y = #{f2}t + #{f1}\n"
305
+ [c2,c1,f2,f1]
306
+ end
307
+ def predict(x,y,time)
308
+ trim(time)
309
+ if @tracking.size < 1
310
+ return false
311
+ elsif @tracking.size == 1
312
+ interceptx,intercepty = @tracking[0][0],@tracking[0][1]
313
+ else
314
+ a,b,c,d = findline
315
+ intercepttime = time + distance(a*time+b,c*time+d,x,y)/30.0
316
+ #interceptx,intercepty = limitcoord(intercepttime*a + b, intercepttime*c+d)
317
+ interceptx,intercepty = intercepttime*a + b, intercepttime*c+d
318
+ end
319
+ debug"intercept at (#{interceptx},#{intercepty},#{intercepttime})\n"
320
+ angle = (Math.atan2(y - intercepty,interceptx - x) * 180 / Math::PI)%360
321
+ debug "firing angle is #{angle}\n"
322
+ angle
323
+ end
324
+ def limitcoord(x,y)
325
+ nx=[x,0.0].max
326
+ nx = [nx,@width.to_f].min
327
+ ny = [ny,@height.to_f].min
328
+ [nx,ny]
329
+ end
330
+ end
@@ -0,0 +1,140 @@
1
+ require 'robot'
2
+
3
+ class DuckToEndAllDucks
4
+ include Robot
5
+
6
+ def tick events
7
+ accelerate 1 if velocity < 7
8
+ if close_to_edge
9
+ turn_towards_quadrant get_other_quadrant
10
+ end
11
+ @post_hit_turn ||= 0
12
+ if !events['got_hit'].empty?
13
+ @post_hit_turn = 10
14
+ end
15
+ if @post_hit_turn > 0
16
+ if @post_hit_turn < 70
17
+ turn 10
18
+ @post_hit_turn += 10
19
+ else
20
+ @post_hit_turn = 0
21
+ end
22
+ end
23
+
24
+ @gun_turn_back ||= 50
25
+ @robot_sighted ||= 0
26
+ @fire_in_ticks ||= 2
27
+ if !events['robot_scanned'].empty? and @gun_turn_back > 40
28
+ @robot_sighted = radar_heading
29
+ @turnstep = -5
30
+ @gun_turn_back = 10
31
+ @distance = events['robot_scanned'][0][0]
32
+ if @distance < 500 then fire 3 end
33
+ else
34
+ if @gun_turn_back == 20
35
+ turn_gun @turnstep
36
+ @gun_turn_back += 10
37
+ if @distance < 500
38
+ fire 3
39
+ else
40
+ fire 1
41
+ end
42
+ elsif @gun_turn_back <= 40
43
+ turn_gun @turnstep
44
+ @gun_turn_back += 10
45
+ else
46
+ turn_gun 10
47
+ end
48
+ end
49
+
50
+ end
51
+
52
+ def close_to_edge
53
+ margins = [x, (x - battlefield_width).abs, y, (y - battlefield_height).abs]
54
+ true if margins.min < 200
55
+ end
56
+
57
+ def get_other_quadrant
58
+ other = quadrant
59
+ until other != quadrant do
60
+ other = (rand * 4).to_i
61
+ end
62
+ other
63
+ end
64
+
65
+ # Return 1, 2, 3, 4 depending on which quadrant of the battlefield the robot is in
66
+ # -----
67
+ # |1 2|
68
+ # |3 4|
69
+ # -----
70
+ def quadrant
71
+ left = x < battlefield_width / 2
72
+ right = !left
73
+ top = y < battlefield_height / 2
74
+ bottom = !top
75
+ if left and top
76
+ 1
77
+ elsif right and top
78
+ 2
79
+ elsif left and bottom
80
+ 3
81
+ else
82
+ 4
83
+ end
84
+ end
85
+
86
+ def simple_heading
87
+ if (heading <= 90)
88
+ "ne"
89
+ elsif (heading > 90) and (heading <= 180)
90
+ "nw"
91
+ elsif (heading > 180) and (heading <= 270)
92
+ "sw"
93
+ else
94
+ "se"
95
+ end
96
+ end
97
+
98
+ def turn_towards_quadrant(target_quadrant)
99
+ case quadrant
100
+ when 1
101
+ case target_quadrant
102
+ when 2
103
+ if simple_heading != "ne" then turn 20 end
104
+ when 3
105
+ if simple_heading != "sw" then turn 20 end
106
+ when 4
107
+ if simple_heading != "se" then turn 20 end
108
+ end
109
+ when 2
110
+ case target_quadrant
111
+ when 1
112
+ if simple_heading != "nw" then turn 20 end
113
+ when 3
114
+ if simple_heading != "sw" then turn 20 end
115
+ when 4
116
+ if simple_heading != "se" then turn 20 end
117
+ end
118
+ when 3
119
+ case target_quadrant
120
+ when 1
121
+ if simple_heading != "nw" then turn 20 end
122
+ when 2
123
+ if simple_heading != "ne" then turn 20 end
124
+ when 4
125
+ if simple_heading != "se" then turn 20 end
126
+ end
127
+ when 4
128
+ case target_quadrant
129
+ when 1
130
+ if simple_heading != "nw" then turn 20 end
131
+ when 2
132
+ if simple_heading != "ne" then turn 20 end
133
+ when 3
134
+ if simple_heading != "sw" then turn 20 end
135
+ end
136
+ end
137
+ end
138
+ end
139
+
140
+