Day 12 of Advent of Code is here! We’re half way through! Check out Day 1 for what this is all about. See all of my solutions here. If you’re interested, check out what my colleagues at Slalom are doing with Advent of Code
Do your best!
I highly encourage you to get through the day’s challenge on your own. Certainly refer to this and other’s examples to help you get through. I would love to hear how you did! Did you find a better approach than I did? Do tell!
Running in NodeJS
I’ve moved from dev console to using NodeJS for my challenges. This will provide us with more capabilities to identify issues in our code much faster. Learn more about the move here. As a result, my input and scripts can be found on github.
Day 12: Rain Risk
Part I
“The navigation instructions (your puzzle input) consists of a sequence of single-character actions paired with integer input values. After staring at them for a few minutes, you work out what they probably mean. The ship starts by facing east. Only the L
and R
actions change the direction the ship is facing. (That is, if the ship is facing east and the next instruction is N10
, the ship would move north 10 units, but would still move east if the following action were F
.)
Figure out where the navigation instructions lead. What is the Manhattan distance between that location and the ship’s starting position?” ref
Here’s a sampling of the instructions

Before we start, let’s get pull this data in
const fs = require('fs');
const instructions = fs.readFileSync('./input.txt', 'utf-8').trim().split('\n')
Nothing fancy today, just getting all rows into an array.
It may help to remember what a compass looks like. I do a fair amount of hiking and exploring, I’m looking at these all the time. However, I know many people may not know, especially since Google Maps does it all for us. Here’s a quick refresher:

Note the +
and -
in each direction, we’ll touch upon those shortly. I set up some variables to track the location of our boat:
const directions = ['E', 'S', 'W', 'N']
let dirIndex = 0
let x = 0
let y = 0
The boat lives at one location, a pair of coordinates designed by x
and y
. Could call these longitude and latitude, but x and y are simpler.
x
runs along the west to east, and if heading east, we add tox
, if we go west, we subtract fromx
y
runs along the south to north, if heading north, we add toy
, if we head south, we subtract fromy
The boat starts in the east direction, so that’ll be the initial direction.
Once we can got the concept in our head, this will be much easier. Here’s my code:
const moveShip = (navigate) => {
const direction = directions[dirIndex]
const coordinates = navigate.match(/([A-Z]{1})([0-9]*)/i)
const instruction = coordinates[1]
const unit = Number(coordinates[2])
switch (instruction) {
case 'F':
const multiplier = direction === 'E' || direction === 'N' ? 1 : -1
const isX = direction === 'E' || direction === 'W'
const isY = direction === 'N' || direction === 'S'
if(isX) {
x = x + (unit * multiplier)
}
if (isY) {
y = y + (unit * multiplier)
}
break;
case 'N':
y = y + unit
break;
case 'S':
y = y - unit
break;
case 'E':
x = x + unit
break;
case 'W':
x = x - unit
break;
case 'R':
const rotateRight = unit / 90
dirIndex += rotateRight
break;
case 'L':
const rotateLeft = unit / 90
dirIndex -= rotateLeft
break;
}
if(dirIndex >= directions.length) dirIndex = dirIndex - directions.length
if(dirIndex < 0) dirIndex = directions.length - (dirIndex * -1)
console.log(navigate, 'direction', dirIndex, directions[dirIndex], 'x', x, 'y', y)
}
This method moveShip
moves our ship around:
- We set up some variables
direction
gets us the text value, N, E, S, W, of the direction the ship is currently headingcoordinates
, parses thenavigate
to get theinstruction
andunit
to apply- Yay regex is back!
([A-Z]{1})
gets the first letter, which is in the instruction([0-9]*)
gets the unit number after the letter
- We then use a switch to do the instructions
F
is to move forward, so depending on the direction, we have to add or subtract the unit from ourx
andy
coordinates. If we’re goingN
orE
, then we’re going positive (the+
in the compass image above). Subsequently,S
orW
are going negative.N
andS
add or subtract theunit
from they
variableE
andW
add or subtract theunit
from thex
variableR
andL
rotate the ship, change the direction. Theunit
determines which direction and thankfully are in 90º increments. GoingR
ight is clockwise, let’s go positive. GoingL
eft is counterclockwise, going negative.- If we exceed our direction values, the
directions
array, whether negative or positive, we circle back on the array. So the if we’re atN
now, andR90
, that should beE
, so we go from index3
to index0
.
- That
console.log
is really helpful to see the calculations happen and spot check the math.
Finally, we loop through all of the instructions
from the file and call the moveShip
function above:
instructions.forEach(nav => {
moveShip(nav)
})
if(x < 0) x = x * -1
if(y < 0) y = y * -1
console.log(x, '+', y, 'sum is', x + y)
If we have any negative numbers, we want them positive so we can add them together and get a positive number. Remember a negative y
isn’t actually negative, it’s just South.
Part II
“Before you can give the destination to the captain, you realize that the actual action meanings were printed on the back of the instructions the whole time. Almost all of the actions indicate how to move a waypoint which is relative to the ship’s position. The waypoint starts 10 units east and 1 unit north relative to the ship.What is the Manhattan distance between that location and the ship’s starting position?“
This was hard to wrap my head around, but once I did it was easy. I started with the compass and had a mental model going well, but then we rotated the way point and it all went out. I started drawing out what is going on here and came up with the following:

Let me attempt to explain this a little.
The waypoint is 10 units East, and 1 unit North. The waypoints current location is east-west, x = 10 and north-south, y = 1. Illustrated above to the right side of the boat.
The boat starts at X = 0 and Y = 0, heading East, which is right, and a rotation of 0º. Moving forward 10, F10, units in this direction, I will add to the boat’s X coordinate 10×10 (the waypoint’s relative X position is 10, and I’m moving 10 units), and add to the boat’s Y coordinate 1×10 (the waypoint’s relative Y position is 1 and I’m moving 10 units). The boats new location is 100,10.
With Part 2, the E, S, W, N commands move the waypoint around, not the boat. N2 moves my waypoint up to a Y position of 3, now the waypoint is 10,3.
Rotating is where things get really sticky and where the above image helped a lot. Ignore everything about moving above for a moment. The R and L instructions now rotate the waypoint around the boat. So R90, and the waypoint spins 90º to the right, it’s now facing south. 180º now faces West and so on. That’s clear in the above image.
When we R90, the waypoints east-west, x and north-south, y are 3, -10. See the image above, I’m pointing down, so X is now negative, for south, and Y now points to east. This is really confusing and I didn’t attempt to swap numbers around on each rotation. Instead, I stored the rotation value alongside the waypoint coordinates. When the rotation is 90º, I know my east west line, x, is actually going north and south now, so moving in that direction I have to add to X to keep going south.
After R90, if we get a F20, we subtract 10×20 from our boat’s north-south number (10 being the waypoint’s east-west value, the X facing down) . Then add 1×20 to our boat’s east-west number (1 being the waypoint’s north-south value, the Y going right). If this hurts to think through, there’s a chance I’m explaining it wrong, do let me know if this is confusing.
Let’s check out the code, this works and I think explains it MUCH better
const fs = require('fs');
const instructions = fs.readFileSync('./input.txt', 'utf-8').trim().split('\n')
let eastWest= 0
let northSouth= 0
let waypoint = {
xValue: 10,
yValue: 1,
rotation: 0
}
/*
ROTATION
0 - x heads east, y heads north
90 - x heads south, y heads east
180 - x heads west, y heads south
270 - x heads north, y heads west
*/
const moveShip = (navigate) => {
const coordinates = navigate.match(/([A-Z]{1})([0-9]*)/i)
const instruction = coordinates[1]
const unit = Number(coordinates[2])
switch (instruction) {
case 'F':
switch(waypoint.rotation) {
case 0:
eastWest += waypoint.xValue * unit
northSouth += waypoint.yValue * unit
break;
case 90:
eastWest += waypoint.yValue * unit
northSouth += waypoint.xValue * unit * -1
break;
case 180:
eastWest += waypoint.xValue * unit * -1
northSouth += waypoint.yValue * unit * -1
break;
case 270:
eastWest += waypoint.yValue * unit * -1
northSouth += waypoint.xValue * unit
break;
}
break;
case 'N':
switch(waypoint.rotation) {
case 0:
waypoint.yValue += unit
break;
case 90:
waypoint.xValue -= unit
break;
case 180:
waypoint.yValue -= unit
break;
case 270:
waypoint.xValue += unit
break;
}
break;
case 'S':
switch(waypoint.rotation) { // same as N but *-1
case 0:
waypoint.yValue -= unit
break;
case 90:
waypoint.xValue += unit
break;
case 180:
waypoint.yValue += unit
break;
case 270:
waypoint.xValue -= unit
break;
}
break;
case 'E':
switch(waypoint.rotation) {
case 0:
waypoint.xValue += unit
break;
case 90:
waypoint.yValue += unit
break;
case 180:
waypoint.xValue -= unit
break;
case 270:
waypoint.yValue -= unit
break;
}
break;
case 'W':
switch(waypoint.rotation) { // -1 * East
case 0:
waypoint.xValue -= unit
break;
case 90:
waypoint.yValue -= unit
break;
case 180:
waypoint.xValue += unit
break;
case 270:
waypoint.yValue += unit
break;
}
break;
case 'R':
waypoint.rotation += unit
if(waypoint.rotation > 270) waypoint.rotation -= 360
break;
case 'L':
waypoint.rotation -= unit
if(waypoint.rotation < 0) waypoint.rotation += 360
break;
}
console.log(navigate, 'direction', waypoint.xValue, 'by', waypoint.yValue, 'rotation', waypoint.rotation, 'eastWest', eastWest, 'northSouth', northSouth)
}
instructions.forEach(nav => {
moveShip(nav)
})
if(eastWest< 0) eastWest = eastWest* -1
if(northSouth< 0) northSouth = northSouth* -1
console.log(eastWest, '+', northSouth, 'sum is',eastWest + northSouth)
After getting the instructions, I created the eastWest
and northSouth
variables to manage where the boat it. I moved from X and Y because seeing the waypoint’s X and Y was confusing me too much. I made a single object to manage the waypoint. This has the x and y for the waypoint and what rotation it’s on.
Right in the moveShip
method, the first instruction in the switch is the F
orward command. I think this will help explain what I was trying to explain above. Depending on the rotation, we either add or subtract from the boat’s east-west and north-south positioning.
The next few cases are to move the waypoint. They all have to take into consideration the current rotation of the waypoint, to know what direction to move in.
The final two rotate it, which is easier this time than in Part 1.
I again logged it out, which helps a lot in testing and troubleshooting.
Finally, we have the same small clean up lines from Part 1, and the answer.
How did it go for you?
How did you find the answer on your own? How did you do it? Anything stump you? I’d love to hear how you did! Please comment below! I have also loaded up just the challenge and code from this and my other days on github, you can follow along there too: pretty Git pages or the code in the repo.