brawl 0.0.0.alpha → 0.0.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.
- data/.gitignore +1 -0
- data/.rspec +0 -0
- data/README.md +43 -0
- data/_design/ClassDescriptions.txt +98 -0
- data/_design/Psudo_Program.rb +113 -0
- data/_design/array.rb +4 -0
- data/_design/threads.rb +71 -0
- data/_spike/Communications/communications.rb +2 -0
- data/_spike/Communications/lib/communications/com_linker.rb +11 -0
- data/_spike/Communications/lib/communications/null_modem.rb +11 -0
- data/_spike/Communications/spec/communications/com_linker_spec.rb +37 -0
- data/_spike/DRb/arena.rb +32 -0
- data/_spike/DRb/battle_controller.rb +54 -0
- data/_spike/DRb/bot.rb +23 -0
- data/_spike/DRb/bot_runner.rb +110 -0
- data/_spike/DRb/comment.txt +11 -0
- data/_spike/DRb/server.rb +28 -0
- data/_spike/DRb/test_bot.rb +6 -0
- data/_spike/array.rb +7 -0
- data/_spike/atan2.rb +39 -0
- data/_spike/battle.rb +202 -0
- data/_spike/break.rb +10 -0
- data/_spike/circles.rb +29 -0
- data/_spike/cleaner_attribs.rb +13 -0
- data/_spike/comlink.rb +61 -0
- data/_spike/concat.rb +27 -0
- data/_spike/example_bot.rb +42 -0
- data/_spike/forwarding_instance.rb +32 -0
- data/_spike/hash_loop.rb +17 -0
- data/_spike/hashing.rb +7 -0
- data/_spike/hook.rb +19 -0
- data/_spike/mod.rb +10 -0
- data/_spike/point_in_cone.rb +20 -0
- data/_spike/runner.rb +44 -0
- data/_spike/safe.rb +28 -0
- data/brawl.gemspec +4 -3
- data/example/example_battle.rb +173 -0
- data/example/logview.txt +6394 -0
- data/lib/brawl.rb +14 -3
- data/lib/brawl/_helper.rb +65 -0
- data/lib/brawl/arena.rb +118 -0
- data/lib/brawl/basic_arena_object.rb +35 -0
- data/lib/brawl/basic_bot.rb +69 -0
- data/lib/brawl/battle_controller.rb +97 -0
- data/lib/brawl/bot_proxy.rb +60 -0
- data/lib/brawl/clock.rb +36 -0
- data/lib/brawl/parts.rb +3 -0
- data/lib/brawl/parts/basic_motor.rb +55 -0
- data/lib/brawl/parts/basic_scanner.rb +33 -0
- data/lib/brawl/parts/basic_weapon.rb +47 -0
- data/lib/brawl/version.rb +1 -1
- data/lib/brawl/wall.rb +9 -0
- data/spec/brawl/arena_spec.rb +163 -0
- data/spec/brawl/basic_arena_object_spec.rb +40 -0
- data/spec/brawl/basic_bot_spec.rb +84 -0
- data/spec/brawl/battle_controller_spec.rb +138 -0
- data/spec/brawl/clock_spec.rb +28 -0
- data/spec/brawl/helper_spec.rb +23 -0
- data/spec/brawl/parts/basic_motor_spec.rb +220 -0
- data/spec/brawl/parts/basic_scanner_spec.rb +101 -0
- data/spec/brawl/parts/basic_weapon_spec.rb +146 -0
- data/spec/spec_helper.rb +5 -0
- metadata +101 -10
data/lib/brawl/clock.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
module Brawl
|
2
|
+
|
3
|
+
class Clock
|
4
|
+
|
5
|
+
attr_reader :tick_rate, :ticks, :state
|
6
|
+
|
7
|
+
def initialize(tick_rate=0.05)
|
8
|
+
@tick_rate = tick_rate
|
9
|
+
@state = :wait
|
10
|
+
@ticks = 0
|
11
|
+
end
|
12
|
+
|
13
|
+
def start
|
14
|
+
@state = :running
|
15
|
+
ticking
|
16
|
+
end
|
17
|
+
|
18
|
+
def stop
|
19
|
+
@state = :stopping
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def ticking
|
25
|
+
Thread.start {
|
26
|
+
while @state == :running
|
27
|
+
sleep(@tick_rate)
|
28
|
+
@ticks += 1
|
29
|
+
end
|
30
|
+
@state = :stopped
|
31
|
+
}
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
data/lib/brawl/parts.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
module Brawl
|
2
|
+
|
3
|
+
module BasicMotor
|
4
|
+
|
5
|
+
attr_reader :move_max, :turn_max
|
6
|
+
|
7
|
+
def initialize(params={})
|
8
|
+
@move_max = params[:move_max] || 5
|
9
|
+
@turn_max = params[:turn_max] || 90
|
10
|
+
end
|
11
|
+
|
12
|
+
def move(count=1)
|
13
|
+
|
14
|
+
heading_radian = Helper.to_radians((@heading + (count < 0 ? 180 : 0)))
|
15
|
+
count = count.abs
|
16
|
+
count = [count, @move_max].min
|
17
|
+
|
18
|
+
count.times do
|
19
|
+
x = @location[:x] + Math.sin(heading_radian).round(DECIMAL_PLACES)
|
20
|
+
y = @location[:y] + Math.cos(heading_radian).round(DECIMAL_PLACES)
|
21
|
+
break unless @arena.in_bounds?({x: x, y: y})
|
22
|
+
@location[:x], @location[:y] = x, y
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def turn(params)
|
27
|
+
# refactor
|
28
|
+
if params.is_a?(Hash)
|
29
|
+
turn_to(params[:to_angle]) if params[:to_angle]
|
30
|
+
turn_by(params[:by_degrees]) if params[:by_degrees]
|
31
|
+
else
|
32
|
+
angles = {left: -90, right: 90, around: 180}
|
33
|
+
turn_by(angles[params])
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def turn_to(angle)
|
40
|
+
turn_by_angle = Helper.wrap_angle(angle - @heading)
|
41
|
+
turn_by(turn_by_angle)
|
42
|
+
end
|
43
|
+
|
44
|
+
def turn_by(degrees)
|
45
|
+
degrees = boundscheck_angle(degrees)
|
46
|
+
@heading = (@heading + degrees) % 360
|
47
|
+
end
|
48
|
+
|
49
|
+
def boundscheck_angle(angle)
|
50
|
+
[angle.abs % 360, @turn_max].min * (angle.abs / angle)
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Brawl
|
2
|
+
module BasicScanner
|
3
|
+
|
4
|
+
attr_reader :scan_max, :angle_max
|
5
|
+
|
6
|
+
DECIMAL_PLACES = 1
|
7
|
+
|
8
|
+
def initialize(params={})
|
9
|
+
@scan_max = params[:scan_max] || 10
|
10
|
+
@angle_max = params[:angle_max] || 45
|
11
|
+
end
|
12
|
+
|
13
|
+
def scan(params={})
|
14
|
+
angle = [@angle_max, params[:angle] ||= @angle_max].min
|
15
|
+
|
16
|
+
cone = {
|
17
|
+
origin: @location,
|
18
|
+
direction: params[:direction],
|
19
|
+
radius: @scan_max,
|
20
|
+
angle: angle,
|
21
|
+
}
|
22
|
+
|
23
|
+
@arena.get_all_objects.collect do |info_hash|
|
24
|
+
next if info_hash[:id] == @id
|
25
|
+
if obj = Helper.point_in_cone?(cone.merge(point: info_hash[:location]))
|
26
|
+
info_hash.merge(obj)
|
27
|
+
end
|
28
|
+
end.compact
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Brawl
|
2
|
+
module BasicWeapon
|
3
|
+
|
4
|
+
attr_reader :range, :reload_time, :power
|
5
|
+
|
6
|
+
def initialize(params={})
|
7
|
+
|
8
|
+
@reload_time = params[:reload_time] || 10
|
9
|
+
@range = params[:range] || 10
|
10
|
+
@power = params[:power] || 1
|
11
|
+
|
12
|
+
@reload_countdown = 0
|
13
|
+
end
|
14
|
+
|
15
|
+
def shoot(direction=@heading)
|
16
|
+
return false if reload_countdown > 0
|
17
|
+
@reload_countdown = @reload_time + @arena.ticks
|
18
|
+
|
19
|
+
cone = {
|
20
|
+
origin: @location,
|
21
|
+
direction: direction,
|
22
|
+
radius: @range,
|
23
|
+
angle: 2
|
24
|
+
}
|
25
|
+
|
26
|
+
# refactor
|
27
|
+
possible_hits = @arena.get_all_objects.collect do |object|
|
28
|
+
if object[:id] != @id &&
|
29
|
+
hit = Helper.point_in_cone?(cone.merge(point: object[:location]))
|
30
|
+
object.merge(hit)
|
31
|
+
end
|
32
|
+
end.compact
|
33
|
+
return if possible_hits.empty?
|
34
|
+
|
35
|
+
# refactor
|
36
|
+
hit = possible_hits.sort{|a,b| a[:distance] <=> b[:distance]}.first
|
37
|
+
@arena.forward_damage(damage: @power, target: hit[:id])
|
38
|
+
hit
|
39
|
+
end
|
40
|
+
|
41
|
+
def reload_countdown
|
42
|
+
return 0 if @reload_countdown <= @arena.ticks
|
43
|
+
@reload_countdown - @arena.ticks
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
data/lib/brawl/version.rb
CHANGED
data/lib/brawl/wall.rb
ADDED
@@ -0,0 +1,163 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Brawl::Arena do
|
4
|
+
|
5
|
+
let(:arena){Brawl::Arena.new(size: {width: 10, length: 10})}
|
6
|
+
let(:object1){Brawl::BasicArenaObject.new}
|
7
|
+
let(:object2){Brawl::BasicArenaobject.new}
|
8
|
+
|
9
|
+
context "when initializing" do
|
10
|
+
|
11
|
+
it "should start the clock automatically" do
|
12
|
+
arena = Brawl::Arena.new(size: {width: 100, length: 100})
|
13
|
+
expect{sleep(0.1)}.should change(arena, :ticks)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context "when determining size" do
|
18
|
+
|
19
|
+
it "should set the size when initialized" do
|
20
|
+
Brawl::Arena.new(
|
21
|
+
size: {width: 100, length: 100}
|
22
|
+
).size.should == {width: 100, length: 100}
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should have convinence method for length" do
|
26
|
+
arena = Brawl::Arena.new(size: {width: 44, length: 923})
|
27
|
+
arena.length.should == 923
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should have convinence method for width" do
|
31
|
+
arena = Brawl::Arena.new(size: {width: 234, length: 63})
|
32
|
+
arena.width.should == 234
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
context "when adding objects" do
|
38
|
+
|
39
|
+
it "should place an object" do
|
40
|
+
arena.add_object(object1).should be_true
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should not place objects where there is an object already" do
|
44
|
+
object1 = Brawl::BasicArenaObject.new(location: {x: 10, y: 10})
|
45
|
+
object2 = Brawl::BasicArenaObject.new(location: {x: 10, y: 10})
|
46
|
+
arena.add_object(object1)
|
47
|
+
arena.add_object(object2).should be_false
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should not place objects that already exist" do
|
51
|
+
arena.add_object(object1)
|
52
|
+
arena.add_object(object1).should be_false
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
context "when removing objects" do
|
58
|
+
|
59
|
+
it "should remove an object using the object itself" do
|
60
|
+
arena.add_object(object1)
|
61
|
+
arena.remove_object(object1).should == object1
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should not remove objects that don't exist" do
|
65
|
+
arena.remove_object(object1).should be_nil
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
context "when moving objects" do
|
71
|
+
|
72
|
+
before(:each) do
|
73
|
+
object1 = Brawl::BasicArenaObject.new(location: {x: 5, y: 5})
|
74
|
+
arena.add_object(object1)
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should move an object from one location to another" do
|
78
|
+
arena.move_object(object1 => {x: 1, y: 1}).should be_true
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should not move an object if its already in the location" do
|
82
|
+
arena.move_object(object1 => {x: 5, y: 5}).should_not be_true
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should move an object to the correct location" do
|
86
|
+
arena.move_object(object1 => {x: 1, y: 1})
|
87
|
+
object1.location.should == {x: 1, y: 1}
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should not move above the bounds" do
|
91
|
+
# note the zero based locations
|
92
|
+
arena.move_object(object1 => {x: 0, y: 100}).should be_false
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should not move below the bounds" do
|
96
|
+
arena.move_object(object1 => {x: -1, y: 5}).should be_false
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
context "when getting objects" do
|
102
|
+
|
103
|
+
it "should retrieve objects by a key and value" do
|
104
|
+
object1 = Brawl::BasicArenaObject.new(location: {x: 5, y: 5})
|
105
|
+
arena.add_object(object1)
|
106
|
+
arena.get_object(id: object1.id).should_not be_nil
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should retrieve public object properties not the object itself" do
|
110
|
+
object1 = Brawl::BasicArenaObject.new(location: {x: 5, y: 5})
|
111
|
+
arena.add_object(object1)
|
112
|
+
arena.get_object(id: object1.id).should == object1.properties
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
|
117
|
+
context "when pinging locations for objects" do
|
118
|
+
|
119
|
+
it "should return object information for a location" do
|
120
|
+
object1 = Brawl::BasicArenaObject.new(location: {x: 5, y: 5})
|
121
|
+
arena.add_object(object1)
|
122
|
+
arena.ping(x: 5, y: 5).should == object1.properties
|
123
|
+
end
|
124
|
+
|
125
|
+
it "should return nothing for an empty location" do
|
126
|
+
arena.ping(x: 5, y: 5).should be_nil
|
127
|
+
end
|
128
|
+
|
129
|
+
it "should return a wall for the areas around the arena" do
|
130
|
+
arena.ping(x:-1,y:0).select{|k,_|[:class,:location].include? k}.should ==
|
131
|
+
{class: Brawl::Wall, location: {x:-1, y:0}}
|
132
|
+
end
|
133
|
+
|
134
|
+
it "should return nothing for areas outside the wall" do
|
135
|
+
# note that corners can't be "seen" from inside the arena so are not walls
|
136
|
+
arena.ping(x:-1,y:-1).should be_nil
|
137
|
+
arena.ping(x:10,y:10).should be_nil
|
138
|
+
arena.ping(x:-1,y:10).should be_nil
|
139
|
+
arena.ping(x:10,y:-1).should be_nil
|
140
|
+
arena.ping(x:0,y:101).should be_nil
|
141
|
+
arena.ping(x:11,y:0).should be_nil
|
142
|
+
arena.ping(x:11,y:11).should be_nil
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
146
|
+
|
147
|
+
context "when damage occurs" do
|
148
|
+
|
149
|
+
it 'should forward damage to the damaged object' do
|
150
|
+
expect{arena.forward_damage(damage: 1, target: object1.id)}.should
|
151
|
+
change(object1, :health).by(-1)
|
152
|
+
end
|
153
|
+
|
154
|
+
end
|
155
|
+
|
156
|
+
it "should set the clock to the given clock object" do
|
157
|
+
clock = Brawl::Clock.new
|
158
|
+
arena.set_clock clock
|
159
|
+
arena.clock.should == clock
|
160
|
+
end
|
161
|
+
|
162
|
+
|
163
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Brawl::BasicArenaObject do
|
4
|
+
|
5
|
+
let(:object){Brawl::BasicArenaObject.new}
|
6
|
+
|
7
|
+
it "should set a globally unique ID" do
|
8
|
+
object.id.should_not be_nil
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should set a default location of {x: 0, y: 0}" do
|
12
|
+
object.location.should == {x: 0, y: 0}
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should set a default heading of 0" do
|
16
|
+
object.heading.should == 0
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should set a default health of 1" do
|
20
|
+
object.health.should == 1
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should override a default value if a specific value is given" do
|
24
|
+
object = Brawl::BasicArenaObject.new(health: 20)
|
25
|
+
object.health.should == 20
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should have a hash of property values" do
|
29
|
+
object.properties.should be_a(Hash)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should reduce its health based on damage received" do
|
33
|
+
expect{object.damage(1)}.should change(object, :health).by(-1)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should never reduce health to less than 0" do
|
37
|
+
expect{object.damage(100)}.should change(object, :health).to(0)
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Brawl::BasicBot do
|
4
|
+
|
5
|
+
let(:arena){Brawl::Arena.new(size: {width: 100, length: 100})}
|
6
|
+
let(:bot) {Brawl::BasicBot.new(arena: arena, location: {x: 0.0, y: 0.0})}
|
7
|
+
|
8
|
+
it "should provide a hash of 'public' properites for the arena" do
|
9
|
+
bot.properties.should_not be_nil
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should have the methods of the parts that are injected into it" do
|
13
|
+
bot = Brawl::BasicBot.new(
|
14
|
+
location: {x: 0.0, y: 0.0},
|
15
|
+
heading: 0,
|
16
|
+
arena: arena,
|
17
|
+
parts: {Foo => {baz: "Baz set"}}
|
18
|
+
)
|
19
|
+
bot.should respond_to(:bar)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should access properties of the instance" do
|
23
|
+
bot = Brawl::BasicBot.new(
|
24
|
+
location: {x: 53.0, y: 34.0},
|
25
|
+
heading: 0,
|
26
|
+
arena: arena,
|
27
|
+
parts: {Foo => {baz: "Baz set"}}
|
28
|
+
)
|
29
|
+
bot.bar.should == {x: 53.0, y: 34.0}
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should initialize parts" do
|
33
|
+
bot = Brawl::BasicBot.new(
|
34
|
+
location: {x: 0.0, y: 0.0},
|
35
|
+
heading: 0,
|
36
|
+
arena: arena,
|
37
|
+
parts: {Foo => {baz: "Baz set"}}
|
38
|
+
)
|
39
|
+
bot.baz.should == "Baz set"
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should initialize more than one part" do
|
43
|
+
bot = Brawl::BasicBot.new(
|
44
|
+
location: {x: 0.0, y: 0.0},
|
45
|
+
heading: 0,
|
46
|
+
arena: arena,
|
47
|
+
parts: {Foo => {baz: "Baz set"}, Qux => {quux: "Quux set"}}
|
48
|
+
)
|
49
|
+
bot.quux.should == "Quux set"
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should have methods of more than one part" do
|
53
|
+
bot = Brawl::BasicBot.new(
|
54
|
+
location: {x: 11.0, y: 222.0},
|
55
|
+
heading: 0,
|
56
|
+
arena: arena,
|
57
|
+
parts: {Foo => {baz: "Baz set"}, Qux => {quux: "Quux set"}}
|
58
|
+
)
|
59
|
+
bot.phoo.should == {x: 11.0, y: 222.0}
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
module Foo
|
65
|
+
attr_accessor :baz
|
66
|
+
def initialize(params={})
|
67
|
+
@baz = params[:baz]
|
68
|
+
end
|
69
|
+
def bar
|
70
|
+
@location
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
module Qux
|
75
|
+
attr_accessor :quux
|
76
|
+
def initialize(params={})
|
77
|
+
@quux = params[:quux]
|
78
|
+
end
|
79
|
+
def phoo
|
80
|
+
@location
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
|