123 lines
3 KiB
JavaScript
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),
|
||
|
};
|