mid-kid
6 years ago
3 changed files with 4422 additions and 0 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 |
File diff suppressed because it is too large
@ -0,0 +1,262 @@ |
|||
#include <stdlib.h> |
|||
#include <stdio.h> |
|||
|
|||
#include <glib.h> |
|||
|
|||
#define REGS 4 |
|||
|
|||
typedef long 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; |
|||
}; |
|||
|
|||
struct sample { |
|||
reg_t before[REGS]; |
|||
reg_t after[REGS]; |
|||
struct instr instr; |
|||
}; |
|||
|
|||
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 sample *parse_samples(const char *fname, int *len, |
|||
struct instr **program, int *program_len) |
|||
{ |
|||
FILE *f = fopen(fname, "r"); |
|||
if (!f) { |
|||
perror(fname); |
|||
return NULL; |
|||
} |
|||
|
|||
GArray *array = g_array_new(FALSE, FALSE, sizeof(struct sample)); |
|||
|
|||
// Haha what is proper parsing
|
|||
struct sample sample; |
|||
while (fscanf(f, |
|||
"Before: [%ld, %ld, %ld, %ld]\n" |
|||
"%d %d %d %d\n" |
|||
"After: [%ld, %ld, %ld, %ld]\n\n", |
|||
&sample.before[0], &sample.before[1], |
|||
&sample.before[2], &sample.before[3], |
|||
(int *)&sample.instr.i, &sample.instr.a, |
|||
&sample.instr.b, &sample.instr.c, |
|||
&sample.after[0], &sample.after[1], |
|||
&sample.after[2], &sample.after[3] |
|||
) == 12) { |
|||
g_array_append_val(array, sample); |
|||
} |
|||
|
|||
fscanf(f, "\n\n"); |
|||
|
|||
GArray *prog_array = g_array_new(FALSE, FALSE, sizeof(struct instr)); |
|||
|
|||
struct instr instr; |
|||
while (fscanf(f, "%d %d %d %d\n", |
|||
(int *)&instr.i, &instr.a, &instr.b, &instr.c) == 4) { |
|||
g_array_append_val(prog_array, instr); |
|||
} |
|||
|
|||
fclose(f); |
|||
|
|||
*program_len = prog_array->len; |
|||
*program = (struct instr *)g_array_free(prog_array, FALSE); |
|||
|
|||
*len = array->len; |
|||
return (struct sample *)g_array_free(array, FALSE); |
|||
} |
|||
|
|||
int main() |
|||
{ |
|||
int samples_len; |
|||
struct instr *program; |
|||
int program_len; |
|||
struct sample *samples = parse_samples("input", &samples_len, |
|||
&program, &program_len); |
|||
if (!samples) return 1; |
|||
|
|||
reg_t *regs = g_new0(reg_t, REGS); |
|||
enum instr_id *mapping = g_new(enum instr_id, INSTR_ID_COUNT); |
|||
|
|||
for (enum instr_id *map = mapping; |
|||
map < mapping + INSTR_ID_COUNT; map++) { |
|||
*map = INSTR_ID_COUNT; |
|||
} |
|||
|
|||
int changed = 1; |
|||
|
|||
while (changed) { |
|||
changed = 0; |
|||
|
|||
for (enum instr_id id = 0; id < INSTR_ID_COUNT; id++) { |
|||
if (mapping[id] != INSTR_ID_COUNT) continue; |
|||
|
|||
int possible[INSTR_ID_COUNT] = {[0 ... INSTR_ID_COUNT - 1] = 1}; |
|||
for (enum instr_id *map = mapping; |
|||
map < mapping + INSTR_ID_COUNT; map++) { |
|||
if (*map != INSTR_ID_COUNT) possible[*map] = 0; |
|||
} |
|||
|
|||
for (struct sample *sample = samples; |
|||
sample < samples + samples_len; sample++) { |
|||
if (sample->instr.i != id) continue; |
|||
|
|||
struct instr instr; |
|||
memcpy(&instr, &sample->instr, sizeof(struct instr)); |
|||
for (enum instr_id i = 0; i < INSTR_ID_COUNT; i++) { |
|||
if (!possible[i]) continue; |
|||
|
|||
instr.i = i; |
|||
memcpy(regs, sample->before, sizeof(reg_t) * REGS); |
|||
instr_interpret(regs, &instr); |
|||
if (memcmp(regs, sample->after, sizeof(reg_t) * REGS) != 0) { |
|||
possible[i] = 0; |
|||
} |
|||
} |
|||
} |
|||
|
|||
printf("%02d: ", id); |
|||
for (enum instr_id i = 0; i < INSTR_ID_COUNT; i++) { |
|||
if (possible[i]) printf("%s ", instr_str[i]); |
|||
} |
|||
putchar('\n'); |
|||
|
|||
int tally = 0; |
|||
for (int *i = possible; i < possible + INSTR_ID_COUNT; i++) tally += *i; |
|||
if (!tally) { |
|||
fprintf(stderr, "Instruction %d could not be identified!\n", id); |
|||
goto error; |
|||
} |
|||
if (tally != 1) continue; |
|||
|
|||
for (enum instr_id i = 0; i < INSTR_ID_COUNT; i++) { |
|||
if (possible[i]) { |
|||
mapping[id] = i; |
|||
break; |
|||
} |
|||
} |
|||
changed = 1; |
|||
printf("-- %02d: %s (%02d)\n", id, instr_str[mapping[id]], mapping[id]); |
|||
} |
|||
} |
|||
|
|||
putchar('\n'); |
|||
for (int i = 0; i < INSTR_ID_COUNT; i++) { |
|||
printf("%02d: %s (%02d)\n", i, instr_str[mapping[i]], mapping[i]); |
|||
} |
|||
|
|||
memset(regs, 0, sizeof(reg_t) * REGS); |
|||
for (struct instr *instr = program; |
|||
instr < program + program_len; instr++) { |
|||
if (instr->i >= INSTR_ID_COUNT) { |
|||
fprintf(stderr, "ERROR: Invalid instruction ID %d\n", (int)instr->i); |
|||
goto error; |
|||
} |
|||
|
|||
instr->i = mapping[instr->i]; |
|||
instr_interpret(regs, instr); |
|||
} |
|||
|
|||
printf("%lu\n", regs[0]); |
|||
|
|||
error: |
|||
g_free(mapping); |
|||
g_free(regs); |
|||
g_free(program); |
|||
g_free(samples); |
|||
return 0; |
|||
} |
Loading…
Reference in new issue