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
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,102 @@
1
+ class Battlefield
2
+ attr_reader :width
3
+ attr_reader :height
4
+ attr_reader :robots
5
+ attr_reader :teams
6
+ attr_reader :bullets
7
+ attr_reader :explosions
8
+ attr_reader :toolboxes
9
+ attr_reader :time
10
+ attr_reader :seed
11
+ attr_reader :timeout # how many ticks the match can go before ending.
12
+ attr_reader :game_over
13
+ attr_reader :toolboxes
14
+ attr_reader :with_toolboxes
15
+ attr_reader :config
16
+
17
+ def initialize width, height, timeout, seed, with_toolboxes, merge, write_config
18
+ @config = Configuration::new
19
+ if merge and File::exist?('./rrobots.yml') then
20
+ file = YAML::load(File.open('./rrobots.yml'))
21
+ file.extend(Configuration_accessors)
22
+ [:game, :toolboxes, :robots, :bullets, :battlefield].each do |accessor|
23
+ @config.send(accessor).merge(file.send(accessor))
24
+ end
25
+ end
26
+ @config.write_config if write_config
27
+ @width = (width != self.config.battlefield[:width]) ? width : self.config.battlefield[:width]
28
+ @height = (height != self.config.battlefield[:height]) ? height : self.config.battlefield[:height]
29
+ @seed = seed
30
+ @time = 0
31
+ @robots = []
32
+ @toolboxes = []
33
+ @with_toolboxes = (self.config.toolboxes[:with_toolboxes] != with_toolboxes)? with_toolboxes : self.config.toolboxes[:with_toolboxes]
34
+ @teams = Hash.new{|h,k| h[k] = [] }
35
+ @bullets = []
36
+ @explosions = []
37
+ @timeout = timeout
38
+ @game_over = false
39
+ srand @seed
40
+ end
41
+
42
+ def << object
43
+ case object
44
+ when RobotRunner
45
+ @robots << object
46
+ @teams[object.team] << object
47
+ when Bullet
48
+ @bullets << object
49
+ when Explosion
50
+ @explosions << object
51
+ when Toolbox
52
+ @toolboxes << object
53
+ end
54
+ end
55
+
56
+ def tick
57
+ explosions.delete_if{|explosion| explosion.dead}
58
+ explosions.each{|explosion| explosion.tick}
59
+
60
+ toolboxes.delete_if{|toolbox| toolbox.dead}
61
+ toolboxes.each{|toolbox| toolbox.tick}
62
+
63
+ bullets.delete_if{|bullet| bullet.dead}
64
+ bullets.each{|bullet| bullet.tick}
65
+
66
+ spawning_toolboxes if with_toolboxes
67
+
68
+ robots.each do |robot|
69
+ begin
70
+ robot.send :internal_tick unless robot.dead
71
+ rescue Exception => bang
72
+ puts "#{robot} made an exception:"
73
+ puts "#{bang.class}: #{bang}", bang.backtrace
74
+ robot.instance_eval{@energy = -1}
75
+ end
76
+ end
77
+
78
+ @time += 1
79
+ live_robots = robots.find_all{|robot| !robot.dead}
80
+ @game_over = ( (@time >= timeout) or # timeout reached
81
+ (live_robots.length == 0) or # no robots alive, draw game
82
+ (live_robots.all?{|r| r.team == live_robots.first.team})) # all other teams are dead
83
+ not @game_over
84
+ end
85
+
86
+ def state
87
+ {:explosions => explosions.map{|e| e.state},
88
+ :bullets => bullets.map{|b| b.state},
89
+ :toolboxes => toolbox.map{|t| t.state},
90
+ :robots => robots.map{|r| r.state}}
91
+ end
92
+
93
+ def spawning_toolboxes
94
+ if rand(self.config.toolboxes[:spawning_chances]) == 10 and !self.game_over then
95
+ x = rand(self.width).to_i
96
+ y = rand(self.height).to_i
97
+ toolbox = Toolbox.new(self, x, y, 0, self.config.toolboxes[:energy_heal_points])
98
+ self << toolbox
99
+ end
100
+ end
101
+
102
+ end
@@ -0,0 +1,39 @@
1
+ class Bullet
2
+ attr_accessor :x
3
+ attr_accessor :y
4
+ attr_accessor :heading
5
+ attr_accessor :speed
6
+ attr_accessor :energy
7
+ attr_accessor :dead
8
+ attr_accessor :origin
9
+
10
+ def initialize bf, x, y, heading, speed, energy, origin
11
+ @x, @y, @heading, @origin = x, y, heading, origin
12
+ @speed, @energy = speed, energy
13
+ @battlefield, dead = bf, false
14
+ end
15
+
16
+ def state
17
+ {:x=>x, :y=>y, :energy=>energy}
18
+ end
19
+
20
+ def tick
21
+ return if @dead
22
+ @x += Math::cos(@heading.to_rad) * @speed
23
+ @y -= Math::sin(@heading.to_rad) * @speed
24
+
25
+ @dead ||= (@x < 0) || (@x >= @battlefield.width)
26
+ @dead ||= (@y < 0) || (@y >= @battlefield.height)
27
+
28
+ @battlefield.robots.each do |other|
29
+ if (other != origin) && (Math.hypot(@y - other.y, other.x - @x) < 40) && (!other.dead)
30
+ explosion = Explosion.new(@battlefield, other.x, other.y)
31
+ @battlefield << explosion
32
+ damage = other.hit(self)
33
+ origin.damage_given += damage
34
+ origin.kills += 1 if other.dead
35
+ @dead = true
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,26 @@
1
+ module Configuration_accessors
2
+ attr_accessor :game
3
+ attr_accessor :toolboxes
4
+ attr_accessor :robots
5
+ attr_accessor :bullets
6
+ attr_accessor :battlefield
7
+ end
8
+
9
+ class Configuration
10
+
11
+ include Configuration_accessors
12
+
13
+ def write_config
14
+ File.unlink('./rrobots.yml') if File::exist?('./rrobots.yml')
15
+ File.open('./rrobots.yml', 'w') { |f| f.puts self.to_yaml }
16
+ end
17
+
18
+ def initialize
19
+ @game = { :timeout => 50000 }
20
+ @toolboxes = { :with_toolboxes => false, :life_time => 200, :spawning_chances => 100, :energy_heal_points => 20 }
21
+ @robots = { :energy_max => 100 }
22
+ @bullets = { :speed => 30 }
23
+ @battlefield = { :height => 800, :width => 800 }
24
+ end
25
+
26
+ end
@@ -0,0 +1,20 @@
1
+ class Explosion
2
+ attr_accessor :x
3
+ attr_accessor :y
4
+ attr_accessor :t
5
+ attr_accessor :dead
6
+
7
+ def initialize bf, x, y
8
+ @x, @y, @t = x, y, 0
9
+ @battlefield, dead = bf, false
10
+ end
11
+
12
+ def state
13
+ {:x=>x, :y=>y, :t=>t}
14
+ end
15
+
16
+ def tick
17
+ @t += 1
18
+ @dead ||= t > 15
19
+ end
20
+ end
@@ -0,0 +1,10 @@
1
+ class Numeric
2
+ TO_RAD = Math::PI / 180.0
3
+ TO_DEG = 180.0 / Math::PI
4
+ def to_rad
5
+ self * TO_RAD
6
+ end
7
+ def to_deg
8
+ self * TO_DEG
9
+ end
10
+ end
@@ -0,0 +1,122 @@
1
+ module Robot
2
+
3
+ def self.attr_state(*names)
4
+ names.each{|n|
5
+ n = n.to_sym
6
+ attr_writer n
7
+ attr_reader n
8
+ }
9
+ end
10
+
11
+ def self.attr_action(*names)
12
+ names.each{|n|
13
+ n = n.to_sym
14
+ define_method(n){|param| @actions[n] = param }
15
+ }
16
+ end
17
+
18
+ def self.attr_event(*names)
19
+ names.each{|n|
20
+ n = n.to_sym
21
+ define_method(n){ @events[n] }
22
+ }
23
+ end
24
+
25
+ #the state hash of your robot. also accessible through the attr_state methods
26
+ attr_accessor :state
27
+
28
+ #the action hash of your robot
29
+ attr_accessor :actions
30
+
31
+ #the event hash of your robot
32
+ attr_accessor :events
33
+
34
+ #path to where your robot's optional skin images are
35
+ attr_accessor :skin_prefix
36
+
37
+ #team of your robot
38
+ attr_state :team
39
+
40
+ #the height of the battlefield
41
+ attr_state :battlefield_height
42
+
43
+ #the width of the battlefield
44
+ attr_state :battlefield_width
45
+
46
+ #your remaining energy (if this drops below 0 you are dead)
47
+ attr_state :energy
48
+
49
+ #the heading of your gun, 0 pointing east, 90 pointing north, 180 pointing west, 270 pointing south
50
+ attr_state :gun_heading
51
+
52
+ #your gun heat, if this is above 0 you can't shoot
53
+ attr_state :gun_heat
54
+
55
+ #your robots heading, 0 pointing east, 90 pointing north, 180 pointing west, 270 pointing south
56
+ attr_state :heading
57
+
58
+ #your robots radius, if x <= size you hit the left wall
59
+ attr_state :size
60
+
61
+ #the heading of your radar, 0 pointing east, 90 pointing north, 180 pointing west, 270 pointing south
62
+ attr_state :radar_heading
63
+
64
+ #ticks since match start
65
+ attr_state :time
66
+
67
+ #whether the match is over or not, remember to go into cheer mode when this is true ;)
68
+ attr_state :game_over
69
+
70
+ #your speed (-8..8)
71
+ attr_state :speed
72
+ alias :velocity :speed
73
+
74
+ #your x coordinate, 0...battlefield_width
75
+ attr_state :x
76
+
77
+ #your y coordinate, 0...battlefield_height
78
+ attr_state :y
79
+
80
+ #accelerate (max speed is 8, max accelerate is 1/-1, negativ speed means moving backwards)
81
+ attr_action :accelerate
82
+
83
+ #accelerates negativ if moving forward (and vice versa), may take 8 ticks to stop (and you have to call it every tick)
84
+ def stop
85
+ accelerate((speed > 0) ? -1 : ((speed < 0) ? 1 :0))
86
+ end
87
+
88
+ #fires a bullet in the direction of your gun, power is 0.1 - 3, this power is taken from your energy
89
+ attr_action :fire
90
+
91
+ #turns the robot (and the gun and the radar), max 10 degrees per tick
92
+ attr_action :turn
93
+
94
+ #turns the gun (and the radar), max 30 degrees per tick
95
+ attr_action :turn_gun
96
+
97
+ #turns the radar, max 60 degrees per tick
98
+ attr_action :turn_radar
99
+
100
+ #broadcast message to other robots
101
+ attr_action :broadcast
102
+
103
+ #say something to the spectators
104
+ attr_action :say
105
+
106
+ #if you got hit last turn, this won't be empty
107
+ attr_event :got_hit
108
+
109
+ #distances to robots your radar swept over during last tick
110
+ attr_event :robot_scanned
111
+
112
+ #distances to robots your radar swept over during last tick
113
+ attr_event :toolbox_scanned
114
+
115
+ #broadcasts received last turn
116
+ attr_event :broadcasts
117
+
118
+ end
119
+
120
+ require 'robotrunner'
121
+
122
+
@@ -0,0 +1,260 @@
1
+ class RobotRunner
2
+
3
+ STATE_IVARS = [ :x, :y, :gun_heat, :heading, :gun_heading, :radar_heading, :time, :size, :speed, :energy, :team ]
4
+ NUMERIC_ACTIONS = [ :fire, :turn, :turn_gun, :turn_radar, :accelerate ]
5
+ STRING_ACTIONS = [ :say, :broadcast ]
6
+
7
+ STATE_IVARS.each{|iv|
8
+ attr_accessor iv
9
+ }
10
+ NUMERIC_ACTIONS.each{|iv|
11
+ attr_accessor "#{iv}_min", "#{iv}_max"
12
+ }
13
+ STRING_ACTIONS.each{|iv|
14
+ attr_accessor "#{iv}_max"
15
+ }
16
+
17
+ #AI of this robot
18
+ attr_accessor :robot
19
+
20
+ #team of this robot
21
+ attr_accessor :team
22
+
23
+ #keeps track of total damage done by this robot
24
+ attr_accessor :damage_given
25
+
26
+ #keeps track of the kills
27
+ attr_accessor :kills
28
+
29
+ #keeps track of the catched toolboxes
30
+ attr_accessor :catched_toolboxes
31
+
32
+ attr_reader :actions, :speech
33
+
34
+ def initialize robot, bf, team=0
35
+ @robot = robot
36
+ @battlefield = bf
37
+ @team = team
38
+ set_action_limits
39
+ set_initial_state
40
+ @events = Hash.new{|h, k| h[k]=[]}
41
+ @actions = Hash.new(0)
42
+ end
43
+
44
+ def skin_prefix
45
+ @robot.skin_prefix
46
+ end
47
+
48
+ def set_initial_state
49
+ @x = @battlefield.width / 2
50
+ @y = @battlefield.height / 2
51
+ @speech_counter = -1
52
+ @speech = nil
53
+ @time = 0
54
+ @size = 60
55
+ @speed = 0
56
+ @energy_max = @battlefield.config.robots[:energy_max]
57
+ @energy = @battlefield.config.robots[:energy_max]
58
+ @damage_given = 0
59
+ @kills = 0
60
+ @catched_toolboxes = 0
61
+ teleport
62
+ end
63
+
64
+ def teleport(distance_x=@battlefield.width / 2, distance_y=@battlefield.height / 2)
65
+ @x += ((rand-0.5) * 2 * distance_x).to_i
66
+ @y += ((rand-0.5) * 2 * distance_y).to_i
67
+ @gun_heat = 3
68
+ @heading = (rand * 360).to_i
69
+ @gun_heading = @heading
70
+ @radar_heading = @heading
71
+ end
72
+
73
+ def set_action_limits
74
+ @fire_min, @fire_max = 0, 3
75
+ @turn_min, @turn_max = -10, 10
76
+ @turn_gun_min, @turn_gun_max = -30, 30
77
+ @turn_radar_min, @turn_radar_max = -60, 60
78
+ @accelerate_min, @accelerate_max = -1, 1
79
+ @teleport_min, @teleport_max = 0, 100
80
+ @say_max = 256
81
+ @broadcast_max = 16
82
+ end
83
+
84
+ def hit bullet
85
+ damage = bullet.energy
86
+ @energy -= damage
87
+ @events['got_hit'] << [@energy]
88
+ damage
89
+ end
90
+
91
+ def heal toolbox
92
+ healing = toolbox.energy
93
+ @energy += healing
94
+ @energy = @energy_max if @energy > @energy_max
95
+ self.catched_toolboxes += 1
96
+ healing
97
+ end
98
+
99
+ def dead
100
+ @energy < 0
101
+ end
102
+
103
+ def clamp(var, min, max)
104
+ val = 0 + var # to guard against poisoned vars
105
+ if val > max
106
+ max
107
+ elsif val < min
108
+ min
109
+ else
110
+ val
111
+ end
112
+ end
113
+
114
+ def internal_tick
115
+ update_state
116
+ robot_tick
117
+ parse_actions
118
+ fire
119
+ turn
120
+ move
121
+ scan
122
+ speak
123
+ broadcast
124
+ @time += 1
125
+ end
126
+
127
+ def parse_actions
128
+ @actions.clear
129
+ NUMERIC_ACTIONS.each{|an|
130
+ @actions[an] = clamp(@robot.actions[an], send("#{an}_min"), send("#{an}_max"))
131
+ }
132
+ STRING_ACTIONS.each{|an|
133
+ if @robot.actions[an] != 0
134
+ @actions[an] = String(@robot.actions[an])[0, send("#{an}_max")]
135
+ end
136
+ }
137
+ @actions
138
+ end
139
+
140
+ def state
141
+ current_state = {}
142
+ STATE_IVARS.each{|iv|
143
+ current_state[iv] = send(iv)
144
+ }
145
+ current_state[:battlefield_width] = @battlefield.width
146
+ current_state[:battlefield_height] = @battlefield.height
147
+ current_state[:game_over] = @battlefield.game_over
148
+ current_state
149
+ end
150
+
151
+ def update_state
152
+ new_state = state
153
+ @robot.state = new_state
154
+ new_state.each{|k,v|
155
+ @robot.send("#{k}=", v)
156
+ }
157
+ @robot.events = @events.dup
158
+ @robot.actions ||= Hash.new(0)
159
+ @robot.actions.clear
160
+ end
161
+
162
+ def robot_tick
163
+ @robot.tick @robot.events
164
+ @events.clear
165
+ end
166
+
167
+ def fire
168
+ if (@actions[:fire] > 0) && (@gun_heat == 0)
169
+ bullet = Bullet.new(@battlefield, @x, @y, @gun_heading, @battlefield.config.bullets[:speed] , @actions[:fire]*3.0, self)
170
+ 3.times{bullet.tick}
171
+ @battlefield << bullet
172
+ @gun_heat = @actions[:fire]
173
+ end
174
+ @gun_heat -= 0.1
175
+ @gun_heat = 0 if @gun_heat < 0
176
+ end
177
+
178
+ def turn
179
+ @old_radar_heading = @radar_heading
180
+ @heading += @actions[:turn]
181
+ @gun_heading += (@actions[:turn] + @actions[:turn_gun])
182
+ @radar_heading += (@actions[:turn] + @actions[:turn_gun] + @actions[:turn_radar])
183
+ @new_radar_heading = @radar_heading
184
+
185
+ @heading %= 360
186
+ @gun_heading %= 360
187
+ @radar_heading %= 360
188
+ end
189
+
190
+ def move
191
+ @speed += @actions[:accelerate]
192
+ @speed = 8 if @speed > 8
193
+ @speed = -8 if @speed < -8
194
+
195
+ @x += Math::cos(@heading.to_rad) * @speed
196
+ @y -= Math::sin(@heading.to_rad) * @speed
197
+
198
+ @x = @size if @x - @size < 0
199
+ @y = @size if @y - @size < 0
200
+ @x = @battlefield.width - @size if @x + @size >= @battlefield.width
201
+ @y = @battlefield.height - @size if @y + @size >= @battlefield.height
202
+ end
203
+
204
+ def scan
205
+ @battlefield.robots.each do |other|
206
+ if (other != self) && (!other.dead)
207
+ a = Math.atan2(@y - other.y, other.x - @x) / Math::PI * 180 % 360
208
+ if (@old_radar_heading <= a && a <= @new_radar_heading) || (@old_radar_heading >= a && a >= @new_radar_heading) ||
209
+ (@old_radar_heading <= a+360 && a+360 <= @new_radar_heading) || (@old_radar_heading >= a+360 && a+360 >= new_radar_heading) ||
210
+ (@old_radar_heading <= a-360 && a-360 <= @new_radar_heading) || (@old_radar_heading >= a-360 && a-360 >= @new_radar_heading)
211
+ @events['robot_scanned'] << [Math.hypot(@y - other.y, other.x - @x)]
212
+ end
213
+ end
214
+ end
215
+ @battlefield.toolboxes.each do |toolbox|
216
+ if (!toolbox.dead)
217
+ a = Math.atan2(@y - toolbox.y, toolbox.x - @x) / Math::PI * 180 % 360
218
+ if (@old_radar_heading <= a && a <= @new_radar_heading) || (@old_radar_heading >= a && a >= @new_radar_heading) ||
219
+ (@old_radar_heading <= a+360 && a+360 <= @new_radar_heading) || (@old_radar_heading >= a+360 && a+360 >= new_radar_heading) ||
220
+ (@old_radar_heading <= a-360 && a-360 <= @new_radar_heading) || (@old_radar_heading >= a-360 && a-360 >= @new_radar_heading)
221
+ @events['toolbox_scanned'] << [Math.hypot(@y - toolbox.y, toolbox.x - @x)]
222
+ end
223
+ end
224
+ end
225
+ end
226
+
227
+ def speak
228
+ if @actions[:say] != 0
229
+ @speech = @actions[:say]
230
+ @speech_counter = 50
231
+ elsif @speech and (@speech_counter -= 1) < 0
232
+ @speech = nil
233
+ end
234
+ end
235
+
236
+ def broadcast
237
+ @battlefield.robots.each do |other|
238
+ if (other != self) && (!other.dead)
239
+ msg = other.actions[:broadcast]
240
+ if msg != 0
241
+ a = Math.atan2(@y - other.y, other.x - @x) / Math::PI * 180 % 360
242
+ dir = 'east'
243
+ dir = 'north' if a.between? 45,135
244
+ dir = 'west' if a.between? 135,225
245
+ dir = 'south' if a.between? 225,315
246
+ @events['broadcasts'] << [msg, dir]
247
+ end
248
+ end
249
+ end
250
+ end
251
+
252
+ def to_s
253
+ @robot.class.name
254
+ end
255
+
256
+ def name
257
+ @robot.class.name
258
+ end
259
+
260
+ end