colstrom-rtanque 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +22 -0
- data/.rspec +2 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +10 -0
- data/.yardopts +4 -0
- data/Gemfile +4 -0
- data/Gemfile.ci +6 -0
- data/LICENSE.txt +22 -0
- data/README.md +168 -0
- data/Rakefile +1 -0
- data/bin/rtanque +117 -0
- data/lib/rtanque.rb +31 -0
- data/lib/rtanque/arena.rb +8 -0
- data/lib/rtanque/bot.rb +117 -0
- data/lib/rtanque/bot/brain.rb +50 -0
- data/lib/rtanque/bot/brain_helper.rb +23 -0
- data/lib/rtanque/bot/command.rb +23 -0
- data/lib/rtanque/bot/radar.rb +54 -0
- data/lib/rtanque/bot/sensors.rb +37 -0
- data/lib/rtanque/bot/turret.rb +14 -0
- data/lib/rtanque/configuration.rb +47 -0
- data/lib/rtanque/explosion.rb +23 -0
- data/lib/rtanque/gui.rb +25 -0
- data/lib/rtanque/gui/bot.rb +71 -0
- data/lib/rtanque/gui/bot/health_color_calculator.rb +37 -0
- data/lib/rtanque/gui/draw_group.rb +30 -0
- data/lib/rtanque/gui/explosion.rb +25 -0
- data/lib/rtanque/gui/shell.rb +31 -0
- data/lib/rtanque/gui/window.rb +64 -0
- data/lib/rtanque/heading.rb +162 -0
- data/lib/rtanque/match.rb +73 -0
- data/lib/rtanque/match/tick_group.rb +50 -0
- data/lib/rtanque/movable.rb +51 -0
- data/lib/rtanque/normalized_attr.rb +69 -0
- data/lib/rtanque/point.rb +140 -0
- data/lib/rtanque/runner.rb +88 -0
- data/lib/rtanque/shell.rb +44 -0
- data/lib/rtanque/version.rb +3 -0
- data/resources/images/body.png +0 -0
- data/resources/images/bullet.png +0 -0
- data/resources/images/explosions/explosion2-1.png +0 -0
- data/resources/images/explosions/explosion2-10.png +0 -0
- data/resources/images/explosions/explosion2-11.png +0 -0
- data/resources/images/explosions/explosion2-12.png +0 -0
- data/resources/images/explosions/explosion2-13.png +0 -0
- data/resources/images/explosions/explosion2-14.png +0 -0
- data/resources/images/explosions/explosion2-15.png +0 -0
- data/resources/images/explosions/explosion2-16.png +0 -0
- data/resources/images/explosions/explosion2-17.png +0 -0
- data/resources/images/explosions/explosion2-18.png +0 -0
- data/resources/images/explosions/explosion2-19.png +0 -0
- data/resources/images/explosions/explosion2-2.png +0 -0
- data/resources/images/explosions/explosion2-20.png +0 -0
- data/resources/images/explosions/explosion2-21.png +0 -0
- data/resources/images/explosions/explosion2-22.png +0 -0
- data/resources/images/explosions/explosion2-23.png +0 -0
- data/resources/images/explosions/explosion2-24.png +0 -0
- data/resources/images/explosions/explosion2-25.png +0 -0
- data/resources/images/explosions/explosion2-26.png +0 -0
- data/resources/images/explosions/explosion2-27.png +0 -0
- data/resources/images/explosions/explosion2-28.png +0 -0
- data/resources/images/explosions/explosion2-29.png +0 -0
- data/resources/images/explosions/explosion2-3.png +0 -0
- data/resources/images/explosions/explosion2-30.png +0 -0
- data/resources/images/explosions/explosion2-31.png +0 -0
- data/resources/images/explosions/explosion2-32.png +0 -0
- data/resources/images/explosions/explosion2-33.png +0 -0
- data/resources/images/explosions/explosion2-34.png +0 -0
- data/resources/images/explosions/explosion2-35.png +0 -0
- data/resources/images/explosions/explosion2-36.png +0 -0
- data/resources/images/explosions/explosion2-37.png +0 -0
- data/resources/images/explosions/explosion2-38.png +0 -0
- data/resources/images/explosions/explosion2-39.png +0 -0
- data/resources/images/explosions/explosion2-4.png +0 -0
- data/resources/images/explosions/explosion2-40.png +0 -0
- data/resources/images/explosions/explosion2-41.png +0 -0
- data/resources/images/explosions/explosion2-42.png +0 -0
- data/resources/images/explosions/explosion2-43.png +0 -0
- data/resources/images/explosions/explosion2-44.png +0 -0
- data/resources/images/explosions/explosion2-45.png +0 -0
- data/resources/images/explosions/explosion2-46.png +0 -0
- data/resources/images/explosions/explosion2-47.png +0 -0
- data/resources/images/explosions/explosion2-48.png +0 -0
- data/resources/images/explosions/explosion2-49.png +0 -0
- data/resources/images/explosions/explosion2-5.png +0 -0
- data/resources/images/explosions/explosion2-50.png +0 -0
- data/resources/images/explosions/explosion2-51.png +0 -0
- data/resources/images/explosions/explosion2-52.png +0 -0
- data/resources/images/explosions/explosion2-53.png +0 -0
- data/resources/images/explosions/explosion2-54.png +0 -0
- data/resources/images/explosions/explosion2-55.png +0 -0
- data/resources/images/explosions/explosion2-56.png +0 -0
- data/resources/images/explosions/explosion2-57.png +0 -0
- data/resources/images/explosions/explosion2-58.png +0 -0
- data/resources/images/explosions/explosion2-59.png +0 -0
- data/resources/images/explosions/explosion2-6.png +0 -0
- data/resources/images/explosions/explosion2-60.png +0 -0
- data/resources/images/explosions/explosion2-61.png +0 -0
- data/resources/images/explosions/explosion2-62.png +0 -0
- data/resources/images/explosions/explosion2-63.png +0 -0
- data/resources/images/explosions/explosion2-64.png +0 -0
- data/resources/images/explosions/explosion2-65.png +0 -0
- data/resources/images/explosions/explosion2-66.png +0 -0
- data/resources/images/explosions/explosion2-67.png +0 -0
- data/resources/images/explosions/explosion2-68.png +0 -0
- data/resources/images/explosions/explosion2-69.png +0 -0
- data/resources/images/explosions/explosion2-7.png +0 -0
- data/resources/images/explosions/explosion2-70.png +0 -0
- data/resources/images/explosions/explosion2-71.png +0 -0
- data/resources/images/explosions/explosion2-8.png +0 -0
- data/resources/images/explosions/explosion2-9.png +0 -0
- data/resources/images/grass.png +0 -0
- data/resources/images/radar.png +0 -0
- data/resources/images/turret.png +0 -0
- data/rtanque.gemspec +34 -0
- data/sample_bots/camper.rb +79 -0
- data/sample_bots/keyboard.rb +50 -0
- data/sample_bots/seek_and_destroy.rb +53 -0
- data/screenshots/battle_1.png +0 -0
- data/screenshots/battle_2.png +0 -0
- data/spec/rtanque/bot_spec.rb +239 -0
- data/spec/rtanque/heading_spec.rb +279 -0
- data/spec/rtanque/match_spec.rb +46 -0
- data/spec/rtanque/normalized_attr_spec.rb +90 -0
- data/spec/rtanque/point_spec.rb +196 -0
- data/spec/rtanque/radar_spec.rb +87 -0
- data/spec/rtanque/shell_spec.rb +35 -0
- data/spec/rtanque_spec.rb +34 -0
- data/spec/spec_helper.rb +51 -0
- data/templates/bot.erb +17 -0
- metadata +315 -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
|
data/rtanque.gemspec
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'rtanque/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "colstrom-rtanque"
|
8
|
+
gem.version = RTanque::VERSION
|
9
|
+
gem.authors = ["Adam Williams"]
|
10
|
+
gem.email = ["pwnfactory@gmail.com"]
|
11
|
+
gem.summary = %q{RTanque is a game for programmers. Players program the brain of a tank and then send their tank into battle against other tanks.}
|
12
|
+
gem.description = %q{RTanque is a game for programmers. Players program the brain of a tank and then send their tank+brain into battle with other tanks. All tanks are otherwise equal.
|
13
|
+
|
14
|
+
Rules of the game are simple: Last bot standing wins. Gameplay is also pretty simple. Each tank has a base, turret and radar, each of which rotate independently. The base moves the tank, the turret has a gun mounted to it which can fire at other tanks, and the radar detects other tanks in its field of vision.
|
15
|
+
|
16
|
+
Have fun competing against friends' tanks or the sample ones included. Maybe you'll start a small league at your local Ruby meetup.}
|
17
|
+
gem.homepage = "https://github.com/awilliams/RTanque"
|
18
|
+
gem.license = 'MIT'
|
19
|
+
|
20
|
+
gem.files = `git ls-files`.split($/)
|
21
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
22
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
23
|
+
gem.require_paths = ["lib"]
|
24
|
+
|
25
|
+
gem.add_dependency 'gosu', '~> 0.10', '>= 0.7.45'
|
26
|
+
gem.add_dependency 'configuration', '~> 1.3.2'
|
27
|
+
gem.add_dependency 'octokit', '~> 2.7.0'
|
28
|
+
gem.add_dependency 'thor', '~> 0.17.0'
|
29
|
+
gem.add_dependency 'texplay', '~> 0.4', '>= 0.4.3'
|
30
|
+
|
31
|
+
gem.add_development_dependency 'pry'
|
32
|
+
gem.add_development_dependency 'rspec', '~> 2.13.0'
|
33
|
+
gem.add_development_dependency 'rspec-mocks', '~> 2.13.0'
|
34
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# Camper: Sample Bot
|
2
|
+
#
|
3
|
+
# Enjoys sitting in the corners and firing powerful shots
|
4
|
+
class Camper < RTanque::Bot::Brain
|
5
|
+
NAME = 'Camper'
|
6
|
+
include RTanque::Bot::BrainHelper
|
7
|
+
|
8
|
+
CORNERS = [:NW, :NE, :SE, :SW]
|
9
|
+
TURRET_FIRE_RANGE = RTanque::Heading::ONE_DEGREE * 1.0
|
10
|
+
SWITCH_CORNER_TICK_RANGE = (600..1000)
|
11
|
+
|
12
|
+
def tick!
|
13
|
+
self.hide_in_corners
|
14
|
+
if (target = self.nearest_target)
|
15
|
+
self.fire_upon(target)
|
16
|
+
else
|
17
|
+
self.detect_targets
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def fire_upon(target)
|
22
|
+
self.command.radar_heading = target.heading
|
23
|
+
self.command.turret_heading = target.heading
|
24
|
+
if self.sensors.turret_heading.delta(target.heading).abs < TURRET_FIRE_RANGE
|
25
|
+
self.command.fire(MAX_FIRE_POWER)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def nearest_target
|
30
|
+
self.sensors.radar.min { |a,b| a.distance <=> b.distance }
|
31
|
+
end
|
32
|
+
|
33
|
+
def detect_targets
|
34
|
+
self.command.radar_heading = self.sensors.radar_heading + MAX_RADAR_ROTATION
|
35
|
+
self.command.turret_heading = self.sensors.heading + RTanque::Heading::HALF_ANGLE
|
36
|
+
end
|
37
|
+
|
38
|
+
def hide_in_corners
|
39
|
+
@corner_cycle ||= CORNERS.shuffle.cycle
|
40
|
+
self.at_tick_interval(self.camp_interval) {
|
41
|
+
self.corner = @corner_cycle.next
|
42
|
+
self.reset_camp_interval
|
43
|
+
}
|
44
|
+
self.corner ||= @corner_cycle.next
|
45
|
+
self.move_to_corner
|
46
|
+
end
|
47
|
+
|
48
|
+
def move_to_corner
|
49
|
+
if self.corner
|
50
|
+
command.heading = self.sensors.position.heading(RTanque::Point.new(*self.corner, self.arena))
|
51
|
+
command.speed = MAX_BOT_SPEED
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def corner=(corner_name)
|
56
|
+
@corner = case corner_name
|
57
|
+
when :NE
|
58
|
+
[self.arena.width, self.arena.height]
|
59
|
+
when :SE
|
60
|
+
[self.arena.width, 0]
|
61
|
+
when :SW
|
62
|
+
[0, 0]
|
63
|
+
else
|
64
|
+
[0, self.arena.height]
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def corner
|
69
|
+
@corner
|
70
|
+
end
|
71
|
+
|
72
|
+
def camp_interval
|
73
|
+
@camp_interval ||= self.reset_camp_interval
|
74
|
+
end
|
75
|
+
|
76
|
+
def reset_camp_interval
|
77
|
+
@camp_interval = rand(SWITCH_CORNER_TICK_RANGE.max - SWITCH_CORNER_TICK_RANGE.min) + SWITCH_CORNER_TICK_RANGE.min
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
# Keyboard: Sample Bot
|
3
|
+
#
|
4
|
+
# Special bot controlled with the keyboard
|
5
|
+
#
|
6
|
+
# Controls:
|
7
|
+
# w drive forward
|
8
|
+
# s drive backwards
|
9
|
+
# a rotate left
|
10
|
+
# d rotate right
|
11
|
+
#
|
12
|
+
# ↑ fire powerful shot
|
13
|
+
# ↓ fire week shot
|
14
|
+
# ← rotate turret left
|
15
|
+
# → rotate turret right
|
16
|
+
class Keyboard < RTanque::Bot::Brain
|
17
|
+
include RTanque::Bot::BrainHelper
|
18
|
+
|
19
|
+
NAME = 'Keyboard'
|
20
|
+
|
21
|
+
def tick!
|
22
|
+
command.radar_heading = sensors.radar_heading + (RTanque::Heading::ONE_DEGREE * 30)
|
23
|
+
|
24
|
+
if sensors.button_down?(Gosu::KbLeft)
|
25
|
+
command.turret_heading = sensors.turret_heading - (RTanque::Heading::ONE_DEGREE * 10)
|
26
|
+
elsif sensors.button_down?(Gosu::KbRight)
|
27
|
+
command.turret_heading = sensors.turret_heading + (RTanque::Heading::ONE_DEGREE * 10)
|
28
|
+
end
|
29
|
+
|
30
|
+
if sensors.button_down?('a')
|
31
|
+
command.heading = sensors.heading - (RTanque::Heading::ONE_DEGREE * 10)
|
32
|
+
elsif sensors.button_down?('d')
|
33
|
+
command.heading = sensors.heading + (RTanque::Heading::ONE_DEGREE * 10)
|
34
|
+
end
|
35
|
+
|
36
|
+
if sensors.button_down?('w')
|
37
|
+
command.speed = 10
|
38
|
+
elsif sensors.button_down?('s')
|
39
|
+
command.speed = -10
|
40
|
+
else
|
41
|
+
command.speed = 0
|
42
|
+
end
|
43
|
+
|
44
|
+
if sensors.button_down?(Gosu::KbUp)
|
45
|
+
command.fire_power = 5
|
46
|
+
elsif sensors.button_down?(Gosu::KbDown)
|
47
|
+
command.fire_power = 1
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# Seek&Destroy: Sample Bot
|
2
|
+
#
|
3
|
+
# Enjoys following and target and firing many shots
|
4
|
+
class SeekAndDestroy < RTanque::Bot::Brain
|
5
|
+
NAME = 'Seek&Destroy'
|
6
|
+
include RTanque::Bot::BrainHelper
|
7
|
+
|
8
|
+
TURRET_FIRE_RANGE = RTanque::Heading::ONE_DEGREE * 5.0
|
9
|
+
|
10
|
+
def tick!
|
11
|
+
@desired_heading ||= nil
|
12
|
+
|
13
|
+
if (lock = self.get_radar_lock)
|
14
|
+
self.destroy_lock(lock)
|
15
|
+
@desired_heading = nil
|
16
|
+
else
|
17
|
+
self.seek_lock
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def destroy_lock(reflection)
|
22
|
+
command.heading = reflection.heading
|
23
|
+
command.radar_heading = reflection.heading
|
24
|
+
command.turret_heading = reflection.heading
|
25
|
+
command.speed = reflection.distance > 200 ? MAX_BOT_SPEED : MAX_BOT_SPEED / 2.0
|
26
|
+
if (reflection.heading.delta(sensors.turret_heading)).abs < TURRET_FIRE_RANGE
|
27
|
+
command.fire(reflection.distance > 200 ? MAX_FIRE_POWER : MIN_FIRE_POWER)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def seek_lock
|
32
|
+
if sensors.position.on_wall?
|
33
|
+
@desired_heading = sensors.heading + RTanque::Heading::HALF_ANGLE
|
34
|
+
end
|
35
|
+
command.radar_heading = sensors.radar_heading + MAX_RADAR_ROTATION
|
36
|
+
command.speed = 1
|
37
|
+
if @desired_heading
|
38
|
+
command.heading = @desired_heading
|
39
|
+
command.turret_heading = @desired_heading
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def get_radar_lock
|
44
|
+
@locked_on ||= nil
|
45
|
+
lock = if @locked_on
|
46
|
+
sensors.radar.find { |reflection| reflection.name == @locked_on } || sensors.radar.first
|
47
|
+
else
|
48
|
+
sensors.radar.first
|
49
|
+
end
|
50
|
+
@locked_on = lock.name if lock
|
51
|
+
lock
|
52
|
+
end
|
53
|
+
end
|
Binary file
|
Binary file
|
@@ -0,0 +1,239 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe RTanque::Bot do
|
4
|
+
before(:each) { @brain_tick_lambda = lambda { } }
|
5
|
+
let(:bot){ brain_bot(&@brain_tick_lambda) }
|
6
|
+
|
7
|
+
context '#dead?' do
|
8
|
+
it 'should not initially be dead' do
|
9
|
+
expect(bot.dead?).to be_false
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'should be true if health is below min' do
|
13
|
+
bot.health = RTanque::Configuration.bot.health.min - 1
|
14
|
+
expect(bot.dead?).to be_true
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
context '#sensors' do
|
19
|
+
it 'should return a Sensors instance' do
|
20
|
+
expect(bot.sensors).to be_instance_of RTanque::Bot::Sensors
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should correctly transfer values from bot' do
|
24
|
+
bot.health = 5
|
25
|
+
bot.speed = -2
|
26
|
+
expect(bot.sensors.health).to eq 5
|
27
|
+
expect(bot.sensors.speed).to eq -2
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context '#tick' do
|
32
|
+
context 'no commands' do
|
33
|
+
it 'should not update bot position, heading on tick' do
|
34
|
+
bot.tick
|
35
|
+
expect(bot.position.x).to eq 0.0
|
36
|
+
expect(bot.position.y).to eq 0.0
|
37
|
+
expect(bot.heading).to eq 0
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'command with speed' do
|
42
|
+
before(:each) do
|
43
|
+
bot.speed = 1
|
44
|
+
bot.heading = 0
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'should update bot position on tick' do
|
48
|
+
bot.tick
|
49
|
+
expect(bot.position.x).to eq 0.0
|
50
|
+
expect(bot.position.y).to eq 1.0
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'should keep updating bot position' do
|
54
|
+
5.times { bot.tick }
|
55
|
+
expect(bot.position.x).to eq 0.0
|
56
|
+
expect(bot.position.y).to eq 5.0
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'should stop at arena limit' do
|
60
|
+
(@arena.height + 2).times { bot.tick }
|
61
|
+
expect(bot.position.x).to eq 0.0
|
62
|
+
expect(bot.position.y).to eq @arena.height
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
context 'command with heading' do
|
67
|
+
before(:each) do
|
68
|
+
bot.heading = RTanque::Heading::EAST
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'should have heading east' do
|
72
|
+
bot.tick
|
73
|
+
expect(bot.heading).to eq RTanque::Heading::EAST
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'should keep heading east' do
|
77
|
+
5.times { bot.tick }
|
78
|
+
expect(bot.heading).to eq RTanque::Heading::EAST
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'should maintain heading given null heading' do
|
82
|
+
bot.tick
|
83
|
+
@brain_tick_lambda = lambda { command.heading = nil }
|
84
|
+
expect(bot.heading).to eq RTanque::Heading::EAST
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'should not change radar and turret headings' do
|
88
|
+
bot.tick
|
89
|
+
expect(bot.radar.heading).to eq 0.0
|
90
|
+
expect(bot.turret.heading).to eq 0.0
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
context 'radar heading' do
|
95
|
+
before(:each) do
|
96
|
+
bot.radar.heading = RTanque::Heading::EAST
|
97
|
+
bot.tick
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'should change radar heading' do
|
101
|
+
expect(bot.radar.heading).to eq RTanque::Heading::EAST
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'should not change bot heading' do
|
105
|
+
expect(bot.heading).to eq 0
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
context 'turret heading' do
|
110
|
+
before(:each) do
|
111
|
+
bot.turret.heading = RTanque::Heading::EAST
|
112
|
+
bot.tick
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'should change radar heading' do
|
116
|
+
expect(bot.turret.heading).to eq RTanque::Heading::EAST
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'should not change bot heading' do
|
120
|
+
expect(bot.heading).to eq 0
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
context 'fire power' do
|
125
|
+
it 'bot should have 0 fire_power' do
|
126
|
+
bot.tick
|
127
|
+
expect(bot.fire_power).to eq 0
|
128
|
+
end
|
129
|
+
|
130
|
+
it 'bot should have fire_power reset' do
|
131
|
+
bot.fire_power = 1
|
132
|
+
bot.tick
|
133
|
+
expect(bot.fire_power).to eq 0
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
context 'command with error' do
|
138
|
+
before(:each) do
|
139
|
+
@brain_tick_lambda = lambda { raise 'oops' }
|
140
|
+
end
|
141
|
+
|
142
|
+
it 'should capture error' do
|
143
|
+
expect{ bot.tick }.not_to raise_exception
|
144
|
+
end
|
145
|
+
|
146
|
+
it 'should reduce bot health' do
|
147
|
+
original_health = bot.health
|
148
|
+
bot.tick
|
149
|
+
expect(bot.health).to be < original_health
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
context 'bot command speed' do
|
155
|
+
before(:each) do
|
156
|
+
@brain_tick_lambda = lambda { command.speed = RTanque::Bot::MAX_SPEED + 1 }
|
157
|
+
bot.tick
|
158
|
+
end
|
159
|
+
|
160
|
+
it 'should respect step size' do
|
161
|
+
expect(bot.speed).to eq RTanque::Configuration.bot.speed_step
|
162
|
+
end
|
163
|
+
|
164
|
+
it 'should respect max speed' do
|
165
|
+
times = RTanque::Bot::MAX_SPEED / RTanque::Configuration.bot.speed_step
|
166
|
+
(times + 1).to_i.times { bot.tick }
|
167
|
+
expect(bot.speed).to eq RTanque::Bot::MAX_SPEED
|
168
|
+
end
|
169
|
+
|
170
|
+
it 'should respect min speed' do
|
171
|
+
@brain_tick_lambda = lambda { command.speed = -(RTanque::Bot::MAX_SPEED + 1) }
|
172
|
+
times = RTanque::Bot::MAX_SPEED / RTanque::Configuration.bot.speed_step
|
173
|
+
(times + 1).to_i.times { bot.tick }
|
174
|
+
expect(bot.speed).to eq RTanque::Bot::MAX_SPEED
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
context 'bot command heading' do
|
179
|
+
it 'should respect step size' do
|
180
|
+
@brain_tick_lambda = lambda { command.heading = RTanque::Heading::S }
|
181
|
+
bot.tick
|
182
|
+
expect(bot.heading).to eq RTanque::Heading.new(RTanque::Configuration.bot.turn_step)
|
183
|
+
end
|
184
|
+
|
185
|
+
it 'should respect step size in negative' do
|
186
|
+
@brain_tick_lambda = lambda { command.heading = -RTanque::Heading::S }
|
187
|
+
bot.tick
|
188
|
+
expect(bot.heading).to eq RTanque::Heading.new(-RTanque::Configuration.bot.turn_step)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
context 'bot command radar heading' do
|
193
|
+
it 'should respect step size' do
|
194
|
+
@brain_tick_lambda = lambda { command.radar_heading = RTanque::Heading::S }
|
195
|
+
bot.tick
|
196
|
+
expect(bot.radar.heading).to eq RTanque::Heading.new(RTanque::Configuration.radar.turn_step)
|
197
|
+
end
|
198
|
+
|
199
|
+
it 'should respect step size in negative' do
|
200
|
+
@brain_tick_lambda = lambda { command.radar_heading = -RTanque::Heading::S }
|
201
|
+
bot.tick
|
202
|
+
expect(bot.radar.heading).to eq RTanque::Heading.new(-RTanque::Configuration.radar.turn_step)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
context 'bot command turret heading' do
|
207
|
+
it 'should respect step size' do
|
208
|
+
@brain_tick_lambda = lambda { self.command.turret_heading = RTanque::Heading::S }
|
209
|
+
bot.tick
|
210
|
+
expect(bot.turret.heading).to eq RTanque::Heading.new(RTanque::Configuration.turret.turn_step)
|
211
|
+
end
|
212
|
+
|
213
|
+
it 'should respect step size in negative' do
|
214
|
+
@brain_tick_lambda = lambda { self.command.turret_heading = -RTanque::Heading::S }
|
215
|
+
bot.tick
|
216
|
+
expect(bot.turret.heading).to eq RTanque::Heading.new(-RTanque::Configuration.turret.turn_step)
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
context 'bot command fire_power' do
|
221
|
+
it 'should respect max' do
|
222
|
+
@brain_tick_lambda = lambda { command.fire_power = RTanque::Bot::MAX_FIRE_POWER + 1 }
|
223
|
+
bot.tick
|
224
|
+
expect(bot.fire_power).to eq RTanque::Bot::MAX_FIRE_POWER
|
225
|
+
end
|
226
|
+
|
227
|
+
it 'should respect min' do
|
228
|
+
@brain_tick_lambda = lambda { command.fire_power = RTanque::Bot::MIN_FIRE_POWER - 1 }
|
229
|
+
bot.tick
|
230
|
+
expect(bot.fire_power).to eq RTanque::Bot::MIN_FIRE_POWER
|
231
|
+
end
|
232
|
+
|
233
|
+
it 'should not allow constant shooting' do
|
234
|
+
@brain_tick_lambda = lambda { command.fire_power = RTanque::Bot::MAX_FIRE_POWER }
|
235
|
+
5.times { bot.tick }
|
236
|
+
expect(bot.fire_power).not_to eq RTanque::Bot::MAX_FIRE_POWER
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|