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.
@@ -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