colstrom-rtanque 0.1.3
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.
- 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
|