Skip to content

Commit

Permalink
Day 20, Part 2: WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
michaeladler committed Jan 2, 2024
1 parent 8f5ca20 commit d1356de
Showing 1 changed file with 139 additions and 71 deletions.
210 changes: 139 additions & 71 deletions src/day20/solve.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ typedef struct {

typedef struct {
CharSlice99 source, destination;
pulse_e input;
pulse_e pulse;
} state_t;

#define P
Expand All @@ -59,6 +59,106 @@ typedef struct {
static size_t module_t_hash(module_t *item) { return XXH3_64bits(item->name.ptr, item->name.len); }
static int module_t_equal(module_t *lhs, module_t *rhs) { return CharSlice99_primitive_eq(lhs->name, rhs->name); }

typedef struct {
i32 low_count;
i32 high_count;
pulse_e pulse; // pulse value of "from -> to"
} push_result_t;

static push_result_t push_button(ust_module_t *modules, CharSlice99 from, CharSlice99 to) {
push_result_t result = {.low_count = 0, .high_count = 0};

_cleanup_(que_state_t_free) que_state_t queue = que_state_t_init();
que_state_t_push(&queue, (state_t){.source = CharSlice99_from_str("button"),
.destination = CharSlice99_from_str("broadcaster"),
.pulse = PULSE_LOW});
while (!que_state_t_empty(&queue)) {
state_t *current = que_state_t_front(&queue);
/*
log_debug("%.*s -%c-> %.*s", current->source.len, current->source.ptr, current->input == PULSE_HIGH ? 'H' : 'L',
current->destination.len, current->destination.ptr);
*/
if (current->pulse == PULSE_HIGH) {
result.high_count++;
} else {
result.low_count++;
}
if (CharSlice99_primitive_eq(from, current->source) && CharSlice99_primitive_eq(to, current->destination)) {
result.pulse = current->pulse;
}

ust_module_t_node *node = ust_module_t_find(modules, (module_t){.name = current->destination});
if (node) {
module_t *m = &node->key;
switch (m->kind) {
case BROADCAST:
for (int i = 0; i < m->output_count; i++) {
state_t item = {
.source = current->destination,
.destination = m->output[i],
.pulse = current->pulse,
};
que_state_t_push(&queue, item);
}
break;
case FLIP_FLOP:
if (current->pulse == PULSE_LOW) {
m->state.on = !m->state.on;
for (int i = 0; i < m->output_count; i++) {
state_t item = {
.source = current->destination,
.destination = m->output[i],
.pulse = m->state.on ? PULSE_HIGH : PULSE_LOW,
};
que_state_t_push(&queue, item);
}
}
break;
case CONJUNCTION:
// the conjunction module first updates its memory for that input
for (int i = 0; i < m->state.list.len; i++) {
conjunction_item_t *item = &m->state.list.items[i];
if (CharSlice99_primitive_eq(item->name, current->source)) {
item->pulse = current->pulse;
break;
}
}
// if high pulses for all inputs, it sends a low pulse; otherwise, it sends a high pulse
pulse_e pulse = PULSE_LOW;
for (int i = 0; i < m->state.list.len; i++) {
conjunction_item_t *item = &m->state.list.items[i];
if (item->pulse == PULSE_LOW) {
pulse = PULSE_HIGH;
break;
}
}
for (int i = 0; i < m->output_count; i++) {
state_t item = {
.source = current->destination,
.destination = m->output[i],
.pulse = pulse,
};
que_state_t_push(&queue, item);
}
break;
}
}
que_state_t_pop(&queue);
}
return result;
}

static void reset_modules(ust_module_t *modules) {
foreach (ust_module_t, modules, it) {
module_t *m = &it.node->key;
if (m->kind == FLIP_FLOP) {
m->state.on = false;
} else if (m->kind == CONJUNCTION) {
for (int i = 0; i < m->state.list.len; i++) { m->state.list.items[i].pulse = PULSE_LOW; }
}
}
}

void solve(char *buf, size_t buf_size, Solution *result) {
i64 part1 = 0, part2 = 0;

Expand Down Expand Up @@ -103,11 +203,14 @@ void solve(char *buf, size_t buf_size, Solution *result) {
}

// initialize conjunction items with their incoming signals to low
CharSlice99 lg = {.len = 0};
foreach (ust_module_t, &modules, it) {
module_t *m = &it.node->key;
CharSlice99 source = m->name;
for (int i = 0; i < m->output_count; i++) {
CharSlice99 destination = m->output[i];
if (CharSlice99_primitive_eq(destination, CharSlice99_from_str("rx"))) { lg = source; }

ust_module_t_node *node = ust_module_t_find(&modules, (module_t){.name = destination});
if (node == NULL) continue;
module_t *dest_module = &node->key;
Expand All @@ -130,83 +233,48 @@ void solve(char *buf, size_t buf_size, Solution *result) {
}
}

_cleanup_(que_state_t_free) que_state_t queue = que_state_t_init();
i64 high_count = 0, low_count = 0;
int low_count = 0, high_count = 0;
CharSlice99 empty = CharSlice99_from_str("");
for (int round = 1; round <= 1000; round++) {
que_state_t_push(&queue, (state_t){.source = CharSlice99_from_str("button"),
.destination = CharSlice99_from_str("broadcaster"),
.input = PULSE_LOW});
while (!que_state_t_empty(&queue)) {
state_t *current = que_state_t_front(&queue);
log_debug("%.*s -%c-> %.*s", current->source.len, current->source.ptr,
current->input == PULSE_HIGH ? 'H' : 'L', current->destination.len, current->destination.ptr);
if (current->input == PULSE_HIGH) {
high_count++;
} else {
low_count++;
}
push_result_t hl = push_button(&modules, empty, empty);
low_count += hl.low_count, high_count += hl.high_count;
}
part1 = high_count * low_count;

ust_module_t_node *node = ust_module_t_find(&modules, (module_t){.name = current->destination});
if (node) {
module_t *m = &node->key;
switch (m->kind) {
case BROADCAST:
for (int i = 0; i < m->output_count; i++) {
state_t item = {
.source = current->destination,
.destination = m->output[i],
.input = current->input,
};
que_state_t_push(&queue, item);
}
break;
case FLIP_FLOP:
if (current->input == PULSE_LOW) {
m->state.on = !m->state.on;
for (int i = 0; i < m->output_count; i++) {
state_t item = {
.source = current->destination,
.destination = m->output[i],
.input = m->state.on ? PULSE_HIGH : PULSE_LOW,
};
que_state_t_push(&queue, item);
}
}
break;
case CONJUNCTION:
// the conjunction module first updates its memory for that input
for (int i = 0; i < m->state.list.len; i++) {
conjunction_item_t *item = &m->state.list.items[i];
if (CharSlice99_primitive_eq(item->name, current->source)) {
item->pulse = current->input;
break;
}
}
// if high pulses for all inputs, it sends a low pulse; otherwise, it sends a high pulse
pulse_e pulse = PULSE_LOW;
for (int i = 0; i < m->state.list.len; i++) {
conjunction_item_t *item = &m->state.list.items[i];
if (item->pulse == PULSE_LOW) {
pulse = PULSE_HIGH;
break;
}
}
for (int i = 0; i < m->output_count; i++) {
state_t item = {
.source = current->destination,
.destination = m->output[i],
.input = pulse,
};
que_state_t_push(&queue, item);
}
/*
* 1. &lg -> rx has to send a low pulse
* 2. So everything (4 modules) going into lq must send a high pulse.
* 3. For each of the 4 modules, check how many button presses it takes to send a high pulse to lq.
* 4. The answer is the lcm of these button presses.
*/
if (lg.len > 0) {
log_debug("rx source: %.*s", lg.len, lg.ptr);
ust_module_t_node *node = ust_module_t_find(&modules, (module_t){.name = lg});
module_t *lg_module = &node->key;
assert(lg_module->kind == CONJUNCTION);

CharSlice99 lg_sources[4];
for (int i = 0; i < lg_module->state.list.len; i++) {
lg_sources[i] = lg_module->state.list.items[i].name;
log_debug("source: %.*s", lg_sources[i].len, lg_sources[i].ptr);
}

i64 button_presses[4];
for (int i = 0; i < 4; i++) {
reset_modules(&modules);
i32 count = 0;
while (count > 0) {
push_result_t result = push_button(&modules, lg_sources[i], lg);
count++;
if (result.pulse == PULSE_HIGH) { // FIXME: this never happens
printf("took %d button presses", count);
button_presses[i] = count;
break;
}
}
que_state_t_pop(&queue);
assert(count > 0);
}
log_debug("round %d: low_count: %ld, high_count: %ld", round, low_count, high_count);
}
part1 += high_count * low_count;

snprintf(result->part1, sizeof(result->part1), "%ld", part1);
snprintf(result->part2, sizeof(result->part2), "%ld", part2);
Expand Down

0 comments on commit d1356de

Please sign in to comment.