This commit is contained in:
dobiadi
2024-12-24 16:03:40 +01:00
parent d85878bca2
commit 4e44650a01
6 changed files with 858 additions and 0 deletions

BIN
day24/c/day24 Executable file
View File

Binary file not shown.

469
day24/c/day24.c Normal file
View File

@@ -0,0 +1,469 @@
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#define CHARS_MAX 64
#define MAX_GATES_PER_WIRE 16
#define MAX_WIRES 16*1024
#define MAX_GATES 8*1024
#define c2i(a) ((a) >= 'a' ? ((a) - 'a') : ((a) - '0' + 26))
int cmp(const void* a, const void* b) {
const char **pa = (const char**)a;
const char **pb = (const char**)b;
if ((*pa)[0] != (*pb)[0]) {
return (*pa)[0] - (*pb)[0];
}
if ((*pa)[1] != (*pb)[1]) {
return (*pa)[1] - (*pb)[1];
}
return (*pa)[2] - (*pb)[2];
}
typedef struct node {
struct node *children[36];
struct wire *value;
char key;
uint8_t is_leaf;
} node_t;
node_t* create_node() {
node_t *node = calloc(1, sizeof(node[0]));
return node;
}
node_t* search(node_t* root, char* word) {
node_t* node = root;
for (int i = 0; i < 3; i++) {
if (node->children[c2i(word[i])] == NULL) {
return NULL;
}
node = node->children[c2i(word[i])];
}
return node;
}
void insert(node_t* root, char* word, struct wire *value) {
node_t* node = root;
for (int i = 0; i < 3; i++) {
if (node->children[c2i(word[i])] == NULL) {
node->children[c2i(word[i])] = create_node();
}
node = node->children[c2i(word[i])];
}
node->value = value;
node->is_leaf = 1;
}
void free_node(node_t* node) {
for (int i = 0; i < 36; i++) {
if (node->children[i] != NULL) {
free_node(node->children[i]);
}
}
free(node->value);
free(node);
}
typedef struct wire {
char name[3];
int signal;
struct gate *gates[MAX_GATES_PER_WIRE];
int output_gate_count;
struct gate *generator;
} wire_t;
typedef enum {
AND,
OR,
XOR
} gate_type_t;
typedef struct gate {
wire_t *inputs[2];
wire_t *output;
gate_type_t type;
} gate_t;
void process_wire(wire_t *wire);
uint64_t get_output(node_t *wires, char c);
void reset(node_t *wires);
void set_input1(node_t *wires, uint64_t value);
void set_input2(node_t *wires, uint64_t value);
void backtrack(node_t *wires, wire_t **list, int *list_count, wire_t* wire);
int is_correct(node_t *wires, int i, wire_t **initial_wires);
void get_activated_gates(node_t *wires, gate_t **list, int *list_count);
int main() {
char *p, *buf, c;
buf = calloc(CHARS_MAX, sizeof(char));
p = buf;
wire_t **initial_wires = calloc(MAX_WIRES, sizeof(wire_t*));
int initial_wire_count = 0;
int reading_initial_wires = 1;
char (*preparsed_gates)[10] = calloc(MAX_GATES, sizeof(preparsed_gates[0]));
int gate_count = 0;
while ((c = getchar()) != EOF) {
*p++ = c;
if (c != '\n') {
continue;
}
if (reading_initial_wires) {
if (buf[0] == '\n') {
reading_initial_wires = 0;
memset(buf, 0, CHARS_MAX);
p = buf;
continue;
}
initial_wires[initial_wire_count] = calloc(1, sizeof(wire_t));
initial_wires[initial_wire_count]->name[0] = buf[0];
initial_wires[initial_wire_count]->name[1] = buf[1];
initial_wires[initial_wire_count]->name[2] = buf[2];
initial_wires[initial_wire_count++]->signal = buf[5] == '1' ? 1 : 0;
} else {
preparsed_gates[gate_count][0] = buf[0];
preparsed_gates[gate_count][1] = buf[1];
preparsed_gates[gate_count][2] = buf[2];
preparsed_gates[gate_count][3] = buf[4] == 'A' ? AND : (buf[4] == 'O' ? OR : XOR);
p = buf;
while (*p++ != ' ');
while (*p++ != ' ');
preparsed_gates[gate_count][4] = p[0];
preparsed_gates[gate_count][5] = p[1];
preparsed_gates[gate_count][6] = p[2];
while (*p++ != ' ');
while (*p++ != ' ');
preparsed_gates[gate_count][7] = p[0];
preparsed_gates[gate_count][8] = p[1];
preparsed_gates[gate_count][9] = p[2];
gate_count++;
}
memset(buf, 0, CHARS_MAX);
p = buf;
}
free(buf);
// Create trie of wires
node_t *wires = create_node();
// Insert initial wires
for (int i = 0; i < initial_wire_count; i++) {
insert(wires, initial_wires[i]->name, initial_wires[i]);
}
// Go through gates and extract previously unknown wires
for (int i = 0; i < gate_count; i++) {
char* wire_name = &preparsed_gates[i][0];
node_t *wire = search(wires, wire_name);
if (wire == NULL || wire->is_leaf == 0) {
wire_t *value = calloc(1, sizeof(wire_t));
memcpy(value->name, wire_name, 3);
value->signal = -1;
insert(wires, value->name, value);
}
wire_name = &preparsed_gates[i][4];
wire = search(wires, wire_name);
if (wire == NULL || wire->is_leaf == 0) {
wire_t *value = calloc(1, sizeof(wire_t));
memcpy(value->name, wire_name, 3);
value->signal = -1;
insert(wires, value->name, value);
}
wire_name = &preparsed_gates[i][7];
wire = search(wires, wire_name);
if (wire == NULL || wire->is_leaf == 0) {
wire_t *value = calloc(1, sizeof(wire_t));
memcpy(value->name, wire_name, 3);
value->signal = -1;
insert(wires, value->name, value);
}
}
// Now link everything together
gate_t *gates = calloc(MAX_GATES, sizeof(gates[0]));
for (int i = 0; i < gate_count; i++) {
// Link gate inputs/outputs
gates[i].type = preparsed_gates[i][3];
wire_t *wire1 = search(wires, &preparsed_gates[i][0])->value;
gates[i].inputs[0] = wire1;
wire_t *wire2 = search(wires, &preparsed_gates[i][4])->value;
gates[i].inputs[1] = wire2;
wire_t *wire3 = search(wires, &preparsed_gates[i][7])->value;
gates[i].output = wire3;
// Link wires to gates
wire1->gates[wire1->output_gate_count++] = &gates[i];
wire2->gates[wire2->output_gate_count++] = &gates[i];
wire3->generator = &gates[i];
}
free(preparsed_gates);
for (int i = 0; i < initial_wire_count; i++) {
process_wire(initial_wires[i]);
}
uint64_t output = get_output(wires, 'z');
printf("%lu\n", output);
char **part2 = calloc(8, sizeof(part2[0]));
int part2_c = 0;
wire_t **relevant_gates = calloc(MAX_GATES, sizeof(wire_t*));
relevant_gates[0] = search(wires, "z00")->value;
int relevant_gate_count = 1;
int pc = 1;
for (int i = 1; i < 64; i++) {
char buf[4];
sprintf(buf, "z%02d", i);
node_t *generator_node = search(wires, buf);
if (generator_node) {
backtrack(wires, relevant_gates, &relevant_gate_count, generator_node->value);
if (!is_correct(wires, i, initial_wires)) {
gate_t **activated = calloc(MAX_GATES, sizeof(gate_t*));
gate_t **switchable = calloc(MAX_GATES, sizeof(gate_t*));
int activated_count = 0;
int switchable_count = 0;
get_activated_gates(wires, activated, &activated_count);
for (int j = 0; j < activated_count; j++) {
int found = 0;
for (int jj = 0; jj < pc; jj++) {
if (relevant_gates[jj] == activated[j]->output) {
found = 1;
break;
}
}
if (!found) {
switchable[switchable_count++] = activated[j];
}
}
// Try to switch each switchable
int br = 0;
for (int s1 = 0; s1 < switchable_count; s1++) {
for (int s2 = s1 + 1; s2 < switchable_count; s2++) {
wire_t *tmp = switchable[s2]->output;
switchable[s2]->output = switchable[s1]->output;
switchable[s1]->output = tmp;
// Check switched version
if (is_correct(wires, i, initial_wires)) {
part2[part2_c++] = switchable[s1]->output->name;
part2[part2_c++] = switchable[s2]->output->name;
br = 1;
break;
}
switchable[s1]->output = switchable[s2]->output;
switchable[s2]->output = tmp;
}
if (br) {
break;
}
}
free(activated);
free(switchable);
}
pc = relevant_gate_count;
}
}
qsort(part2, part2_c, sizeof(char*), cmp);
for (int i = 0; i < part2_c; i++) {
printf("%c%c%c", part2[i][0], part2[i][1], part2[i][2]);
if (i != part2_c - 1) {
printf(",");
}
}
printf("\n");
free(initial_wires);
free_node(wires);
free(gates);
free(relevant_gates);
free(part2);
}
int eval_gate(gate_t gate) {
switch (gate.type) {
case AND:
return gate.inputs[0]->signal & gate.inputs[1]->signal;
case OR:
return gate.inputs[0]->signal | gate.inputs[1]->signal;
case XOR:
return gate.inputs[0]->signal ^ gate.inputs[1]->signal;
}
return -1;
}
void process_wire(wire_t *wire) {
// Try each of its outputs
for (int i = 0; i < wire->output_gate_count; i++) {
// Check if gate has both of it's outputs set
if (wire->gates[i]->inputs[0]->signal != -1 && wire->gates[i]->inputs[1]->signal != -1) {
wire->gates[i]->output->signal = eval_gate(*wire->gates[i]);
process_wire(wire->gates[i]->output);
}
}
}
void set_input1(node_t *wires, uint64_t value) {
for (int i = 0; i < INT_MAX; i++) {
char buf[4];
sprintf(buf, "x%02d", i);
node_t *node = search(wires, buf);
if (node == NULL) {
break;
}
node->value->signal = (value >> i) & 1;
}
}
void set_input2(node_t *wires, uint64_t value) {
for (int i = 0; i < INT_MAX; i++) {
char buf[4];
sprintf(buf, "y%02d", i);
node_t *node = search(wires, buf);
if (node == NULL) {
break;
}
node->value->signal = (value >> i) & 1;
}
}
uint64_t get_output(node_t *wires, char c) {
uint64_t result = 0;
for (int i = 0; i < INT_MAX; i++) {
char buf[4];
sprintf(buf, "%c%02d", c, i);
node_t *node = search(wires, buf);
if (node == NULL) {
break;
}
result += (uint64_t)node->value->signal << i;
}
return result;
}
void reset(node_t *wires) {
if (wires == NULL) {
return;
}
for (int i = 0; i < 36; i++) {
reset(wires->children[i]);
}
if (wires->value != NULL) {
wires->value->signal = -1;
}
}
void backtrack(node_t *wires, wire_t **list, int *list_count, wire_t* wire) {
if (wire == NULL) {
return;
}
int found = 0;
for (int i = 0; i < *list_count; i++) {
if (wire == list[i]) {
found = 1;
break;
}
}
if (found) {
return;
}
list[*list_count] = wire;
(*list_count)++;
if (wire->generator) {
backtrack(wires, list, list_count, wire->generator->inputs[0]);
backtrack(wires, list, list_count, wire->generator->inputs[1]);
}
}
void get_activated_gates(node_t *wires, gate_t **list, int *list_count) {
if (wires == NULL) {
return;
}
if (wires->value != NULL && wires->value->generator != NULL && wires->value->signal != -1) {
int found = 0;
for (int i = 0; i < *list_count; i++) {
if (wires->value->generator == list[i]) {
found = 1;
break;
}
}
if (!found) {
list[*list_count] = wires->value->generator;
(*list_count)++;
}
}
// Iterate each wire
for (int i = 0; i < 36; i++) {
get_activated_gates(wires->children[i], list, list_count);
}
}
int is_correct(node_t *wires, int i, wire_t **initial_wires) {
for (int j = 0; j < 2; j++) {
for (int k = 0; k < 2; k++) {
for (int jj = 0; jj < 2; jj++) {
for (int kk = 0; kk < 2; kk++) {
reset(wires);
set_input1(wires, ((uint64_t)j << i) + ((uint64_t)k << (i-1)));
set_input2(wires, ((uint64_t)jj << i) + ((uint64_t)kk << (i-1)));
uint64_t e = ((uint64_t)j << i) + ((uint64_t)k << (i-1)) + ((uint64_t)jj << i) + ((uint64_t)kk << (i-1));
char buf[4];
for (int ii = 0; ii <= i; ii++) {
if (i == 45) {
continue;
}
sprintf(buf, "x%02d", ii);
wire_t *x = search(wires, buf)->value;
process_wire(x);
sprintf(buf, "y%02d", ii);
wire_t *y = search(wires, buf)->value;
process_wire(y);
}
for (int ii = 0; ii < i-1; ii++) {
sprintf(buf, "z%02d", ii);
wire_t *z = search(wires, buf)->value;
if (z->signal != 0) {
return 0;
}
}
sprintf(buf, "z%02d", i-1);
wire_t *z = search(wires, buf)->value;
if (z->signal != (k ^ kk)) {
return 0;
}
sprintf(buf, "z%02d", i);
z = search(wires, buf)->value;
if (z->signal != ((j ^ jj) ^ (k & kk))) {
return 0;
}
}
}
}
}
return 1;
}

