# RRobots (#59)

**URL:** <https://www.ruby-forum.com/t/rrobots-59/80650>\
**Category:** Ruby\
**Created:** [December 29, 2005, 4:21pm UTC](https://www.ruby-forum.com/t/rrobots-59/80650 "2005-12-29T16:21:51Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![bbazzarrakk](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/47e85d/32.png) [@bbazzarrakk](https://www.ruby-forum.com/u/bbazzarrakk)\
**Post date:** [December 29, 2005, 4:21pm UTC](https://www.ruby-forum.com/t/rrobots-59/80650/1 "2005-12-29T16:21:51Z")

</div>

The tournament has been run, so let’s begin with the official results.  
You can  
find the complete statistics here:

```
http://www.rubyquiz.com/rrobots/tournament.html

```

Briefly though, here are the total wins:

```
+------------------+-------+
| Bot | Wins |
+------------------+-------+
| Ente | 241.5 |
| RubberDuck | 228.0 |
| RubberDuckLinear | 179.0 |
| WKB | 177.5 |
| Kite2 | 165.0 |
| DuckBill09 | 161.0 |
| CloseTalker | 153.0 |
| GayRush | 115.0 |
| HornRobot | 108.0 |
| Harlock | 67.0 |
| SporkBot | 55.0 |
+------------------+-------+

```

Looks like our big winner was Ente. I’m told that’s German for duck.  
Congratulations to Jannis Harder, Ente’s creator.

Ente is just shy of 500 lines of code, so we’re going to get the short  
version  
below. As always, I suggest looking at the actual code. Here’s the  
start of  
the robot:

```
require 'robot'

class << Module.new # anonymous container

  module RobotMath

    def weighted_linear_regression(data)
      # ...
    end

    def zero_fixed_linear_regression(data)
      # ...
    end

    def offset(heading_a,heading_b = 0)
      # ...
    end

  end

  # ...

```

Obviously, we have the required module for the robot interface. Then we  
see the  
definition of some simple math helpers.

The interesting part of the above code to me was the second line. Since  
this  
code has no need to refer to the defined modules, classes, and methods  
outside  
of its own scope, the whole mess added to an anonymous namespace. That  
seems  
like a clever way to guard against name collision, among other uses.

One of the larger tasks all the robots had to deal with was turning.  
You have  
to ensure your robot, radar, and gun are facing where you need at any  
given  
time. Ente has a whole module of helpers for this:

```
  # ...

  module Turnarounder
    # ...

    def head_to deg # ...
    def head_gun_to deg # ...
    def head_radar_to deg # ...
    def next_delta_heading # ...
    alias turn_amount next_delta_heading
    def ready? # ...
    def next_heading # ...
    def turn_gun_amount # ...
    def gun_ready? # ...
    def next_delta_gun_heading # ...
    def next_gun_heading # ...
    def turn_radar_amount # ...
    def radar_ready? # ...
    def next_delta_radar_heading # ...
    def next_radar_heading # ...
    def final_turn # ...
    def turn x # ...
    def turn_gun x # ...
    def turn_radar x # ...
    def mid_radar_heading # ...

  end

  # ...

```

The functionality of those methods should be fairly obvious from the  
names and  
we will see them put to use in a bit.

Next we have a module for movement:

```
  # ...

  module Pointanizer
    include Math
    include RobotMath
    include Turnarounder

    def move_to x,y
      @move_x = x
      @move_y = y
      @move_mode = :to
    end

    def move mode,x,y
      @move_x,@move_y = x,y
      @move_mode = mode
    end

    def halt
      @move_mode = false
    end

    def moving?
       @move_mode
    end

    def on_wall?
      xcor <= size*3 or ycor <= size*3 or
      battlefield_width - xcor <= size*3 or
      battlefield_height - ycor <= size*3
    end

    def final_point

        yc = ycor-@move_y rescue 0
        xc = @move_x-xcor rescue 0

        if hypot(yc,xc) < size/3
          @move_mode = false
        end

        acc = true

        case @move_mode
        when :to
          head_to atan2(yc,xc).to_deg
        when :away
          head_to atan2(yc,xc).to_deg+180
        when :side_a
          head_to atan2(yc,xc).to_deg+60
        when :side_b
          head_to atan2(yc,xc).to_deg-60
        when nil,false
          acc = false
        else
          raise "Unknown move mode!"
        end

        accelerate(8) if acc

    end

    def rad_to_xy(r,d)
      return xcor + cos(r.to_rad)*d, \
             ycor - sin(r.to_rad)*d
    end

  end

  # ...

```

We’re starting to see robot specific knowledge here. This module deals  
with  
robot movement. The methods move() and move\_to() are used to set a new  
destination, or halt() can stop the robot.

If you glance through final\_point(), you will see the various movement  
modes  
this robot uses. For example, :away will turn you 180 degrees so you  
move  
“away” from the indicated destination.

Now we’re ready for a look at Ente’s brain:

```
  # ...

  class Brain
    include Math
    include RobotMath
    include Turnarounder
    include Pointanizer

    # ...

    attr_accessor :predx, :predy

    def initialize(robot)
      @robot = robot
      super()

      @points = []

      @last_seen_time = -TRACK_TIMEOUT

      @radar_speed = 1
      @track_mul = 1

      @searching =0
      @seeking =0

      #movement
      @move_direction = 1
      @lasthitcount = 0
      @lasthitcount2 = false
      @lastchange = -TIMEOUT
    end

    # ...

    def predict ptime
      # ...
    end

    def predcurrent
      @predx,@predy = predict time unless @predx
    end

    def tick events

      fire 0.1

      #event processing

      # ...

      #moving

      # ...

      #aiming

      # ...

      #scanning

      # ...

    end

    def method_missing(*args,&block)
      @robot.relay(*args,&block)
    end

  end

  # ...

```

The majority of that is the tick() method, of course. It’s quite a  
beast and  
I’m not even going to try to predict all that it does. The comments in  
it will  
tell you what the following calculations are for, at least. (Jannis  
should feel  
free to reply with a detailed breakdown… 😃 )

One thing that is interesting in the above code is the use of the passed  
in  
@robot. Take a look at the first line in the constructor and the  
definition of  
method\_missing() at the end of this class. In order to understand that,  
we need  
to see the last class:

```
  # ...

  class Proxy
    include ::Robot

    def initialize
      @brain = Brain.new(self)
    end

    EXPORT_MAP = Hash.new{|h,k|k}

    EXPORT_MAP['xcor'] = 'x'
    EXPORT_MAP['ycor'] = 'y'
    EXPORT_MAP['proxy_turn'] = 'turn'
    EXPORT_MAP['proxy_turn_gun'] = 'turn_gun'
    EXPORT_MAP['proxy_turn_radar'] = 'turn_radar'

    def relay(method,*args,&block)
      self.send(EXPORT_MAP[method.to_s],*args,&block)
    end

    def tick events
      @brain.tick events
    end

  end

  # ...

```

As you can see, Proxy ties together the Brain class and the Robot module  
with a  
combination of relay() and the Brain.method\_missing() we saw earlier.  
You could  
swap out brains by changing the assignment in initialize(), or even  
reassign  
@brain at runtime to switch behaviors.

Only one issue remains. RRobots is expecting an Ente class to be  
defined but we  
haven’t seen that yet. That needs to be resolved before we leave this  
anonymous  
namespace we’re in and lose access to all of these classes. Here’s the  
final  
chunk of code that handles just that:

```
  # ...

  classname = "Ente"
  unless Object.const_defined?(classname)
    Object.const_set(classname,Class.new(Proxy))
  end
end

```

A new class is created by subclassing Proxy and that class is assigned  
to a  
constant on Object by the name of Ente. That ensures RRobots will find  
what it  
expects when the time comes.

My thanks to all the robot coders, especially for the robots I didn’t  
show  
above. They all wrote some interesting code. Also, a big thank you to  
Simon  
Kroeger who helped me setup this quiz, and ran the final tournament.

Tomorrow, Christer N. has a fun little maze of numbers for us…

---

<div class="post-metadata">

**Author:** ![bbazzarrakk](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/47e85d/32.png) [@bbazzarrakk](https://www.ruby-forum.com/u/bbazzarrakk)\
**Post date:** [December 29, 2005, 4:40pm UTC](https://www.ruby-forum.com/t/rrobots-59/80650/2 "2005-12-29T16:40:00Z")

</div>

On Dec 29, 2005, at 9:18 AM, Ruby Q. wrote:

> | DuckBill09 | 161.0 |  
> | CloseTalker | 153.0 |  
> | GayRush | 115.0 |  
> | HornRobot | 108.0 |  
> | Harlock | 67.0 |  
> | SporkBot | 55.0 |  
> ±-----------------±------+

It has been pointed out that EdBot is missing from the statistics.  
This is an error on the part of the quiz runners, and we are working  
to correct it…

Sorry about that.

James Edward G. II

---

<div class="post-metadata">

**Author:** ![bbazzarrakk](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/47e85d/32.png) [@bbazzarrakk](https://www.ruby-forum.com/u/bbazzarrakk)\
**Post date:** [December 29, 2005, 5:10pm UTC](https://www.ruby-forum.com/t/rrobots-59/80650/3 "2005-12-29T17:10:57Z")

</div>

I’m realy sorry!

I double checked the ML for ‘rrobot’ and ‘59’ but missed “[SOLUTION]  
Robot”. Again, thats my fault - new tournament results will follow soon.

cheers

Simon

---

<div class="post-metadata">

**Author:** ![bbazzarrakk](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/47e85d/32.png) [@bbazzarrakk](https://www.ruby-forum.com/u/bbazzarrakk)\
**Post date:** [December 29, 2005, 10:28pm UTC](https://www.ruby-forum.com/t/rrobots-59/80650/4 "2005-12-29T22:28:23Z")

</div>

On Dec 29, 2005, at 9:38 AM, James Edward G. II wrote:

> > | WKB | 177.5 |  
> > This is an error on the part of the quiz runners, and we are  
> > working to correct it…

Updated results are now online at:

[http://www.rubyquiz.com/rrobots/tournament.html](http://www.rubyquiz.com/rrobots/tournament.html)

James Edward G. II

---

<div class="post-metadata">

**Author:** ![bbazzarrakk](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/47e85d/32.png) [@bbazzarrakk](https://www.ruby-forum.com/u/bbazzarrakk)\
**Post date:** [December 29, 2005, 5:23pm UTC](https://www.ruby-forum.com/t/rrobots-59/80650/5 "2005-12-29T17:23:06Z")

</div>

Ok, i ran a quick tournament with 3 matches per round just to see if  
there are major impacts on the ranking:

```
  +------------------+-------+
  | Bot | Wins |
  +------------------+-------+
  | Ente | 31.0 |
  | RubberDuck | 30.0 |
  | Kite2 | 20.0 |
  | DuckBill09 | 18.0 |
  | RubberDuckLinear | 18.0 |
  | CloseTalker | 17.0 |
  | WKB | 15.0 |
  | GayRush | 15.0 |
  | EdBot | 13.0 |
  | HornRobot | 7.0 |
  | Harlock | 7.0 |
  | SporkBot | 7.0 |
  +------------------+-------+

```

I will start a 30 match tournament, but this will take some hours to  
complete.

cheers

Simon

---

<div class="post-metadata">

**Author:** ![bbazzarrakk](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/47e85d/32.png) [@bbazzarrakk](https://www.ruby-forum.com/u/bbazzarrakk)\
**Post date:** [December 30, 2005, 10:54am UTC](https://www.ruby-forum.com/t/rrobots-59/80650/6 "2005-12-30T10:54:28Z")

</div>

On 12/29/05, Ruby Q. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> Looks like our big winner was Ente. I’m told that’s German for duck.  
> Congratulations to Jannis Harder, Ente’s creator.
> 
> Ente is just shy of 500 lines of code, so we’re going to get the short version  
> below. As always, I suggest looking at the actual code. Here’s the start of  
> the robot:

My head exploded reading that. I wish I didn’t hate math so much. ☹

---

<div class="post-metadata">

**Author:** ![bbazzarrakk](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/47e85d/32.png) [@bbazzarrakk](https://www.ruby-forum.com/u/bbazzarrakk)\
**Post date:** [December 30, 2005, 2:52pm UTC](https://www.ruby-forum.com/t/rrobots-59/80650/7 "2005-12-30T14:52:53Z")

</div>

On Dec 30, 2005, at 3:52 AM, Joe Van D. wrote:

> My head exploded reading that. I wish I didn’t hate math so  
> much. ☹

There was definitely a pattern to the big winners: Lots of math. 😉

James Edward G. II
