Published
Edited
Dec 13, 2020
Insert cell
md`# Advent of Code 2002 Day 12`
Insert cell
class Ship {
constructor() {
this.dir = 'E';
this.north = 0;
this.east = 0;
}

move(direction, amount) {
switch (direction) {
case 'N':
this.north += amount;
break;
case 'S':
this.north -= amount;
break;
case 'E':
this.east += amount;
break;
case 'W':
this.east -= amount;
break;
default:
throw `Bad direction: ${direction} : ${amount}`;
}
}

rotate(direction, amount) {
const oldDir = this.dir;
if ('R' === direction) {
const dirs = ['N', 'E', 'S', 'W'];
const currIndex = dirs.indexOf(this.dir);
this.dir = dirs[((amount % 360) / 90 + currIndex) % 4];
} else {
const dirs = ['N', 'W', 'S', 'E'];
const currIndex = dirs.indexOf(this.dir);
this.dir = dirs[((amount % 360) / 90 + currIndex) % 4];
}
if (!this.dir)
throw `Weird state after ${direction} : ${amount} : ${oldDir}`;
return this;
}

execute(command) {
const action = command[0],
amount = parseInt(command.substring(1));
switch (action) {
case 'F':
this.move(this.dir, amount);
break;
case 'N':
case 'S':
case 'E':
case 'W':
this.move(action, amount);
break;
case 'R':
case 'L':
this.rotate(action, amount);
break;
default:
throw `Bad action: ${action} : ${amount}`;
}
return [action, amount];
}
}
Insert cell
{
const ship = new Ship();
ship.dir = 'S';
ship.rotate('L', 90);
return ship;
}
Insert cell
((90 % 360) / 90 - 0) % 4
Insert cell
run = input => {
const ship = new Ship();
const steps = input.split('\n');
steps.forEach(step => ship.execute(step));
return Math.abs(ship.north) + Math.abs(ship.east);
}
Insert cell
Insert cell
run(testInput)
Insert cell
Insert cell
Insert cell
run(input)
Insert cell
Insert cell
class WaypointShip {
constructor() {
this.north = 0;
this.east = 0;
this.waypointNorth = 1;
this.waypointEast = 10;
}

moveWaypoint(direction, amount) {
switch (direction) {
case 'N':
this.waypointNorth += amount;
break;
case 'S':
this.waypointNorth -= amount;
break;
case 'E':
this.waypointEast += amount;
break;
case 'W':
this.waypointEast -= amount;
break;
default:
throw `Bad direction: ${direction} : ${amount}`;
}
}

rotate(direction, amount) {
for (let i = 0; i < amount; i += 90) {
let newEast = this.waypointNorth,
newNorth = this.waypointEast;
if ('R' === direction) {
newNorth *= -1;
} else {
newEast *= -1;
}
this.waypointNorth = newNorth;
this.waypointEast = newEast;
}
return this;
}

execute(command) {
const action = command[0],
amount = parseInt(command.substring(1));
switch (action) {
case 'F':
this.north += this.waypointNorth * amount;
this.east += this.waypointEast * amount;
break;
case 'N':
case 'S':
case 'E':
case 'W':
this.moveWaypoint(action, amount);
break;
case 'R':
case 'L':
this.rotate(action, amount);
break;
default:
throw `Bad action: ${action} : ${amount}`;
}
return [action, amount];
}
}
Insert cell
deg2Rad = ( deg ) => deg * Math.PI / 180
Insert cell
deg2Rad(90)
Insert cell
rotate = (x, y, degrees) => {
const rads = deg2Rad(degrees);
const x1 = x * Math.cos(rads) - y * Math.sin(rads);
const y1 = x * Math.sin(rads) + y * Math.cos(rads);
return [x1, y1];
}
Insert cell
[[10, 4], rotate(10, 4, 90), rotate(-4, 10, 90), rotate(-10, -4, 90)]
Insert cell
new WaypointShip().rotate('L', 270)
Insert cell
{
const ship = new WaypointShip();
ship.execute('F10');
ship.execute('N3');
ship.execute('F7');
ship.execute('R90');
return ship;
}
Insert cell
run2 = input => {
const ship = new WaypointShip();
const steps = input.split('\n');
steps.forEach(step => ship.execute(step));
return Math.abs(ship.north) + Math.abs(ship.east);
}
Insert cell
run2(testInput)
Insert cell
run2(input)
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more