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