rrobots 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. data/.gitignore +4 -0
  2. data/Gemfile +4 -0
  3. data/README.rdoc +93 -0
  4. data/Rakefile +1 -0
  5. data/VERSION +1 -0
  6. data/bin/rrobots +154 -0
  7. data/bin/tournament +275 -0
  8. data/lib/rrobots.rb +6 -0
  9. data/lib/rrobots/battlefield.rb +69 -0
  10. data/lib/rrobots/bullet.rb +39 -0
  11. data/lib/rrobots/explosion.rb +20 -0
  12. data/lib/rrobots/gui.rb +2 -0
  13. data/lib/rrobots/gui/gosuarena.rb +124 -0
  14. data/lib/rrobots/gui/leaderboard.rb +19 -0
  15. data/lib/rrobots/images/blue_body000.bmp +0 -0
  16. data/lib/rrobots/images/blue_radar000.bmp +0 -0
  17. data/lib/rrobots/images/blue_turret000.bmp +0 -0
  18. data/lib/rrobots/images/bullet.png +0 -0
  19. data/lib/rrobots/images/explosion00.bmp +0 -0
  20. data/lib/rrobots/images/explosion01.bmp +0 -0
  21. data/lib/rrobots/images/explosion02.bmp +0 -0
  22. data/lib/rrobots/images/explosion03.bmp +0 -0
  23. data/lib/rrobots/images/explosion04.bmp +0 -0
  24. data/lib/rrobots/images/explosion05.bmp +0 -0
  25. data/lib/rrobots/images/explosion06.bmp +0 -0
  26. data/lib/rrobots/images/explosion07.bmp +0 -0
  27. data/lib/rrobots/images/explosion08.bmp +0 -0
  28. data/lib/rrobots/images/explosion09.bmp +0 -0
  29. data/lib/rrobots/images/explosion10.bmp +0 -0
  30. data/lib/rrobots/images/explosion11.bmp +0 -0
  31. data/lib/rrobots/images/explosion12.bmp +0 -0
  32. data/lib/rrobots/images/explosion13.bmp +0 -0
  33. data/lib/rrobots/images/explosion14.bmp +0 -0
  34. data/lib/rrobots/images/lime_body000.bmp +0 -0
  35. data/lib/rrobots/images/lime_radar000.bmp +0 -0
  36. data/lib/rrobots/images/lime_turret000.bmp +0 -0
  37. data/lib/rrobots/images/red_body000.bmp +0 -0
  38. data/lib/rrobots/images/red_radar000.bmp +0 -0
  39. data/lib/rrobots/images/red_turret000.bmp +0 -0
  40. data/lib/rrobots/images/space.png +0 -0
  41. data/lib/rrobots/images/white_body000.bmp +0 -0
  42. data/lib/rrobots/images/white_radar000.bmp +0 -0
  43. data/lib/rrobots/images/white_turret000.bmp +0 -0
  44. data/lib/rrobots/images/yellow_body000.bmp +0 -0
  45. data/lib/rrobots/images/yellow_radar000.bmp +0 -0
  46. data/lib/rrobots/images/yellow_turret000.bmp +0 -0
  47. data/lib/rrobots/numeric.rb +10 -0
  48. data/lib/rrobots/robot.rb +115 -0
  49. data/lib/rrobots/robot_runner.rb +237 -0
  50. data/lib/rrobots/tournament.rb +2 -0
  51. data/lib/rrobots/tournament/match.rb +71 -0
  52. data/lib/rrobots/tournament/round.rb +56 -0
  53. data/lib/rrobots/version.rb +3 -0
  54. data/rrobots.gemspec +25 -0
  55. metadata +113 -0
