3
\$\begingroup\$

I have written a simplified version of the Mars Rover challenge in Ruby. Please review it for best coding practices.

A rover’s position and location is represented by a combination of x and y co-ordinates and a letter representing one of the four cardinal compass points. The plateau is divided up into a grid to simplify navigation. An example position might be 0, 0, N, which means the rover is in the bottom left corner and facing North.

In order to control a rover , NASA sends a simple string of letters. The possible letters are ‘L’, ‘R’ and ‘M’. ‘L’ and ‘R’ makes the rover spin 90 degrees left or right respectively, without moving from its current spot. ‘M’ means move forward one grid point, and maintain the same heading.

class Rover
  def initialize(x, y, direction)
    @x = x
    @y = y
    @direction = direction
  end

  def instruction(position)
    position.each do |input|
      if input == 'L'
        left
      elsif input == 'R'
        right
      else
        move
      end
    end
      puts "this is where the rover should be: x= #{@x} y= #{@y} facing= #{@direction}"
  end

  def right
    if @direction == 'S'
        puts "the rover is facing West."
      @direction = 'W'
    elsif @direction == 'N'
        puts "the rover is facting East"
      @direction = 'E'
    elsif @direction == 'W'
        puts "the rover is facting North"
      @direction = 'N'
    else
      puts "the rover is facing South"
      @direction = 'S'
    end
  end

  def left
    if @direction == 'N'
        puts "the rover is facing North."
      @direction = 'W'
    elsif @direction == 'W'
        puts "the rover is facting West"
      @direction = 'S'
    elsif @direction == 'E'
        puts "the rover is facting East"
      @direction = 'N'
    else
      puts "the rover is facing South"
      @direction = 'E'
    end
  end

  def move
    if @direction == 'N'
      @y += 1
    elsif @direction == 'E'
      @x += 1
    elsif @direction == 'S'
      @y -= 1
    else
      @x -= 1
    end
  end
end

#instance of our rovers with direction x, y, direction facing N, E, S, or W
mars_rover_a = Rover.new(0,0,'N')
# mars_rover_a.move()
mars_rover_b = Rover.new(1,1,'E')

#call the instruction for each instance of the object rover
mars_rover_a.instruction(['L','M','R','M','L','M','R','R','M'])
mars_rover_b.instruction(['R','M','M','L','M','L','L','M'])
\$\endgroup\$
1
\$\begingroup\$

I'd suggest that the position, and maybe orientation also, ought to be its own object ... "Location"?

I'd also prefer to use symbols rather than strings where possible, and rely on data rather than logic (see use of hashes below).

You might be interested in implementing a builder method, in which the methods called simply return the original object, which allows commands to be daisy-chained ...

class Location
  LEFT = {
    n: :w,
    e: :n,
    s: :e,
    w: :s
  }

  RIGHT = {
    n: :e,
    e: :s,
    s: :w,
    w: :n
  }

  def initialize(x:, y:, direction:)
    @x         = x
    @y         = y
    @direction = direction
  end

  def left
    @direction = LEFT.fetch(@direction)
    self
  end

  def right
    @direction = RIGHT.fetch(@direction)
    self
  end

  def move
    case direction
    when :n
      self.y += 1
    when :e
      self.x += 1
    when :s
      self.y -= 1
    when :w
      self.x -= 1
    end
    self
  end

  attr_reader :x, :y, :direction

  private

  attr_writer :x, :y, :direction
end

Hence:

2.4.5 :125 >   l = Location.new(x: 0, y: 0, direction: :n)
 => #<Location:0x00007f9f5329e858 @x=0, @y=0, @direction=:n> 
2.4.5 :126 > l.left.move.right.move.left.move.right.right.move
 => #<Location:0x00007f9f5329e858 @x=-1, @y=1, @direction=:e> 
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.