rubots 0.1

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.
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubots'
4
+
5
+ Rubots.run_game ARGV
@@ -0,0 +1,17 @@
1
+ require 'gosu'
2
+ require 'rubots/graphics'
3
+ require 'rubots/game'
4
+ require 'rubots/robot'
5
+ require 'rubots/command'
6
+ require 'rubots/beam'
7
+ require 'rubots/strategy'
8
+ require 'rubots/strategy_loader'
9
+ require 'rubots/samples'
10
+
11
+ module Rubots
12
+ def self.run_game(params)
13
+ game = Game.new StrategyLoader.load(params)
14
+
15
+ Graphics::Window.new(game).show
16
+ end
17
+ end
@@ -0,0 +1,48 @@
1
+ module Rubots
2
+ class Beam
3
+ attr_reader :source_x, :source_y, :angle
4
+
5
+ def initialize(source_x, source_y, angle)
6
+ @source_x = source_x
7
+ @source_y = source_y
8
+ @angle = angle
9
+ end
10
+
11
+ def self.from(robot)
12
+ real_angle = (robot.angle + robot.gun_angle) % 360
13
+ new robot.x, robot.y, real_angle
14
+ end
15
+
16
+ def check_hit(robot)
17
+ if found_hit?(robot)
18
+ robot.destroy
19
+ puts "#{robot.name} hit by laser"
20
+ end
21
+ end
22
+
23
+ # Laser beam is:
24
+ # (x - x0) = tan(angle)(y0 - y)
25
+ # We check for X:
26
+ # x = tan(angle)(y0 - y) + x0
27
+ # We check for Y
28
+ # y = (x0 - x)/tan(angle) - y0
29
+ HIT_THRESHOLD = 16
30
+ def found_hit?(robot)
31
+ return false if robot.x == @source_x && robot.y == @source_y # Avoid hitting self
32
+
33
+ # Check we're pointing to the right quadrant
34
+ return false if robot.x > @source_x && (@angle > 190 && @angle < 350)
35
+ return false if robot.x < @source_x && (@angle < 170 && @angle > 10)
36
+ return false if robot.y > @source_y && (@angle > 280 || @angle < 80)
37
+ return false if robot.y < @source_y && (@angle < 260 && @angle > 100)
38
+
39
+ tan_angle = Math.tan(@angle * Math::PI / 180)
40
+
41
+ test_x = tan_angle * (@source_y - robot.y) + @source_x
42
+ return true if (test_x - robot.x).abs < HIT_THRESHOLD
43
+
44
+ test_y = (@source_x - robot.x)/tan_angle - @source_y
45
+ (test_y - robot.y).abs < HIT_THRESHOLD
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,6 @@
1
+ require 'rubots/command/base'
2
+ require 'rubots/command/rotate_to'
3
+ require 'rubots/command/throttle'
4
+ require 'rubots/command/rotate_gun_to'
5
+ require 'rubots/command/fire'
6
+ require 'rubots/command/do_nothing'
@@ -0,0 +1,10 @@
1
+ module Rubots
2
+ module Command
3
+ class Base
4
+ def cooldown
5
+ 0
6
+ end
7
+ end
8
+ end
9
+ end
10
+
@@ -0,0 +1,10 @@
1
+ module Rubots
2
+ module Command
3
+ class DoNothing < Base
4
+ def apply_to(robot)
5
+ # Nothing
6
+ end
7
+ end
8
+ end
9
+ end
10
+
@@ -0,0 +1,13 @@
1
+ module Rubots
2
+ module Command
3
+ class Fire < Base
4
+ def apply_to(robot)
5
+ robot.do_fire
6
+ end
7
+
8
+ def cooldown
9
+ 60
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,14 @@
1
+ module Rubots
2
+ module Command
3
+ class RotateGunTo < Base
4
+ def initialize(angle)
5
+ @angle = angle % Robot::MAX_GUN_ANGLE
6
+ end
7
+
8
+ def apply_to(robot)
9
+ robot.desired_gun_angle = @angle
10
+ end
11
+ end
12
+ end
13
+ end
14
+
@@ -0,0 +1,13 @@
1
+ module Rubots
2
+ module Command
3
+ class RotateTo < Base
4
+ def initialize(angle)
5
+ @angle = angle % Robot::MAX_ANGLE
6
+ end
7
+
8
+ def apply_to(robot)
9
+ robot.desired_angle = @angle
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,19 @@
1
+ module Rubots
2
+ module Command
3
+ class Throttle
4
+ def initialize(throttle)
5
+ @throttle = throttle
6
+ @throttle = 0 if @throttle < 0
7
+ @throttle = Robot::MAX_THROTTLE if @throttle > Robot::MAX_THROTTLE
8
+ end
9
+
10
+ def apply_to(robot)
11
+ robot.desired_throttle = @throttle
12
+ end
13
+
14
+ def cooldown
15
+ 5
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,81 @@
1
+ module Rubots
2
+ class Game
3
+ attr_reader :robots, :laser_beams
4
+ MAP_HEIGHT = 700
5
+ MAP_WIDTH = 1000
6
+
7
+ def initialize(robots)
8
+ @robots = robots.map { |klass| Robot.new(klass, self, *random_location) }
9
+ end
10
+
11
+ def tick
12
+ @laser_beams = []
13
+ @robots.each { |robot| robot.tick }
14
+ @robots.each { |robot| robot.tick_fire }
15
+ check_collisions
16
+ check_out_of_area
17
+ check_beam_hits
18
+ clean_up_bodies
19
+ end
20
+
21
+ def map
22
+ OpenStruct.new width: MAP_WIDTH, height: MAP_HEIGHT
23
+ end
24
+
25
+ def laser_fire(beam)
26
+ @laser_beams << beam
27
+ end
28
+
29
+ def over?
30
+ @robots.count <= 1
31
+ end
32
+
33
+ def winner
34
+ return nil unless over?
35
+
36
+ @robots.first || OpenStruct.new(name: "Nobody")
37
+ end
38
+
39
+ private
40
+
41
+ # TODO enforce separation
42
+ def random_location
43
+ x = rand(MAP_WIDTH)
44
+ y = rand(MAP_HEIGHT)
45
+ [x, y]
46
+ end
47
+
48
+ COLLISION_DISTANCE = 32
49
+ def check_collisions
50
+ @robots.each do |r1|
51
+ @robots.each do |r2|
52
+ next if r1 == r2
53
+ if r1.distance_to(r2) < COLLISION_DISTANCE
54
+ r1.destroy
55
+ puts "#{r1.name} destroyed by collision with #{r2.name}"
56
+ end
57
+ end
58
+ end
59
+ end
60
+
61
+ def check_beam_hits
62
+ @laser_beams.each do |beam|
63
+ @robots.each { |robot| beam.check_hit robot }
64
+ end
65
+ end
66
+
67
+ def check_out_of_area
68
+ @robots.each do |r|
69
+ if r.x > MAP_WIDTH || r.y > MAP_HEIGHT || r.x < 0 || r.y < 0
70
+ r.destroy
71
+ puts "#{r.name} hit the invisible wall and was destroyed"
72
+ end
73
+ end
74
+ end
75
+
76
+ def clean_up_bodies
77
+ @robots.reject!(&:destroyed?)
78
+ end
79
+
80
+ end
81
+ end
@@ -0,0 +1,4 @@
1
+ require 'rubots/graphics/window'
2
+ require 'rubots/graphics/robot'
3
+ require 'rubots/graphics/beam'
4
+ require 'rubots/graphics/assets'
@@ -0,0 +1,11 @@
1
+ module Rubots
2
+ module Graphics
3
+ class Assets
4
+ MEDIA_DIR = File.join(File.dirname(__FILE__), '..', '..', '..', 'media')
5
+ PEW_SOUND = File.join(MEDIA_DIR, "pew.wav")
6
+ ROBOT_IMG = File.join(MEDIA_DIR, "robot.png")
7
+ GUN_IMG = File.join(MEDIA_DIR, "gun.png")
8
+ DEAD_IMG = File.join(MEDIA_DIR, "deadbot.png")
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,32 @@
1
+ module Rubots
2
+ module Graphics
3
+ class Beam
4
+ BEAM_LENGTH = 10000 # As long as it goes out of the screen it's good
5
+ BEAM_DURATION = 30 # For how many ticks is the beam visible
6
+
7
+ def initialize(window, beam)
8
+ @beam = beam
9
+ @duration = BEAM_DURATION
10
+ @window = window
11
+ @pew = Gosu::Sample.new(window, Assets::PEW_SOUND)
12
+ @pew.play
13
+ end
14
+
15
+ def decay
16
+ @duration -= 1
17
+ end
18
+
19
+ def expired?
20
+ @duration <= 0
21
+ end
22
+
23
+ def draw
24
+ rad_angle = @beam.angle * Math::PI / 180
25
+ x_end = @beam.source_x + Math.sin(rad_angle) * BEAM_LENGTH
26
+ y_end = @beam.source_y + Math.cos(rad_angle) * BEAM_LENGTH * -1
27
+ beam_color = 0xffff0000
28
+ @window.draw_line @beam.source_x, @beam.source_y, beam_color, x_end, y_end, beam_color
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,25 @@
1
+ module Rubots
2
+ module Graphics
3
+ class Robot
4
+ Z_AXIS = 10
5
+
6
+ def initialize(window, robot)
7
+ @robot = robot
8
+ @image = Gosu::Image.new(window, Assets::ROBOT_IMG, false)
9
+ @gun_image = Gosu::Image.new(window, Assets::GUN_IMG, false)
10
+ @dead_image = Gosu::Image.new(window, Assets::DEAD_IMG, false)
11
+ @font = Gosu::Font.new(window, Gosu::default_font_name, 14)
12
+ end
13
+
14
+ def draw
15
+ if @robot.destroyed?
16
+ @dead_image.draw_rot(@robot.x, @robot.y, Z_AXIS, 0)
17
+ else
18
+ @image.draw_rot(@robot.x, @robot.y, Z_AXIS, @robot.angle)
19
+ @gun_image.draw_rot(@robot.x, @robot.y, Z_AXIS + 1, @robot.angle + @robot.gun_angle)
20
+ end
21
+ @font.draw_rel(@robot.name, @robot.x, @robot.y + 20, Z_AXIS + 2, 0.5, 1.0, 1.0, 1.0, 0xffffff00)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,43 @@
1
+ module Rubots
2
+ module Graphics
3
+ class Window < Gosu::Window
4
+ def initialize(game)
5
+ @game = game
6
+ super Game::MAP_WIDTH, Game::MAP_HEIGHT, false
7
+ self.caption = "LASER RUBOTS PEW PEW PEW"
8
+ @robots = @game.robots.map { |r| Robot.new self, r }
9
+ @beams = []
10
+ end
11
+
12
+ GAME_END_TICKS = 150
13
+ def update
14
+ if !@game_over
15
+ @game.tick
16
+ @beams += @game.laser_beams.map { |b| Beam.new self, b }
17
+ decay_beams
18
+ @game_over = @game.over?
19
+ else
20
+ @game_over_countdown ||= GAME_END_TICKS
21
+ @game_over_countdown -= 1
22
+ if @game_over_countdown == 0
23
+ puts "#{@game.winner.name} wins the game."
24
+ exit
25
+ end
26
+ end
27
+
28
+ end
29
+
30
+ def draw
31
+ @robots.each &:draw
32
+ @beams.each &:draw
33
+ end
34
+
35
+ private
36
+
37
+ def decay_beams
38
+ @beams.each(&:decay)
39
+ @beams.reject!(&:expired?)
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,152 @@
1
+ require 'ostruct'
2
+
3
+ module Rubots
4
+ class Robot
5
+ attr_reader :x, :y, :angle, :gun_angle
6
+ attr_writer :desired_angle, :desired_throttle, :desired_gun_angle
7
+
8
+ # Some constants
9
+ MAX_ANGLE = 360 # Maximum angle. Wraps around to zero after this.
10
+ ANGLE_STEP = 1 # How much we change angle each tick.
11
+
12
+ MAX_THROTTLE = 10 # Max throttle. Can't go above.
13
+ THROTTLE_STEP = 1 # How much we change throttle each tick.
14
+
15
+ SPEED_FACTOR = 1 # How much movement does each throttle step represent
16
+
17
+ MAX_GUN_ANGLE = 360 # Maximum gun angle. Wraps around to zero after this.
18
+ GUN_ANGLE_STEP = 2 # How much we change angle each tick.
19
+
20
+
21
+ def initialize(strategy_class, game, x, y)
22
+ @x = x
23
+ @y = y
24
+ @throttle = @desired_throttle = 0.0
25
+ @angle = @desired_angle = 0.0
26
+ @gun_angle = @desired_gun_angle = 0.0
27
+ @game = game
28
+
29
+ @strategy = strategy_class.new(@game.map, robot_data, nil)
30
+
31
+ @destroyed = false
32
+
33
+ @cooldown_timer = 0
34
+ end
35
+
36
+ def tick
37
+ return if @destroyed
38
+
39
+ if @cooldown_timer > 0
40
+ @cooldown_timer -= 1
41
+ else
42
+ command = @strategy.get_command(robot_data, targets_data)
43
+ command.apply_to(self)
44
+ @cooldown_timer = command.cooldown
45
+ end
46
+ tick_angle
47
+ tick_throttle
48
+ tick_movement
49
+ tick_gun
50
+ end
51
+
52
+ # It's a separate method because we want fire to be after *every* robot moved
53
+ def tick_fire
54
+ if @firing
55
+ @game.laser_fire(Beam.from(self))
56
+ @firing = false
57
+ end
58
+ end
59
+
60
+ def name
61
+ @strategy.name
62
+ end
63
+
64
+ def do_fire
65
+ @firing = true
66
+ end
67
+
68
+ def distance_to(other)
69
+ x_dist = @x - other.x
70
+ y_dist = @y - other.y
71
+ Math.sqrt(x_dist ** 2 + y_dist ** 2)
72
+ end
73
+
74
+ def destroy
75
+ @throttle = 0
76
+ @destroyed = true
77
+ end
78
+
79
+ def destroyed?
80
+ @destroyed
81
+ end
82
+
83
+ private
84
+
85
+ def robot_data
86
+ OpenStruct.new x: @x, y: @y, angle: @angle, throttle: @throttle, gun_angle: @gun_angle
87
+ end
88
+
89
+ def targets_data
90
+ @game.robots.map do |target_robot|
91
+ next if target_robot == self
92
+ x_dist = @x - target_robot.x
93
+ y_dist = @y - target_robot.y
94
+ distance = Math.sqrt(x_dist ** 2 + y_dist ** 2)
95
+ actual_angle = Math.atan2(x_dist, -y_dist) * 180 / Math::PI + 180
96
+ relative_angle = (actual_angle - @angle) % 360
97
+
98
+ OpenStruct.new name: target_robot.name, distance: distance, angle: relative_angle
99
+ end.compact
100
+ end
101
+
102
+ def tick_angle
103
+ if @desired_angle != @angle
104
+ if (@desired_angle - @angle).abs < ANGLE_STEP
105
+ @angle = @desired_angle # Fractional angles
106
+ else
107
+ diff = @desired_angle - @angle
108
+ sign = diff / diff.abs
109
+ sign = sign * -1 if diff.abs > MAX_ANGLE / 2.0
110
+ @angle += sign * ANGLE_STEP
111
+ @angle += MAX_ANGLE if @angle < 0
112
+ @angle -= MAX_ANGLE if @angle >= MAX_ANGLE
113
+ end
114
+ end
115
+ end
116
+
117
+ def tick_throttle
118
+ if @desired_throttle != @throttle
119
+ diff = @desired_throttle - @throttle
120
+ if diff.abs < THROTTLE_STEP
121
+ @throttle = @desired_throttle
122
+ else
123
+ @throttle += (diff / diff.abs) * THROTTLE_STEP
124
+ end
125
+ end
126
+ end
127
+
128
+ def tick_movement
129
+ movement = @throttle * SPEED_FACTOR
130
+ rad_angle = angle * Math::PI / 180
131
+ mov_x = Math.sin(rad_angle) * movement
132
+ mov_y = Math.cos(rad_angle) * movement * -1
133
+ @x += mov_x
134
+ @y += mov_y
135
+ end
136
+
137
+ def tick_gun
138
+ if @desired_gun_angle != @gun_angle
139
+ if (@desired_gun_angle - @gun_angle).abs < GUN_ANGLE_STEP
140
+ @gun_angle = @desired_gun_angle # Fractional angles
141
+ else
142
+ diff = @desired_gun_angle - @gun_angle
143
+ sign = diff / diff.abs
144
+ sign = sign * -1 if diff.abs > MAX_GUN_ANGLE / 2.0
145
+ @gun_angle += sign * GUN_ANGLE_STEP
146
+ @gun_angle += MAX_GUN_ANGLE if @gun_angle < 0
147
+ @gun_angle -= MAX_GUN_ANGLE if @gun_angle >= MAX_GUN_ANGLE
148
+ end
149
+ end
150
+ end
151
+ end
152
+ end
@@ -0,0 +1,4 @@
1
+ require 'rubots/samples/sitting_duck'
2
+ require 'rubots/samples/rotator'
3
+ require 'rubots/samples/target_finder'
4
+ require 'rubots/samples/artillery'
@@ -0,0 +1,24 @@
1
+ module Rubots
2
+ module Samples
3
+ # Points at a target and fires a single shot.
4
+ class Artillery < Strategy
5
+ def initialize(map, me, targets)
6
+ @fired = false
7
+ end
8
+
9
+ def command(me, targets)
10
+ if me.angle != 90
11
+ rotate_to 90
12
+ elsif me.gun_angle != targets.first.angle
13
+ rotate_gun_to targets.first.angle
14
+ else
15
+ fire
16
+ end
17
+ end
18
+
19
+ def name
20
+ "Artillery"
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,24 @@
1
+ module Rubots
2
+ module Samples
3
+ # Rotates in place direction
4
+ class Rotator < Strategy
5
+ def initialize(map, me, targets)
6
+ @direction = :left
7
+ end
8
+
9
+ def command(me, targets)
10
+ if @direction == :left
11
+ @direction = :right if me.angle == 270
12
+ rotate_to 270
13
+ else
14
+ @direction = :left if me.angle == 89
15
+ rotate_to 89
16
+ end
17
+ end
18
+
19
+ def name
20
+ "Rotator"
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,11 @@
1
+ module Rubots
2
+ module Samples
3
+ # Just stays there
4
+ class SittingDuck < Strategy
5
+
6
+ def name
7
+ "Duck"
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,68 @@
1
+ module Rubots
2
+ module Samples
3
+ # Homes into the center of the map, then stays there, points up, and aims down.
4
+ class TargetFinder < Strategy
5
+ ANGLE_DOWN = 180
6
+ ANGLE_UP = 0
7
+ ANGLE_LEFT = 270
8
+ ANGLE_RIGHT = 90
9
+
10
+ def initialize(map, me, targets)
11
+ @finding = :x
12
+ @map = map
13
+ @find_x = map.width / 2
14
+ @find_y = map.height / 2
15
+ end
16
+
17
+ def command(me, targets)
18
+ if @finding == :x
19
+ find_x(me)
20
+ elsif @finding == :y
21
+ find_y(me)
22
+ elsif me.angle != 0
23
+ rotate_to 0
24
+ else
25
+ rotate_gun_to 180
26
+ end
27
+ end
28
+
29
+ def name
30
+ "GoToCenter"
31
+ end
32
+
33
+ def find_x(me)
34
+ if me.x > @find_x && me.angle != ANGLE_LEFT
35
+ rotate_to ANGLE_LEFT
36
+ elsif me.x < @find_x && me.angle != ANGLE_RIGHT
37
+ rotate_to ANGLE_RIGHT
38
+ elsif me.x != @find_x
39
+ if (@find_x - me.x).abs > 50
40
+ throttle 4
41
+ else
42
+ throttle 1
43
+ end
44
+ else # At pos x
45
+ @finding = :y
46
+ throttle 0
47
+ end
48
+ end
49
+
50
+ def find_y(me)
51
+ if me.y > @find_y && me.angle != ANGLE_UP
52
+ rotate_to ANGLE_UP
53
+ elsif me.y < @find_y && me.angle != ANGLE_DOWN
54
+ rotate_to ANGLE_DOWN
55
+ elsif me.y != @find_y
56
+ if (@find_y - me.y).abs > 50
57
+ throttle 5
58
+ else
59
+ throttle 1
60
+ end
61
+ else # At pos y
62
+ @finding = :none
63
+ throttle 0
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,44 @@
1
+ module Rubots
2
+ class Strategy
3
+ def initialize(map, me, targets)
4
+ end
5
+
6
+ # Called by the Robot to get a command
7
+ def get_command(me, targets)
8
+ @command_queue ||= []
9
+ command(me, targets) if @command_queue.empty?
10
+ @command_queue.shift || Command::DoNothing.new
11
+ end
12
+
13
+ # When get_command is out of commands, it calls this, which will queue commands
14
+ def command(me, targets)
15
+ # Implement in subclass
16
+ end
17
+
18
+ def name
19
+ "Unnamed robot"
20
+ end
21
+
22
+ protected
23
+
24
+ def rotate_to(angle)
25
+ @command_queue << Command::RotateTo.new(angle)
26
+ end
27
+
28
+ def rotate_gun_to(angle)
29
+ @command_queue << Command::RotateGunTo.new(angle)
30
+ end
31
+
32
+ def throttle(throttle)
33
+ @command_queue << Command::Throttle.new(throttle)
34
+ end
35
+
36
+ def fire
37
+ @command_queue << Command::Fire.new
38
+ end
39
+
40
+ def do_nothing
41
+ @command_queue << Command::DoNothing.new
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,51 @@
1
+ module Rubots
2
+ class StrategyLoader
3
+ def self.load(params)
4
+ return default_lineup unless params.any?
5
+
6
+ params.map { |p| new(p).strategy_class }
7
+ end
8
+
9
+ def self.default_lineup
10
+ [ Samples::Rotator, Samples::SittingDuck, Samples::TargetFinder,
11
+ Samples::Artillery ]
12
+ end
13
+
14
+ def initialize(name)
15
+ @name = name
16
+ end
17
+
18
+ def strategy_class
19
+ if is_sample?
20
+ sample_class
21
+ else
22
+ class_from_file
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def class_from_file
29
+ load @name
30
+
31
+ class_name = camelize(File.basename(@name, ".rb"))
32
+ Rubots.const_get(class_name)
33
+ end
34
+
35
+ def is_sample?
36
+ @name.match /^sample:/
37
+ end
38
+
39
+ def sample_class
40
+ Samples.const_get(camelize(@name.split(':').last))
41
+ end
42
+
43
+ def camelize(term)
44
+ string = term.to_s
45
+ string = string.sub(/^[a-z\d]*/) { $&.capitalize }
46
+ string.gsub!(/(?:_|(\/))([a-z\d]*)/i) { "#{$1}#{$2.capitalize}" }
47
+ string.gsub!('/', '::')
48
+ string
49
+ end
50
+ end
51
+ end
Binary file
Binary file
Binary file
Binary file
metadata ADDED
@@ -0,0 +1,91 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rubots
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Nacho Facello
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-06-04 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: gosu
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 0.7.50
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 0.7.50
30
+ description: A small simple game where you program robots to fight to the death using
31
+ red lasers
32
+ email: nacho@nucleartesuji.com
33
+ executables:
34
+ - rubots
35
+ extensions: []
36
+ extra_rdoc_files: []
37
+ files:
38
+ - lib/rubots/samples.rb
39
+ - lib/rubots/graphics.rb
40
+ - lib/rubots/game.rb
41
+ - lib/rubots/beam.rb
42
+ - lib/rubots/command/rotate_gun_to.rb
43
+ - lib/rubots/command/throttle.rb
44
+ - lib/rubots/command/do_nothing.rb
45
+ - lib/rubots/command/rotate_to.rb
46
+ - lib/rubots/command/fire.rb
47
+ - lib/rubots/command/base.rb
48
+ - lib/rubots/strategy.rb
49
+ - lib/rubots/strategy_loader.rb
50
+ - lib/rubots/robot.rb
51
+ - lib/rubots/graphics/assets.rb
52
+ - lib/rubots/graphics/beam.rb
53
+ - lib/rubots/graphics/robot.rb
54
+ - lib/rubots/graphics/window.rb
55
+ - lib/rubots/samples/sitting_duck.rb
56
+ - lib/rubots/samples/rotator.rb
57
+ - lib/rubots/samples/artillery.rb
58
+ - lib/rubots/samples/target_finder.rb
59
+ - lib/rubots/command.rb
60
+ - lib/rubots.rb
61
+ - media/deadbot.png
62
+ - media/gun.png
63
+ - media/robot.png
64
+ - media/pew.wav
65
+ - bin/rubots
66
+ homepage: http://github.com/nachof/laser_rubots
67
+ licenses:
68
+ - MIT
69
+ post_install_message:
70
+ rdoc_options: []
71
+ require_paths:
72
+ - lib
73
+ required_ruby_version: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ! '>='
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ required_rubygems_version: !ruby/object:Gem::Requirement
80
+ none: false
81
+ requirements:
82
+ - - ! '>='
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
85
+ requirements: []
86
+ rubyforge_project:
87
+ rubygems_version: 1.8.23
88
+ signing_key:
89
+ specification_version: 3
90
+ summary: Laser Rubots!
91
+ test_files: []