#define _GNU_SOURCE #include #include #include #include #define STACK_SZ UINT8_MAX+1 typedef uint8_t stackpointer_t; uint64_t parse_number(char *end); int main(int argc, char **argv) { FILE *input; char *line = NULL; size_t line_length = 0; if (argc == 1 || argv[1][0] == '-') input = stdin; else if ((input = fopen(argv[1], "r")) == NULL) { fprintf(stderr, "Cannot open file %s\n", argv[1]); return -1; } uint64_t total_copies = 0; size_t winning_numbers_len = 0; uint8_t *winning_numbers = NULL; char *colon_pos = NULL, *pipe_pos = NULL; uint64_t stack[STACK_SZ] = {0}; stackpointer_t stack_pos = 0; while (getline(&line, &line_length, input) != -1) { colon_pos = strchr(line, ':'); pipe_pos = strchr(line, '|'); if (winning_numbers == NULL) { winning_numbers_len = (pipe_pos - colon_pos - 2) / 3; winning_numbers = (uint8_t *) calloc(winning_numbers_len, sizeof(uint8_t)); } for (size_t i = 0, wl_pos = (size_t)colon_pos+4; i < winning_numbers_len; ++i, wl_pos += 3) winning_numbers[i] = parse_number((char *)(wl_pos-1)); uint64_t card_copies = 1 + stack[stack_pos++]; total_copies += card_copies; stackpointer_t old_sp = stack_pos; for (char *n_pos = pipe_pos + 4;; n_pos += 3) { uint8_t n = parse_number(n_pos-1); for (size_t i = 0; i < winning_numbers_len; ++i) { if (n != winning_numbers[i]) continue; stack[stack_pos++] += card_copies; break; } if (*n_pos == '\n') break; } stack_pos = old_sp; memset(line, 0, line_length); } free(winning_numbers); printf("%lu\n", total_copies); return 0; } uint64_t parse_number(char *end) { uint64_t num = 0; for (size_t n = 1;; n *= 10) { if (*end>>4 != 0x3) break; num += (*end&0xf) * n; --end; } return num; }