#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>
typedef struct ll {
int val;
struct ll *nxt;
} ll;
int step(int *prog, int proglen, int *pc, FILE *input, int stage);
int read_prog(int *prog, int proglen, int pos, int mode);
void write_prog(int *prog, int proglen, int pos, int value);
int* do_read(int *len, FILE *source);
int ll_length(ll *head);
ll* ll_read(FILE *);
void ll_free(ll *head);
int* to_a(ll *head, int *len);
int main(int argc, char **argv) {
int proglen = 0;
int pc = 0;
int *prog = NULL;
int stage = 0;
if(argc != 4) {
fprintf(stderr, "Usage: day5 <part> <program> <input>\n");
return 1;
}
sscanf(argv[1], "%d", &stage);
FILE *src = strcmp(argv[2], "-") == 0 ? stdin : fopen(argv[2], "r");
FILE *input = strcmp(argv[3], "-") == 0 ? stdin: fopen(argv[3], "r");
if(src == input) {
fprintf(stderr, "Only one of <program> and <input> can be stdin\n");
return 1;
}
prog = do_read(&proglen, src);
while(step(prog, proglen, &pc, input, stage)) {}
printf("\n");
}
static inline unsigned int pow_i(int base, unsigned int p) {
int a = 1;
int b = base;
unsigned int x = 1;
while(x) {
if(x & p) {
a *= b;
}
b *= base;
x = x << 1;
}
return a;
}
static inline int get_mode(int opcode, int argn) {
return (opcode / pow_i(10, argn + 1)) % 10;
}
#define ARG(n) read_prog(prog, proglen, (*pc) + n, get_mode(prog[*pc], n))
int step(int *prog, int proglen, int *pc, FILE *input, int stage) {
static int delimiter = 0;
int n = 0;
if(*pc >= proglen) return 0;
switch(prog[*pc] % 10) {
case 1:
write_prog(prog, proglen, (*pc) + 3, ARG(1) + ARG(2));
*pc += 4;
return 1;
case 2:
write_prog(prog, proglen, (*pc) + 3, ARG(1) * ARG(2));
*pc += 4;
return 1;
case 3:
fscanf(input, "%d", &n);
fscanf(input, ",");
write_prog(prog, proglen,(*pc) + 1, n);
*pc += 2;
return 1;
case 4:
printf("%s%d", delimiter ? ", " : "", ARG(1));
delimiter = 1;
*pc += 2;
return 1;
case 5:
if(stage >= 2) {
if(ARG(1) != 0) {
*pc = ARG(2);
} else {
*pc += 3;
}
return 1;
} else {
return 0;
}
case 6:
if(stage >= 2) {
if(ARG(1) == 0) {
*pc = ARG(2);
} else {
*pc += 3;
}
return 1;
} else {
return 0;
}
case 7:
if(stage >= 2) {
write_prog(prog, proglen, (*pc) + 3, ARG(1) < ARG(2));
*pc += 4;
return 1;
} else {
return 0;
}
case 8:
if(stage >= 2) {
write_prog(prog, proglen, (*pc) + 3, ARG(1) == ARG(2));
*pc += 4;
return 1;
} else {
return 0;
}
default:
return 0;
}
}
int read_prog(int *prog, int proglen, int pos, int mode) {
if(pos < 0 || pos >= proglen) {
return 0;
}
if(mode) {
return prog[pos];
} else {
return read_prog(prog, proglen, prog[pos], 1);
}
}
void write_prog(int *prog, int proglen, int pos, int value) {
if(pos <= proglen) {
int real_pos = prog[pos];
if(real_pos <= proglen) {
prog[real_pos] = value;
}
}
}
int* do_read(int *len, FILE *source) {
ll* as_list = NULL;
int *r = NULL;
as_list = ll_read(source);
r = to_a(as_list, len);
ll_free(as_list);
return r;
}
int* to_a(ll *head, int *len) {
int *r = NULL;
int i = 0;
if(!head)
return NULL;
*len = ll_length(head);
r = malloc(*len * sizeof(int));
while(head) {
r[i++] = head->val;
head = head->nxt;
}
return r;
}
ll* ll_read(FILE *source) {
ll *head = NULL;
ll *cur = NULL;
ll *tmp = NULL;
int x;
while(!feof(source)) {
fscanf(source, "%d", &x);
fscanf(source, ",");
tmp = malloc(sizeof(ll));
tmp->val = x;
if(!head) {
head = tmp;
}
if(cur) {
cur->nxt = tmp;
}
cur = tmp;
}
return head;
}
int ll_length(ll *head) {
int r = 0;
while(head) {
r++;
head = head->nxt;
}
return r;
}
void ll_free(ll *head) {
ll *nxt;
while(head) {
nxt = head->nxt;
free(head);
head = nxt;
}
}