#include #include #include #define REGS 6 typedef int reg_t; enum instr_id { INSTR_ADDR, INSTR_ADDI, INSTR_MULR, INSTR_MULI, INSTR_BANR, INSTR_BANI, INSTR_BORR, INSTR_BORI, INSTR_SETR, INSTR_SETI, INSTR_GTIR, INSTR_GTRI, INSTR_GTRR, INSTR_EQIR, INSTR_EQRI, INSTR_EQRR, INSTR_ID_COUNT }; struct instr { enum instr_id i; int a; int b; int c; }; const char *instr_str[] = { "addr", "addi", "mulr", "muli", "banr", "bani", "borr", "bori", "setr", "seti", "gtir", "gtri", "gtrr", "eqir", "eqri", "eqrr" }; void instr_interpret(reg_t *r, struct instr *i) { switch (i->i) { case INSTR_ADDR: case INSTR_MULR: case INSTR_BANR: case INSTR_BORR: case INSTR_GTRR: case INSTR_EQRR: if (i->b >= REGS) return; // fallthrough case INSTR_ADDI: case INSTR_MULI: case INSTR_BANI: case INSTR_BORI: case INSTR_SETR: case INSTR_GTRI: case INSTR_EQRI: if (i->a >= REGS) return; // fallthrough case INSTR_SETI: if (i->c >= REGS) return; break; case INSTR_GTIR: case INSTR_EQIR: if (i->b >= REGS) return; if (i->c >= REGS) return; break; default: break; } switch (i->i) { case INSTR_ADDR: r[i->c] = r[i->a] + r[i->b]; break; case INSTR_ADDI: r[i->c] = r[i->a] + i->b; break; case INSTR_MULR: r[i->c] = r[i->a] * r[i->b]; break; case INSTR_MULI: r[i->c] = r[i->a] * i->b; break; case INSTR_BANR: r[i->c] = r[i->a] & r[i->b]; break; case INSTR_BANI: r[i->c] = r[i->a] & i->b; break; case INSTR_BORR: r[i->c] = r[i->a] | r[i->b]; break; case INSTR_BORI: r[i->c] = r[i->a] | i->b; break; case INSTR_SETR: r[i->c] = r[i->a]; break; case INSTR_SETI: r[i->c] = i->a; break; case INSTR_GTIR: r[i->c] = (i->a > r[i->b]) ? 1 : 0; break; case INSTR_GTRI: r[i->c] = (r[i->a] > i->b) ? 1 : 0; break; case INSTR_GTRR: r[i->c] = (r[i->a] > r[i->b]) ? 1 : 0; break; case INSTR_EQIR: r[i->c] = (i->a == r[i->b]) ? 1 : 0; break; case INSTR_EQRI: r[i->c] = (r[i->a] == i->b) ? 1 : 0; break; case INSTR_EQRR: r[i->c] = (r[i->a] == r[i->b]) ? 1 : 0; break; default: break; } } struct instr *parse_instructions(const char *fname, int *len, int *ip) { FILE *f = fopen(fname, "r"); if (!f) { perror(fname); return NULL; } GArray *array = g_array_new(FALSE, FALSE, sizeof(struct instr)); char *line = NULL; size_t line_len = 0; while (getline(&line, &line_len, f) != -1) { char *args = strchr(line, ' '); if (!args) continue; *args++ = '\0'; if (strcmp(line, "#ip") == 0) { *ip = strtol(args, NULL, 0); continue; } struct instr instr = {0}; for (int i = 0; i < INSTR_ID_COUNT; i++) { if (strcmp(line, instr_str[i]) == 0) { instr.i = i; break; } } sscanf(args, "%d %d %d", &instr.a, &instr.b, &instr.c); g_array_append_val(array, instr); } free(line); fclose(f); *len = array->len; return (struct instr *)g_array_free(array, FALSE); } void print_regs(reg_t *regs, FILE *f) { putc('[', f); for (int i = 0; i < REGS - 1; i++) { fprintf(f, "%d, ", regs[i]); } fprintf(f, "%d]", regs[REGS - 1]); } int main(int argc, char *argv[]) { int debug = 0; if (argc > 1 && strcmp(argv[1], "-debug") == 0) debug = 1; int ip = 0; int instructions_len = 0; struct instr *instructions = parse_instructions("input", &instructions_len, &ip); if (!instructions) return 1; if (ip >= REGS) ip = 0; GHashTable *seen = g_hash_table_new(NULL, NULL); gpointer last = 0; reg_t *regs = g_new0(reg_t, REGS); while (regs[ip] >= 0 && regs[ip] < instructions_len) { struct instr *instr = &instructions[regs[ip]]; // Day 21 part 2 optimizations... if (regs[ip] == 17) { regs[5] >>= 8; regs[ip] = 8; continue; } if (debug) { fprintf(stderr, "ip=%d ", regs[ip]); print_regs(regs, stderr); fprintf(stderr, " %s %d %d %d ", instr_str[instr->i], instr->a, instr->b, instr->c); } instr_interpret(regs, instr); if (debug) { print_regs(regs, stderr); putc('\n', stderr); } // Day 21 part 2 solution... if (instr->i == INSTR_EQRR && (instr->a == 0 || instr->b == 0)) { int reg = instr->a; if (reg == 0) reg = instr->b; if (reg != 0 && reg < REGS) { gpointer val = GINT_TO_POINTER(regs[reg]); if (g_hash_table_contains(seen, val)) { printf("Last value: %p\n", last); break; } last = val; g_hash_table_add(seen, val); } } regs[ip]++; } print_regs(regs, stdout); putchar('\n'); g_hash_table_destroy(seen); g_free(regs); g_free(instructions); return 0; }