Change the facing with a turn_left method in Ruby

Viewed 126

I need to create a method turn_left who changes the facing, facing always start in :south (Im implementing a robot who moves into a board) so if i call method turn_left should change the facing to East and then to North and to West and then return to south. Im thinking in something like this:

    {
     0: S
     1: E
     2: N
     3: W
    }

this is my code

# Models the Robor behavior for the game
class Robot

 def initialize(attr = {})
 # @position = attr[:position]
 # @move = attr[:move]
   @facing = :south
 # @turn_left =
 # @turn_right =
 # @errors =
 end

 def position
 end

 def move
 end

 def facing
  @facing
 end

 def turn_left

 end

 def turn_right
 end

 def errors
 end
end

Thank you so much!!!

4 Answers

How about something like this:

class Robot
  FACINGS = [:south, :east, :north, :west]

  def initialize(attr = {})
    @facing_index = 0 # south
  end

  def facing
    FACINGS[@facing_index]
  end

  def turn_left
    @facing_index += 1
    @facing_index %= 4
  end

  def turn_right
    @facing_index -= 1
    @facing_index %= 4
  end
end

The %= 4 (or, if you really want to generalise this further, %= FACINGS.length) performs modulo arithmetic to "wrap" the current index back into the range 0-3.

Therefore by incrementing/decrementing this number, you can toggle between the four directions.


I don't know how you intent to implement position, move and errors, but I presume that's beyond the scope of your question.

You could store the directions in an array:

def initialize
  @dirs = [:S, :W, :N, :E]
end

With the first entry being the facing direction:

def facing
  @dirs.first
end

When the robot turns left, you rotate! the array counter clockwise:

def turn_left
  @dirs.rotate! -1
end

Or clockwise when turning right: (the 1 could be omitted here)

def turn_right
  @dirs.rotate! 1
end
left = {:n=>:w, :w=>:s, :s=>:e, :e=>:n}
right = left.invert
  #=> {:w=>:n, :s=>:w, :e=>:s, :n=>:e}

pos = :s

pos = left[pos]
  #=> :e
pos = right[pos]
  #=> :w

I would go with degrees instead of an enumeration. That way you can manipulate the facing by adding/subtracting n degrees from the current facing.

class Robot
  attr_accessor :facing

  def initialize(**attrs)
    self.facing = attrs[:facing] || 180 # south
  end

  def rotate!(degrees)
    self.facing = (self.facing + degrees) % 360
  end

  def rotate_left!
    rotate!(-90)
  end

  def rotate_right!
    rotate!(90)
  end
end

You can then use a relatively simple method to convert degrees to cardinal (compass points):

class Robot
  COMPASS_POINTS = %w[N E S W]

  # ...

  def compass_point
    seg_size = 360 / COMPASS_POINTS.size
    COMPASS_POINTS[((facing + (seg_size / 2)) % 360) / seg_size]
  end
end

This one is taken from the geocoder gem.

This might seem a bit more complicated but lets you store executed commands as rotate: 90 or rotate: -90 if you want to keep track of it. It also lets you rotate the robot a full (stepless) 360 degrees if wanted.

Related