# Advent of Code 2020: Day 12 (Ruby solution)

Subscribe to my newsletter and never miss my upcoming articles

Today's puzzle are to simulate ship's routes. The navigation instructions (input file) consists of a sequence of single-character actions paired with integer input values

• Action N means to move north by the given value.
• Action S means to move south by the given value.
• Action E means to move east by the given value.
• Action W means to move west by the given value.
• Action L means to turn left the given number of degrees.
• Action R means to turn right the given number of degrees.
• Action F means to move forward by the given value in the direction the ship is currently facing.

Here is my ship implementation form the first task.

``````require 'matrix'

WORLD_DIRECTIONS = {
'N' => Vector[0, 1],
'E' => Vector[1, 0],
'S' => Vector[0, -1],
'W' => Vector[-1, 0]
}.freeze

def number_of_crosses action, angle
((action == 'L' ? 1 : -1) * angle / 90) % 4
end

class Ship

def initialize
@position = Vector[0, 0]
@rotation = Vector[1, 0]
end

def navigate instructions
instructions.each do |instruction|
action = instruction[0]
value = instruction.scan(/\d+/).first.to_i
process_instruction action, value
end
end

protected

def process_instruction action, value
if action.start_with? 'L', 'R'
rotate action, value
else
move action, value
end
end

def rotate action, angle
number_of_crosses(action, angle).times { @rotation = @rotation.cross }
end

def move action, distance
vector = WORLD_DIRECTIONS.merge('F' => @rotation)[action]
@position += distance * vector
end
end
``````

In the second task, instruction are different:

• Action N means to move the waypoint north by the given value.
• Action S means to move the waypoint south by the given value.
• Action E means to move the waypoint east by the given value.
• Action W means to move the waypoint west by the given value.
• Action L means to rotate the waypoint around the ship left (counter-clockwise) the given number of degrees.
• Action R means to rotate the waypoint around the ship right (clockwise) the given number of degrees.
• Action F means to move forward to the waypoint a number of times equal to the given value.

I provided a second ship implementation extending the previous one. Here is the rest of the code:

``````class ShipWithWaypoints < Ship
def initialize
@waypoint_position = Vector[10, 1]
super
end

protected

def process_instruction action, value
if action.start_with? 'L', 'R'
rotate_waypoint action, value
elsif action.start_with? 'F'
move value
else
move_waypoint action, value
end
end

def rotate_waypoint action, angle
number_of_crosses(action, angle).times { @waypoint_position = @waypoint_position.cross }
end

def move_waypoint action, distance
vector = WORLD_DIRECTIONS[action]
@waypoint_position += distance * vector
end

def move value
@position += @waypoint_position * value
end
end

instructions = file.lines
[Ship, ShipWithWaypoints].each do |ship_type|
ship = ship_type.new
ship.navigate(instructions)
puts(ship.position.sum { |v| v.abs })
end
``````