Browse Source

day21p2

master
mid-kid 6 years ago
parent
commit
ab8bee199b
  1. 4
      day21p1/main.c
  2. 12
      day21p2/Makefile
  3. 32
      day21p2/input
  4. 64
      day21p2/input.dec
  5. 226
      day21p2/main.c

4
day21p1/main.c

@ -204,7 +204,7 @@ int main(int argc, char *argv[])
print_regs(regs, stdout); print_regs(regs, stdout);
putchar('\n'); putchar('\n');
free(regs); g_free(regs);
free(instructions); g_free(instructions);
return 0; return 0;
} }

12
day21p2/Makefile

@ -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

32
day21p2/input

@ -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

64
day21p2/input.dec

@ -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)

226
day21p2/main.c

@ -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…
Cancel
Save