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'])
1 Answer 1
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>