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
|
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
|
data/images/toolbox.gif
ADDED
|
Binary file
|
data/lib/battlefield.rb
ADDED
|
@@ -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
|
data/lib/bullets.rb
ADDED
|
@@ -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
|
data/lib/explosions.rb
ADDED
|
@@ -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
|
data/lib/overloads.rb
ADDED
data/lib/robot.rb
ADDED
|
@@ -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
|
+
|
data/lib/robotrunner.rb
ADDED
|
@@ -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
|