Permalink
Browse files

yardoc'd

  • Loading branch information...
1 parent fc180d0 commit 9b179c296616300d62d72824881f17473f43dd56 @awilliams committed Mar 10, 2013
View
@@ -18,3 +18,5 @@ tmp
.idea
twitter_images/
bots/
+example.rb
+examples/
View
@@ -0,0 +1,4 @@
+--markup markdown
+--no-private
+--files sample_bots/*
+-
View
@@ -5,7 +5,7 @@ RTanque is a game for ( *Ruby* ) programmers. Players program the brain of a tan
Rules of the game are simple: Last bot standing wins. Gameplay is also pretty simple. Each tank has a **base**, **turret** and **radar**, each of which rotate independently. The base moves the tank, the turret has a gun mounted to it which can fire at other tanks, and the radar detects other tanks in its field of vision.
-Have fun competing against friends' tanks or the sample ones included. Maybe you'll start a small league at your local Ruby meetup.
+Have fun competing against friends' tanks or the sample ones included. Maybe you'll start a small league at your local Ruby meetup. CLI provides easy way to download bots from gists.
Sound difficult or time consuming? It's not! Check out the included sample tank [Seek&Destroy](https://github.com/awilliams/RTanque/blob/master/sample_bots/seek_and_destroy.rb) (which is actually fairly difficult to beat with the keyboard controlled bot). Note that it clocks in at under 50 LOC.
@@ -23,12 +23,12 @@ RTanque is based on the Java project [Robocode](http://robocode.sourceforge.net/
* [RRobots fork](https://github.com/ralreegorganon/rrobots)
* [FightCode](http://fightcodegame.com/) - Online javascript tank game
* [Scalatron](http://scalatron.github.com/) - Scala bot game
-* [More...](https://www.google.com/?q=robocode%20clone)
+* [Many more...](https://www.google.com/?q=robocode%20clone)
## Requirements
* The [Gosu](https://github.com/jlnr/gosu) library used for rendering has some dependencies. Use the [Gosu getting started](https://github.com/jlnr/gosu/wiki/Getting-Started-on-Linux) to resolve any for your system.
- * Ruby 1.9.3 (tested on 1.8.7 and 1.9.2)
+ * Ruby 2.0.0 or 1.9.3 (tested on 1.8.7 and 1.9.2)
## Quick Start
@@ -43,11 +43,19 @@ Make a project directory, init bundler, add the RTanque gem, and create a bot:
*Drive the Keyboard bot with asdf. Aim/fire with the arrow keys*
+## [RTanque Documentation](http://rubydoc.info/github/awilliams/RTanque/master/frames/file/README.md)
+
+ * [RTanque](http://rubydoc.info/github/awilliams/RTanque/master/frames/RTanque)
+ * [RTanque::Bot::Brain](http://rubydoc.info/github/awilliams/RTanque/master/frames/RTanque/Bot/Brain)
+ * [RTanque::Heading](http://rubydoc.info/github/awilliams/RTanque/master/frames/RTanque/Heading)
+ * [RTanque::Point](http://rubydoc.info/github/awilliams/RTanque/master/frames/RTanque/Point)
+
## Bot API
The tank api consists of reading input from Brain#sensors and giving output to Brain#command
**Brain#sensors**
+
```ruby
class Bot < RTanque::Bot::Brain
# RTanque::Bot::Sensors =
@@ -68,6 +76,7 @@ class Bot < RTanque::Bot::Brain
end
```
**Brain#command**
+
```ruby
class Bot < RTanque::Bot::Brain
# RTanque::Bot::Command =
View
@@ -1,4 +1,15 @@
+# RTanque
+#
+# #Interesting classes for the spelunker:
+#
+# * {RTanque::Bot::Brain} All brains should inherit from this class
+# * {RTanque::Bot::Sensors} Instance provided to {RTanque::Bot::Brain#sensors}
+# * {RTanque::Bot::Command} Instance provided to {RTanque::Bot::Brain#command}
+# * {RTanque::Heading} Handles angles
+# * {RTanque::Point} Handles coordinates
+# * {RTanqueCLI} CLI
module RTanque
+ # @!visibility private
def self.round(numeric, precision = nil)
if RUBY_VERSION >= '1.9'
numeric.round(precision)
View
@@ -1,13 +1,33 @@
module RTanque
class Bot
+ # Commands the associated {RTanque::Bot}. This class should be inherited from and {NAME} and {#tick!} overridden.
+ #
+ # See {RTanque::Bot::BrainHelper} for a useful mixin
+ #
+ # Sample bots:
+ #
+ # * {file:sample_bots/seek_and_destroy.rb SeekAndDestroy}
+ # * {file:sample_bots/camper.rb Camper}
+ # * {file:sample_bots/keyboard.rb Keyboard} Special bot controlled by the keyboard
+ #
class Brain
+ # Bot's display name
+ # @!parse NAME = 'bot name'
+
+ # @!attribute [r] sensors
+ # @return [RTanque::Bot::Sensors]
+ # @!attribute [r] command
+ # @return [RTanque::Bot::Command]
attr_accessor :sensors, :command
+ # @return [RTanque::Arena]
attr_reader :arena
+ # @!visibility private
def initialize(arena)
@arena = arena
end
+ # @!visibility private
def tick(sensors)
self.sensors = sensors
RTanque::Bot::Command.new.tap do |empty_command|
@@ -16,8 +36,14 @@ def tick(sensors)
end
end
+ # Main logic goes here
+ #
+ # Get input from {#sensors}. See {RTanque::Bot::Sensors}
+ #
+ # Give output to {#command}. See {RTanque::Bot::Command}
+ # @abstract
def tick!
- # main logic goes here
+ # Sweet bot logic
end
end
end
@@ -1,7 +1,7 @@
module RTanque
class Bot
+ # Some helpful constants and methods for use as mixin in {RTanque::Bot::Brain}
module BrainHelper
- # Some helpful constants
BOT_RADIUS = Bot::RADIUS
MAX_FIRE_POWER = Bot::MAX_FIRE_POWER
MIN_FIRE_POWER = Bot::MIN_FIRE_POWER
@@ -12,6 +12,9 @@ module BrainHelper
MAX_RADAR_ROTATION = Configuration.radar.turn_step
# Run block every 'num_of_ticks'
+ # @param [Integer] num_of_ticks tick interval at which to execute block
+ # @yield
+ # @return [void]
def at_tick_interval(num_of_ticks)
yield if sensors.ticks % num_of_ticks == 0
end
View
@@ -1,5 +1,19 @@
module RTanque
class Bot
+ # Command provide output from the {RTanque::Bot::Brain} about the current state of the {RTanque::Match}
+ #
+ # They are made available to {RTanque::Bot::Brain} via {RTanque::Bot::Brain#command}
+ #
+ # All values are bound. Setting an out-of-bounds value will result in it being set to the max/min allowed value.
+ #
+ # @attr_writer [Float] speed
+ # @attr_writer [Float, RTanque::Heading] heading
+ # @attr_writer [Float, RTanque::Heading] radar_heading
+ # @attr_writer [Float, RTanque::Heading] turret_heading
+ # @attr_writer [Float, nil] fire_power sets firing power. Setting to nil will stop firing. See {#fire}
+ #
+ # @param [Float] power alias to {#fire_power=}
+ # @!method fire(power)
Command = Struct.new(:speed, :heading, :radar_heading, :turret_heading, :fire_power) do
def fire(power = 3)
self.fire_power = power
View
@@ -7,6 +7,11 @@ class Radar
VISION_RANGE = Configuration.radar.vision
attr_normalized(:heading, Heading::FULL_RANGE, Configuration.radar.turn_step)
+ # A Reflection is the information obtained for a bot detected by {RTanque::Bot::Radar}
+ #
+ # @attr_reader [RTanque::Heading] heading
+ # @attr_reader [Float] distance
+ # @attr_reader [String] name
Reflection = Struct.new(:heading, :distance, :name) do
def self.new_from_points(from_position, to_position, &tap)
self.new(from_position.heading(to_position), from_position.distance(to_position)).tap(&tap)
View
@@ -1,5 +1,18 @@
module RTanque
class Bot
+ # Sensors provide input to the {RTanque::Bot::Brain} about the current state of the {RTanque::Match}
+ #
+ # They are made available to {RTanque::Bot::Brain} via {RTanque::Bot::Brain#sensors}
+ #
+ # @attr_reader [Integer] ticks number of ticks, starts at 0
+ # @attr_reader [Float] health health of bot. if == 0, dead
+ # @attr_reader [Float] gun_energy energy of cannon. if < 0, cannot fire
+ # @attr_reader [Float] speed
+ # @attr_reader [RTanque::Point] position
+ # @attr_reader [RTanque::Heading] heading
+ # @attr_reader [RTanque::Heading] radar_heading
+ # @attr_reader [RTanque::Heading] turret_heading
+ # @attr_reader [Enumerator] radar enumerates all bots scanned by the radar, yielding {RTanque::Bot::Radar::Reflection}
Sensors = Struct.new(:ticks, :health, :speed, :position, :heading, :radar, :radar_heading, :turret_heading, :gun_energy) do
def initialize(*args, &block)
super(*args)
@@ -3,6 +3,7 @@
module RTanque
one_degree = (Math::PI / 180.0)
+ # @!visibility private
Configuration = ::Configuration.for('default') do
raise_brain_tick_errors true
View
@@ -1,5 +1,34 @@
# -*- encoding: utf-8 -*-
module RTanque
+ # A Heading represents an angle. Basically a wrapper around `Float` bound to `(0..Math::PI * 2)`
+ #
+ # 0.0 == `RTanque::Heading::NORTH` is 'up'
+ #
+ # ##Basic Usage
+ # RTanque::Heading.new(Math::PI)
+ # # => <RTanque::Heading: 1.0rad 180.0deg>
+ #
+ # RTanque::Heading.new(Math::PI) + RTanque::Heading.new(Math::PI)
+ # # => <RTanque::Heading: 0.0rad 0.0deg>
+ #
+ # RTanque::Heading.new(Math::PI / 2.0) + Math::PI
+ # # => <RTanque::Heading: 1.5rad 270.0deg>
+ #
+ # RTanque::Heading.new(0.0) == 0
+ # # => true
+ #
+ # ##Utility Methods
+ # RTanque::Heading.new_from_degrees(180.0)
+ # # => <RTanque::Heading: 1.0rad 180.0deg>
+ #
+ # RTanque::Heading.new(Math::PI).to_degrees
+ # # => 180.0
+ #
+ # RTanque::Heading.new_between_points(RTanque::Point.new(0,0), RTanque::Point.new(2,3))
+ # # => <RTanque::Heading: 0.1871670418109988rad 33.690067525979785deg>
+ #
+ # RTanque::Heading.new_from_degrees(1).delta(RTanque::Heading.new_from_degrees(359))
+ # # => -0.034906585039886195
class Heading < Numeric
FULL_ANGLE = Math::PI * 2.0
HALF_ANGLE = Math::PI
@@ -35,57 +64,79 @@ def self.rand
attr_reader :radians
+ # Creates a new RTanque::Heading
+ # @param [#to_f] radians degree to wrap (in radians)
def initialize(radians = NORTH)
@radians = self.extract_radians_from_value(radians) % FULL_ANGLE
@memoized = {} # allow memoization since @some_var ||= x doesn't work when frozen
self.freeze
end
+ # difference between `self` and `to` respecting negative angles
+ # @param [#to_f] to
+ # @return [Float]
def delta(to)
diff = (to.to_f - self.to_f).abs % FULL_ANGLE
diff = -(FULL_ANGLE - diff) if diff > Math::PI
to < self ? -diff : diff
end
+ # @return [RTanque::Heading]
def clone
self.class.new(self.radians)
end
+ # @param [#to_f] other_heading
+ # @return [Boolean]
def ==(other_heading)
self.to_f == other_heading.to_f
end
# continue with Numeric's pattern
+ # @param [#to_f] other_heading
+ # @return [Boolean]
def eql?(other_heading)
other_heading.instance_of?(self.class) && self.==(other_heading)
end
+ # @param [#to_f] other_heading
+ # @return [Boolean]
def <=>(other_heading)
self.to_f <=> other_heading.to_f
end
- def +(r)
- self.class.new(self.radians + self.extract_radians_from_value(r))
+ # @param [#to_f] other_heading
+ # @return [RTanque::Heading]
+ def +(other_heading)
+ self.class.new(self.radians + self.extract_radians_from_value(other_heading))
end
- def -(r)
- self.+(-r)
+ # @param [#to_f] other_heading
+ # @return [RTanque::Heading]
+ def -(other_heading)
+ self.+(-other_heading)
end
- def *(r)
- self.class.new(self.radians * self.extract_radians_from_value(r))
+ # @param [#to_f] other_heading
+ # @return [RTanque::Heading]
+ def *(other_heading)
+ self.class.new(self.radians * self.extract_radians_from_value(other_heading))
end
- def /(r)
- self.*(1.0 / r)
+ # @param [#to_f] other_heading
+ # @return [RTanque::Heading]
+ def /(other_heading)
+ self.*(1.0 / other_heading)
end
# unary operator
+ # @return [RTanque::Heading]
def +@
self.class.new(+self.radians)
end
# unary operator
+ # @return [RTanque::Heading]
def -@
self.class.new(-self.radians)
end
@@ -95,13 +146,15 @@ def to_s
end
def inspect
- "<#{self.class.name}: #{self.to_f}rad #{self.to_degrees}°>"
+ "<#{self.class.name}: #{self.radians}rad #{self.to_degrees}deg>"
end
+ # @return [Float]
def to_f
self.radians
end
+ # @return [Float]
def to_degrees
@memoized[:to_degrees] ||= (self.radians * 180.0) / Math::PI
end
Oops, something went wrong.

0 comments on commit 9b179c2

Please sign in to comment.