|
1 | | -import { combinations, permutations } from "combinatorial-generators"; |
2 | | - |
3 | 1 | function read(wiresMap, prefix) { |
4 | | - const out = [ |
5 | | - ...wiresMap.entries().filter(([wire]) => wire.startsWith(prefix)), |
6 | | - ]; |
7 | | - const n = out |
8 | | - .sort((a, b) => b[0].localeCompare(a[0])) |
9 | | - .map(x => x[1]) |
10 | | - .join(""); |
11 | | - return parseInt(n, 2); |
| 2 | + let out = [...wiresMap.keys().filter(x => x.startsWith(prefix))]; |
| 3 | + out = out.sort().reverse(); |
| 4 | + return out.map(x => wiresMap.get(x)).join(""); |
12 | 5 | } |
13 | 6 |
|
14 | 7 | function run(gates, wiresMap) { |
15 | 8 | let done = false; |
16 | 9 | while (!done) { |
17 | 10 | done = true; |
18 | | - gates.forEach(({ left, op, right, wire }) => { |
19 | | - let a = wiresMap.get(left); |
20 | | - let b = wiresMap.get(right); |
| 11 | + gates.forEach(({ a, op, b, wire }) => { |
| 12 | + a = wiresMap.get(a); |
| 13 | + b = wiresMap.get(b); |
21 | 14 | if (a !== undefined && b !== undefined) { |
22 | | - if (op === "AND") { |
23 | | - wiresMap.set(wire, a & b); |
24 | | - } else if (op === "OR") { |
25 | | - wiresMap.set(wire, a | b); |
26 | | - } else if (op === "XOR") { |
27 | | - wiresMap.set(wire, a ^ b); |
28 | | - } |
| 15 | + if (op === "AND") wiresMap.set(wire, a & b); |
| 16 | + if (op === "OR") wiresMap.set(wire, a | b); |
| 17 | + if (op === "XOR") wiresMap.set(wire, a ^ b); |
29 | 18 | } else done = false; |
30 | 19 | }); |
31 | 20 | } |
32 | | - return read(wiresMap, "z"); |
| 21 | + return parseInt(read(wiresMap, "z"), 2); |
33 | 22 | } |
34 | 23 |
|
35 | | -export function part1(input) { |
| 24 | +function parse(input) { |
36 | 25 | let [wires, gates] = input.split("\n\n"); |
37 | 26 | let wiresMap = new Map(); |
38 | 27 | wires.split("\n").forEach(line => { |
39 | 28 | let [wire, value] = line.split(": "); |
40 | 29 | wiresMap.set(wire, +value); |
41 | | - return { wire, value: +value }; |
42 | 30 | }); |
43 | 31 | gates = gates.split("\n").map(line => { |
44 | | - let [left, op, right, , wire] = line.split(" "); |
45 | | - return { left, op, right, wire }; |
| 32 | + let [a, op, b, , wire] = line.split(" "); |
| 33 | + [a, b] = [a, b].sort(); |
| 34 | + return { a, op, b, wire }; |
46 | 35 | }); |
| 36 | + return { wiresMap, gates }; |
| 37 | +} |
| 38 | + |
| 39 | +export function part1(input) { |
| 40 | + let { wiresMap, gates } = parse(input); |
47 | 41 | return run(gates, wiresMap); |
48 | 42 | } |
49 | 43 |
|
50 | | -//shameless rip off from reddit :( |
| 44 | +// full adder |
| 45 | +// https://www.build-electronic-circuits.com/wp-content/uploads/2022/10/fullAdder-1-1024x473.png |
| 46 | +// X XOR Y => M |
| 47 | +// X AND Y => N |
| 48 | +// CIN XOR M => Z |
| 49 | +// CIN AND M => R |
| 50 | +// R OR N => COUT |
51 | 51 | export function part2(input) { |
52 | | - let [, gates] = input.split("\n\n"); |
53 | | - gates = gates.split("\n"); |
54 | | - |
| 52 | + let { gates, wiresMap } = parse(input); |
55 | 53 | function find(a, b, op) { |
56 | | - const gate = gates.find( |
57 | | - gate => |
58 | | - gate.startsWith(`${a} ${op} ${b}`) || |
59 | | - gate.startsWith(`${b} ${op} ${a}`), |
60 | | - ); |
61 | | - return gate?.split(" -> ").pop(); |
| 54 | + [a, b] = [a, b].sort(); |
| 55 | + return gates.find(x => x.a === a && x.b === b && x.op === op)?.wire; |
62 | 56 | } |
63 | | - |
64 | | - // half adder |
65 | | - // X1 XOR Y1 => M1 |
66 | | - // X1 AND Y1 => N1 |
67 | | - // C0 AND M1 => R1 |
68 | | - // C0 XOR M1 -> Z1 |
69 | | - // R1 OR N1 -> C1 |
70 | 57 | let swapped = []; |
71 | | - let c0 = null; |
72 | | - for (let i = 0; i < 45; i++) { |
73 | | - let n = i.toString().padStart(2, "0"); |
74 | | - let m1, n1, r1, z1, c1; |
75 | | - m1 = find(`x${n}`, `y${n}`, "XOR"); |
76 | | - n1 = find(`x${n}`, `y${n}`, "AND"); |
77 | | - if (c0) { |
78 | | - r1 = find(c0, m1, "AND"); |
79 | | - if (!r1) { |
80 | | - [n1, m1] = [m1, n1]; |
81 | | - swapped.push(m1, n1); |
82 | | - r1 = find(c0, m1, "AND"); |
83 | | - } |
84 | | - |
85 | | - z1 = find(c0, m1, "XOR"); |
86 | | - if (m1?.startsWith("z")) { |
87 | | - [m1, z1] = [z1, m1]; |
88 | | - swapped.push(m1, z1); |
89 | | - } |
90 | | - if (n1?.startsWith("z")) { |
91 | | - [n1, z1] = [z1, n1]; |
92 | | - swapped.push(n1, z1); |
93 | | - } |
94 | | - if (r1?.startsWith("z")) { |
95 | | - [r1, z1] = [z1, r1]; |
96 | | - swapped.push(r1, z1); |
97 | | - } |
98 | | - |
99 | | - c1 = find(r1, n1, "OR"); |
100 | | - if (c1?.startsWith("z") && c1 !== "z45") { |
101 | | - [c1, z1] = [z1, c1]; |
102 | | - swapped.push(c1, z1); |
103 | | - } |
104 | | - } |
105 | | - c0 = c1 || n1; |
| 58 | + let { length } = read(wiresMap, "x"); |
| 59 | + let cin = find("x00", "y00", "AND"); |
| 60 | + for (let i = 1; i < length; i++) { |
| 61 | + let num = i.toString().padStart(2, "0"); |
| 62 | + let m = find(`x${num}`, `y${num}`, "XOR"); |
| 63 | + let n = find(`x${num}`, `y${num}`, "AND"); |
| 64 | + if (find(cin, n, "XOR")) swapped.push(...([m, n] = [n, m])); |
| 65 | + let z = find(cin, m, "XOR"); |
| 66 | + let r = find(cin, m, "AND"); |
| 67 | + if (find(r, z, "OR")) swapped.push(...([n, z] = [z, n])); |
| 68 | + if (find(n, z, "OR")) swapped.push(...([r, z] = [z, r])); |
| 69 | + let cout = find(r, n, "OR"); |
| 70 | + if (cout === `z${num}`) swapped.push(...([z, cout] = [cout, z])); |
| 71 | + cin = cout; |
106 | 72 | } |
107 | 73 | return swapped.sort().join(","); |
108 | 74 | } |
109 | | - |
110 | | -// my slow solution, runs for ever... |
111 | | -export function oldpart2(input, n = 4, check = (x, y) => x + y) { |
112 | | - let [wires, gates] = input.split("\n\n"); |
113 | | - let wiresMap = new Map(); |
114 | | - wires.split("\n").forEach(line => { |
115 | | - let [wire, value] = line.split(": "); |
116 | | - wiresMap.set(wire, +value); |
117 | | - return { wire, value: +value }; |
118 | | - }); |
119 | | - gates = gates.split("\n").map(line => { |
120 | | - let [left, op, right, , wire] = line.split(" "); |
121 | | - return { left, op, right, wire }; |
122 | | - }); |
123 | | - let pairs = combinations( |
124 | | - gates.map(({ wire }) => wire), |
125 | | - 2 * n, |
126 | | - ); |
127 | | - let x = read(wiresMap, "x"); |
128 | | - let y = read(wiresMap, "y"); |
129 | | - let found = pairs.find(pair => { |
130 | | - let options = permutations(pair); |
131 | | - return options.find(permutation => { |
132 | | - let replacements = new Map(); |
133 | | - for (let i = 0; i < permutation.length; i += 2) { |
134 | | - if (permutation[i].localeCompare(permutation[i + 1]) < 0) return false; |
135 | | - replacements.set(permutation[i], permutation[i + 1]); |
136 | | - replacements.set(permutation[i + 1], permutation[i]); |
137 | | - } |
138 | | - let newGates = gates.map(({ left, op, right, wire }) => { |
139 | | - return { |
140 | | - left, |
141 | | - op, |
142 | | - right, |
143 | | - wire: replacements.get(wire) || wire, |
144 | | - }; |
145 | | - }); |
146 | | - let newWiresMap = new Map(wiresMap.entries()); |
147 | | - if (run(newGates, newWiresMap) === check(x, y)) { |
148 | | - //try another number just to make sure addition works |
149 | | - newWiresMap.set("x04", 1); |
150 | | - let x = read(newWiresMap, "x"); |
151 | | - let y = read(newWiresMap, "y"); |
152 | | - let newGates = gates.map(({ left, op, right, wire }) => { |
153 | | - return { |
154 | | - left, |
155 | | - op, |
156 | | - right, |
157 | | - wire: replacements.get(wire) || wire, |
158 | | - }; |
159 | | - }); |
160 | | - if (run(newGates, newWiresMap) === check(x, y)) return true; |
161 | | - } |
162 | | - }); |
163 | | - }); |
164 | | - return found.sort().join(","); //? |
165 | | -} |
0 commit comments