Add solution day 24

This commit is contained in:
monoid 2024-12-24 23:29:19 +09:00
parent 096208c2e5
commit 134bf147e9
5 changed files with 753 additions and 0 deletions

10
day_24/example.txt Normal file
View File

@ -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

313
day_24/input.txt Normal file
View File

@ -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

47
day_24/larger_example.txt Normal file
View File

@ -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

123
day_24/solve_1.ts Normal file
View File

@ -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<InputData> {
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<string, BitValue> = new Map();
private gates: InputData['gates'];
private results: Map<string, BitValue> = 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);
}

260
day_24/solve_2.ts Normal file
View File

@ -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<string, Set<string>> {
// const deps = new Map<string, Set<string>>();
// 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<number>((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<number>((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(","));
}