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.
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
+