Skip to content

Commit d43bfda

Browse files
authored
Day 24 (#27)
1 parent ad18d62 commit d43bfda

File tree

3 files changed

+534
-0
lines changed

3 files changed

+534
-0
lines changed

Day24.c

+246
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
#include "Helpers.c"
2+
3+
#define CAP 300
4+
5+
typedef enum {
6+
Halt = 0,
7+
Inp,
8+
Mul,
9+
Eql,
10+
Mod,
11+
Div,
12+
Add
13+
} Operation;
14+
15+
typedef enum {
16+
W = 0,
17+
X,
18+
Y,
19+
Z
20+
} Var;
21+
22+
typedef enum {
23+
FromVar = 1,
24+
FromImm
25+
} SrcType;
26+
27+
typedef struct {
28+
Operation op;
29+
Var dest;
30+
SrcType src;
31+
union {
32+
Var srcVar;
33+
int srcImm;
34+
};
35+
} Instruction;
36+
37+
#define NOT_FOUND_CAP 500
38+
#define INDEX_CAP 16384
39+
40+
static int64_t notFoundCache[14][INDEX_CAP][NOT_FOUND_CAP];
41+
static int nNotFoundCache[14][INDEX_CAP];
42+
43+
static Var varFromChar(char c) {
44+
switch (c) {
45+
case 'w': return W;
46+
case 'x': return X;
47+
case 'y': return Y;
48+
case 'z': return Z;
49+
default: assert(false && "Unknown variable");
50+
}
51+
}
52+
53+
static Operation opFromString(const char *str) {
54+
if (strcmp(str, "mul") == 0) {
55+
return Mul;
56+
} else if (strcmp(str, "eql") == 0) {
57+
return Eql;
58+
} else if (strcmp(str, "mod") == 0) {
59+
return Mod;
60+
} else if (strcmp(str, "add") == 0) {
61+
return Add;
62+
} else if (strcmp(str, "div") == 0) {
63+
return Div;
64+
} else {
65+
assert(false && "Unknown operation");
66+
}
67+
}
68+
69+
static void parse(const char *input, Instruction instructions[14][CAP]) {
70+
int charsRead = 0;
71+
int filled = 1;
72+
char op[5] = {0};
73+
char dest[6] = {0};
74+
char src[6] = {0};
75+
int imm = 0;
76+
77+
int n = 0;
78+
int chunk = -1;
79+
80+
while (filled > 0) {
81+
filled = sscanf(input, "inp %1[wxyz]\n%n", dest, &charsRead);
82+
83+
if (filled == 1 && charsRead > 0) {
84+
input += charsRead;
85+
86+
n = 0;
87+
++chunk;
88+
instructions[chunk][n++] = (Instruction){.op = Inp,
89+
.dest = varFromChar(dest[0]),
90+
.src = FromImm,
91+
.srcImm = 0};
92+
} else {
93+
filled = sscanf(input, "%4s %1[wxyz] %d\n%n", op, dest, &imm, &charsRead);
94+
95+
if (filled == 3 && charsRead > 0) {
96+
input += charsRead;
97+
98+
instructions[chunk][n++] = (Instruction){.op = opFromString(op),
99+
.dest = varFromChar(dest[0]),
100+
.src = FromImm,
101+
.srcImm = imm};
102+
} else {
103+
filled = sscanf(input, "%4s %1[wxyz] %1[wxyz]\n%n", op, dest, src, &charsRead);
104+
105+
if (filled == 3 && charsRead > 0) {
106+
input += charsRead;
107+
108+
instructions[chunk][n++] = (Instruction){.op = opFromString(op),
109+
.dest = varFromChar(dest[0]),
110+
.src = FromVar,
111+
.srcVar = varFromChar(src[0])};
112+
}
113+
}
114+
}
115+
}
116+
}
117+
118+
static bool run(const Instruction *i, int64_t vars[4], int input) {
119+
int64_t srcValue = i->src == FromImm ? i->srcImm : vars[i->srcVar];
120+
121+
switch (i->op) {
122+
case Halt:
123+
return false;
124+
case Inp:
125+
vars[i->dest] = input;
126+
break;
127+
case Add:
128+
vars[i->dest] += srcValue;
129+
break;
130+
case Div:
131+
assert(srcValue != 0);
132+
vars[i->dest] /= srcValue;
133+
break;
134+
case Eql:
135+
vars[i->dest] = vars[i->dest] == srcValue;
136+
break;
137+
case Mod:
138+
assert(vars[i->dest] >= 0);
139+
assert(srcValue > 0);
140+
vars[i->dest] %= srcValue;
141+
break;
142+
case Mul:
143+
vars[i->dest] *= srcValue;
144+
break;
145+
}
146+
147+
return true;
148+
}
149+
150+
static inline int64_t runProgram(const Instruction program[CAP], int64_t initZ, int input) {
151+
int64_t vars[4] = {0, 0, 0, initZ};
152+
153+
for (const Instruction *i = program; run(i, vars, input); ++i) {
154+
}
155+
156+
return vars[Z];
157+
}
158+
159+
static int64_t findLargestMonad(const Instruction programs[14][CAP], int64_t initZ, uint8_t digitIndex, int64_t currentMonad) {
160+
size_t index = (uint64_t)initZ & (uint64_t)(INDEX_CAP - 1);
161+
162+
for (int i = 0; i < nNotFoundCache[digitIndex][index]; ++i) {
163+
if (notFoundCache[digitIndex][index][i] == initZ) {
164+
return -1;
165+
}
166+
}
167+
168+
for (int d = 9; d >= 1; --d) {
169+
int64_t resultZ = runProgram(programs[digitIndex], initZ, d);
170+
171+
if (digitIndex == 13) {
172+
if (resultZ == 0) {
173+
return d + currentMonad * 10;
174+
}
175+
} else {
176+
int64_t nextMonad = findLargestMonad(programs, resultZ, digitIndex + 1, d + currentMonad * 10);
177+
178+
if (nextMonad > 0) {
179+
return nextMonad;
180+
}
181+
}
182+
}
183+
184+
notFoundCache[digitIndex][index][nNotFoundCache[digitIndex][index]++] = initZ;
185+
assert(nNotFoundCache[digitIndex][index] < NOT_FOUND_CAP);
186+
187+
return -1;
188+
}
189+
190+
static int64_t findSmallestMonad(const Instruction programs[14][CAP], int64_t initZ, uint8_t digitIndex, int64_t currentMonad) {
191+
size_t index = (uint64_t)initZ & (uint64_t)(INDEX_CAP - 1);
192+
193+
for (int i = 0; i < nNotFoundCache[digitIndex][index]; ++i) {
194+
if (notFoundCache[digitIndex][index][i] == initZ) {
195+
return -1;
196+
}
197+
}
198+
199+
for (int d = 1; d <= 9; ++d) {
200+
int64_t resultZ = runProgram(programs[digitIndex], initZ, d);
201+
202+
if (digitIndex == 13) {
203+
if (resultZ == 0) {
204+
return d + currentMonad * 10;
205+
}
206+
} else {
207+
int64_t nextMonad = findSmallestMonad(programs, resultZ, digitIndex + 1, d + currentMonad * 10);
208+
209+
if (nextMonad > 0) {
210+
return nextMonad;
211+
}
212+
}
213+
}
214+
215+
notFoundCache[digitIndex][index][nNotFoundCache[digitIndex][index]++] = initZ;
216+
assert(nNotFoundCache[digitIndex][index] < NOT_FOUND_CAP);
217+
218+
return -1;
219+
}
220+
221+
static int64_t partOne(const Instruction programs[14][CAP]) {
222+
memset(nNotFoundCache, 0, sizeof(nNotFoundCache));
223+
return findLargestMonad(programs, 0, 0, 0);
224+
}
225+
226+
static int64_t partTwo(const Instruction programs[14][CAP]) {
227+
memset(nNotFoundCache, 0, sizeof(nNotFoundCache));
228+
return findSmallestMonad(programs, 0, 0, 0);
229+
}
230+
231+
int main() {
232+
const char *input = Helpers_readInputFile(__FILE__);
233+
234+
Instruction programs[14][CAP] = {0};
235+
parse(input, programs);
236+
237+
Helpers_assert(PART1, Helpers_clock(),
238+
partOne(programs),
239+
79999999999999, 99196997985942);
240+
241+
Helpers_assert(PART2, Helpers_clock(),
242+
partTwo(programs),
243+
13111111111111, 84191521311611);
244+
245+
return 0;
246+
}

Day24.example.txt

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
inp w
2+
mul x 0
3+
add x z
4+
mod x 26
5+
div z 26
6+
add x -6
7+
eql x w
8+
eql x 0
9+
mul y 0
10+
add y 25
11+
mul y x
12+
add y 1
13+
mul z y
14+
mul y 0
15+
add y w
16+
add y 10
17+
mul y x
18+
add z y
19+
inp w
20+
mul x 0
21+
add x z
22+
mod x 26
23+
div z 26
24+
add x -8
25+
eql x w
26+
eql x 0
27+
mul y 0
28+
add y 25
29+
mul y x
30+
add y 1
31+
mul z y
32+
mul y 0
33+
add y w
34+
add y 3
35+
mul y x
36+
add z y

0 commit comments

Comments
 (0)