313
day24/input.txt Normal file
View File

@@ -0,0 +1,313 @@
x00: 1
x01: 1
x02: 1
x03: 1
x04: 0
x05: 1
x06: 0
x07: 1
x08: 0
x09: 1
x10: 1
x11: 1
x12: 1
x13: 1
x14: 1
x15: 0
x16: 0
x17: 1
x18: 0
x19: 0
x20: 1
x21: 1
x22: 0
x23: 1
x24: 1
x25: 1
x26: 1
x27: 0
x28: 0
x29: 1
x30: 0
x31: 1
x32: 0
x33: 0
x34: 1
x35: 0
x36: 1
x37: 0
x38: 1
x39: 1
x40: 0
x41: 1
x42: 0
x43: 1
x44: 1
y00: 1
y01: 1
y02: 1
y03: 1
y04: 1
y05: 0
y06: 0
y07: 0
y08: 0
y09: 0
y10: 1
y11: 0
y12: 0
y13: 1
y14: 1
y15: 0
y16: 0
y17: 0
y18: 0
y19: 0
y20: 0
y21: 1
y22: 1
y23: 1
y24: 1
y25: 1
y26: 1
y27: 0
y28: 0
y29: 0
y30: 1
y31: 1
y32: 0
y33: 1
y34: 0
y35: 1
y36: 0
y37: 0
y38: 0
y39: 0
y40: 1
y41: 1
y42: 1
y43: 0
y44: 1
stn AND ffg -> tnr
y43 XOR x43 -> vfw
x37 AND y37 -> gnn
x12 AND y12 -> knv
hqw AND jmq -> djd
pqv AND kcv -> mnv
gtf OR jjt -> dfv
x38 AND y38 -> qjd
x40 AND y40 -> kqh
ghk XOR pnr -> z09
vjd XOR kmb -> z10
ftt XOR hwf -> z37
x33 XOR y33 -> shg
shg AND gfm -> vqw
jvj OR bch -> jmq
y27 XOR x27 -> hqw
jsr XOR kph -> z13
y35 AND x35 -> rkm
ccq OR hns -> vdt
x22 AND y22 -> hcv
x11 XOR y11 -> mws
ctp OR mdt -> nqv
y24 XOR x24 -> jjh
x43 AND y43 -> dkq
y13 AND x13 -> qmc
swk OR dgd -> tjh
jqm AND fjc -> ktw
fkq OR qfs -> dkn
sdn XOR hrm -> z14
y22 XOR x22 -> hrj
mhm XOR mhc -> z34
rbm OR bjj -> tmm
gqq OR nnk -> stv
jbc OR mnv -> z32
y39 AND x39 -> gtf
crw OR bbv -> wvt
y05 AND x05 -> vfm
mjf OR srr -> dpv
y08 XOR x08 -> dnc
x01 XOR y01 -> qtg
y36 XOR x36 -> fjc
kdn XOR fvk -> z29
msp AND shq -> dqc
vdt XOR rjv -> z25
dpv AND mgr -> fvd
bqf AND vnc -> jjt
x09 XOR y09 -> ghk
ckj AND jjh -> hns
mpm XOR gtn -> z21
x35 XOR y35 -> rpq
y16 XOR x16 -> btj
wkh XOR fhk -> z17
y31 XOR x31 -> mbc
gsv AND qtg -> vjb
y23 AND x23 -> jmr
jpj XOR brn -> z18
crb AND gqd -> fpk
x07 AND y07 -> hhm
spg XOR bfw -> z44
djd OR wqf -> msp
gsv XOR qtg -> z01
x10 XOR y10 -> vjd
x20 XOR y20 -> pwm
nct OR mmk -> gtn
hrj AND tjh -> wfs
y13 XOR x13 -> kph
pjv XOR bhn -> z05
fhk AND wkh -> vpv
dnc XOR rtp -> cdj
x40 XOR y40 -> tqg
ckj XOR jjh -> z24
x23 XOR y23 -> crb
y14 AND x14 -> vjh
tqg AND dfv -> dbc
y10 AND x10 -> fkq
kcv XOR pqv -> gfm
x18 XOR y18 -> brn
x02 AND y02 -> hjk
wdg XOR fbp -> z03
y08 AND x08 -> z08
x32 XOR y32 -> pqv
tqg XOR dfv -> z40
jdh OR qrw -> z45
x00 XOR y00 -> z00
gtm OR mqp -> tfr
x12 XOR y12 -> dmv
mdr OR dqc -> fvk
dmv AND wvt -> tkv
gfm XOR shg -> z33
dbc OR kqh -> tkw
x21 AND y21 -> swk
jhb XOR tkw -> z41
dkn XOR mws -> z11
x05 XOR y05 -> pjv
x04 AND y04 -> wmc
fgk AND jbp -> rdf
y16 AND x16 -> dwj
hqw XOR jmq -> z27
gnn OR qmd -> kvn
msp XOR shq -> z28
mhs AND pbn -> whd
pnr AND ghk -> kgf
y31 AND x31 -> tnf
pwm XOR cjh -> z20
y19 AND x19 -> stp
tdc XOR scp -> z30
y03 AND x03 -> tqj
fpk OR jmr -> ckj
skt OR cdj -> pnr
gtn AND mpm -> dgd
wmc OR whd -> bhn
dpv XOR mgr -> z19
y17 XOR x17 -> fhk
y03 XOR x03 -> fbp
btj AND tmm -> z16
stv XOR vfw -> z43
tjh XOR hrj -> z22
y11 AND x11 -> bbv
cpp OR tnf -> kcv
pbn XOR mhs -> z04
x17 AND y17 -> pjm
bmh OR tqj -> mhs
fgk XOR jbp -> z06
x25 XOR y25 -> rjv
kvn XOR qjd -> z38
y21 XOR x21 -> mpm
qfv OR hjk -> wdg
y36 AND x36 -> jwh
knv OR tkv -> jsr
tnr OR hhm -> rtp
mhm AND mhc -> hsq
qjd AND kvn -> bgj
brn AND jpj -> srr
hwf AND ftt -> qmd
pjv AND bhn -> jnn
x42 AND y42 -> gqq
btj XOR tmm -> mrb
x28 AND y28 -> mdr
y39 XOR x39 -> vnc
dwj OR mrb -> wkh
rpq XOR pfh -> z35
y25 AND x25 -> ctp
stp OR fvd -> cjh
cgp OR vjh -> gjd
crb XOR gqd -> z23
x26 XOR y26 -> stc
y44 XOR x44 -> spg
nqv XOR stc -> z26
bqf XOR vnc -> z39
x42 XOR y42 -> msd
x00 AND y00 -> gsv
rpq AND pfh -> bdd
x01 AND y01 -> wcd
x02 XOR y02 -> vgg
x38 XOR y38 -> dhm
y09 AND x09 -> btq
wdg AND fbp -> bmh
x06 XOR y06 -> fgk
qpq OR vqw -> mhm
dmv XOR wvt -> z12
y32 AND x32 -> jbc
rdf OR kcg -> ffg
ffg XOR stn -> z07
sdn AND hrm -> cgp
scp AND tdc -> pkv
fvk AND kdn -> kvv
ktw OR jwh -> hwf
spg AND bfw -> qrw
x27 AND y27 -> wqf
rkm OR bdd -> jqm
x37 XOR y37 -> ftt
y30 AND x30 -> nmd
y07 XOR x07 -> stn
y41 XOR x41 -> jhb
vfw AND stv -> nfk
y04 XOR x04 -> pbn
rtp AND dnc -> skt
jrd OR qmc -> hrm
kmb AND vjd -> qfs
nmd OR pkv -> sjk
tkw AND jhb -> gtm
nfk OR dkq -> bfw
x29 AND y29 -> shs
jqm XOR fjc -> z36
sjk AND mbc -> cpp
x20 AND y20 -> mmk
y33 AND x33 -> qpq
hsq OR fgq -> pfh
gbg XOR vgg -> z02
jnn OR vfm -> jbp
pwm AND cjh -> nct
dkn AND mws -> crw
mbc XOR sjk -> z31
dhm OR bgj -> bqf
y34 AND x34 -> fgq
x06 AND y06 -> kcg
x41 AND y41 -> mqp
kvv OR shs -> scp
btq OR kgf -> kmb
rjv AND vdt -> mdt
x15 AND y15 -> rbm
x44 AND y44 -> jdh
gbg AND vgg -> qfv
x18 AND y18 -> mjf
y19 XOR x19 -> mgr
msd XOR tfr -> z42
y30 XOR x30 -> tdc
y24 AND x24 -> ccq
x28 XOR y28 -> shq
stc AND nqv -> bch
y14 XOR x14 -> sdn
gjd AND jfh -> bjj
x34 XOR y34 -> mhc
vpv OR pjm -> jpj
msd AND tfr -> nnk
x26 AND y26 -> jvj
kph AND jsr -> jrd
jfh XOR gjd -> z15
x15 XOR y15 -> jfh
y29 XOR x29 -> kdn
vjb OR wcd -> gbg
hcv OR wfs -> gqd

10
day24/sample.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

47
day24/sample2.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

19
day24/sample3.txt Normal file
View File

@@ -0,0 +1,19 @@
x00: 0
x01: 1
x02: 0
x03: 1
x04: 0
x05: 1
y00: 0
y01: 0
y02: 1
y03: 1
y04: 0
y05: 1
x00 AND y00 -> z05
x01 AND y01 -> z02
x02 AND y02 -> z01
x03 AND y03 -> z03
x04 AND y04 -> z04
x05 AND y05 -> z00