initial
This commit is contained in:
392
farm/farm.c
Normal file
392
farm/farm.c
Normal file
@@ -0,0 +1,392 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#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 <maps file> <program file>\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;
|
||||
}
|
||||
Reference in New Issue
Block a user