Skip to content

Instantly share code, notes, and snippets.

@bluepichu
Created December 24, 2024 06:01
Show Gist options
  • Save bluepichu/80c0bc1230dbccd469c532a4eaf6115d to your computer and use it in GitHub Desktop.
Save bluepichu/80c0bc1230dbccd469c532a4eaf6115d to your computer and use it in GitHub Desktop.
import { Advent, f, fm, chr, ord } from "advent";
import { Set, Map } from "immutable";
const { compute, computeCheck } = await Advent({ day: 24 });
// compute(1, async (input) => {
// const data = input.parse(f.dis("\n\n", f.nl(f.match`${fm.str().as("inp")}: ${fm.int().as("val")}`), f.nl(f.match`${fm.str().as("a")} ${fm.str().as("op")} ${fm.str().as("b")} -> ${fm.str().as("out")}`), (init, ops) => ({ init, ops })));
// let refs = Map<string, Set<string>>();
// let revRefs = Map<string, Set<string>>();
// for (const { a, op, b, out } of data.ops) {
// refs = refs.update(out, Set(), (s) => s.add(a).add(b));
// revRefs = revRefs.update(a, Set(), (s) => s.add(out));
// revRefs = revRefs.update(b, Set(), (s) => s.add(out));
// }
// let results = Map<string, number>();
// let ready: string[] = [];
// for (const { inp, val } of data.init) {
// results = results.set(inp, val);
// for (const revRef of revRefs.get(inp, Set<string>())) {
// refs = refs.update(revRef, Set(), (s) => s.delete(inp));
// console.log(inp, revRef, refs.get(revRef)!.size);
// if (refs.get(revRef)!.size === 0) {
// ready.push(revRef);
// }
// }
// }
// while (ready.length > 0) {
// const next = ready.shift()!;
// const { a, op, b, out } = data.ops.find((op) => op.out === next)!;
// let result: number;
// if (op === "AND") {
// result = results.get(a)! & results.get(b)!;
// } else if (op === "OR") {
// result = results.get(a)! | results.get(b)!;
// } else if (op === "XOR") {
// result = results.get(a)! ^ results.get(b)!;
// } else {
// throw new Error("Unknown op");
// }
// results = results.set(out, result);
// for (const revRef of revRefs.get(out, Set<string>())) {
// refs = refs.update(revRef, Set(), (s) => s.delete(out));
// console.log(out, revRef, refs.get(revRef)!.size);
// if (refs.get(revRef)!.size === 0) {
// ready.push(revRef);
// }
// }
// }
// let ans = 0;
// for (let i = 0; true; i++) {
// const key = `z${i.toString().padStart(2, "0")}`;
// if (results.has(key)) {
// ans += results.get(key)! * Math.pow(2, i);
// } else {
// break;
// }
// }
// console.log(results.toJSON());
// return ans;
// });
const swaps = Map<string, string>({
kwb: "z12",
z12: "kwb",
qkf: "z16",
z16: "qkf",
z24: "tgr",
tgr: "z24",
cph: "jqn",
jqn: "cph",
});
compute(2, async (input) => {
const data = input.parse(f.dis("\n\n", f.nl(f.match`${fm.str().as("inp")}: ${fm.int().as("val")}`), f.nl(f.match`${fm.str().as("a")} ${fm.str().as("op")} ${fm.str().as("b")} -> ${fm.str().as("out")}`), (init, ops) => ({ init, ops })));
for (const op of data.ops) {
op.out = swaps.get(op.out, op.out);
}
let refs = Map<string, Set<string>>();
let revRefs = Map<string, Set<string>>();
for (const { a, op, b, out } of data.ops) {
refs = refs.update(out, Set(), (s) => s.add(a).add(b));
revRefs = revRefs.update(a, Set(), (s) => s.add(out));
revRefs = revRefs.update(b, Set(), (s) => s.add(out));
}
let results = Map<string, number>();
let ready: string[] = [];
let rename = Map<string, string>();
for (const { inp, val } of data.init) {
results = results.set(inp, val);
rename = rename.set(inp, inp);
for (const revRef of revRefs.get(inp, Set<string>())) {
refs = refs.update(revRef, Set(), (s) => s.delete(inp));
console.log(inp, revRef, refs.get(revRef)!.size);
if (refs.get(revRef)!.size === 0) {
ready.push(revRef);
}
}
}
while (ready.length > 0) {
const next = ready.shift()!;
const { a, op, b, out } = data.ops.find((op) => op.out === next)!;
let result: number;
switch (op) {
case "XOR": {
if (out.startsWith("z")) {
const idx = parseInt(out.slice(1));
if (idx === 0) {
// ok
break;
} else {
const aRename = rename.get(a)!;
const bRename = rename.get(b)!;
const expected = [`init${idx}`, `carry${idx - 1}`];
const actual = [aRename, bRename];
expected.sort();
actual.sort();
if (expected[0] !== actual[0] || expected[1] !== actual[1]) {
throw new Error(`Expected ${expected.join(", ")} but got ${actual.join(", ")} at ${out}`);
}
// ok
break;
}
} else {
// should be init
const aRename = rename.get(a)!;
const bRename = rename.get(b)!;
const actual = [aRename, bRename];
actual.sort();
if (actual[0].startsWith("x") && actual[1].startsWith("y") && actual[0].slice(1) === actual[1].slice(1)) {
// ok
const idx = parseInt(actual[0].slice(1));
rename = rename.set(out, `init${idx}`);
break;
} else {
throw new Error(`Expected init but got ${actual.join(", ")} at ${out}`);
}
}
}
case "AND": {
// should be icarry or midcarry
const aRename = rename.get(a)!;
const bRename = rename.get(b)!;
const actual = [aRename, bRename];
actual.sort();
if (actual[0].startsWith("x") && actual[1].startsWith("y") && actual[0].slice(1) === actual[1].slice(1)) {
// ok, icarry
const idx = parseInt(actual[0].slice(1));
if (idx === 0) {
rename = rename.set(out, `carry${idx}`);
} else {
rename = rename.set(out, `icarry${idx}`);
}
break;
} else if (actual[0].startsWith("carry") && actual[1].startsWith("init") && parseInt(actual[0].slice(5), 10) === parseInt(actual[1].slice(4), 10) - 1) {
// ok, midcarry
const idx = parseInt(actual[0].slice(5)) + 1;
if (idx === 0) {
rename = rename.set(out, `carry${idx}`);
} else {
rename = rename.set(out, `midcarry${idx}`);
}
break;
} else {
throw new Error(`Expected icarry or midcarry but got ${actual.join(", ")} at ${out}`);
}
}
case "OR": {
// should be carry
const aRename = rename.get(a)!;
const bRename = rename.get(b)!;
const actual = [aRename, bRename];
actual.sort();
if (actual[0].startsWith("icarry") && actual[1].startsWith("midcarry") && parseInt(actual[0].slice(6), 10) === parseInt(actual[1].slice(8), 10)) {
// ok
const idx = parseInt(actual[0].slice(6));
rename = rename.set(out, `carry${idx}`);
break;
} else {
throw new Error(`Expected carry but got ${actual.join(", ")} at ${out}`);
}
}
}
for (const revRef of revRefs.get(out, Set<string>())) {
refs = refs.update(revRef, Set(), (s) => s.delete(out));
console.log(out, revRef, refs.get(revRef)!.size);
if (refs.get(revRef)!.size === 0) {
ready.push(revRef);
}
}
console.log(rename.toJSON());
}
let ans = 0;
for (let i = 0; true; i++) {
const key = `z${i.toString().padStart(2, "0")}`;
if (results.has(key)) {
ans += results.get(key)! * Math.pow(2, i);
} else {
break;
}
}
console.log(results.toJSON());
const keys = swaps.keySeq().toArray();
keys.sort();
return keys.join(",");
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment