Thinking in OO


#1

Hi all,

Trying hard to get my brain wrapped around the concepts of OO (using
Ruby which i’m also new to but doesn’t seem as foreign to me). I’m
using rrobots (at rubyforge) to practice…

This is what’s provided to me:

#state:

team

battlefield_height

battlefield_width

energy

gun_heading

gun_heat

heading

size

radar_heading

time

game_over

speed

x

y

#actions:

accelerate

stop

fire

turn

turn_gun

turn_radar

broadcast

say

#events:

broadcast

got_hit

robot_scanned

Now I’ve started to write a bot serveral times, but I’m thinking I need
to back up a bit and figure out who to approach this from an OO
standpoint.

Ruby reinforces the idea of passing messages to objects (right?). My
instinct
is to write methods named turn.left, turn.right, sleep.up, speed.down,
gun.fire, radar.sweep, etc…

But maybe that’s not abstract enough. Maybe methods like evade,
attack, attacked are more inline with OO thinking?

Is there one best way to think about this problem? Or am I
over-analyzing?

Thanks!

Greg


#2

Hi –

On Sun, 23 Apr 2006, Greg C. wrote:

battlefield_height

x

#events:
gun.fire, radar.sweep, etc…
The question you should ask is: is there an entity called a “turn” in
the universe of your application – the domain – which can perform an
action, or which has a property, called “left”? I would say the
answer is no. A turn might have a “direction” property, and that
might be “left”. But turn.left suggests that you’re telling a turn to
left, or to show you its left, neither of which really fits.

(It’s true that you’ll see libraries that do things like:
turn.five.degrees.to.the.left, but I consider that serious dot-abuse
and would stay away from it.)

So, you’re likely to see things like:

robot.turn :direction => “left”, :degrees => 5

where direction and degrees are actually hash keys that can be parsed
out in the turn method and used to modify state (x and y, I would
assume).

Anyway, for me, the main thing is that every message that goes to an
object should make sense either as a command to the object, or as a
request for information from the object.

David


David A. Black (removed_email_address@domain.invalid)
Ruby Power and Light, LLC (http://www.rubypowerandlight.com)

“Ruby for Rails” PDF now on sale! http://www.manning.com/black
Paper version coming in early May!


#3

In my latest attempt at writing a bot, my objects are radar, gun and
tank.

methods are things like increase (scan), decrease (scan), reverse,
adjust, etc.

There’s also a bit of procedural code in the main (tick) method to
know what object to call with what method. Is that acceptable in OO?

Code follows - not the smartest bot in the world (he doesn;t even move
yet - trying to get the radar to lock-on consitently), but i’m hoping
it’s a good start that I can add to.

Any/all suggestion and criticism are very welcome!

Greg

require ‘robot’

#in this script, heading is absolute (0-360), dir (direction) is
relative (± and probably no more than 60)

#available options:

#state:

team

battlefield_height

battlefield_width

energy

gun_heading

gun_heat

heading

size

radar_heading

time

game_over

speed

x

y

#actions:

accelerate

stop

fire

turn

turn_gun

turn_radar

broadcast

say

#events:

broadcast

got_hit

robot_scanned

####### Need Unit Tests!!!

class GoofeyDuck
include Robot

def initialize
@got_hit = 0
@found
@seen #found previous round…

@radar = Radar.new
@gun = Gun.new
@tank = Tank.new

end

def tick(events)

@got_hit = events['got_hit']
@found =  events['robot_scanned'] if 

(!events[‘robot_scanned’].empty?)

#set radar
if (@found)
  @radar.decrease(1) unless (@radar.dir.abs <= 1)
  @radar.reverse
  @seen = 1
  say "Locked"
elsif (@seen)
  @radar.increase(3)
  @radar.reverse
  @seen = !@seen
  say "Dang, Lost em"
else
  @radar.increase(2)
  say "Tracking...."
end
@radar.dir = verify(@radar.dir, @radar.max)

#set gun
@gun.adjust(@radar.mid(radar_heading), gun_heading)
@gun.dir = verify(@gun.dir, @gun.max)

#fire or no?
if (@found)
  @gun.fire += 0.1
else
  @gun.fire -= 0.1 unless (@gun.fire <= 0)
end

@gun.fire = verify(@gun.fire, 3)

#pass results
turn_radar(verify(@radar.adjust(@gun.dir), @radar.max)) #adjust 

radar to gun
turn_gun(@gun.dir)
turn(@tank.dir)
accelerate(@tank.vel)
fire(@gun.fire)
say “Uh oh” if (energy <= 10)

puts @gun.fire

#reset
@found = !@found if (@found)

end

def verify(dir, max)
if (dir > max)
dir = max
elsif (dir.abs > max)
dir = (max * -1)
end
dir
end

end

class Radar
include Robot

attr_reader :dir, :max
attr_writer :dir

def initialize
@dir = 60
@max = 60 #max delta
end

def increase(amt)
z = @dir <=> 0
@dir += (amt * z)
end

def decrease(amt)
z = @dir <=> 0
@dir -= (amt * z)
end

def reverse
@dir *= -1
end

def adjust(gun)
@dir - gun
end

def mid(head) #in degrees…
head + (@dir/2)
end

end

class Gun
include Robot

attr_reader :dir, :fire, :max
attr_writer :dir, :fire

def initialize
@dir = 0
@max = 30 #max delta
@fire = 0.1
end

def adjust(target, gun_head)
@dir = target - gun_head
end

end

class Tank
include Robot

attr_reader :dir, :vel
attr_writer :dir, :vel

def initialize
@dir = 0
@max = 10 #max delta
@vel = 0
end

end