Created
December 24, 2024 06:01
-
-
Save bluepichu/80c0bc1230dbccd469c532a4eaf6115d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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