jsadvent/solutions/2020/12.js

123 lines
3 KiB
JavaScript

const { Glib, Vector, twodee } = require('../../lib');
const LEFT = new Map([
[twodee.DIRECTIONS.UP.string, twodee.DIRECTIONS.LEFT],
[twodee.DIRECTIONS.LEFT.string, twodee.DIRECTIONS.DOWN],
[twodee.DIRECTIONS.DOWN.string, twodee.DIRECTIONS.RIGHT],
[twodee.DIRECTIONS.RIGHT.string, twodee.DIRECTIONS.UP],
]);
const RIGHT = new Map([
[twodee.DIRECTIONS.UP.string, twodee.DIRECTIONS.RIGHT],
[twodee.DIRECTIONS.RIGHT.string, twodee.DIRECTIONS.DOWN],
[twodee.DIRECTIONS.DOWN.string, twodee.DIRECTIONS.LEFT],
[twodee.DIRECTIONS.LEFT.string, twodee.DIRECTIONS.UP],
]);
const INSTRUCTIONS1 = {
N: (count, state) => {
return {
...state,
location: state.location.add(twodee.DIRECTIONS.UP.multiply(count)),
};
},
S: (count, state) => {
return {
...state,
location: state.location.add(twodee.DIRECTIONS.DOWN.multiply(count)),
};
},
E: (count, state) => {
return {
...state,
location: state.location.add(twodee.DIRECTIONS.RIGHT.multiply(count)),
};
},
W: (count, state) => {
return {
...state,
location: state.location.add(twodee.DIRECTIONS.LEFT.multiply(count)),
};
},
F: (count, state) => {
return {
...state,
location: state.location.add(state.direction.multiply(count)),
};
},
L: (count, state) => {
let direction = state.direction;
for (let i = 0; i < count; i += 90) {
direction = LEFT.get(direction.string);
}
return {
...state,
direction,
};
},
R: (count, state) => {
let direction = state.direction;
for (let i = 0; i < count; i += 90) {
direction = RIGHT.get(direction.string);
}
return {
...state,
direction,
};
},
};
const INSTRUCTIONS2 = {
...INSTRUCTIONS1,
F: (count, state) => {
return {
...state,
ship: state.ship.add(state.location.multiply(count)),
};
},
// todo: (soon) implement a matrix library so this gets better
L: (count, state) => {
let location = state.location;
for (let i = 0; i < count; i += 90) {
location = new Vector(-location.v[1], location.v[0]);
}
return {
...state,
location,
};
},
R: (count, state) => {
let location = state.location;
for (let i = 0; i < count; i += 90) {
location = new Vector(location.v[1], -location.v[0]);
}
return {
...state,
location,
};
},
};
const solve = (input, ops, start = twodee.ORIGIN) =>
Glib.fromLines(input, ops)
.map(([instruction, ...number]) => ({
instruction,
count: BigInt(number.join('')),
}))
.reduce(
(state, { instruction, count }) => {
return ops[instruction](count, state);
},
{
location: start,
direction: twodee.DIRECTIONS.RIGHT,
ship: twodee.ORIGIN,
},
);
module.exports = {
1: (input) => solve(input, INSTRUCTIONS1).location.distance(twodee.ORIGIN),
2: (input) =>
solve(input, INSTRUCTIONS2, new Vector(10, 1)).ship.distance(twodee.ORIGIN),
};