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), };