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