realtimebattle 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,4 @@
1
+ require 'tasks/distribution'
2
+ require 'tasks/testing'
3
+
4
+ task :default => :spec
@@ -0,0 +1,4 @@
1
+ ---
2
+ :major: 0
3
+ :minor: 1
4
+ :patch: 0
@@ -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
@@ -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
@@ -0,0 +1,9 @@
1
+ class Bullet
2
+ def step(contact_type, contact_distance)
3
+ contact_distance > speed ? :move : :impact
4
+ end
5
+
6
+ def speed
7
+ 2
8
+ end
9
+ end
@@ -0,0 +1,11 @@
1
+ class GeometryHelper
2
+ def advance(x, y, distance, direction)
3
+ [x + Math.cos(to_rad(direction)) * distance, y + Math.sin(to_rad(direction)) * distance].map{|x| x.round}
4
+ end
5
+
6
+ private
7
+
8
+ def to_rad(degree)
9
+ degree * Math::PI/180
10
+ end
11
+ end
@@ -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
@@ -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
@@ -0,0 +1,9 @@
1
+ require 'spec/spec_helper'
2
+
3
+ describe Bot do
4
+ describe '#speed' do
5
+ it "should be 1" do
6
+ Bot.new.speed.should == 1
7
+ end
8
+ end
9
+ end
@@ -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
@@ -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