data/lib/rrobots.rb ADDED
@@ -0,0 +1,6 @@
1
+ require 'rrobots/robot'
2
+ require 'rrobots/battlefield'
3
+ require 'rrobots/explosion'
4
+ require 'rrobots/bullet'
5
+ require 'rrobots/robot_runner'
6
+ require 'rrobots/numeric'
@@ -0,0 +1,69 @@
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 :time
9
+ attr_reader :seed
10
+ attr_reader :timeout # how many ticks the match can go before ending.
11
+ attr_reader :game_over
12
+
13
+ def initialize width, height, timeout, seed
14
+ @width, @height = width, height
15
+ @seed = seed
16
+ @time = 0
17
+ @robots = []
18
+ @teams = Hash.new{|h,k| h[k] = [] }
19
+ @bullets = []
20
+ @explosions = []
21
+ @timeout = timeout
22
+ @game_over = false
23
+ srand @seed
24
+ end
25
+
26
+ def << object
27
+ case object
28
+ when RobotRunner
29
+ @robots << object
30
+ @teams[object.team] << object
31
+ when Bullet
32
+ @bullets << object
33
+ when Explosion
34
+ @explosions << object
35
+ end
36
+ end
37
+
38
+ def tick
39
+ explosions.delete_if{|explosion| explosion.dead}
40
+ explosions.each{|explosion| explosion.tick}
41
+
42
+ bullets.delete_if{|bullet| bullet.dead}
43
+ bullets.each{|bullet| bullet.tick}
44
+
45
+ robots.each do |robot|
46
+ begin
47
+ robot.send :internal_tick unless robot.dead
48
+ rescue Exception => bang
49
+ puts "#{robot} made an exception:"
50
+ puts "#{bang.class}: #{bang}", bang.backtrace
51
+ robot.instance_eval{@energy = -1}
52
+ end
53
+ end
54
+
55
+ @time += 1
56
+ live_robots = robots.find_all{|robot| !robot.dead}
57
+ @game_over = ( (@time >= timeout) or # timeout reached
58
+ (live_robots.length == 0) or # no robots alive, draw game
59
+ (live_robots.all?{|r| r.team == live_robots.first.team})) # all other teams are dead
60
+ not @game_over
61
+ end
62
+
63
+ def state
64
+ {:explosions => explosions.map{|e| e.state},
65
+ :bullets => bullets.map{|b| b.state},
66
+ :robots => robots.map{|r| r.state}}
67
+ end
68
+
69
+ 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,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,2 @@
1
+ require 'rrobots/gui/leaderboard'
2
+ require 'rrobots/gui/gosuarena'
@@ -0,0 +1,124 @@
1
+ require 'gosu'
2
+
3
+ BIG_FONT = 'Courier New'
4
+ SMALL_FONT = 'Courier New'
5
+ COLORS = ['white', 'blue', 'yellow', 'red', 'lime']
6
+ FONT_COLORS = [0xffffffff, 0xff0008ff, 0xfffff706, 0xffff0613, 0xff00ff04]
7
+
8
+ GosuRobot = Struct.new(:body, :gun, :radar, :speech, :info, :status, :color, :font_color)
9
+
10
+ module ZOrder
11
+ Background, Robot, Explosions, UI = *0..3
12
+ end
13
+
14
+ class RRobotsGameWindow < Gosu::Window
15
+ attr_reader :battlefield, :xres, :yres
16
+ attr_accessor :on_game_over_handlers, :boom, :robots, :bullets, :explosions
17
+
18
+ def initialize(battlefield, xres, yres)
19
+ super(xres, yres, false, 16)
20
+ self.caption = 'RRobots'
21
+ @font = Gosu::Font.new(self, BIG_FONT, 24)
22
+ @small_font = Gosu::Font.new(self, SMALL_FONT, 24) #xres/100
23
+ @background_image = Gosu::Image.new(self, File.join(File.dirname(__FILE__),"../images/space.png"), true)
24
+ @battlefield = battlefield
25
+ @xres, @yres = xres, yres
26
+ @on_game_over_handlers = []
27
+ init_window
28
+ init_simulation
29
+ @leaderboard = Leaderboard.new(self, @robots)
30
+ end
31
+
32
+ def on_game_over(&block)
33
+ @on_game_over_handlers << block
34
+ end
35
+
36
+ def init_window
37
+ @boom = (0..14).map do |i|
38
+ Gosu::Image.new(self, File.join(File.dirname(__FILE__),"../images/explosion#{i.to_s.rjust(2, '0')}.bmp"))
39
+ end
40
+ @bullet_image = Gosu::Image.new(self, File.join(File.dirname(__FILE__),"../images/bullet.png"))
41
+ end
42
+
43
+ def init_simulation
44
+ @robots, @bullets, @explosions = {}, {}, {}
45
+ end
46
+
47
+ def draw
48
+ simulate
49
+ draw_battlefield
50
+ @leaderboard.draw
51
+ if button_down? Gosu::Button::KbEscape
52
+ self.close
53
+ end
54
+ end
55
+
56
+ def draw_battlefield
57
+ draw_robots
58
+ draw_bullets
59
+ draw_explosions
60
+ end
61
+
62
+ def simulate(ticks=1)
63
+ @explosions.reject!{|e,tko| e.dead }
64
+ @bullets.reject!{|b,tko| b.dead }
65
+ @robots.reject! { |ai,tko| ai.dead}
66
+ ticks.times do
67
+ if @battlefield.game_over
68
+ @on_game_over_handlers.each{|h| h.call(@battlefield) }
69
+ winner = @robots.keys.first
70
+ whohaswon = if winner.nil?
71
+ "Draw!"
72
+ elsif @battlefield.teams.all?{|k,t|t.size<2}
73
+ "#{winner.name} won!"
74
+ else
75
+ "Team #{winner.team} won!"
76
+ end
77
+ text_color = winner ? winner.team : 7
78
+ @font.draw_rel("#{whohaswon}", xres/2, yres/2, ZOrder::UI, 0.5, 0.5, 1, 1, 0xffffff00)
79
+ end
80
+ @battlefield.tick
81
+ end
82
+ end
83
+
84
+ def draw_robots
85
+ @battlefield.robots.each_with_index do |ai, i|
86
+ next if ai.dead
87
+ col = COLORS[i % COLORS.size]
88
+ font_col = FONT_COLORS[i % FONT_COLORS.size]
89
+ @robots[ai] ||= GosuRobot.new(
90
+ Gosu::Image.new(self, File.join(File.dirname(__FILE__),"../images/#{col}_body000.bmp")),
91
+ Gosu::Image.new(self, File.join(File.dirname(__FILE__),"../images/#{col}_turret000.bmp")),
92
+ Gosu::Image.new(self, File.join(File.dirname(__FILE__),"../images/#{col}_radar000.bmp")),
93
+ @small_font,
94
+ @small_font,
95
+ @small_font,
96
+ col,
97
+ font_col
98
+ )
99
+ @robots[ai].body.draw_rot(ai.x / 2, ai.y / 2, ZOrder::Robot, (-(ai.heading-90)) % 360)
100
+ @robots[ai].gun.draw_rot(ai.x / 2, ai.y / 2, ZOrder::Robot, (-(ai.gun_heading-90)) % 360)
101
+ @robots[ai].radar.draw_rot(ai.x / 2, ai.y / 2, ZOrder::Robot, (-(ai.radar_heading-90)) % 360)
102
+
103
+ @robots[ai].speech.draw_rel(ai.speech.to_s, ai.x / 2, ai.y / 2 - 40, ZOrder::UI, 0.5, 0.5, 1, 1, font_col)
104
+ @robots[ai].info.draw_rel("#{ai.name}", ai.x / 2, ai.y / 2 + 30, ZOrder::UI, 0.5, 0.5, 1, 1, font_col)
105
+ @robots[ai].info.draw_rel("#{ai.energy.to_i}", ai.x / 2, ai.y / 2 + 50, ZOrder::UI, 0.5, 0.5, 1, 1, font_col)
106
+ end
107
+ end
108
+
109
+ def draw_bullets
110
+ @battlefield.bullets.each do |bullet|
111
+ @bullets[bullet] ||= @bullet_image
112
+ @bullets[bullet].draw(bullet.x / 2, bullet.y / 2, ZOrder::Explosions)
113
+ end
114
+ end
115
+
116
+ def draw_explosions
117
+ @battlefield.explosions.each do |explosion|
118
+ @explosions[explosion] = boom[explosion.t % 14]
119
+ @explosions[explosion].draw_rot(explosion.x / 2, explosion.y / 2, ZOrder::Explosions, 0)
120
+ end
121
+ end
122
+ end
123
+
124
+
@@ -0,0 +1,19 @@
1
+ class Leaderboard
2
+ def initialize(window, robots)
3
+ @font_size = 24
4
+ @robots = robots
5
+ @font = Gosu::Font.new(window, 'Courier New', @font_size)
6
+ @x_offset = @font_size
7
+ @y_offset = @font_size * 2
8
+ end
9
+
10
+ def draw
11
+ if @robots
12
+ @robots.each_with_index do |r, i|
13
+ y = @y_offset + i * @font_size
14
+ @font.draw("#{r.first.name}", @x_offset, y, ZOrder::UI, 1.0, 1.0, r.last.font_color)
15
+ @font.draw("#{r.first.energy.to_i}", @x_offset + (@font_size * 6), y, ZOrder::UI, 1.0, 1.0, r.last.font_color)
16
+ end
17
+ end
18
+ end
19
+ end
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,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,115 @@
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
+ #broadcasts received last turn
113
+ attr_event :broadcasts
114
+
115
+ end