aoc-2021/src/day_8.c

229 lines
5.9 KiB
C

#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <math.h>
#include "puzzle_input.h"
#include "day.h"
#define SIGNAL_PATTERN_DIGITS 10
#define OUTPUT_DIGITS 4
#define MAX_ENTRIES 1000
typedef struct {
uint8_t signal_patterns[SIGNAL_PATTERN_DIGITS];
uint8_t outputs[OUTPUT_DIGITS];
} display_entry_t;
parse_ret_t parse_display(char * display_str, uint8_t * display_state) {
while (*display_str != '\0') {
uint8_t bit_to_set;
if (*display_str < 'a' || *display_str > 'g') {
return PARSER_INVALID;
}
bit_to_set = *display_str - 'a';
*display_state |= 1 << bit_to_set;
display_str++;
}
return PARSER_OK;
}
parse_ret_t parse_display_group(char * display_group_str, uint8_t * display_group, uint16_t display_group_max_len) {
char * tok = strtok(display_group_str, " ");
uint16_t display_index = 0;
if (display_group_str == NULL) {
return PARSE_NULL;
}
while (tok != NULL) {
parse_ret_t ret = parse_display(tok, &display_group[display_index]);
if (ret != PARSER_OK) {
return ret;
}
tok = strtok(NULL, " ");
display_index++;
if (display_index > display_group_max_len) {
return PARSER_RANGE_OVERFLOW;
}
}
if (display_index != display_group_max_len) {
return PARSER_INVALID;
}
return PARSER_OK;
}
parse_ret_t parse_display_entry(char * buffer, void * data, uint16_t index) {
display_entry_t * display_entries = (display_entry_t *)data;
char * signal_patterns = strtok(buffer, "|");
char * outputs = strtok(NULL, "|");
display_entry_t * entry = &display_entries[index];
parse_ret_t res;
res = parse_display_group(signal_patterns, entry->signal_patterns, SIGNAL_PATTERN_DIGITS);
if (res != PARSER_OK) {
return res;
}
res = parse_display_group(outputs, entry->outputs, OUTPUT_DIGITS);
if (res != PARSER_OK) {
return res;
}
return PARSER_OK;
}
uint8_t count_bits(uint8_t val) {
uint8_t on_count = 0;
for (int bit_ndx = 0; bit_ndx < 7; bit_ndx++) {
if ((val >> bit_ndx) & 0b1) {
on_count++;
}
}
return on_count;
}
static void part_1(display_entry_t * entries, uint16_t entry_len) {
uint32_t easy_digit_count = 0;
for (int entry_ndx = 0; entry_ndx < entry_len; entry_ndx++) {
display_entry_t * entry = &entries[entry_ndx];
uint32_t count_per_row = 0;
for (int disp_ndx = 0; disp_ndx < OUTPUT_DIGITS; disp_ndx++) {
uint8_t on_count = count_bits(entry->outputs[disp_ndx]);
switch (on_count) {
case 2: // 1
case 4: // 4
case 3: // 7
case 7: // 8
count_per_row++;
default:
break;
}
}
easy_digit_count += count_per_row;
}
printf("PART 1: Easy digit count is: %u\n", easy_digit_count);
}
static uint8_t fix_wire_crossing(uint8_t state, uint8_t crossed_four, uint8_t crossed_7) {
uint8_t new_state;
uint8_t on_count = count_bits(state);
switch (on_count) {
case 2: // 1
new_state = 1;
break;
case 3: // 7
new_state = 7;
break;
case 4: // 4
new_state = 4;
break;
case 5: // 2, 3, 5
if ((state & crossed_7) == crossed_7) {
new_state = 3;
}
else if (count_bits(state & crossed_four) == 3) {
new_state = 5;
}
else {
new_state = 2;
}
break;
case 6: // 0, 6, 9
if ((state & crossed_four) == crossed_four) {
new_state = 9;
}
else if ((state & crossed_7) == crossed_7) {
new_state = 0;
}
else {
new_state = 6;
}
break;
case 7: // 8
new_state = 8;
break;
default:
break;
}
return new_state;
}
static void part_2(display_entry_t * entries, uint16_t entry_len) {
uint32_t sum = 0;
for (int entry_ndx = 0; entry_ndx < entry_len; entry_ndx++) {
display_entry_t * entry = &entries[entry_ndx];
uint8_t crossed_4 = 0;
uint8_t crossed_7 = 0;
for (int disp_ndx = 0; disp_ndx < OUTPUT_DIGITS + SIGNAL_PATTERN_DIGITS; disp_ndx++) {
uint8_t display_state;
if (disp_ndx < SIGNAL_PATTERN_DIGITS) {
display_state = entry->signal_patterns[disp_ndx];
}
else {
display_state = entry->outputs[disp_ndx-OUTPUT_DIGITS];
}
uint8_t bit_count = count_bits(display_state);
if (bit_count == 4) {
crossed_4 = display_state;
}
else if (bit_count == 3) {
crossed_7 = display_state;
}
}
if (crossed_7 == 0 || crossed_4 == 0) {
printf("oopsie woopise, a lil fucky wucky\n");
return;
}
for (int disp_ndx = 0; disp_ndx < OUTPUT_DIGITS; disp_ndx++) {
uint8_t display_state = entry->outputs[disp_ndx];
uint8_t val = fix_wire_crossing(display_state, crossed_4, crossed_7);
sum += (val * (int32_t)pow(10, (OUTPUT_DIGITS-disp_ndx-1)));
}
}
printf("PART 2: Output sum: %d\n", sum);
}
display_entry_t entries_g[MAX_ENTRIES] = {0};
int day_8() {
parse_ret_t res;
uint16_t display_len;
res = read_input_single_line("../inputs/day_8.txt", (void *)entries_g, MAX_ENTRIES, parse_display_entry, &display_len);
if (res != PARSER_OK) {
printf("Unable to parse input: %d\n", res);
return -1;
}
part_1(entries_g, display_len);
part_2(entries_g, display_len);
return 0;
}