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/.gitignore CHANGED
@@ -2,3 +2,4 @@
2
2
  .bundle
3
3
  Gemfile.lock
4
4
  pkg/*
5
+ .DS_Store
data/.rspec ADDED
File without changes
data/README.md ADDED
@@ -0,0 +1,43 @@
1
+ # Brawl
2
+
3
+ A dangerous robotic programming game that will kill you in your sleep.
4
+
5
+ Write robotic assassins using Ruby and watch them as they do your evil bidding.
6
+
7
+ ## Status
8
+ **Alpha Development**
9
+
10
+ Brawl is a work in progress but currently supports running bots on your local machine with limited security.
11
+
12
+ ## Features
13
+ The framework is designed from the ground up to be extendable. Want to add some new functionality to robots like dropping land mines, semi-intelligent turrets, or heat seeking missiles? Just write a new part and load it into your bot.
14
+
15
+ ## Security
16
+ Brawl was also designed to be secure (when the DRb methodology is implemented). In the secure version (in prototype stage now) bot code runs in a $SAFE = 3 process fork and communicates via a wrapper that uses DRb to talk to a proxy object.
17
+
18
+ Whew, that was a mouth full but what it basically means is you can feel reasonably safe running other people's code on your machine. They won't be able to erase your hard drive, probably, much less hack your bots or the game engine to cheat.
19
+
20
+ Legal Notice: This is not a guarantee of fitness or anything else. If you use other people's code without understanding what it does expect your entire system to melt.
21
+
22
+ ## Example bot programs
23
+
24
+ This is a really dumb robot that just scans for enemies and shoots at them. If it can't find an enemy it will move around till it does. How would you improve it?
25
+
26
+ code do |bot|
27
+ @dir ||= 0
28
+ targets = bot.scan direction: @dir, angle: 90
29
+ @dir += 45
30
+ @dir %= 360
31
+ unless targets.each do |target|
32
+ unless target[:class] == Brawl::Wall
33
+ results = shoot(target[:bearing])
34
+ end
35
+ end.empty?
36
+ else
37
+ if rand(0) > 0.5
38
+ bot.turn [:left,:right,:around].sample
39
+ end
40
+ bot.move rand(3) + 1
41
+ end
42
+ end
43
+
@@ -0,0 +1,98 @@
1
+ Brainstorming how it's all going to fit together.
2
+ I'll probably toss a lot of this as I get into coding but this helps me think about the problem.
3
+
4
+
5
+ Code loader
6
+ Encapsulates code input.
7
+
8
+ This could be from a file, a webpage, a database, etc.
9
+
10
+
11
+ BasicRobot
12
+ Defines the minimum objects a robot should have.
13
+
14
+ For instance it should have a motor, a scanner, a weapon, and a shield
15
+
16
+
17
+ BasicObject?
18
+ Should I define a basic object or objects like weapons, motors, scanners, or just a basic object that can interact with the world.
19
+
20
+ It could have properties like x,y... that couples it to the Area though doesn't it?
21
+
22
+
23
+ RobotSpecs
24
+ A model that describes how many points are assigned to each component of a robot.
25
+
26
+ Does this even need to be a class? It's basically just an array. Maybe this can encapsulate how to read that using given Data API.
27
+
28
+
29
+ RobotRules
30
+ This model defines how many points mean what in a RobotSpec.
31
+
32
+ For instance how much damage a Laser set to 8 does or how much damage a shield set to 4 mitigates. This is how the game will be balanced.
33
+
34
+
35
+ Code parser/DSL
36
+ Handles converting raw bot code into runnable code.
37
+
38
+
39
+ Code runner
40
+ Runs the code in a safe manner.
41
+
42
+ This will most likely be by containing it in a tread with $SAFE = 4.
43
+
44
+
45
+ Communication Layer
46
+ Sends messages back and forth between the arena and the code runner.
47
+
48
+ This could be as simply as wiring up the receive to the transmit and vice versa for local running to a web based interface using Sinatra.
49
+ It should handle communication from multiple clients securely (a bot shouldn't be able to lie about who it is)
50
+
51
+
52
+ BotController
53
+ This controller is the glue that pushes all the buttons of the classes needed to make a bot run like: Code loader, Code parser, a communication layer, and the code runner.
54
+
55
+
56
+ ArenaController
57
+ Orchestrates all the classes needed to make combat work like Layouts, Arena and Bot Rules, and ScoreKeeping.
58
+
59
+
60
+ ArenaLayout
61
+ The model that describes what an arena looks like.
62
+
63
+ How long and wide it is and where obstacles are.
64
+
65
+
66
+ ArenaRules
67
+ A model that contains rules for battles.
68
+
69
+ This could be things like how many battles to fight, the maximum number of points allowed for a bot, time limits, etc.
70
+
71
+
72
+ ScoreKeeping
73
+ Stores the results of battles.
74
+
75
+
76
+ Data API
77
+ Basic interface to datastores.
78
+
79
+ This could be a JSON or YAML file or a database. This should be injected into a model so the model knows how to read data.
80
+
81
+
82
+ Config
83
+ Bootstraps the basic configuration for the ApplicationController.
84
+
85
+ This might contain server locations, DataAPI types, and communication layer types.
86
+
87
+
88
+ Application Controller
89
+ This is what orchestrates all the other classes into a usable application.
90
+
91
+ This could be a CLI 'bot developer client or server or it could decide what it is by the way you run it. It could run a GUI.
92
+
93
+
94
+ BattleView
95
+ Displays information about a running battle and its results.
96
+
97
+
98
+
@@ -0,0 +1,113 @@
1
+ # Brainstorming what a bot program might look like so I can figure out how to deal with it
2
+
3
+ # I've removed the idea of throttling. Throttling changes the model from event based
4
+ # to event/queue based so then there's no point in multi-threading in the first place.
5
+
6
+ # Bots are divided into classes by points and attachments (mixin modules that add more functionality)
7
+ # A basic bot might be allowed 10 points to allocate. The more points the better the system of course.
8
+ #
9
+
10
+ # This defines your robot's characteristics
11
+ Bot.build
12
+ {
13
+ # required
14
+ scanner: 2,
15
+ motor: 2,
16
+ laser: 2,
17
+ shield: 4,
18
+ # optional
19
+ name: "Full function bot",
20
+ author: "Mike Bethany",
21
+ description: "A simple but full featured robot to show all the capabilities",
22
+ revision: '0.0.1',
23
+ }
24
+ # Should there be some kind of GUID handed out by a central command to identify bots?
25
+
26
+ # These are things that can happen and should be responded to
27
+ event :enemy_found
28
+ event :enemy_lost
29
+
30
+ # This loop looks for an enemy and tries to track it
31
+ # (loop creates a thread)
32
+ @contact = nil
33
+ BasicScanner.loop do
34
+ # try to keep the scanner locked on the enemy
35
+ if @contact and @contact.is_enemy?
36
+ direction, sweep, range = contact.direction - 5, 10, @contact.range + 2
37
+ else
38
+ # lazy scanning
39
+ # It's very slow since it's scanning the maximum range in a full circle
40
+ direction, sweep, range = 0, 360, :max
41
+ end
42
+ @contact = scan direction: direction, sweep: sweep, range: range
43
+ end
44
+
45
+ # Another scanner thread that is a lot faster and just looks for walls
46
+ BasicScanner.loop do
47
+ if check_for_walls(:front)
48
+ [:left, :right].each do |direction|
49
+ @walls[direction] = check_for_walls(direction)
50
+ end
51
+ end
52
+ fire_event(:wall)
53
+ end
54
+
55
+ def check_for_walls(direction)
56
+ # This is a really fast scan because it's scanning the minimum distance at only 1 degree
57
+ !BasicScanner.scan direction: direction, sweep: 1, range: Motor.speed
58
+ end
59
+
60
+ BasicScanner.loop do
61
+
62
+ end
63
+
64
+ # Another low priority thread that moves the bot around randomly
65
+ Motor.loop do
66
+
67
+ if Motor.dead_end
68
+ reverse
69
+ Motor.dead_end = false
70
+ else
71
+ # mostly go straight but turn randomly sometimes
72
+ unless rand(100) > 70 and check_for_wall(:front)
73
+ forward unless Motor.direction == :forward
74
+ else
75
+ # turning takes time and is blocking
76
+ Motor.dead_end = random_turn
77
+ end
78
+ end
79
+
80
+ end
81
+
82
+ def random_turn
83
+ directions = [:left,:right]
84
+ while pick = directions.delete(rand(directions.length))
85
+ unless check_for_wall(pick)
86
+ turn pick
87
+ break
88
+ end
89
+ end
90
+ !directions.is_empty?
91
+ end
92
+
93
+ # This does not create a thread/loop but instead dynamcially creates a method using the given block
94
+ # You can call it whatever you want as long as you don't pick something that's already taken.
95
+ # If you try to overwrite methods that are important to the bot like forward or reverse they
96
+ # won't be used since this would break the system's ability to interact with your bot.
97
+ Laser.engage do |contact|
98
+ # lazy aiming (a better approach might be to remember the last few contacts and try to extrapolate location)
99
+
100
+ # Aim sends the command to move the turrent but it's a non-blocking call
101
+ aim contact.direction
102
+
103
+ # Since aim is a non-blocking call you might not actually be pointed at the enemy yet
104
+ fire if contact.distance <= Laser.range and BasicScanner.scan direction: contact.direction, sweep: 3, range: contact.distance, priority: 5
105
+ end
106
+
107
+ # Again this method is created dynamically using the given block
108
+ Motor.pursue do |contact|
109
+
110
+ end
111
+
112
+
113
+
data/_design/array.rb ADDED
@@ -0,0 +1,4 @@
1
+ puts Array.public_methods(false)
2
+ puts
3
+ puts
4
+ puts Array.new.public_methods(false).sort.inspect
@@ -0,0 +1,71 @@
1
+ Thread.abort_on_exception = true
2
+
3
+ class Time
4
+ def self.time
5
+ Time.now.strftime("%H:%M:%S.%L")
6
+ end
7
+ end
8
+
9
+ module Kernel
10
+ def tputs(message)
11
+ puts "#{Time.time} #{message}"
12
+ end
13
+ end
14
+
15
+ class Resource
16
+ @mutex = Mutex.new
17
+
18
+ def self.do(count, time)
19
+ tputs "do: #{count}"
20
+ count.times do |index|
21
+ self.use(count, time, index)
22
+ end
23
+ end
24
+
25
+ def self.use(count, time, index)
26
+ @mutex.synchronize do
27
+ timeout = Time.now + time
28
+ sleep(0.01) while Time.now < timeout
29
+ tputs "#{index} for count: #{count}"
30
+ end
31
+ # This sleep seems to be crucial. The mutex is released but if I
32
+ # don't have a sleep here the next thing waiting for the mutex
33
+ # doesn't seem to get the resource.
34
+ sleep(0.001)
35
+ end
36
+
37
+ end
38
+
39
+ class Worker
40
+
41
+ def initialize(&block)
42
+ @block = block
43
+ end
44
+
45
+ def start
46
+ @stop_working = nil
47
+ tputs "Starting: #{@block}"
48
+ Thread.new do
49
+ until @stop_working
50
+ @block.call
51
+ end
52
+ end
53
+ end
54
+
55
+ def stop
56
+ @stop_working = false
57
+ end
58
+ end
59
+
60
+ #slow = Worker.new {Resource.do_something(5,0.2)}
61
+ #fast = Worker.new {sleep(0.5);Resource.do_something(1,0.1)}
62
+ slow = Worker.new {Resource.do(3,0.25)}
63
+ fast = Worker.new {sleep(1.5); Resource.do(1,0.1)}
64
+ slow.start
65
+ fast.start
66
+ stop = Time.now + 5
67
+ sleep(0.01) while stop > Time.now
68
+
69
+ slow.stop
70
+ fast.stop
71
+
@@ -0,0 +1,2 @@
1
+ require_relative "communications/null_modem"
2
+ require_relative "communications/com_linker"
@@ -0,0 +1,11 @@
1
+ module Brawl
2
+ module Communications
3
+ class ProxyGenerator
4
+ def self.link(com_layer, server)
5
+ client.public_methods(false).each do |method|
6
+ com_layer.link_method(client, server, method)
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Brawl
2
+ module Communications
3
+ class NullModem
4
+ def link_method(client, server, method)
5
+ client.class.send :define_method, method do |*params, &block|
6
+ server.send method, *params, &bloc
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+
3
+ describe Brawl::Communications::Linker do
4
+
5
+ it "should link two classes using a communication class"
6
+
7
+ end
8
+
9
+ class Foo
10
+ def bar(value)
11
+ "doh!"
12
+ end
13
+ def baz(value1, value2)
14
+ "Oh, noos!"
15
+ end
16
+ def qux
17
+ "Fudge!"
18
+ end
19
+ def quux(value1, value2, &block)
20
+ "Nope, nope, nope"
21
+ end
22
+ end
23
+
24
+ class FooProxy
25
+ def bar(value)
26
+ "#{value}"
27
+ end
28
+ def baz(value1, value2)
29
+ "#{value1}, #{value2}"
30
+ end
31
+ def qux
32
+ yield "FooProxy"
33
+ end
34
+ def quux(value1, value2, &block)
35
+ yield ["FooProxy", "#{value1}, #{value2}"]
36
+ end
37
+ end
@@ -0,0 +1,32 @@
1
+ class Arena
2
+ attr_accessor :counter
3
+ def initialize
4
+ @counter = ""
5
+ @bots = {}
6
+ end
7
+
8
+ def add_bot(client_id)
9
+ @bots[client_id] = {location: 0}
10
+ end
11
+
12
+ def move(value, client_id)
13
+ puts "move called: #{value.inspect}; #{client_id}"
14
+ @bots[client_id][:location] += value.first
15
+ end
16
+
17
+ end
18
+
19
+ class ArenaProxy
20
+
21
+ attr_accessor :client_id
22
+
23
+ def initialize(arena, client_id=nil)
24
+ @arena = arena
25
+ @client_id = client_id
26
+ end
27
+
28
+ def move(amount)
29
+ @arena.move(amount, client_id)
30
+ end
31
+
32
+ end