#include #include #include #include "maps.h" #include "program.h" #include "ant.h" #define TICKS 2000 #define MAX_OPS 64 #define NUM_CHANNELS 4 const char map_offsets[] = { 0, -MAP_WIDTH , 1, MAP_WIDTH, -1 }; #define MIN(X,Y) ((X) < (Y) ? (X) : (Y)) #define MAX(X,Y) ((X) > (Y) ? (X) : (Y)) #define cell_from(org, dir) (org) + map_offsets[(dir)] #define reg_id(rid) (rid) < 8 ? (rid) : (rid) - 0x80 #define get_value(ant, v) (v) < 0x80 ? (v) : get_reg((ant), (v)) static inline unsigned int rnum(unsigned int* rstate) { unsigned int e = *rstate + 0x9e3779b9; *rstate = e; e = (e ^ (e >> 16)) * 0x85ebca6b; e = (e ^ (e >> 13)) * 0xc2b2ae35; e = e ^ (e >> 16); //e = e / 0x100000000; return e; } // static inline unsigned int rnum(unsigned int* rstate) { // return rand(); // } static inline void set_reg(struct Ant* ant, unsigned char rid, unsigned int v) { switch(reg_id(rid)) { case 0: ant->r0 = v; break; case 1: ant->r1 = v; break; case 2: ant->r2 = v; break; case 3: ant->r3 = v; break; case 4: ant->r4 = v; break; case 5: ant->r5 = v; break; case 6: ant->r6 = v; break; case 7: ant->r7 = v; break; } } static inline unsigned int get_reg(struct Ant* ant, unsigned char rid) { switch(reg_id(rid)) { case 0: return ant->r0; case 1: return ant->r1; case 2: return ant->r2; case 3: return ant->r3; case 4: return ant->r4; case 5: return ant->r5; case 6: return ant->r6; case 7: return ant->r7; default: return 0; } } #ifdef DEBUG #define debug(msg, ...) printf((msg), ##__VA_ARGS__) #else #define debug(msg, ...) #endif #define debug_ant(ant) debug("A%d @%d:%d R:%02x %02x %02x %02x %02x %02x %02x %02x\n", (ant)->id, (ant)->cell % MAP_WIDTH, (ant)->cell / MAP_WIDTH, (ant)->r0, (ant)->r1, (ant)->r2, (ant)->r3, (ant)->r4, (ant)->r5, (ant)->r6, (ant)->r7) #define debug_ins(pc, ins) debug("I%02d %s %02x %02x %02x\n", pc, instruction_names[ins->op], ins->arg1, ins->arg2, ins->arg3) int run_simulations(struct Maps* maps, struct Program* program) { int ops; int cost; int score; int dirs[4]; unsigned int rstate; int cell; int found_dirs = 0; struct Map* map; int v1, v2, v3, res; struct Ant* ant; unsigned int pc; struct Instruction* ins; struct Ant* ants = create_ants(); unsigned char food[NUM_CELLS]; unsigned char smells[NUM_CHANNELS][NUM_CELLS]; for (unsigned int mi = 0; mi < maps->num_maps; mi++) { map = &maps->maps + mi; debug("MAP %s\n", map->name); memset(&smells, 0, NUM_CHANNELS * NUM_CELLS); reset_ants(ants, map->nest); score = 0; rstate = 2; for (int i = 0; i < NUM_CELLS; i++ ) { food[i] = map->cells[i] == CELL_FOOD ? 1 : 0; } for (int t=0; t < TICKS; t++) { for (int ai=0; ai < NUM_ANTS; ai++) { ops = 0; while (ops < MAX_OPS) { cost = 1; ant = &ants[ai]; pc = ant->pc; ins = &program->instructions + pc; debug_ins(pc, ins); ant->pc = (pc + 1) % program->num_instructions; switch(ins->op) { case INS_ID: set_reg(ant, ins->arg1, ant->id); break; case INS_TAG: //noop break; case INS_MOVE: v1 = get_value(ant, ins->arg1); if (v1 == 5) { v1 = rnum(&rstate) % 4 + 1; } cell = cell_from(ant->cell, v1); if (cell > 0 && cell < NUM_CELLS && map->cells[cell] != CELL_WALL) { ant->cell = cell; } cost += MAX_OPS; break; case INS_SENSE: v1 = get_value(ant, ins->arg1); v2 = ins->arg2; found_dirs = 0; if (map->cells[cell_from(ant->cell, 1)] == v1) dirs[found_dirs++] = 1; if (map->cells[cell_from(ant->cell, 2)] == v1) dirs[found_dirs++] = 2; if (map->cells[cell_from(ant->cell, 3)] == v1) dirs[found_dirs++] = 3; if (map->cells[cell_from(ant->cell, 4)] == v1) dirs[found_dirs++] = 4; if (found_dirs == 0) { res = 0; } else if (found_dirs == 1) { res = dirs[0]; } else { res = dirs[rnum(&rstate) % found_dirs]; } set_reg(ant, v2, res); break; case INS_PROBE: v1 = get_value(ant, ins->arg1); v1 = cell_from(ant->cell, v1); v1 = map->cells[v1]; set_reg(ant, ins->arg2, v1); break; case INS_PICKUP: debug("PICKUP?\n"); if (!ant->carrying && food[ant->cell] > 0) { ant->carrying = food[ant->cell]--; debug("PICKUP!\n"); } cost += MAX_OPS; break; case INS_CARRYING: set_reg(ant, ins->arg1, ant->carrying); break; case INS_DROP: debug("DROP?\n"); if (ant->carrying) { ant -> carrying = 0; if (map->nest == ant->cell){ debug("DROP SCORE\n"); score += 1; } else { food[ant->cell] += 1; debug("DROP!\n"); } } cost += MAX_OPS; break; case INS_SMELL: v1 = get_value(ant, ins->arg1); v2 = ins->arg2; res = 0; v3 = smells[v1][cell_from(ant->cell, 1)]; if (v3 > res) found_dirs = 0; if (v3 >= res) dirs[found_dirs++] = 1; v3 = smells[v1][cell_from(ant->cell, 2)]; if (v3 > res) found_dirs = 0; if (v3 >= res) dirs[found_dirs++] = 2; v3 = smells[v1][cell_from(ant->cell, 3)]; if (v3 > res) found_dirs = 0; if (v3 >= res) dirs[found_dirs++] = 3; v3 = smells[v1][cell_from(ant->cell, 4)]; if (v3 > res) found_dirs = 0; if (v3 >= res) dirs[found_dirs++] = 4; if (res == 0) { res = (rnum(&rstate) % 4) + 1; }else if (found_dirs == 1) { res = dirs[0]; } else { res = dirs[rnum(&rstate) % found_dirs]; } set_reg(ant, v2, res); break; case INS_SNIFF: v1 = ins->arg1; v2 = get_value(ant, ins->arg2); v2 = cell_from(ant->cell, v2); v1 = smells[v1][v2]; set_reg(ant, ins->arg3, v1); break; case INS_MARK: v1 = get_value(ant, ins->arg1); v2 = get_value(ant, ins->arg2); v3 = smells[v1][ant->cell]; smells[v1][ant->cell] = MAX(v3+v2, 255); break; case INS_SET: set_reg(ant, ins->arg1, ins->arg2); break; case INS_AND: v1 = get_value(ant, ins->arg1); v2 = get_value(ant, ins->arg2); set_reg(ant, ins->arg1, v1 & v2); break; case INS_OR: v1 = get_value(ant, ins->arg1); v2 = get_value(ant, ins->arg2); set_reg(ant, ins->arg1, v1 | v2); break; case INS_XOR: v1 = get_value(ant, ins->arg1); v2 = get_value(ant, ins->arg2); set_reg(ant, ins->arg1, v1 | v2); break; case INS_LSHIFT: v1 = get_value(ant, ins->arg1); v2 = get_value(ant, ins->arg2); set_reg(ant, ins->arg1, v1 << v2); break; case INS_RSHIFT: v1 = get_value(ant, ins->arg1); v2 = get_value(ant, ins->arg2); set_reg(ant, ins->arg1, v1 >> v2); break; case INS_ADD: v1 = get_value(ant, ins->arg1); v2 = get_value(ant, ins->arg2); set_reg(ant, ins->arg1, v1 + v2); break; case INS_SUB: v1 = get_value(ant, ins->arg1); v2 = get_value(ant, ins->arg2); set_reg(ant, ins->arg1, v1 - v2); break; case INS_MUL: v1 = get_value(ant, ins->arg1); v2 = get_value(ant, ins->arg2); set_reg(ant, ins->arg1, v1 * v2); break; case INS_DIV: v1 = get_value(ant, ins->arg1); v2 = get_value(ant, ins->arg2); if (v2 != 0) { set_reg(ant, ins->arg1, v1 / v2); } break; case INS_MOD: v1 = get_value(ant, ins->arg1); v2 = get_value(ant, ins->arg2); set_reg(ant, ins->arg1, v1 % v2); break; case INS_RANDOM: v2 = get_value(ant, ins->arg2); if (v2 != 0) { v1 = rnum(&rstate) % v2; set_reg(ant, ins->arg1, v1); } break; case INS_SJR: ant->jr = *((int*)ins) >> 8; break; case INS_MJR: ant->jr = get_value(ant, ins->arg1); break; case INS_JMP: ant->pc = ant->jr; break; case INS_CALL: set_reg(ant, ins->arg1, ant->pc); ant->pc = ant->jr; break; case INS_JEQ: v1 = get_value(ant, ins->arg1); v2 = get_value(ant, ins->arg2); if (v1 == v2) { ant->pc = ant->jr; } break; case INS_JNE: v1 = get_value(ant, ins->arg1); v2 = get_value(ant, ins->arg2); if (v1 != v2) { ant->pc = ant->jr; } break; case INS_JGT: v1 = get_value(ant, ins->arg1); v2 = get_value(ant, ins->arg2); if (v1 > v2) { ant->pc = ant->jr; } break; case INS_JLT: v1 = get_value(ant, ins->arg1); v2 = get_value(ant, ins->arg2); if (v1 < v2) { ant->pc = ant->jr; } break; }; debug_ant(ant); ops += cost; } } for (int pi = 0; pi < NUM_CHANNELS; pi++) { for (int ci = 0; ci < NUM_CELLS; ci++) { if (smells[pi][ci] > 0) smells[pi][ci]--; } } } } return score; } int main(int argc, char* argv[]) { struct Program* program = NULL; struct Maps* maps = NULL; int score = 0; if (argc < 3) { printf("Usage: farm \n"); return 1; } char* maps_filename = argv[1]; char* program_filename = argv[2]; maps = load_maps(maps_filename); program = load_program(program_filename); int result = 0; if (maps == NULL) { printf("Could not load maps\n"); result = 2; }else if (program == NULL) { printf("Could not load program\n"); result = 3; } else { score = run_simulations(maps, program); } free(program); free(maps); printf("Score: %d\n", score); return result; }