expeditaet
Version:
Advent of Code Solutions
131 lines (119 loc) • 3.24 kB
text/typescript
/* eslint-disable @typescript-eslint/no-non-null-assertion */
import { IntCodeComputer } from '@alexaegis/advent-of-code-intcode';
import { task } from '@alexaegis/advent-of-code-lib';
import packageJson from '../package.json';
import { computeMap, parse, Tile } from './parse.js';
export enum MovementFunction {
A = 'A',
B = 'B',
C = 'C',
}
export enum Turn {
LEFT = 'L',
RIGHT = 'R',
}
export const getFullPath = (input: string): string[] => {
const [map, vacuum] = computeMap(input);
const path: (Turn | string)[] = [];
let steps = 0;
for (;;) {
const checkThere = vacuum.pos.add(vacuum.dir);
if (map.get(checkThere.toString()) === Tile.SCAFFOLD) {
vacuum.pos.addMut(vacuum.dir); // step
steps++;
} else {
const checkRight = vacuum.pos.add(vacuum.dir.right());
const checkLeft = vacuum.pos.add(vacuum.dir.left());
const hasRight = map.get(checkRight.toString()) === Tile.SCAFFOLD;
const hasLeft = map.get(checkLeft.toString()) === Tile.SCAFFOLD;
if (hasRight && !hasLeft) {
vacuum.dir = vacuum.dir.right();
if (steps) {
path.push(steps.toString());
}
path.push(Turn.LEFT);
steps = 0;
} else if (!hasRight && hasLeft) {
vacuum.dir = vacuum.dir.left();
if (steps) {
path.push(steps.toString());
}
path.push(Turn.RIGHT);
steps = 0;
} else {
vacuum.pos.addMut(vacuum.dir);
if (steps) {
path.push(steps.toString());
}
break;
}
}
}
return path;
};
export const compress = (
fragments: string[],
prevRes: string[] = [],
maxDepth = 3,
): string[] | undefined => {
const maxLen = 20;
if (maxDepth <= 0) {
return undefined;
}
if (
fragments.length > 0 &&
fragments.every((fragment) => fragment.length < maxLen && fragment === fragments[0])
) {
return [fragments[0]!];
}
for (let w = 6; w < maxLen; w++) {
const c = fragments[0]!.slice(0, Math.max(0, w));
const f = fragments.flatMap((fragment) => fragment.split(c)).filter((fr) => !!fr);
const result = compress(f, prevRes, maxDepth - 1);
if (result) {
return [c, ...result];
}
}
return undefined;
};
const encode = (s: string): number[] => {
let r = s;
if (s.endsWith(',')) {
r = s.slice(0, Math.max(0, s.length - 1));
}
r = r + '\n';
return [...r].map((c) => c.codePointAt(0) ?? 0);
};
export const p2 =
(video = false) =>
(input: string): number => {
const intCode = new IntCodeComputer(parse(input));
intCode.tape.set(0, 2);
const fullPath = getFullPath(input);
let main = fullPath.join(',') + ',';
const r = compress([main]);
if (r) {
for (const [i, fr] of r.entries())
main = main.replaceAll(new RegExp(fr, 'gi'), String.fromCodePoint(65 + i) + ',');
intCode.pushInput(...encode(main));
for (const fn of r) intCode.pushInput(...encode(fn));
intCode.pushInput((video ? 'y' : 'n').codePointAt(0) ?? 0);
intCode.pushInput('\n'.codePointAt(0) ?? 9);
let row = '';
for (const o of intCode.iter()) {
const s = String.fromCodePoint(o);
if (s === '\n') {
if (video) {
console.log(row);
}
row = '';
} else if (o < 1000) {
row += s;
} else {
return o;
}
}
}
return 0;
};
await task(p2(false), packageJson.aoc); // 840248 ~110ms