mid-kid
6 years ago
5 changed files with 336 additions and 2 deletions
@ -0,0 +1,12 @@ |
|||
CFLAGS := -Wall -Wextra -std=c17 -D_GNU_SOURCE |
|||
|
|||
LIBS := glib-2.0 |
|||
CFLAGS += $(shell pkg-config --cflags $(LIBS)) |
|||
LDLIBS := $(shell pkg-config --libs $(LIBS)) |
|||
|
|||
.PHONY: all |
|||
all: main |
|||
|
|||
.PHONY: clean |
|||
clean: |
|||
rm -f main |
@ -0,0 +1,32 @@ |
|||
#ip 4 |
|||
seti 123 0 2 |
|||
bani 2 456 2 |
|||
eqri 2 72 2 |
|||
addr 2 4 4 |
|||
seti 0 0 4 |
|||
seti 0 8 2 |
|||
bori 2 65536 5 |
|||
seti 2238642 0 2 |
|||
bani 5 255 3 |
|||
addr 2 3 2 |
|||
bani 2 16777215 2 |
|||
muli 2 65899 2 |
|||
bani 2 16777215 2 |
|||
gtir 256 5 3 |
|||
addr 3 4 4 |
|||
addi 4 1 4 |
|||
seti 27 3 4 |
|||
seti 0 8 3 |
|||
addi 3 1 1 |
|||
muli 1 256 1 |
|||
gtrr 1 5 1 |
|||
addr 1 4 4 |
|||
addi 4 1 4 |
|||
seti 25 4 4 |
|||
addi 3 1 3 |
|||
seti 17 2 4 |
|||
setr 3 9 5 |
|||
seti 7 9 4 |
|||
eqrr 2 0 3 |
|||
addr 3 4 4 |
|||
seti 5 0 4 |
@ -0,0 +1,64 @@ |
|||
#ip 4 |
|||
|
|||
; while (123 & 456 != 72); |
|||
00: seti 123 0 2 |
|||
01: bani 2 456 2 |
|||
02: eqri 2 72 2 |
|||
03: addr 2 4 4 |
|||
04: seti 0 0 4 |
|||
|
|||
05: seti 0 8 2 ; r2 = 0 |
|||
; xref 30 |
|||
06: bori 2 65536 5 ; r5 = r2 | 0x10000 |
|||
07: seti 2238642 0 2 ; r2 = 2238642 |
|||
; xref 27 |
|||
08: bani 5 255 3 ; r3 = r5 & 0xff |
|||
09: addr 2 3 2 ; r2 = r2 + r3 |
|||
10: bani 2 16777215 2 ; r2 = r2 & 0xffffff |
|||
11: muli 2 65899 2 ; r2 = r2 * 65899 |
|||
12: bani 2 16777215 2 ; r2 = r2 & 0xffffff |
|||
; trash = r3 |
|||
; keep = r2, r5 |
|||
|
|||
13: gtir 256 5 3 ; if (0x100 > r5) |
|||
14: addr 3 4 4 ; then |
|||
15: addi 4 1 4 ; (false) jr +1 (17) |
|||
16: seti 27 3 4 ; (true ) jp 27 (28) |
|||
|
|||
; xref 16 (256 <= r5) |
|||
; r5 >>= 8 |
|||
17: seti 0 8 3 ; r3 = 0 |
|||
18: addi 3 1 1 ; r1 = r3 + 1 |
|||
19: muli 1 256 1 ; r1 = r1 * 0x100 |
|||
20: gtrr 1 5 1 ; if (r1 > r5) |
|||
21: addr 1 4 4 ; then |
|||
22: addi 4 1 4 ; .. |
|||
23: seti 25 4 4 ; .. |
|||
24: addi 3 1 3 ; (false) r3 = r3 + 1 |
|||
25: seti 17 2 4 ; (false) jp 17 (18) |
|||
26: setr 3 9 5 ; (true ) r5 = r3 |
|||
27: seti 7 9 4 ; (true ) jp 07 (08) |
|||
|
|||
; xref 16 (256 > r5) |
|||
28: eqrr 2 0 3 ; if (r2 == r0) |
|||
29: addr 3 4 4 ; then |
|||
30: seti 5 0 4 ; (false) jp 05 (06) |
|||
; (true ) exit |
|||
|
|||
; ===== HIGH-LEVEL PSEUDOCODE ===== |
|||
|
|||
r2 = 0 |
|||
|
|||
do { |
|||
r5 = r2 | 0x10000 |
|||
r2 = 2238642 |
|||
|
|||
while (1) { |
|||
// r2 = (r2 + r5) * 65899 |
|||
r2 = (((r2 + (r5 & 0xff)) & 0xffffff) * 65899) & 0xffffff |
|||
|
|||
if (0x100 > r5) break |
|||
|
|||
r5 >>= 8 |
|||
} |
|||
} while (r2 != r0) |
@ -0,0 +1,226 @@ |
|||
#include <stdlib.h> |
|||
#include <stdio.h> |
|||
|
|||
#include <glib.h> |
|||
|
|||
#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; |
|||
} |
Loading…
Reference in new issue