Advent of Code 2020: Day 12 (Ruby solution)
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
attr_reader :position
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
file = File.read('inputs/day12.txt')
instructions = file.lines
[Ship, ShipWithWaypoints].each do |ship_type|
ship = ship_type.new
ship.navigate(instructions)
puts(ship.position.sum { |v| v.abs })
end