|
- //
- // Created by red on 05/12/19.
- //
-
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include "intcode.h"
-
- ival out_val(long n) {
- ival v;
- v.type = IVAL_OUT;
- v.num = n;
- return v;
- }
-
- ival err_val(long n) {
- ival v;
- v.type = IVAL_ERR;
- v.err = n;
- return v;
- }
-
- ival end_val() {
- ival v;
- v.type = IVAL_END;
- return v;
- }
-
- ival cont_val() {
- ival v;
- v.type = IVAL_CONT;
- return v;
- }
-
- void ival_print(ival v) {
- switch (v.type) {
- case IVAL_ERR: {
- switch (v.err) {
- case IERR_OUT_OF_BOUNDS: printf("error: read/write out of bounds\n");
- break;
- case IERR_BAD_OP: printf("error: bad opcode\n");
- break;
- }
- }
- case IVAL_OUT: {
- printf("Output value: %ld\n", v.num);
- }
- }
- }
-
- int power (int base, int pow) {
- if (pow <= 0) return 1;
- else return base*power(base,pow-1);
- }
-
- void get_operands (intcode* m, long** operands) {
- long opcode = m->tape[m->index] / 100;
- for (size_t i = 0; i < 3; i++) {
- long addr_mode = opcode % 10;
- opcode = opcode / 10;
- long* v = 0;
- switch (addr_mode) {
- case 0: v = &m->tape[m->tape[m->index + i + 1]]; break;
- case 1: v = &m->tape[m->index + i + 1]; break;
- case 2: {
- long delta = m->tape[m->index + i + 1];
- v = &m->tape[m->relative_base + delta];
- }
- }
- operands[i] = v;
- }
- }
-
- ival op_add (intcode* m, long** operands) {
- *operands[2] = *operands[0] + *operands[1];
- m->index += 4;
- return cont_val();
- }
-
- ival op_mul (intcode* m, long** operands) {
- *operands[2] = *operands[0] * *operands[1];
- m->index += 4;
- return cont_val();
- }
-
- ival op_in (intcode* m, long** operands) {
- *operands[0] = m->input_tape[0];
- m->index += 2;
- m->input_tape = m->input_tape+1;
- return cont_val();
- }
-
- ival op_out (intcode* m, long** operands) {
- m->index += 2;
- long v = *operands[0];
- return out_val(v);
- }
-
- ival op_jnz (intcode* m, long** operands) {
- if (*operands[0] != 0) {
- m->index = (size_t) *operands[1];
- } else {
- m->index += 3;
- }
- return cont_val();
- }
-
- ival op_jez (intcode* m, long** operands) {
- if (*operands[0] == 0) {
- m->index = (size_t) *operands[1];
- } else {
- m->index += 3;
- }
- return cont_val();
- }
-
- ival op_lt (intcode* m, long** operands) {
- long result;
- if (*operands[0] < *operands[1]) {
- result = 1;
- } else result = 0;
- *operands[2] = result;
- m->index += 4;
- return cont_val();
- }
-
- ival op_eq (intcode* m, long** operands) {
- long result;
- if (*operands[0] == *operands[1]) {
- result = 1;
- } else result = 0;
- *operands[2] = result;
- m->index += 4;
- return cont_val();
- }
-
- ival op_rbs (intcode* m, long** operands) {
- m->relative_base += *operands[0];
- m->index += 2;
- return cont_val();
- }
-
- ival step (intcode* m) {
- long* operands[3];
- get_operands(m, operands);
- long opcode = m->tape[m->index];
- opcode = opcode % 100;
- switch (opcode) {
- case 99: return end_val();
- case 1: return op_add(m, operands);
- case 2: return op_mul(m, operands);
- case 3: return op_in(m, operands);
- case 4: return op_out(m, operands);
- case 5: return op_jnz(m, operands);
- case 6: return op_jez(m, operands);
- case 7: return op_lt(m, operands);
- case 8: return op_eq(m, operands);
- case 9: return op_rbs(m, operands);
- default: return err_val(IERR_BAD_OP);
- }
- }
-
- ival run (intcode* m) {
- for (;;) {
- //size_t i = m->index;
- //printf("DEBUG: next 4 values: %d %d %d %d\n", m->tape[i], m->tape[i+1], m->tape[i+2], m->tape[i+3]);
- ival v = step(m);
- switch (v.type) {
- case IVAL_ERR:
- case IVAL_END:
- case IVAL_OUT: return v;
- default: break;
- }
- }
- };
-
- intcode* read_file(char *filename, size_t buf_size) {
- long* tape = calloc(buf_size, sizeof(long));
- memset((void*) tape, 0, sizeof(long)*buf_size);
- FILE* file = fopen(filename, "r");
- size_t i;
- for (i = 0; i < buf_size; i++) {
- long a;
- long err = fscanf(file, "%ld,", &a);
- if (err == EOF) break;
- tape[i] = a;
- }
- static intcode v;
- v.tape = tape;
- v.index = 0;
- v.tape_l = i;
- v.relative_base = 0;
- return &v;
- }
-
- intcode *clone(intcode *m, size_t buf_size) {
- static intcode v;
- long* tape = calloc(buf_size, sizeof(long));
- memcpy((void*) tape, (void*) m->tape, sizeof(long)*m->tape_l);
- v.tape = tape;
- v.index = 0;
- v.tape_l = m->tape_l;
- v.relative_base = m->relative_base;
- return &v;
- }
|