aboutsummaryrefslogtreecommitdiff
path: root/2024
diff options
context:
space:
mode:
authorSebastiano Tronto <sebastiano@tronto.net>2024-12-25 00:40:50 +0100
committerSebastiano Tronto <sebastiano@tronto.net>2024-12-25 00:40:50 +0100
commit19be9f44dbecdde03662be2248eda5b739d67038 (patch)
treec38bfee181b388b777da27a63cae19ce7e7861eb /2024
parent21e1237e93703f632253f042bd5877998d81c507 (diff)
downloadaoc-19be9f44dbecdde03662be2248eda5b739d67038.tar.gz
aoc-19be9f44dbecdde03662be2248eda5b739d67038.zip
Day 24 2024 still don't know how I managed to solve this
Diffstat (limited to '2024')
-rw-r--r--2024/24/Makefile11
-rwxr-xr-x2024/24/clean.sh3
-rw-r--r--2024/24/day24a.cpp88
-rw-r--r--2024/24/day24b.cpp247
-rw-r--r--2024/learned.txt1
5 files changed, 350 insertions, 0 deletions
diff --git a/2024/24/Makefile b/2024/24/Makefile
new file mode 100644
index 0000000..1291678
--- /dev/null
+++ b/2024/24/Makefile
@@ -0,0 +1,11 @@
1CC=g++ -std=c++20 -g -Wall
2
3a:
4 ${CC} -o a.out day24a.cpp
5 ./a.out
6
7b:
8 ${CC} -o b.out day24b.cpp
9 ./b.out
10
11.PHONY: a b
diff --git a/2024/24/clean.sh b/2024/24/clean.sh
new file mode 100755
index 0000000..891ecf7
--- /dev/null
+++ b/2024/24/clean.sh
@@ -0,0 +1,3 @@
1#!/bin/sh
2
3sed 's/XOR/^/; s/OR/|/; s/AND/\&/'
diff --git a/2024/24/day24a.cpp b/2024/24/day24a.cpp
new file mode 100644
index 0000000..231b206
--- /dev/null
+++ b/2024/24/day24a.cpp
@@ -0,0 +1,88 @@
1/* Use clean.sh on the input first */
2
3#include <algorithm>
4#include <cstdint>
5#include <iostream>
6#include <map>
7#include <queue>
8#include <ranges>
9#include <set>
10#include <sstream>
11#include <string>
12#include <string_view>
13#include <vector>
14using namespace std;
15
16int8_t state[36*36*36];
17
18int d(char x) { return x >= 'a' && x <= 'z' ? x-'a' : 26+x-'0'; }
19int index(char a, char b, char c) { return d(c) + 36 * (d(b) + 36 * d(a)); }
20int z(int i) { return index('z', (i/10)+'0', (i%10)+'0'); }
21
22enum class Op { AND, OR, XOR };
23
24class Gate {
25public:
26 int x, y, z;
27 Op op;
28
29 bool ready() const {
30 return state[x] != -1 && state[y] != -1;
31 }
32
33 bool operate() const { /* Returns true if the operation flips a bit */
34 auto oldstate = state[z];
35 switch (op) {
36 case Op::AND:
37 state[z] = state[x] & state[y];
38 break;
39 case Op::OR:
40 state[z] = state[x] | state[y];
41 break;
42 case Op::XOR:
43 state[z] = state[x] ^ state[y];
44 break;
45 }
46 return oldstate != state[z];
47 }
48};
49
50Op make_op(char c) {
51 switch (c) {
52 case '&': return Op::AND;
53 case '|': return Op::OR;
54 default: return Op::XOR;
55 }
56}
57
58int main() {
59 vector<Gate> gates;
60 fill(state, state + 36*36*36, -1);
61 string line;
62
63 while (getline(cin, line) && line != "")
64 state[index(line[0], line[1], line[2])] = line[5]-'0';
65
66 while (getline(cin, line))
67 gates.push_back(Gate {
68 .x = index(line[0], line[1], line[2]),
69 .y = index(line[6], line[7], line[8]),
70 .z = index(line[13], line[14], line[15]),
71 .op = make_op(line[4])
72 });
73
74 for (bool flag = true; flag; ) {
75 flag = false;
76 for (auto g : gates)
77 if (g.ready())
78 flag = flag || g.operate();
79 }
80
81 int64_t result = 0;
82 for (int64_t i = 0, j = 1; state[z(i)] != -1; i++, j *= 2)
83 result += (int64_t)state[z(i)] * j;
84
85 cout << result << endl;
86
87 return 0;
88}
diff --git a/2024/24/day24b.cpp b/2024/24/day24b.cpp
new file mode 100644
index 0000000..ba8e347
--- /dev/null
+++ b/2024/24/day24b.cpp
@@ -0,0 +1,247 @@
1/*
2
3I don't know what addition circuits look like, but they should have some
4kind of regular structure. I manually inspected how the first few digits
5behave to get an idea.
6
7With some more manual inspection I noticed that the "temporary result"
8gates that are results of a XOR operation always appear as terms in
9exactly one XOR and one AND operation; the same thing happens for
10OR-results, while AND-results appear as terms only in one OR operation.
11
12This excludes z-gates, which are the result of a XOR operation (except
13for z45, which is the result of an OR operation) and do not appear as
14terms in any other operation. And of course "errors" do not follow this
15pattern either.
16
17So what I do is going through all gates and see if their result
18satisfies the conditions above. This gives 8 candidates for the error,
19but unfortunately they were not the correct answer (I tried submitting
20this list 3 times).
21
22I thought about it a bit longer and I realized that one of the entries
23in my list is rfg, which appears as the result of x00 & y00. I thought
24that since this was the first digit, it could be an edge case and thus
25correctly behaving differently from the others. This leaves me with
267 candidates only, so I have to find another one.
27
28One of the gates I had to swap (z23) was the result of an OR operation,
29but should have been the result o a XOR. But any XOR-result could be
30swapped with an OR-result without breaking the conditions I guessed at the
31beginning. So I tried them all: for every XOR-gate I swapped the results
32with my other 7 candidates in every way possible according to my rules,
33and checked which of these re-arrangements gave the correct answer for
34the example input.
35
36I found two candidates (kdf and nsr). I could have checked more inputs
37to see which of the two worked, or I could just try both of them. Of
38course, I choose the second option, and kdf worked.
39
40Did I get the gold star? Yes. Do I know how I was supposed to solve this
41problem? Not a clue. But hey, I solved it without hints, a win is a win.
42
43*/
44
45#include <algorithm>
46#include <cstdint>
47#include <iostream>
48#include <map>
49#include <queue>
50#include <ranges>
51#include <set>
52#include <sstream>
53#include <string>
54#include <string_view>
55#include <vector>
56using namespace std;
57
58enum class Op { AND, OR, XOR };
59
60class Gate {
61public:
62 int x, y, z;
63 Op op;
64
65 bool ready(const int8_t *state) const {
66 return state[x] != -1 && state[y] != -1;
67 }
68
69 bool operate(int8_t *state) const { /* Returns true if the operation flips a bit */
70 auto oldstate = state[z];
71 switch (op) {
72 case Op::AND:
73 state[z] = state[x] & state[y];
74 break;
75 case Op::OR:
76 state[z] = state[x] | state[y];
77 break;
78 case Op::XOR:
79 state[z] = state[x] ^ state[y];
80 break;
81 }
82 return oldstate != state[z];
83 }
84};
85
86int8_t state[36*36*36];
87vector<Gate> gates;
88
89int d(char x) { return x >= 'a' && x <= 'z' ? x-'a' : 26+x-'0'; }
90char h(int i) { return i >= 26 ? i-26+'0' : i+'a'; }
91int index(char a, char b, char c) { return d(c) + 36 * (d(b) + 36 * d(a)); }
92string name(int i) {
93 string r = " ";
94 r[0] = h(i / (36*36));
95 r[1] = h((i/ 36) % 36);
96 r[2] = h(i % 36);
97 return r;
98}
99
100int64_t digit(int i, char c) {
101 return index(c, (i/10)+'0', (i%10)+'0');
102}
103
104int64_t getnum(char c, int m) {
105 int64_t result = 0;
106 for (int64_t i = 0, j = 1; i < m; i++, j *= 2)
107 result += (int64_t)state[digit(i, c)] * j;
108 return result;
109}
110
111Op make_op(char c) {
112 switch (c) {
113 case '&': return Op::AND;
114 case '|': return Op::OR;
115 default: return Op::XOR;
116 }
117}
118
119char opname(Op op) {
120 switch (op) {
121 case Op::AND: return '&';
122 case Op::OR: return '|';
123 default: return '^';
124 }
125}
126
127void printop(Gate g, const vector<Op>& a) {
128 cout << name(g.z) << " is " << name(g.x) << " " << opname(g.op)
129 << " " << name(g.y) << " but appears in ";
130 for (auto op : a)
131 cout << opname(op) << " ";
132 cout << endl;
133}
134
135int gg(const string& rr) {
136 for (unsigned i = 0; i < gates.size(); i++)
137 if (name(gates[i].z) == rr)
138 return i;
139 return -1;
140}
141
142void swapgates(vector<Gate>& local_gates, vector<int> ixsa,
143 vector<int> iasx, int iosx, int gswap) {
144}
145
146void run(int8_t *state, const vector<Gate>& gates) {
147 for (bool flag = true; flag; ) {
148 flag = false;
149 for (auto g : gates)
150 if (g.ready(state))
151 flag = flag || g.operate(state);
152 }
153 int64_t x = getnum('x', 45);
154 int64_t y = getnum('y', 45);
155 int64_t z = getnum('z', 46);
156 if (x+y == z) cout << "Correct result! " << z << endl;
157}
158
159int main() {
160 fill(state, state + 36*36*36, -1);
161 string line;
162
163 while (getline(cin, line) && line != "")
164 state[index(line[0], line[1], line[2])] = line[5]-'0';
165
166 while (getline(cin, line))
167 gates.push_back(Gate {
168 .x = index(line[0], line[1], line[2]),
169 .y = index(line[6], line[7], line[8]),
170 .z = index(line[13], line[14], line[15]),
171 .op = make_op(line[4])
172 });
173
174#if 0
175 /* Print error candidates */
176 vector<string> bad;
177 for (auto g : gates) {
178 if (name(g.z)[0] == 'z') {
179 if ((name(g.z) == "z45" && g.op != Op::OR) ||
180 (name(g.z) != "z45" && g.op != Op::XOR)) {
181 printop(g, vector<Op>());
182 bad.push_back(name(g.z));
183 }
184 continue;
185 }
186 vector<Op> appears_in;
187 for (auto f : gates)
188 if (g.z == f.x || g.z == f.y)
189 appears_in.push_back(f.op);
190 if (g.op == Op::AND) {
191 if (appears_in.size() != 1 || appears_in[0] != Op::OR) {
192 printop(g, appears_in);
193 bad.push_back(name(g.z));
194 }
195 } else {
196 if (appears_in.size() != 2 ||
197 find(appears_in.begin(), appears_in.end(), Op::AND) == appears_in.end() ||
198 find(appears_in.begin(), appears_in.end(), Op::XOR) == appears_in.end()) {
199 printop(g, appears_in);
200 bad.push_back(name(g.z));
201 }
202 }
203 }
204
205 sort(bad.begin(), bad.end());
206
207 for (auto b : bad)
208 cout << b << ",";
209 cout << endl;
210#endif
211
212 vector<string> is_xor_shouldbe_and = { "ckj", "rpp", "dbp" };
213 vector<string> is_and_shouldbe_xor = { "fdv", "z15", "z39" };
214 string is_or_shouldbe_xor = "z23";
215
216 vector<int> ixsa = { gg("ckj"), gg("rpp"), gg("dbp") };
217 vector<int> iasx = { gg("fdv"), gg("z15"), gg("z39") };
218 int iosx = gg("z23");
219
220 vector<vector<pair<int, int>>> swaps = {
221 {{ixsa[0],iasx[0]}, {ixsa[1],iasx[1]}, {ixsa[2],iasx[2]}},
222 {{ixsa[0],iasx[0]}, {ixsa[1],iasx[2]}, {ixsa[2],iasx[1]}},
223 {{ixsa[0],iasx[1]}, {ixsa[1],iasx[0]}, {ixsa[2],iasx[2]}},
224 {{ixsa[0],iasx[1]}, {ixsa[1],iasx[2]}, {ixsa[2],iasx[0]}},
225 {{ixsa[0],iasx[2]}, {ixsa[1],iasx[1]}, {ixsa[2],iasx[0]}},
226 {{ixsa[0],iasx[2]}, {ixsa[1],iasx[0]}, {ixsa[2],iasx[1]}}
227 };
228
229 for (unsigned gswap = 0; gswap < gates.size(); gswap++) {
230 if (find(ixsa.begin(), ixsa.end(), gswap) != ixsa.end() ||
231 find(iasx.begin(), iasx.end(), gswap) != iasx.end() ||
232 (int)gswap == iosx || gates[gswap].op != Op::XOR)
233 continue;
234 cout << "Trying gswap " << name(gates[gswap].z) << endl;
235 for (auto ss : swaps) {
236 auto local_state = state;
237 auto local_gates = gates;
238 swap(local_gates[ss[0].first].z, local_gates[ss[0].second].z);
239 swap(local_gates[ss[1].first].z, local_gates[ss[1].second].z);
240 swap(local_gates[ss[2].first].z, local_gates[ss[2].second].z);
241 swap(local_gates[iosx].z, local_gates[gswap].z);
242 run(local_state, local_gates);
243 }
244 }
245
246 return 0;
247}
diff --git a/2024/learned.txt b/2024/learned.txt
index 8dce20a..844def5 100644
--- a/2024/learned.txt
+++ b/2024/learned.txt
@@ -11,3 +11,4 @@ List of things I learned (or refreshed) with this year's AoC.
11* Day 11: if(init; cond) 11* Day 11: if(init; cond)
12* Day 19: more practice with std::string_view for constant string 12* Day 19: more practice with std::string_view for constant string
13* Day 22: std::views::values for map (and keys) 13* Day 22: std::views::values for map (and keys)
14* Day 24: std::fill

Generated with cgit - Back to sebastiano.tronto.net