Skip to content

Instantly share code, notes, and snippets.

@p-a
Last active January 23, 2023 09:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save p-a/b818938caddea82cea5346c42d94e3c2 to your computer and use it in GitHub Desktop.
Save p-a/b818938caddea82cea5346c42d94e3c2 to your computer and use it in GitHub Desktop.
AoC 2022 Day 22 Revisited
import { map, sum } from "../../lib/arrays.js";
import { gcd } from "../../lib/math.js";
import { pipe } from "../../lib/utils.js";
const parse = input => {
const grp = input.split("\n\n");
const net = grp[0]
.split("\n")
.map(([...line]) => line.map(c => c.trim()));
const instr = [...`R${grp[1]}`.matchAll(/(([LR])(\d*))/g)]
.map(([, , a, b]) => [a, b])
.map(([a, b]) => [a === "L" ? -1 : 1, Number(b) || 0]);
const dim = [
Math.max(...net.map(r => r.length)),
net.length,
];
return [
net,
instr,
[[net[0].indexOf("."), 0], 3],
dim,
gcd(...dim),
];
};
// prettier-ignore
const DIR = [[1, 0],[0, 1],[-1, 0],[0, -1]];
const walkFlatEarth = ([net, instr, start, dim]) =>
instr.reduce(([p, f], [turn, steps]) => {
f = (f + 4 + turn) % 4;
let pos, c;
while ((c = net[p[1]][p[0]]) !== "#" && steps >= 0) {
if (c) {
pos = p;
steps--;
}
p = DIR[f].map(
(d, i) => (p[i] + d + dim[i]) % dim[i]
);
}
return [pos, f];
}, start);
/* e------f
/| /|
a------b |
| g----|-h
|/ |/ Roll around a cube *underneath* a cube net and
c------d store fronting face's top-left coordinates and edges.
*/
// prettier-ignore
const DIR_ROT = w => [
[ 0, w, ([a, b, c, d, e, f, g, h]) => [c, d, g, h, a, b, e, f]],
[ 0,-w, ([a, b, c, d, e, f, g, h]) => [e, f, a, b, g, h, c, d]],
[ w, 0, ([a, b, c, d, e, f, g, h]) => [b, f, d, h, a, e, c, g]],
[-w, 0, ([a, b, c, d, e, f, g, h]) => [e, a, g, c, f, b, h, d]],
];
const mapCubeFaces = ([net, instr, start, dim, w]) => {
const q = [
[
[net[0].findIndex(Boolean), 0],
[1, 2, 4, 8, 16, 32, 64, 128],
],
];
const v = new Set();
const faces = [];
while (q.length) {
const [[px, py], corners] = q.shift();
q.push(
...DIR_ROT(w)
.map(([dx, dy, rot]) => [
[px + dx, py + dy],
rot(corners),
])
.filter(
([[x, y]]) =>
net[y]?.[x] &&
!v.has((y << 16) | x) &&
v.add((y << 16) | x)
)
.filter(([xy, [a, b, c, d]]) =>
faces.push([xy, [b | d, d | c, c | a, a | b]])
)
);
}
return [net, instr, start, dim, w, faces];
};
const walkCubicEarth = ([net, instr, start, , w, faces]) =>
instr.reduce(([p, f], [turn, steps]) => {
let facing = (f = (f + 4 + turn) % 4);
let pos, c;
while ((c = net[p[1]]?.[p[0]]) !== "#" && steps >= 0) {
if (c) {
pos = p;
facing = f;
steps--;
p = DIR[facing].map((d, i) => d + p[i]);
} else {
const face = faces.find(([coord]) =>
coord.every((c, i) => c === pos[i] - (pos[i] % w))
);
const edge = face[1][facing];
const [newFacePos, newFace] = faces.find(
f => f !== face && f[1].includes(edge)
);
const newFacing = (newFace.indexOf(edge) + 2) % 4;
let [rx, ry] = p.map(v => v % w);
while (f !== newFacing) {
[rx, ry] = [w - 1 - ry, rx];
f = (f + 1) % 4;
}
p = [rx, ry].map(
(v, i) => newFacePos[i] + ((w + v) % w)
);
}
}
return [pos, facing];
}, start);
const score = ([[col, row], facing]) =>
1000 * (row + 1) + 4 * (col + 1) + facing;
const regroup = input =>
input
.split("\n\n")
.reduce((groups, e, i) => {
if (!groups[i >> 1]) groups.push([]);
groups[i >> 1].push(e);
return groups;
}, [])
.map(v => v.join("\n\n"));
export const part1 = pipe(parse, walkFlatEarth, score);
export const part2 = pipe(
parse,
mapCubeFaces,
walkCubicEarth,
score
);
export const part3 = pipe(regroup, map(part2), sum);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment