Day 24
prelude
https://adventofcode.com/2024/day/24
import { inputDay, munge } from "./lib/utilities.js"
const parser = inp => {
let [gates, operations] = inp.trim().split("\n\n").map(munge)
return [new Map(gates), operations]
}
const test = parser(
"x00: 1\nx01: 1\nx02: 1\ny00: 0\ny01: 1\ny02: 0\n\nx00 AND y00 -> z00\nx01 XOR y01 -> z01\nx02 OR y02 -> z02",
)
display(test)
const input = await inputDay(24, { parser })
display(input)
part 1
function run(gates, operations) {
const zs = operations
.filter(([, , , , out]) => out.startsWith("z"))
.map(([, , , , out]) => out)
.sort((a, b) => a < b)
while (!zs.every(z => gates.has(z))) {
for (const [a, op, b, , out] of operations) {
if (!gates.has(a) || !gates.has(b)) continue
switch (op) {
case "AND":
gates.set(out, gates.get(a) & gates.get(b))
break
case "OR":
gates.set(out, gates.get(a) | gates.get(b))
break
case "XOR":
gates.set(out, gates.get(a) ^ gates.get(b))
break
}
}
}
return parseInt(zs.map(z => gates.get(z)).join(""), 2)
}
display(run(...test))
display(run(...input))
part 2
To solve part 2, I figured out the structure of the 44-bit adder, took notes on what each bit was supposed to look like, then wrote this program to find four spots where the adder was wrong; then I manually verified them and found what they should have been swapped with.
This page helped me figure out what the structure of the adder was.
To add bits a and b, with an output bit and a carry bit, we have (where
By looking at the given operations, I saw that the adder is implemented on bit 1 with carry bit c01
as:
x01 ^ y01 -> temp1
temp1 ^ c01 -> z01
x01 & y01 -> temp2
temp1 & carry -> temp3
temp2 | temp3 -> c02
So I wrote this program to find the instructions that weren't structured as expected
function findswaps(operations) {
for (let i = 1; i < 45; i++) {
let x = `x${String(i).padStart(2, "0")}`
let y = `y${String(i).padStart(2, "0")}`
let z = `z${String(i).padStart(2, "0")}`
// find yN ^ xN -> temp1 or xN ^ yN -> temp1
const temp1 = operations.find(
([a, op, b, , out]) =>
op == "XOR" && ((a == x && b == y) || (a == y && b == x)),
)[4]
if (!temp1) {
display(`failed to find: ${x} ^ ${y} = _`)
continue
}
// find temp1 ^ carry = zN
const res = operations.find(([a, op, b, , out]) => op == "XOR" && out == z)
if (!res) {
display(`failed to find: _ ^ _ = ${z}`)
continue
}
const carry = res[0] == temp1 ? res[2] : res[0]
// find yN & xN -> temp2
const temp2 = operations.find(
([a, op, b, , out]) =>
op == "AND" && ((a == x && b == y) || (a == y && b == x)),
)[4]
if (!temp2) {
display(`failed to find: ${x} & ${y} = _`)
continue
}
// find temp1 ^ carry -> temp3
const res2 = operations.find(
([a, op, b, , out]) =>
op == "XOR" &&
((a == temp1 && b == carry) || (a == carry && b == temp1)),
)
if (!res2) {
display(`failed to find: ${temp1} ^ ${carry} = _`)
continue
}
const temp3 = res2[4]
}
}
findswaps(input[1])