brawl 0.0.0.alpha → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. data/.gitignore +1 -0
  2. data/.rspec +0 -0
  3. data/README.md +43 -0
  4. data/_design/ClassDescriptions.txt +98 -0
  5. data/_design/Psudo_Program.rb +113 -0
  6. data/_design/array.rb +4 -0
  7. data/_design/threads.rb +71 -0
  8. data/_spike/Communications/communications.rb +2 -0
  9. data/_spike/Communications/lib/communications/com_linker.rb +11 -0
  10. data/_spike/Communications/lib/communications/null_modem.rb +11 -0
  11. data/_spike/Communications/spec/communications/com_linker_spec.rb +37 -0
  12. data/_spike/DRb/arena.rb +32 -0
  13. data/_spike/DRb/battle_controller.rb +54 -0
  14. data/_spike/DRb/bot.rb +23 -0
  15. data/_spike/DRb/bot_runner.rb +110 -0
  16. data/_spike/DRb/comment.txt +11 -0
  17. data/_spike/DRb/server.rb +28 -0
  18. data/_spike/DRb/test_bot.rb +6 -0
  19. data/_spike/array.rb +7 -0
  20. data/_spike/atan2.rb +39 -0
  21. data/_spike/battle.rb +202 -0
  22. data/_spike/break.rb +10 -0
  23. data/_spike/circles.rb +29 -0
  24. data/_spike/cleaner_attribs.rb +13 -0
  25. data/_spike/comlink.rb +61 -0
  26. data/_spike/concat.rb +27 -0
  27. data/_spike/example_bot.rb +42 -0
  28. data/_spike/forwarding_instance.rb +32 -0
  29. data/_spike/hash_loop.rb +17 -0
  30. data/_spike/hashing.rb +7 -0
  31. data/_spike/hook.rb +19 -0
  32. data/_spike/mod.rb +10 -0
  33. data/_spike/point_in_cone.rb +20 -0
  34. data/_spike/runner.rb +44 -0
  35. data/_spike/safe.rb +28 -0
  36. data/brawl.gemspec +4 -3
  37. data/example/example_battle.rb +173 -0
  38. data/example/logview.txt +6394 -0
  39. data/lib/brawl.rb +14 -3
  40. data/lib/brawl/_helper.rb +65 -0
  41. data/lib/brawl/arena.rb +118 -0
  42. data/lib/brawl/basic_arena_object.rb +35 -0
  43. data/lib/brawl/basic_bot.rb +69 -0
  44. data/lib/brawl/battle_controller.rb +97 -0
  45. data/lib/brawl/bot_proxy.rb +60 -0
  46. data/lib/brawl/clock.rb +36 -0
  47. data/lib/brawl/parts.rb +3 -0
  48. data/lib/brawl/parts/basic_motor.rb +55 -0
  49. data/lib/brawl/parts/basic_scanner.rb +33 -0
  50. data/lib/brawl/parts/basic_weapon.rb +47 -0
  51. data/lib/brawl/version.rb +1 -1
  52. data/lib/brawl/wall.rb +9 -0
  53. data/spec/brawl/arena_spec.rb +163 -0
  54. data/spec/brawl/basic_arena_object_spec.rb +40 -0
  55. data/spec/brawl/basic_bot_spec.rb +84 -0
  56. data/spec/brawl/battle_controller_spec.rb +138 -0
  57. data/spec/brawl/clock_spec.rb +28 -0
  58. data/spec/brawl/helper_spec.rb +23 -0
  59. data/spec/brawl/parts/basic_motor_spec.rb +220 -0
  60. data/spec/brawl/parts/basic_scanner_spec.rb +101 -0
  61. data/spec/brawl/parts/basic_weapon_spec.rb +146 -0
  62. data/spec/spec_helper.rb +5 -0
  63. metadata +101 -10
data/lib/brawl.rb CHANGED
@@ -1,5 +1,16 @@
1
1
  require "brawl/version"
2
2
 
3
- module Brawl
4
- # Your code goes here...
5
- end
3
+ require "brawl/_helper"
4
+
5
+ require "brawl/clock"
6
+
7
+ require "brawl/basic_arena_object"
8
+ require "brawl/wall"
9
+
10
+ require "brawl/arena"
11
+
12
+ require "brawl/basic_bot"
13
+ require "brawl/parts"
14
+ require "brawl/bot_proxy"
15
+
16
+ require "brawl/battle_controller"
@@ -0,0 +1,65 @@
1
+ module Brawl
2
+
3
+ DECIMAL_PLACES = 1
4
+
5
+ class Helper
6
+
7
+ def self.to_radians(angle)
8
+ angle * (Math::PI / 180)
9
+ end
10
+
11
+ def self.to_degrees(angle)
12
+ angle * (180.0 / Math::PI)
13
+ end
14
+
15
+ # returns a shorter angle if one exists (angle - 180's complement)
16
+ # e.g. wrap_angle(270) = -90
17
+ # wrap_angle(-320) = 40
18
+ # wrap_angle(45) = 45
19
+ def self.wrap_angle(angle)
20
+ # refactor? : can this be simplified?
21
+ return angle unless angle > 180 || angle < -180
22
+ (360 - angle.abs) * (angle.abs / angle) * -1
23
+ end
24
+
25
+ def self.point_in_cone?(params)
26
+
27
+ origin = params[:origin]
28
+ radius = params[:radius]
29
+ angle = params[:angle]
30
+ direction = params[:direction]
31
+ point = params[:point]
32
+
33
+ distance_to_target = distance(origin, point)
34
+ return false if distance_to_target > radius
35
+
36
+ bearing_to_target = bearing(origin, point)
37
+
38
+ min_cone_angle = (direction - (angle / 2)) % 360
39
+ max_cone_angle = (direction + (angle / 2)) % 360
40
+
41
+ greater_than = bearing_to_target >= min_cone_angle
42
+ less_than = bearing_to_target <= max_cone_angle
43
+
44
+ if (min_cone_angle > max_cone_angle && (greater_than || less_than)) ||
45
+ (min_cone_angle <= max_cone_angle && (greater_than && less_than))
46
+ { distance: distance_to_target.round(DECIMAL_PLACES),
47
+ bearing: bearing_to_target}
48
+
49
+ end
50
+ end
51
+
52
+ def self.bearing(origin, target)
53
+ x1, y1, x2, y2 = origin[:x], origin[:y], target[:x], target[:y]
54
+ # correct mathy angles to what everyone on the face of the planet uses
55
+ to_degrees(Math.atan2(x2 - x1, y2 - y1)) % 360
56
+ end
57
+
58
+ def self.distance(point1, point2)
59
+ x1, y1, x2, y2 = point1[:x], point1[:y], point2[:x], point2[:y]
60
+ distance = Math.sqrt((x1 - x2)**2 + (y1 - y2)**2)
61
+ end
62
+
63
+ end
64
+
65
+ end
@@ -0,0 +1,118 @@
1
+ module Brawl
2
+
3
+ class Arena
4
+
5
+ attr_reader :size, :clock
6
+
7
+ def initialize(params={})
8
+ @size = params[:size]
9
+ @objects = []
10
+
11
+ set_clock(params[:clock])
12
+
13
+ add_walls
14
+ end
15
+
16
+ def length
17
+ @size[:length]
18
+ end
19
+
20
+ def width
21
+ @size[:width]
22
+ end
23
+
24
+ def ticks
25
+ @clock.ticks
26
+ end
27
+
28
+ def set_clock(clock=nil)
29
+ @clock = clock || Clock.new
30
+ @clock.start
31
+ end
32
+
33
+ def add_object(object)
34
+ add_objects([object]).first
35
+ end
36
+
37
+ def add_objects(objects_array)
38
+ objects_array.collect do |object|
39
+ if get_object(id: object.id) || ping(object.location)
40
+ false
41
+ else
42
+ !!(@objects << object)
43
+ end
44
+ end
45
+ end
46
+
47
+ def remove_object(object)
48
+ @objects.delete(object)
49
+ end
50
+
51
+ def move_object(object_location_hash)
52
+ object = object_location_hash.keys.first
53
+ location = object_location_hash.values.first
54
+
55
+ return if ping(location)
56
+ return unless in_bounds?(location)
57
+
58
+ !!(object.location = location)
59
+ end
60
+
61
+ # allows searching by object properties like location or id
62
+ def get_object(property_hash)
63
+ property, value = property_hash.first
64
+ @objects.each do |object|
65
+ return object.properties if object.properties[property] == value
66
+ end
67
+ nil
68
+ end
69
+
70
+ def get_all_objects
71
+ @objects.collect {|object| object.properties}
72
+ end
73
+
74
+ def in_bounds?(location)
75
+ return false if location[:x] >= @size[:width] || location[:x] < 0
76
+ return false if location[:y] >= @size[:length] || location[:y] < 0
77
+ true
78
+ end
79
+
80
+ def ping(location)
81
+ get_object(location: location)
82
+ end
83
+
84
+ def forward_damage(params)
85
+ target = @objects.select{|object| object.id == params[:target]}.first
86
+ target.damage(params[:damage])
87
+ end_game if victory?
88
+ end
89
+
90
+ def victory?
91
+ @objects.one? do |object|
92
+ object.class != Wall && object.health > 0
93
+ end ||
94
+ @objects.none? do |object|
95
+ object.class != Wall && object.health > 0
96
+ end
97
+ end
98
+
99
+ def end_game
100
+ @clock.stop
101
+ end
102
+
103
+ private
104
+
105
+ def add_walls
106
+ (0...width).each do |col|
107
+ @objects << Wall.new(location: {x: col, y: -1})
108
+ @objects << Wall.new(location: {x: col, y: length})
109
+ end
110
+ (0...length).each do |row|
111
+ @objects << Wall.new(location: {x: -1, y: row})
112
+ @objects << Wall.new(location: {x: width, y: row})
113
+ end
114
+ end
115
+
116
+ end
117
+
118
+ end
@@ -0,0 +1,35 @@
1
+ require 'uuidtools'
2
+
3
+ module Brawl
4
+
5
+ class BasicArenaObject
6
+
7
+ attr_reader :id, :clock, :name
8
+ attr_accessor :location, :heading, :health
9
+
10
+ def initialize(params={})
11
+ @clock = params[:clock]
12
+ @id = params[:id] || UUIDTools::UUID.timestamp_create.to_s
13
+ @name = params[:name] || self.object_id
14
+ @location = params[:location] || {x: 0, y: 0}
15
+ @heading = params[:heading] || 0
16
+ @health = params[:health] || 1
17
+ @properties = params[:properties] ||
18
+ [:id, :name, :class, :location, :health, :heading]
19
+ end
20
+
21
+ # properties are values that are OK to be publicly 'seen' in the arena
22
+ def properties
23
+ @properties.each_with_object({}) do |property, hash|
24
+ hash[property] = self.send(property)
25
+ end
26
+ end
27
+
28
+ def damage(damage_points)
29
+ @health -= damage_points
30
+ @health < 0 ? @health = 0 : @health
31
+ end
32
+
33
+ end
34
+
35
+ end
@@ -0,0 +1,69 @@
1
+ require 'forwardable'
2
+ require 'uuidtools'
3
+ require 'eventable'
4
+
5
+ module Brawl
6
+
7
+ class BasicBot < BasicArenaObject
8
+ extend Forwardable
9
+
10
+ include Eventable
11
+ event :bot_ran_method
12
+ event :bot_damaged
13
+
14
+ attr_reader :parts
15
+
16
+ DECIMAL_PLACES = 1
17
+
18
+ def initialize(params={})
19
+ @arena = params[:arena]
20
+ @parts = params[:parts]
21
+
22
+ add_parts(@parts, params)
23
+ hook_methods_for_listeners
24
+
25
+ super
26
+
27
+ @arena.add_object(self)
28
+ end
29
+
30
+ def damage(damage_points)
31
+ super
32
+ fire_event(:bot_damaged,
33
+ properties,
34
+ :damage,
35
+ damage_points
36
+ )
37
+ @arena.remove_object(self) if @health <= 0
38
+ end
39
+
40
+ private
41
+
42
+ def add_parts(parts, params)
43
+ return unless parts
44
+ parts.each do |part_module, init_params|
45
+ params.merge! init_params
46
+ # make sure we can fire the module's initialize method
47
+ part_module.send :alias_method, :initialize_parts, :initialize
48
+ extend part_module
49
+ initialize_parts(params)
50
+ end
51
+ end
52
+
53
+ def hook_methods_for_listeners
54
+ public_methods(false).each do |method|
55
+ next if [:properties,:damage].include?(method)
56
+ singleton_class.send :alias_method, "_hook_#{method}", method
57
+
58
+ singleton_class.send :define_method, method do |*params, &block|
59
+ return if @health <= 0
60
+ fire_event(:bot_ran_method, properties, method, *params)
61
+ send "_hook_#{method}".to_sym, *params, &block
62
+ end
63
+
64
+ end
65
+ end
66
+
67
+ end
68
+
69
+ end
@@ -0,0 +1,97 @@
1
+ require 'eventable'
2
+
3
+ module Brawl
4
+
5
+ class BattleController
6
+
7
+ include Eventable
8
+ event :bot_msg
9
+
10
+ attr_accessor :arena, :bots, :clock
11
+
12
+ def initialize(params = {})
13
+ super
14
+
15
+ arena_data = params[:arena]
16
+ make_arena(arena_data)
17
+
18
+ bot_data = params[:bots]
19
+ make_bots(bot_data)
20
+
21
+ clock_data = params[:clock]
22
+ make_clock(clock_data)
23
+
24
+ end
25
+
26
+ def make_arena(arena_data)
27
+ return unless arena_data
28
+ @arena = Brawl::Arena.new(arena_data)
29
+ end
30
+
31
+ def make_clock(clock_data)
32
+ return unless clock_data
33
+ @clock = Clock.new(clock_data[:tick_rate])
34
+ @arena.set_clock(clock) if @arena
35
+ end
36
+
37
+ def make_bots(bot_data)
38
+ return unless bot_data
39
+
40
+ @bots = []
41
+ bot_data.each do |bot_datum|
42
+ bot_params = bot_datum[:params]
43
+
44
+ bot_params.merge!(arena: arena)
45
+ bot_params.merge!(name: bot_datum[:name])
46
+
47
+ location = {location: {x: rand(arena.width), y:rand(arena.length)}}
48
+ bot_params.merge!(location)
49
+
50
+ bot_instance = bot_datum[:class].new(bot_params)
51
+
52
+ bot_instance.register_for_event(
53
+ event: :bot_ran_method,
54
+ listener: self,
55
+ callback: :bot_msg_callback
56
+ )
57
+ bot_instance.register_for_event(
58
+ event: :bot_damaged,
59
+ listener: self,
60
+ callback: :bot_msg_callback
61
+ )
62
+
63
+ bot_proxy = BotProxy.new(
64
+ clock: clock,
65
+ bot: bot_instance,
66
+ code: bot_datum[:code]
67
+ )
68
+
69
+ @bots << {
70
+ name: bot_datum[:name],
71
+ proxy: bot_proxy
72
+ }
73
+ end
74
+ end
75
+
76
+ def bot_msg_callback(*params, &block)
77
+ fire_event(:bot_msg, *params, &block)
78
+ end
79
+
80
+ def victory?
81
+ arena.victory?
82
+ end
83
+
84
+ def start
85
+ @bots.each do |bot|
86
+ bot[:proxy].start
87
+ end
88
+ @clock.start
89
+ end
90
+
91
+ def stop
92
+ @clock.stop
93
+ end
94
+
95
+ end
96
+
97
+ end
@@ -0,0 +1,60 @@
1
+ module Brawl
2
+
3
+ class BotProxy
4
+
5
+ attr_accessor :bot, :last_tick, :msg_log, :clock
6
+
7
+ def initialize(params)
8
+ @clock = params[:clock]
9
+ @bot = params[:bot]
10
+ @code = params[:code]
11
+
12
+ @last_tick = @clock.ticks
13
+ @run = false
14
+
15
+ add_proxy_methods
16
+ end
17
+
18
+ def name
19
+ @bot.name
20
+ end
21
+
22
+ def add_proxy_methods
23
+ # I'm sure there's a better way of doing this
24
+ combined_methods = @bot.public_methods(false)
25
+ combined_methods.concat BasicArenaObject.instance_methods(false)
26
+
27
+ combined_methods.each do |method|
28
+ next if method.to_s[0] == "_"
29
+ singleton_class.send :define_method, method do |*params, &block|
30
+ sleep(0.01) while @clock.ticks <= @last_tick
31
+ @last_tick = @clock.ticks
32
+ @bot.send method, *params, &block
33
+ end
34
+
35
+ end
36
+ end
37
+
38
+ def start
39
+ @run = true
40
+ Thread.start {
41
+ until @clock.state == :stopped || !@run || @health == 0
42
+ sleep(0.01) if @clock.state == :wait
43
+ if @clock.state == :running
44
+ instance_eval("Thread.start{$SAFE=3;#{@code}}.join")
45
+ end
46
+ end
47
+ @run = false
48
+ }
49
+ end
50
+
51
+ def stop
52
+ @run = false
53
+ end
54
+
55
+ def code
56
+ yield self
57
+ end
58
+
59
+ end
60
+ end