diff --git a/day_24/example.txt b/day_24/example.txt new file mode 100644 index 0000000..de04a48 --- /dev/null +++ b/day_24/example.txt @@ -0,0 +1,10 @@ +x00: 1 +x01: 1 +x02: 1 +y00: 0 +y01: 1 +y02: 0 + +x00 AND y00 -> z00 +x01 XOR y01 -> z01 +x02 OR y02 -> z02 \ No newline at end of file diff --git a/day_24/input.txt b/day_24/input.txt new file mode 100644 index 0000000..01c6c6d --- /dev/null +++ b/day_24/input.txt @@ -0,0 +1,313 @@ +x00: 1 +x01: 0 +x02: 1 +x03: 1 +x04: 0 +x05: 0 +x06: 1 +x07: 1 +x08: 0 +x09: 1 +x10: 1 +x11: 1 +x12: 1 +x13: 0 +x14: 1 +x15: 0 +x16: 0 +x17: 0 +x18: 0 +x19: 0 +x20: 1 +x21: 1 +x22: 0 +x23: 1 +x24: 0 +x25: 0 +x26: 1 +x27: 1 +x28: 1 +x29: 1 +x30: 1 +x31: 1 +x32: 1 +x33: 1 +x34: 0 +x35: 1 +x36: 1 +x37: 1 +x38: 0 +x39: 1 +x40: 1 +x41: 0 +x42: 0 +x43: 1 +x44: 1 +y00: 1 +y01: 0 +y02: 0 +y03: 1 +y04: 1 +y05: 0 +y06: 0 +y07: 0 +y08: 0 +y09: 0 +y10: 0 +y11: 1 +y12: 0 +y13: 1 +y14: 0 +y15: 0 +y16: 0 +y17: 1 +y18: 1 +y19: 1 +y20: 1 +y21: 0 +y22: 0 +y23: 0 +y24: 1 +y25: 1 +y26: 0 +y27: 0 +y28: 1 +y29: 1 +y30: 1 +y31: 1 +y32: 1 +y33: 1 +y34: 1 +y35: 1 +y36: 1 +y37: 0 +y38: 1 +y39: 1 +y40: 0 +y41: 0 +y42: 0 +y43: 1 +y44: 1 + +ktr XOR cpc -> z27 +hbk XOR fbg -> z13 +rbm XOR tjp -> z36 +y44 XOR x44 -> njr +x08 XOR y08 -> cfd +gwg XOR ggg -> z04 +y09 XOR x09 -> dsc +ctp OR rjr -> msw +hwk AND jsw -> fnt +x41 XOR y41 -> qvg +bqj OR dqj -> tsk +y37 XOR x37 -> stv +njr XOR tkm -> z44 +x34 XOR y34 -> gjj +x07 AND y07 -> sqm +x20 XOR y20 -> ckr +x05 XOR y05 -> skf +hrn XOR bfj -> z32 +tkm AND njr -> rfc +tgj OR fcp -> kkf +tsk XOR mwp -> z38 +nfs XOR cfd -> z08 +y40 XOR x40 -> fts +x27 AND y27 -> vvc +x18 AND y18 -> ksj +pwm XOR cwd -> z10 +bqd OR fns -> bwp +kjh XOR kkc -> z01 +ncw XOR btr -> z07 +krw AND wnm -> njt +x33 AND y33 -> ffv +qsg XOR msw -> z29 +fvf OR crb -> bdk +rsm OR npk -> std +qnr AND mpn -> qth +y14 AND x14 -> bvm +y39 XOR x39 -> kjv +qnr XOR mpn -> z06 +bgk OR fdc -> hrn +x35 AND y35 -> pbr +y11 XOR x11 -> hwk +mwp AND tsk -> jhw +hgw OR jjg -> qph +hkn OR tmf -> vfn +x32 AND y32 -> wsv +fhv OR rrh -> nwf +bjh AND stv -> dqj +y12 XOR x12 -> wnm +y27 XOR x27 -> cpc +jsw XOR hwk -> z11 +mts OR bvm -> dks +x17 AND y17 -> tfc +hmc AND gjj -> tmf +rdg OR dqs -> nmr +x03 XOR y03 -> dnk +x06 AND y06 -> wgj +fts AND qrk -> fgm +vfw OR nqq -> bjh +knp OR ffv -> hmc +x19 AND y19 -> sgm +y36 AND x36 -> vfw +msh OR rfc -> z45 +qwg AND wvj -> qhq +y15 XOR x15 -> qff +wvj XOR qwg -> cmv +x33 XOR y33 -> snw +x42 XOR y42 -> qcn +y15 AND x15 -> kbj +x29 XOR y29 -> qsg +x06 XOR y06 -> mpn +qmm AND std -> mts +y04 XOR x04 -> ggg +qtk OR qwc -> jsw +y05 AND x05 -> fqb +kkf XOR pbw -> rmj +y35 XOR x35 -> gmv +dhk OR ntq -> knj +y29 AND x29 -> dhk +x43 AND y43 -> scr +x23 AND y23 -> frg +y24 AND x24 -> vjw +y13 AND x13 -> rsm +kfr OR wjq -> gwg +rnk OR fgm -> mng +hbk AND fbg -> npk +qcn XOR msr -> z42 +fqb OR jrk -> qnr +dnk AND wcj -> wjq +kgr XOR kdt -> z28 +nmr AND kqt -> bgk +wbk AND hdt -> nws +bdk AND njp -> fcp +kkf AND pbw -> z23 +y21 XOR x21 -> jkg +qff XOR dks -> z15 +y17 XOR x17 -> wvj +x44 AND y44 -> msh +pkh AND hqn -> gtq +qcn AND msr -> dnf +drf XOR mtd -> z19 +y40 AND x40 -> rnk +hdt XOR wbk -> z43 +bmw XOR dwn -> z26 +wgj OR qth -> ncw +njt OR fjp -> fbg +jvk AND jpt -> nnt +y32 XOR x32 -> bfj +y38 AND x38 -> mwp +x08 AND y08 -> fhv +kjv XOR dqg -> z39 +x10 AND y10 -> qwc +gdv OR mnf -> dwn +gtq OR vjw -> tcr +nvs OR nnt -> wcj +y14 XOR x14 -> qmm +cfd AND nfs -> rrh +qvg XOR mng -> z41 +dsc XOR nwf -> z09 +cmv AND fwm -> wbw +gmv AND vfn -> dbr +mng AND qvg -> wcp +x31 AND y31 -> fdc +cwd AND pwm -> qtk +x41 AND y41 -> rpp +y30 XOR x30 -> rvp +x28 XOR y28 -> kdt +y22 AND x22 -> tgj +krw XOR wnm -> z12 +dbr OR pbr -> tjp +kjh AND kkc -> jjv +gwk OR rwb -> qrk +bdk XOR njp -> z22 +wcp OR rpp -> msr +y00 XOR x00 -> z00 +kdt AND kgr -> ctp +dmf XOR ckr -> z20 +wsv OR wqs -> kpd +x21 AND y21 -> fvf +kpd AND snw -> knp +y38 XOR x38 -> btb +mhj OR sgm -> dmf +y20 AND x20 -> bqd +wcj XOR dnk -> z03 +y12 AND x12 -> fjp +ktr AND cpc -> hvq +ckr AND dmf -> fns +y02 XOR x02 -> jvk +dnf OR hqj -> hdt +x13 XOR y13 -> hbk +x02 AND y02 -> nvs +x00 AND y00 -> kkc +skf AND qph -> jrk +nws OR scr -> tkm +tfc OR qhq -> z17 +x30 AND y30 -> z30 +npn OR jjv -> jpt +kjv AND dqg -> gwk +y03 AND x03 -> kfr +jkg AND bwp -> crb +y18 XOR x18 -> fwm +bmw AND dwn -> gjh +sqm OR qnk -> nfs +x10 XOR y10 -> pwm +y37 AND x37 -> bqj +ksj OR wbw -> mtd +std XOR qmm -> z14 +kbw XOR wnf -> z16 +x28 AND y28 -> rjr +y07 XOR x07 -> btr +fts XOR qrk -> z40 +y16 XOR x16 -> wnf +dsc AND nwf -> ctj +mtd AND drf -> mhj +hrn AND bfj -> wqs +cmv XOR fwm -> z18 +qff AND dks -> ttr +y01 XOR x01 -> kjh +bjh XOR stv -> z37 +qwd OR swm -> qwg +kbj OR ttr -> kbw +y26 XOR x26 -> bmw +x16 AND y16 -> qwd +x42 AND y42 -> hqj +kpd XOR snw -> z33 +knj XOR rvp -> rdg +x24 XOR y24 -> hqn +nhb XOR tcr -> z25 +ncw AND btr -> qnk +tpp OR ctj -> cwd +y39 AND x39 -> rwb +x31 XOR y31 -> kqt +msw AND qsg -> ntq +frg OR rmj -> pkh +qph XOR skf -> z05 +y09 AND x09 -> tpp +y01 AND x01 -> npn +x19 XOR y19 -> drf +y36 XOR x36 -> rbm +jpd OR gjh -> ktr +nmr XOR kqt -> z31 +x26 AND y26 -> jpd +jpt XOR jvk -> z02 +y43 XOR x43 -> wbk +tjp AND rbm -> nqq +x11 AND y11 -> gfg +nhb AND tcr -> gdv +y34 AND x34 -> hkn +hvq OR vvc -> kgr +y25 AND x25 -> mnf +gwg AND ggg -> hgw +pkh XOR hqn -> z24 +fnt OR gfg -> krw +x23 XOR y23 -> pbw +wnf AND kbw -> swm +gmv XOR vfn -> z35 +x22 XOR y22 -> njp +x25 XOR y25 -> nhb +knj AND rvp -> dqs +gjj XOR hmc -> z34 +btb OR jhw -> dqg +x04 AND y04 -> jjg +jkg XOR bwp -> z21 \ No newline at end of file diff --git a/day_24/larger_example.txt b/day_24/larger_example.txt new file mode 100644 index 0000000..09fb230 --- /dev/null +++ b/day_24/larger_example.txt @@ -0,0 +1,47 @@ +x00: 1 +x01: 0 +x02: 1 +x03: 1 +x04: 0 +y00: 1 +y01: 1 +y02: 1 +y03: 1 +y04: 1 + +ntg XOR fgs -> mjb +y02 OR x01 -> tnw +kwq OR kpj -> z05 +x00 OR x03 -> fst +tgd XOR rvg -> z01 +vdt OR tnw -> bfw +bfw AND frj -> z10 +ffh OR nrd -> bqk +y00 AND y03 -> djm +y03 OR y00 -> psh +bqk OR frj -> z08 +tnw OR fst -> frj +gnj AND tgd -> z11 +bfw XOR mjb -> z00 +x03 OR x00 -> vdt +gnj AND wpb -> z02 +x04 AND y00 -> kjc +djm OR pbm -> qhw +nrd AND vdt -> hwm +kjc AND fst -> rvg +y04 OR y02 -> fgs +y01 AND x02 -> pbm +ntg OR kjc -> kwq +psh XOR fgs -> tgd +qhw XOR tgd -> z09 +pbm OR djm -> kpj +x03 XOR y03 -> ffh +x00 XOR y04 -> ntg +bfw OR bqk -> z06 +nrd XOR fgs -> wpb +frj XOR qhw -> z04 +bqk OR frj -> z07 +y03 OR x01 -> nrd +hwm AND bqk -> z03 +tgd XOR rvg -> z12 +tnw OR pbm -> gnj \ No newline at end of file diff --git a/day_24/solve_1.ts b/day_24/solve_1.ts new file mode 100644 index 0000000..b70e5f7 --- /dev/null +++ b/day_24/solve_1.ts @@ -0,0 +1,123 @@ +export type Operation = + 'and' | + 'or' | + 'xor'; + +export type BitValue = 0 | 1; + +export type InputData = { + inputs: { + name: string, + value: BitValue + }[], + + gates: { + lhs: string, + rhs: string, + operation: Operation, + result: string, + }[] +}; + +export async function readData(path: string): Promise { + const text = await Deno.readTextFile(path); + const [ + inputsText, + gatesText + ] = text.replaceAll("\r", "").trim().split('\n\n'); + + const inputs = inputsText.split('\n').map(x => { + const [name, value] = x.split(':'); + return { + name: name.trim(), + value: value.trim() === '1' ? 1 : 0 as BitValue + }; + }); + + const r = /(\w+) (\w+) (\w+) -> (\w+)/; + const gates = gatesText.split('\n').map(x => { + const [_, lhs, operation, rhs, result] = x.match(r)!; + return { + lhs, + operation: operation.toLowerCase() as Operation, + rhs, + result + }; + }); + + return { + inputs, + gates + }; +} + +export function and(lhs: BitValue, rhs: BitValue): BitValue { + return (lhs & rhs) as BitValue; +} + +export function or(lhs: BitValue, rhs: BitValue): BitValue { + return (lhs | rhs) as BitValue; +} + +export function xor(lhs: BitValue, rhs: BitValue): BitValue { + return (lhs ^ rhs) as BitValue; +} + +export function opGate(lhs: BitValue, rhs: BitValue, operation: Operation): BitValue { + switch (operation) { + case 'and': return and(lhs, rhs); + case 'or': return or(lhs, rhs); + case 'xor': return xor(lhs, rhs); + } +} + +export class Executer { + private inputs: Map = new Map(); + private gates: InputData['gates']; + private results: Map = new Map(); + + + constructor(data: InputData) { + this.gates = data.gates; + for (const input of data.inputs) { + this.inputs.set(input.name, input.value); + } + } + + execute(name: string): BitValue { + if (this.inputs.has(name)) { + return this.inputs.get(name)!; + } + if (this.results.has(name)) { + return this.results.get(name)!; + } + const gate = this.gates.find(x => x.result === name); + if (!gate) { + throw new Error(`Gate ${name} not found`); + } + const lhs = this.execute(gate.lhs); + const rhs = this.execute(gate.rhs); + const result = opGate(lhs, rhs, gate.operation); + this.results.set(name, result); + return result; + } +} + +if (import.meta.main) { + const data = await readData('input.txt'); + console.log(data); + const executer = new Executer(data); + + const zs = data.gates.filter(gate => gate.result.startsWith("z")) + .map(gate => gate.result); + zs.sort(); + console.log(zs); + let r = 0n; + let i = 0; + for (const z of zs) { + const result = await executer.execute(z); + const digit = BigInt(result) << BigInt(i++); + r = r | digit; + } + console.log(r); +} \ No newline at end of file diff --git a/day_24/solve_2.ts b/day_24/solve_2.ts new file mode 100644 index 0000000..b956ba5 --- /dev/null +++ b/day_24/solve_2.ts @@ -0,0 +1,260 @@ +import { BitValue, Executer, InputData, readData } from "./solve_1.ts"; +import { red, green } from "jsr:@std/fmt/colors"; + +// export function dependencies(data: InputData): Map> { +// const deps = new Map>(); +// for (const gate of data.gates) { +// // check visited. +// // if visited, skip +// if (deps.has(gate.result)) { +// continue; +// } +// const stack = [gate.result]; +// while (stack.length > 0) { +// const current = stack.pop()!; +// const node = data.gates.find(x => x.result === current)!; +// stack.push(node.lhs); +// stack.push(node.rhs); + +// } +// } +// } + +function swapResult(data: InputData, a: string, b: string) { + data.gates.forEach(gate => { + if (gate.result === a) { + gate.result = b; + } + else if (gate.result === b) { + gate.result = a; + } + }); +} + +function drawMermaidGraph(data: InputData, options: { print?: (str: string) => void } = { + print: console.log +}) { + const print = options.print ?? console.log; + print("graph TD"); + data.inputs.forEach(x => print(` ${x.name}(${x.name} ${x.value})`)); + data.gates.forEach(gate => { + print(` ${gate.lhs} -->|${gate.operation}| ${gate.result}`); + print(` ${gate.rhs} -->|${gate.operation}| ${gate.result}`); + }); +} + +function renameGates(data: InputData, from: string, to: string) { + data.gates.forEach(gate => { + if (gate.lhs === from) { + gate.lhs = to; + } + if (gate.rhs === from) { + gate.rhs = to; + } + if (gate.result === from) { + gate.result = to; + } + }); +} + +function renameForAddOperation(data: InputData): InputData { + const newData = { + inputs: data.inputs, + gates: data.gates.map(gate => ({ ...gate })) + }; + const isRenamed = (name: string) => { + return name.length !== 3; + } + const renameGate = (from: string, to: string) => { + if (isRenamed(from)) { + return; + } + renameGates(newData, from, to); + } + + for (let i = 0; i < newData.gates.length; i++) { + const gate = newData.gates[i]; + const lhs = /(x|y)(\d+)/.exec(gate.lhs); + const rhs = /(x|y)(\d+)/.exec(gate.rhs); + if (lhs && rhs + && lhs[1] != rhs[1] + && lhs[2] === rhs[2]) { + if (gate.operation === "and") { + const newName = `CarryHalf${lhs[2]}_${gate.result}`; + renameGate(gate.result, newName); + } + else if (gate.operation === "xor") { + const newName = `SumHalf${lhs[2]}_${gate.result}`; + renameGate(gate.result, newName); + } + } + } + for (let loop = 0; loop < newData.gates.length * 40; loop++) { + + for (let i = 0; i < newData.gates.length; i++) { + const gate = newData.gates[i]; + const lhs = /(Carry|Sum)/.exec(gate.lhs); + const rhs = /(Carry|Sum)/.exec(gate.rhs); + if (lhs && rhs + && lhs[1] != rhs[1]) { + if (gate.operation === "and") { + // C_in and (A xor B) + A and B = C_out + const newName = `ProgressCarryFull_${gate.result}`; + renameGate(gate.result, newName); + } + } + } + + for (let i = 0; i < newData.gates.length; i++) { + const gate = newData.gates[i]; + const lhs = /(ProgressCarryFull|CarryHalf)/.exec(gate.lhs); + const rhs = /(ProgressCarryFull|CarryHalf)/.exec(gate.rhs); + if (lhs && rhs + && lhs[1] != rhs[1]) { + if (gate.operation === "or") { + const newName = `CarryFull_${gate.result}`; + renameGate(gate.result, newName); + } + } + } + + for (let i = 0; i < newData.gates.length; i++) { + const gate = newData.gates[i]; + const lhs = /(CarryFull|SumHalf)/.exec(gate.lhs); + const rhs = /(CarryFull|SumHalf)/.exec(gate.rhs); + if (lhs && rhs + && lhs[1] !== rhs[1]) { + if (gate.operation === "xor") { + const newName = `SumFull_${gate.result}`; + renameGate(gate.result, newName); + } + } + } + + } + + return newData; +} + +function getXvalue(data: InputData): number { + return data.inputs.filter(x => x.name.startsWith('x')) + .toSorted((a, b) => b.name.localeCompare(a.name)) + .map(x => x.value) + .reduce((acc, val) => acc * 2 + val, 0); +} + +function getYvalue(data: InputData): number { + return data.inputs.filter(x => x.name.startsWith('y')) + .toSorted((a, b) => b.name.localeCompare(a.name)) + .map(x => { + return x.value + }) + .reduce((acc, val) => acc * 2 + val, 0); +} + +function setInputs(data: InputData, x: number, y: number) { + const len = data.inputs.filter(x => x.name.startsWith('x')).length; + const xBits = x.toString(2).padStart(len, '0').split('').map(x => parseInt(x)); + const yBits = y.toString(2).padStart(len, '0').split('').map(x => parseInt(x)); + data.inputs.forEach(v => { + const r = /(\w)(\d+)/.exec(v.name); + if (r && r[1] === 'x') { + v.value = xBits[len - 1 - parseInt(r[2])] as BitValue; + } + if (r && r[1] === 'y') { + v.value = yBits[len - 1 - parseInt(r[2])] as BitValue; + } + }); +} + +if (import.meta.main) { + const data = await readData('input.txt'); + + swapResult(data, 'cmv', 'z17'); + swapResult(data, 'rmj', 'z23'); + swapResult(data, 'rdg', 'z30'); + swapResult(data, 'btb', 'mwp'); + + const errorBitIndex = []; + const len = data.inputs.filter(x => x.name.startsWith('x')).length; + for (let i = 0; i < len; i++) { + // 0 1 check add + // 1 1 check carry + for (const c of [[0,1],[1,1]]) { + const x = c[0] * 2 ** i; + const y = c[1] * 2 ** i; + setInputs(data, x, y); + const xVal = getXvalue(data); + const yVal = getYvalue(data); + const desiredZvalue = xVal + yVal; + console.log(xVal, yVal, desiredZvalue); + const zNames = data.gates.filter(gate => gate.result.startsWith("z")) + .map(gate => gate.result) + .toSorted((a, b) => a.localeCompare(b)); + const desiredZvalueBits = desiredZvalue.toString(2).padStart(zNames.length, '0').split('').toReversed().map(x => parseInt(x)); + const executer = new Executer(data); + const actualZValues = zNames.map(name => executer.execute(name)) + let str = ''; + let diff = false; + for (let i = zNames.length - 1; i >= 0; i--) { + const actual = actualZValues[i]; + const desired = desiredZvalueBits[i]; + diff ||= actual !== desired; + str += actual === desired ? green(actual.toString()) : red(actual.toString()); + } + if (diff) { + errorBitIndex.push(i); + } + console.log(i, c); + console.log("",x.toString(2).padStart(len, '0')); + console.log("",y.toString(2).padStart(len, '0')); + console.log(str); + } + } + console.log(errorBitIndex); + + + // const xVal = getXvalue(data); + // const yVal = getYvalue(data); + // console.log(yVal, yVal.toString(2)); + // const desiredZvalue = xVal + yVal; + // // console.log(xVal + yVal); + // // console.log(desiredZvalueBits); + + // const zNames = data.gates.filter(gate => gate.result.startsWith("z")) + // .map(gate => gate.result) + // .toSorted((a, b) => a.localeCompare(b)); + // const desiredZvalueBits = desiredZvalue.toString(2).padStart(zNames.length, '0').split(''); + // const executer = new Executer(data); + // const actualZValues = zNames.map(name => executer.execute(name)).toReversed() + // // console.log(actualZValues); + + // console.log("actual\t",actualZValues.join('')); + // console.log("desired\t",desiredZvalueBits.join('')); + // // print differences + // let str = ''; + // for (let i = 0; i < zNames.length; i++) { + // const actual = actualZValues[i].toString(); + // const desired = desiredZvalueBits[i]; + // str += actual === desired ? green(actual.toString()) : red(actual.toString()); + // } + // console.log("difference",str); + + const file = Deno.openSync('graph.log', { write: true, create: true, truncate: false }); + drawMermaidGraph(data, { print: (str) =>{ + file.writeSync(new TextEncoder().encode(str + '\n')); + } }); + file.close(); + const renamed = renameForAddOperation(data); + const file2 = Deno.openSync('graph2.log', { write: true, create: true, truncate: false }); + drawMermaidGraph(renamed, { print: (str) =>{ + file2.writeSync(new TextEncoder().encode(str + '\n')); + } }); + file2.close(); + + const solve = ['cmv', 'z17', +'rmj', 'z23', +'rdg', 'z30', +'btb', 'mwp'].sort(); + console.log(solve.join(",")); +} \ No newline at end of file