realtimebattle 0.1.0
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/Rakefile +4 -0
- data/VERSION.yml +4 -0
- data/lib/arena.rb +86 -0
- data/lib/bot.rb +25 -0
- data/lib/bullet.rb +9 -0
- data/lib/geometry_helper.rb +11 -0
- data/lib/object_info.rb +27 -0
- data/spec/arena_spec.rb +67 -0
- data/spec/bot_spec.rb +9 -0
- data/spec/bullet_spec.rb +27 -0
- data/spec/integration_spec.rb +75 -0
- data/spec/object_info_spec.rb +56 -0
- data/spec/spec_helper.rb +1 -0
- metadata +66 -0
data/Rakefile
ADDED
data/VERSION.yml
ADDED
data/lib/arena.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
class Arena
|
2
|
+
def initialize(objects, width, height)
|
3
|
+
@objects = objects.inject({}) do |hash, object|
|
4
|
+
hash[object] = ObjectInfo.new
|
5
|
+
hash
|
6
|
+
end
|
7
|
+
|
8
|
+
@width, @height = width, height
|
9
|
+
@helper = GeometryHelper.new
|
10
|
+
@wall_elements = initialize_wall(width, height)
|
11
|
+
end
|
12
|
+
|
13
|
+
def step
|
14
|
+
@objects.keys.each do |object|
|
15
|
+
action = object.step contact_type(object), contact_distance(object)
|
16
|
+
perform_action object, action
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def info_for(object)
|
21
|
+
@objects[object]
|
22
|
+
end
|
23
|
+
|
24
|
+
def objects
|
25
|
+
@objects.keys
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def initialize_wall(width, height)
|
31
|
+
elements = []
|
32
|
+
(0..width-1).each do |x|
|
33
|
+
elements << [x,0] << [x, height-1]
|
34
|
+
end
|
35
|
+
(0..height-1).each do |y|
|
36
|
+
elements << [0,y] << [width-1, y]
|
37
|
+
end
|
38
|
+
elements
|
39
|
+
end
|
40
|
+
|
41
|
+
def contact_distance(object)
|
42
|
+
step = 1
|
43
|
+
begin
|
44
|
+
info = info_for(object)
|
45
|
+
new_x, new_y = @helper.advance(
|
46
|
+
info.x, info.y, step, info.direction
|
47
|
+
)
|
48
|
+
step += 1
|
49
|
+
return 0 if out_of_bounds?(new_x, new_y)
|
50
|
+
end while !wall?(new_x, new_y)
|
51
|
+
distance_between(new_x - info_for(object).x, new_y - info_for(object).y)
|
52
|
+
end
|
53
|
+
|
54
|
+
def distance_between(delta_x, delta_y)
|
55
|
+
Math.sqrt((delta_x * delta_x) + (delta_y * delta_y))
|
56
|
+
end
|
57
|
+
|
58
|
+
def contact_type(object)
|
59
|
+
:wall
|
60
|
+
end
|
61
|
+
|
62
|
+
def wall?(x, y)
|
63
|
+
@wall_elements.find { |wall| wall == [x, y] }
|
64
|
+
end
|
65
|
+
|
66
|
+
def out_of_bounds?(x, y)
|
67
|
+
x < 0 || y < 0 || x > @width || y > @height
|
68
|
+
end
|
69
|
+
|
70
|
+
def perform_action(object, action)
|
71
|
+
info = @objects[object]
|
72
|
+
|
73
|
+
case Array(action).first
|
74
|
+
when :rotate
|
75
|
+
info.rotate action[1]
|
76
|
+
when :move
|
77
|
+
new_x, new_y = @helper.advance(info.x, info.y, object.speed, info.direction)
|
78
|
+
info.move object.speed unless wall?(new_x, new_y)
|
79
|
+
when :shoot
|
80
|
+
bullet_info = ObjectInfo.new(info.x, info.y, info.direction)
|
81
|
+
@objects[Bullet.new] = bullet_info
|
82
|
+
when :impact
|
83
|
+
@objects.delete object
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
data/lib/bot.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
class Bot
|
2
|
+
|
3
|
+
def initialize
|
4
|
+
@step = 0
|
5
|
+
end
|
6
|
+
|
7
|
+
# possible return value:
|
8
|
+
# :move
|
9
|
+
# [:rotate, degrees] # degrees must be 0..360
|
10
|
+
# :shoot
|
11
|
+
def step(contact_type, contact_distance)
|
12
|
+
@step += 1
|
13
|
+
if @step % 5 == 0
|
14
|
+
[:rotate, 90]
|
15
|
+
elsif @step % 3 == 0
|
16
|
+
:shoot
|
17
|
+
else
|
18
|
+
:move
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def speed
|
23
|
+
1
|
24
|
+
end
|
25
|
+
end
|
data/lib/bullet.rb
ADDED
data/lib/object_info.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
class ObjectInfo
|
2
|
+
attr_accessor :position, :direction
|
3
|
+
|
4
|
+
def initialize(x = 1, y = 1, direction = 0)
|
5
|
+
self.position = [x, y]
|
6
|
+
self.direction = direction
|
7
|
+
@helper = GeometryHelper.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def x
|
11
|
+
position[0]
|
12
|
+
end
|
13
|
+
|
14
|
+
def y
|
15
|
+
position[1]
|
16
|
+
end
|
17
|
+
|
18
|
+
def rotate(angle)
|
19
|
+
self.direction = (direction + angle)
|
20
|
+
self.direction -= 360 if direction > 180
|
21
|
+
self.direction += 360 if direction < -180
|
22
|
+
end
|
23
|
+
|
24
|
+
def move(distance)
|
25
|
+
self.position = @helper.advance x, y, distance, direction
|
26
|
+
end
|
27
|
+
end
|
data/spec/arena_spec.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe Arena do
|
4
|
+
describe '#step' do
|
5
|
+
before(:each) do
|
6
|
+
@bot = Bot.new
|
7
|
+
@arena = Arena.new [@bot], 20, 20
|
8
|
+
@bot_info = @arena.info_for(@bot)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should tell each bot to act" do
|
12
|
+
@bot.should_receive(:step).and_return([])
|
13
|
+
@arena.step
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should tell a bot about the upper wall" do
|
17
|
+
@bot_info.position = [9, 2]
|
18
|
+
@bot_info.direction = 90
|
19
|
+
@bot.should_receive(:step).with(:wall, 17).and_return([])
|
20
|
+
@arena.step
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should tell a bot about the lower wall" do
|
24
|
+
@bot_info.position = [9, 2]
|
25
|
+
@bot_info.direction = -90
|
26
|
+
@bot.should_receive(:step).with(:wall, 2).and_return([])
|
27
|
+
@arena.step
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should tell a bot about the left wall" do
|
31
|
+
@bot_info.position = [9, 2]
|
32
|
+
@bot_info.direction = -180
|
33
|
+
@bot.should_receive(:step).with(:wall, 9).and_return([])
|
34
|
+
@arena.step
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should tell a bot about the right wall" do
|
38
|
+
@bot_info.position = [9, 2]
|
39
|
+
@bot_info.direction = 0
|
40
|
+
@bot.should_receive(:step).with(:wall, 10).and_return([])
|
41
|
+
@arena.step
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should rotate a bot" do
|
45
|
+
@bot_info.direction = 0
|
46
|
+
@bot.stub!(:step => [:rotate, -10])
|
47
|
+
@bot_info.should_receive(:rotate).with(-10)
|
48
|
+
@arena.step
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should move a bot" do
|
52
|
+
@bot_info.position = [10,11]
|
53
|
+
@bot_info.direction = 0
|
54
|
+
@bot.stub!(:step => [:move])
|
55
|
+
@bot_info.should_receive(:move).with(1)
|
56
|
+
@arena.step
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should not move a bot into an obstacle" do
|
60
|
+
@bot_info.position = [18,11]
|
61
|
+
@bot_info.direction = 0
|
62
|
+
@bot.stub!(:step => [:move])
|
63
|
+
@bot_info.should_not_receive(:move)
|
64
|
+
@arena.step
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
data/spec/bot_spec.rb
ADDED
data/spec/bullet_spec.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'spec/spec_helper'
|
2
|
+
|
3
|
+
describe Bullet do
|
4
|
+
describe '#step' do
|
5
|
+
before :each do
|
6
|
+
@bullet = Bullet.new
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should impact contact if there is no space" do
|
10
|
+
@bullet.step(:wall, 0).should == :impact
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should impact if moving will run out space" do
|
14
|
+
@bullet.step(:wall, 2).should == :impact
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should move if there is enough space" do
|
18
|
+
@bullet.step(:wall, 3).should == :move
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#speed' do
|
23
|
+
it "should be 2" do
|
24
|
+
Bullet.new.speed.should == 2
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe 'Real Time Battle' do
|
4
|
+
context 'bot' do
|
5
|
+
before(:each) do
|
6
|
+
@bot = Bot.new
|
7
|
+
@arena = Arena.new [@bot], 10, 10
|
8
|
+
@info = @arena.info_for(@bot)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should move around" do
|
12
|
+
@arena.step # move
|
13
|
+
@info.position.should == [2,1]
|
14
|
+
@arena.step # move
|
15
|
+
@info.position.should == [3,1]
|
16
|
+
@arena.step # shoot
|
17
|
+
@info.position.should == [3,1]
|
18
|
+
@arena.step # move
|
19
|
+
@info.position.should == [4,1]
|
20
|
+
@arena.step # turn
|
21
|
+
@info.position.should == [4,1]
|
22
|
+
@arena.step # shoot
|
23
|
+
@info.position.should == [4,1]
|
24
|
+
@arena.step # move
|
25
|
+
@info.position.should == [4,2]
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'with bullet' do
|
29
|
+
before :each do
|
30
|
+
@arena.step
|
31
|
+
@arena.step
|
32
|
+
@arena.step
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should have two objects in the arena" do
|
36
|
+
@arena.objects.length.should == 2
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should have both objects in the same position and direction" do
|
40
|
+
one = @arena.info_for @arena.objects.first
|
41
|
+
two = @arena.info_for @arena.objects.last
|
42
|
+
|
43
|
+
one.x.should == two.x
|
44
|
+
one.y.should == two.y
|
45
|
+
one.direction.should == two.direction
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context 'bullet' do
|
51
|
+
before :each do
|
52
|
+
@bullet = Bullet.new
|
53
|
+
@arena = Arena.new [@bullet], 10, 10
|
54
|
+
@info = @arena.info_for(@bullet)
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should move around" do
|
58
|
+
@arena.step
|
59
|
+
@info.position.should == [3, 1]
|
60
|
+
@arena.step
|
61
|
+
@info.position.should == [5, 1]
|
62
|
+
@arena.step
|
63
|
+
@info.position.should == [7, 1]
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should remove the bullet from play if it collides with a wall" do
|
67
|
+
@arena.step
|
68
|
+
@arena.step
|
69
|
+
@arena.step
|
70
|
+
@arena.step
|
71
|
+
@arena.step
|
72
|
+
@arena.info_for(@bullet).should be_nil
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe ObjectInfo, 'rotate' do
|
4
|
+
before(:each) do
|
5
|
+
@info = ObjectInfo.new
|
6
|
+
@info.direction = 0
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should add to the direction" do
|
10
|
+
@info.rotate 10
|
11
|
+
@info.direction.should == 10
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should cap the direction at 180" do
|
15
|
+
@info.rotate 170
|
16
|
+
@info.rotate 20
|
17
|
+
@info.direction.should == -170
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should cap the direction at -180" do
|
21
|
+
@info.rotate -170
|
22
|
+
@info.rotate -20
|
23
|
+
@info.direction.should == 170
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe ObjectInfo, 'move' do
|
28
|
+
before(:each) do
|
29
|
+
@info = ObjectInfo.new
|
30
|
+
@info.direction = 0
|
31
|
+
@info.position = [10,10]
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should move the bot to the right" do
|
35
|
+
@info.move 1
|
36
|
+
@info.position.should == [11,10]
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should move the bot to the left" do
|
40
|
+
@info.direction = -180
|
41
|
+
@info.move 1
|
42
|
+
@info.position.should == [9,10]
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should move the bot down" do
|
46
|
+
@info.direction = -90
|
47
|
+
@info.move 1
|
48
|
+
@info.position.should == [10,9]
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should move the bot up" do
|
52
|
+
@info.direction = 90
|
53
|
+
@info.move 1
|
54
|
+
@info.position.should == [10,11]
|
55
|
+
end
|
56
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../realtimebattle'
|
metadata
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: realtimebattle
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Alex Lang, Lukas Rieder, Pat Allan
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-10-03 00:00:00 +02:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description:
|
17
|
+
email: ""
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files: []
|
23
|
+
|
24
|
+
files:
|
25
|
+
- Rakefile
|
26
|
+
- VERSION.yml
|
27
|
+
- lib/arena.rb
|
28
|
+
- lib/bot.rb
|
29
|
+
- lib/bullet.rb
|
30
|
+
- lib/geometry_helper.rb
|
31
|
+
- lib/object_info.rb
|
32
|
+
has_rdoc: true
|
33
|
+
homepage: http://github.com/langalex/realtimebattle_rb
|
34
|
+
licenses: []
|
35
|
+
|
36
|
+
post_install_message:
|
37
|
+
rdoc_options:
|
38
|
+
- --charset=UTF-8
|
39
|
+
require_paths:
|
40
|
+
- lib
|
41
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: "0"
|
46
|
+
version:
|
47
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: "0"
|
52
|
+
version:
|
53
|
+
requirements: []
|
54
|
+
|
55
|
+
rubyforge_project:
|
56
|
+
rubygems_version: 1.3.5
|
57
|
+
signing_key:
|
58
|
+
specification_version: 3
|
59
|
+
summary: RealTimeBattle Ruby
|
60
|
+
test_files:
|
61
|
+
- spec/arena_spec.rb
|
62
|
+
- spec/bot_spec.rb
|
63
|
+
- spec/bullet_spec.rb
|
64
|
+
- spec/integration_spec.rb
|
65
|
+
- spec/object_info_spec.rb
|
66
|
+
- spec/spec_helper.rb
|