initial
This commit is contained in:
6
farm/Dockerfile
Normal file
6
farm/Dockerfile
Normal file
@@ -0,0 +1,6 @@
|
||||
FROM debian
|
||||
RUN apt update && apt install -y curl vim wget xz-utils build-essential less
|
||||
RUN useradd -m dev
|
||||
USER dev
|
||||
WORKDIR /home/dev/farm
|
||||
ADD . /home/dev/farm
|
||||
194
farm/Makefile
Normal file
194
farm/Makefile
Normal file
@@ -0,0 +1,194 @@
|
||||
#### PROJECT SETTINGS ####
|
||||
# The name of the executable to be created
|
||||
BIN_NAME := farm
|
||||
# Compiler used
|
||||
CC ?= gcc
|
||||
# Extension of source files used in the project
|
||||
SRC_EXT = c
|
||||
# Path to the source directory, relative to the makefile
|
||||
SRC_PATH = .
|
||||
# Space-separated pkg-config libraries used by this project
|
||||
LIBS =
|
||||
# General compiler flags
|
||||
COMPILE_FLAGS = -std=c99 -Wall -Wextra -g
|
||||
# Additional release-specific flags
|
||||
RCOMPILE_FLAGS = -D NDEBUG
|
||||
# Additional debug-specific flags
|
||||
DCOMPILE_FLAGS = -D DEBUG
|
||||
# Add additional include paths
|
||||
INCLUDES = -I $(SRC_PATH)
|
||||
# General linker settings
|
||||
LINK_FLAGS =
|
||||
# Additional release-specific linker settings
|
||||
RLINK_FLAGS =
|
||||
# Additional debug-specific linker settings
|
||||
DLINK_FLAGS =
|
||||
# Destination directory, like a jail or mounted system
|
||||
DESTDIR = /
|
||||
# Install path (bin/ is appended automatically)
|
||||
INSTALL_PREFIX = usr/local
|
||||
#### END PROJECT SETTINGS ####
|
||||
|
||||
# Optionally you may move the section above to a separate config.mk file, and
|
||||
# uncomment the line below
|
||||
# include config.mk
|
||||
|
||||
# Generally should not need to edit below this line
|
||||
|
||||
# Obtains the OS type, either 'Darwin' (OS X) or 'Linux'
|
||||
UNAME_S:=$(shell uname -s)
|
||||
|
||||
# Function used to check variables. Use on the command line:
|
||||
# make print-VARNAME
|
||||
# Useful for debugging and adding features
|
||||
print-%: ; @echo $*=$($*)
|
||||
|
||||
# Shell used in this makefile
|
||||
# bash is used for 'echo -en'
|
||||
SHELL = /bin/bash
|
||||
# Clear built-in rules
|
||||
.SUFFIXES:
|
||||
# Programs for installation
|
||||
INSTALL = install
|
||||
INSTALL_PROGRAM = $(INSTALL)
|
||||
INSTALL_DATA = $(INSTALL) -m 644
|
||||
|
||||
# Append pkg-config specific libraries if need be
|
||||
ifneq ($(LIBS),)
|
||||
COMPILE_FLAGS += $(shell pkg-config --cflags $(LIBS))
|
||||
LINK_FLAGS += $(shell pkg-config --libs $(LIBS))
|
||||
endif
|
||||
|
||||
# Verbose option, to output compile and link commands
|
||||
export V := false
|
||||
export CMD_PREFIX := @
|
||||
ifeq ($(V),true)
|
||||
CMD_PREFIX :=
|
||||
endif
|
||||
|
||||
# Combine compiler and linker flags
|
||||
release: export CFLAGS := $(CFLAGS) $(COMPILE_FLAGS) $(RCOMPILE_FLAGS)
|
||||
release: export LDFLAGS := $(LDFLAGS) $(LINK_FLAGS) $(RLINK_FLAGS)
|
||||
debug: export CFLAGS := $(CFLAGS) $(COMPILE_FLAGS) $(DCOMPILE_FLAGS)
|
||||
debug: export LDFLAGS := $(LDFLAGS) $(LINK_FLAGS) $(DLINK_FLAGS)
|
||||
|
||||
# Build and output paths
|
||||
release: export BUILD_PATH := build/release
|
||||
release: export BIN_PATH := bin/release
|
||||
debug: export BUILD_PATH := build/debug
|
||||
debug: export BIN_PATH := bin/debug
|
||||
install: export BIN_PATH := bin/release
|
||||
|
||||
# Find all source files in the source directory, sorted by most
|
||||
# recently modified
|
||||
ifeq ($(UNAME_S),Darwin)
|
||||
SOURCES = $(shell find $(SRC_PATH) -name '*.$(SRC_EXT)' | sort -k 1nr | cut -f2-)
|
||||
else
|
||||
SOURCES = $(shell find $(SRC_PATH) -name '*.$(SRC_EXT)' -printf '%T@\t%p\n' \
|
||||
| sort -k 1nr | cut -f2-)
|
||||
endif
|
||||
|
||||
# fallback in case the above fails
|
||||
rwildcard = $(foreach d, $(wildcard $1*), $(call rwildcard,$d/,$2) \
|
||||
$(filter $(subst *,%,$2), $d))
|
||||
ifeq ($(SOURCES),)
|
||||
SOURCES := $(call rwildcard, $(SRC_PATH), *.$(SRC_EXT))
|
||||
endif
|
||||
|
||||
# Set the object file names, with the source directory stripped
|
||||
# from the path, and the build path prepended in its place
|
||||
OBJECTS = $(SOURCES:$(SRC_PATH)/%.$(SRC_EXT)=$(BUILD_PATH)/%.o)
|
||||
# Set the dependency files that will be used to add header dependencies
|
||||
DEPS = $(OBJECTS:.o=.d)
|
||||
|
||||
# Version macros
|
||||
# Comment/remove this section to remove versioning
|
||||
USE_VERSION := false
|
||||
# If this isn't a git repo or the repo has no tags, git describe will return non-zero
|
||||
ifeq ($(shell git describe > /dev/null 2>&1 ; echo $$?), 0)
|
||||
USE_VERSION := true
|
||||
VERSION := $(shell git describe --tags --long --dirty --always | \
|
||||
sed 's/v\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)-\?.*-\([0-9]*\)-\(.*\)/\1 \2 \3 \4 \5/g')
|
||||
VERSION_MAJOR := $(word 1, $(VERSION))
|
||||
VERSION_MINOR := $(word 2, $(VERSION))
|
||||
VERSION_PATCH := $(word 3, $(VERSION))
|
||||
VERSION_REVISION := $(word 4, $(VERSION))
|
||||
VERSION_HASH := $(word 5, $(VERSION))
|
||||
VERSION_STRING := \
|
||||
"$(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_PATCH).$(VERSION_REVISION)-$(VERSION_HASH)"
|
||||
override CFLAGS := $(CFLAGS) \
|
||||
-D VERSION_MAJOR=$(VERSION_MAJOR) \
|
||||
-D VERSION_MINOR=$(VERSION_MINOR) \
|
||||
-D VERSION_PATCH=$(VERSION_PATCH) \
|
||||
-D VERSION_REVISION=$(VERSION_REVISION) \
|
||||
-D VERSION_HASH=\"$(VERSION_HASH)\"
|
||||
endif
|
||||
|
||||
# Standard, non-optimized release build
|
||||
.PHONY: release
|
||||
release: dirs
|
||||
ifeq ($(USE_VERSION), true)
|
||||
@echo "Beginning release build v$(VERSION_STRING)"
|
||||
else
|
||||
@echo "Beginning release build"
|
||||
endif
|
||||
@$(MAKE) all --no-print-directory
|
||||
|
||||
# Debug build for gdb debugging
|
||||
.PHONY: debug
|
||||
debug: dirs
|
||||
ifeq ($(USE_VERSION), true)
|
||||
@echo "Beginning debug build v$(VERSION_STRING)"
|
||||
else
|
||||
@echo "Beginning debug build"
|
||||
endif
|
||||
@$(MAKE) all --no-print-directory
|
||||
|
||||
# Create the directories used in the build
|
||||
.PHONY: dirs
|
||||
dirs:
|
||||
@echo "Creating directories"
|
||||
@mkdir -p $(dir $(OBJECTS))
|
||||
@mkdir -p $(BIN_PATH)
|
||||
|
||||
# Installs to the set path
|
||||
.PHONY: install
|
||||
install:
|
||||
@echo "Installing to $(DESTDIR)$(INSTALL_PREFIX)/bin"
|
||||
@$(INSTALL_PROGRAM) $(BIN_PATH)/$(BIN_NAME) $(DESTDIR)$(INSTALL_PREFIX)/bin
|
||||
|
||||
# Uninstalls the program
|
||||
.PHONY: uninstall
|
||||
uninstall:
|
||||
@echo "Removing $(DESTDIR)$(INSTALL_PREFIX)/bin/$(BIN_NAME)"
|
||||
@$(RM) $(DESTDIR)$(INSTALL_PREFIX)/bin/$(BIN_NAME)
|
||||
|
||||
# Removes all build files
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@echo "Deleting $(BIN_NAME) symlink"
|
||||
@$(RM) $(BIN_NAME)
|
||||
@echo "Deleting directories"
|
||||
@$(RM) -r build
|
||||
@$(RM) -r bin
|
||||
|
||||
# Main rule, checks the executable and symlinks to the output
|
||||
all: $(BIN_PATH)/$(BIN_NAME)
|
||||
@echo "Making symlink: $(BIN_NAME) -> $<"
|
||||
@$(RM) $(BIN_NAME)
|
||||
@ln -s $(BIN_PATH)/$(BIN_NAME) $(BIN_NAME)
|
||||
|
||||
# Link the executable
|
||||
$(BIN_PATH)/$(BIN_NAME): $(OBJECTS)
|
||||
@echo "Linking: $@"
|
||||
$(CMD_PREFIX)$(CC) $(OBJECTS) $(LDFLAGS) -o $@
|
||||
|
||||
# Add dependency files, if they exist
|
||||
-include $(DEPS)
|
||||
|
||||
# Source file rules
|
||||
# After the first compilation they will be joined with the rules from the
|
||||
# dependency files to provide header dependencies
|
||||
$(BUILD_PATH)/%.o: $(SRC_PATH)/%.$(SRC_EXT)
|
||||
@echo "Compiling: $< -> $@"
|
||||
$(CMD_PREFIX)$(CC) $(CFLAGS) $(INCLUDES) -MP -MMD -c $< -o $@
|
||||
19
farm/ant.c
Normal file
19
farm/ant.c
Normal file
@@ -0,0 +1,19 @@
|
||||
#include "ant.h"
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
void reset_ants(struct Ant* ants, unsigned short nest) {
|
||||
memset(ants, 0, sizeof(struct Ant) * NUM_ANTS);
|
||||
for (int i = 0; i < NUM_ANTS; i++) {
|
||||
ants[i].id = i;
|
||||
ants[i].cell = nest;
|
||||
}
|
||||
}
|
||||
|
||||
struct Ant* create_ants() {
|
||||
int ants_size = sizeof(struct Ant) * NUM_ANTS;
|
||||
struct Ant *ants = (struct Ant *)malloc(ants_size);
|
||||
return ants;
|
||||
}
|
||||
25
farm/ant.h
Normal file
25
farm/ant.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#ifdef DEBUG
|
||||
#define NUM_ANTS 1
|
||||
#else
|
||||
#define NUM_ANTS 200
|
||||
#endif
|
||||
|
||||
struct Ant {
|
||||
unsigned char id;
|
||||
unsigned int pc;
|
||||
unsigned short cell;
|
||||
unsigned char carrying;
|
||||
int r0;
|
||||
int r1;
|
||||
int r2;
|
||||
int r3;
|
||||
int r4;
|
||||
int r5;
|
||||
int r6;
|
||||
int r7;
|
||||
int jr;
|
||||
|
||||
};
|
||||
|
||||
struct Ant* create_ants();
|
||||
void reset_ants(struct Ant* ants, unsigned short nest);
|
||||
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;
|
||||
}
|
||||
26
farm/maps.c
Normal file
26
farm/maps.c
Normal file
@@ -0,0 +1,26 @@
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "maps.h"
|
||||
struct Maps* load_maps(char* filename) {
|
||||
FILE* f = fopen(filename, "r");
|
||||
if (f == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
int num_maps;
|
||||
int num_read = fread(&num_maps, 4, 1, f);
|
||||
|
||||
if (num_read != 1 || num_maps > 10000) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int mapfile_size = sizeof(struct Map) * num_maps;
|
||||
struct Maps *maps = (struct Maps *)malloc(mapfile_size + 4);
|
||||
maps->num_maps = num_maps;
|
||||
num_read = fread(&maps->maps, 1, mapfile_size, f);
|
||||
if (num_read != mapfile_size) {
|
||||
return NULL;
|
||||
}
|
||||
fclose(f);
|
||||
return maps;
|
||||
}
|
||||
23
farm/maps.h
Normal file
23
farm/maps.h
Normal file
@@ -0,0 +1,23 @@
|
||||
|
||||
#define MAP_WIDTH 128
|
||||
#define MAP_HEIGHT 128
|
||||
#define NUM_CELLS MAP_WIDTH * MAP_HEIGHT
|
||||
#define MAP_NAME_LENGTH 32
|
||||
#define CELL_EMPTY 0
|
||||
#define CELL_WALL 1
|
||||
#define CELL_FOOD 2
|
||||
#define CELL_NEST 3
|
||||
|
||||
|
||||
struct Map {
|
||||
char name[MAP_NAME_LENGTH];
|
||||
unsigned short nest;
|
||||
unsigned char cells[MAP_WIDTH * MAP_HEIGHT];
|
||||
};
|
||||
|
||||
struct Maps {
|
||||
unsigned int num_maps;
|
||||
struct Map maps;
|
||||
};
|
||||
|
||||
struct Maps* load_maps(char* filename);
|
||||
24
farm/program.c
Normal file
24
farm/program.c
Normal file
@@ -0,0 +1,24 @@
|
||||
#include "program.h"
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
struct Program* load_program(char* filename) {
|
||||
FILE* f = fopen(filename, "r");
|
||||
if (f == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
int num_instructions;
|
||||
int num_read = fread(&num_instructions, 4, 1, f);
|
||||
if (num_read != 1) {
|
||||
return NULL;
|
||||
}
|
||||
int program_size = 4 + num_instructions * 4;
|
||||
struct Program* program = (struct Program *)malloc(program_size);
|
||||
program->num_instructions = num_instructions;
|
||||
num_read = fread(&program->instructions, 1, program_size-4, f);
|
||||
if (num_read != program_size-4) {
|
||||
return NULL;
|
||||
}
|
||||
fclose(f);
|
||||
return program;
|
||||
}
|
||||
70
farm/program.h
Normal file
70
farm/program.h
Normal file
@@ -0,0 +1,70 @@
|
||||
#define INS_NOOP 0
|
||||
#define INS_ID 1
|
||||
#define INS_TAG 2
|
||||
#define INS_MOVE 3
|
||||
|
||||
#define INS_SENSE 4
|
||||
#define INS_PROBE 5
|
||||
|
||||
#define INS_PICKUP 6
|
||||
#define INS_CARRYING 7
|
||||
#define INS_DROP 8
|
||||
|
||||
#define INS_SMELL 9
|
||||
#define INS_SNIFF 0xa
|
||||
#define INS_MARK 0xb
|
||||
|
||||
#define INS_SET 0x10
|
||||
#define INS_AND 0x11
|
||||
#define INS_OR 0x12
|
||||
#define INS_XOR 0x13
|
||||
#define INS_LSHIFT 0x14
|
||||
#define INS_RSHIFT 0x15
|
||||
#define INS_ADD 0x16
|
||||
#define INS_SUB 0x17
|
||||
#define INS_MUL 0x18
|
||||
#define INS_DIV 0x19
|
||||
#define INS_MOD 0x1a
|
||||
#define INS_RANDOM 0x1b
|
||||
|
||||
#define INS_SJR 0x20
|
||||
#define INS_MJR 0x21
|
||||
#define INS_JMP 0x22
|
||||
#define INS_CALL 0x23
|
||||
#define INS_JEQ 0x24
|
||||
#define INS_JNE 0x25
|
||||
#define INS_JGT 0x26
|
||||
#define INS_JLT 0x27
|
||||
|
||||
static char* instruction_names[256] = {
|
||||
/* 0x00 */ "NOOP", "ID ", "TAG ", "MOVE", "SENS", "PROB", "PICK", "CARY", "DROP", "SMEL", "SNIF", "MARK", "?", "?", "?", "?",
|
||||
/* 0x10 */ "SET ", "AND ", "OR ", "XOR ", "SHL ", "SHR ", "ADD ", "SUB ", "MUL ", "DIV ", "MOD", "RAND", "?", "?", "?", "?",
|
||||
/* 0x20 */ "SJR ", "MJR ", "JMP ", "CALL", "JEQ", "JNE ", "JGT ", "JLT ", "?", "?", "?", "?", "?", "?", "?", "?",
|
||||
/* 0x30 */ "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?",
|
||||
/* 0x40 */ "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?",
|
||||
/* 0x50 */ "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?",
|
||||
/* 0x60 */ "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?",
|
||||
/* 0x70 */ "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?",
|
||||
/* 0x80 */ "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?",
|
||||
/* 0x90 */ "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?",
|
||||
/* 0xa0 */ "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?",
|
||||
/* 0xb0 */ "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?",
|
||||
/* 0xc0 */ "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?",
|
||||
/* 0xd0 */ "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?",
|
||||
/* 0xe0 */ "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?",
|
||||
/* 0xf0 */ "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?",
|
||||
};
|
||||
|
||||
struct Instruction {
|
||||
unsigned char op;
|
||||
unsigned char arg1;
|
||||
unsigned char arg2;
|
||||
unsigned char arg3;
|
||||
};
|
||||
|
||||
struct Program {
|
||||
unsigned int num_instructions;
|
||||
struct Instruction instructions;
|
||||
};
|
||||
|
||||
struct Program* load_program(char* filename);
|
||||
Reference in New Issue
Block a user