| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722 |
- #include "simulator.h"
- Simulator::Simulator() {
- programs.reserve(FIELDS_XY * FIELDS_XY);
- // std::srand(std::time(0));
- std::srand(0);
- }
- Position Simulator::calcPosition(Position position, Direction direction, int32_t distance) {
- switch(direction) {
- case Right: return Position{(position.x + distance) % FIELDS_XY, position.y};
- case Down: return Position{position.x, (position.y + distance) % FIELDS_XY};
- case Left: return Position{(position.x - distance) % FIELDS_XY, position.y};
- case Up: return Position{position.x, (position.y - distance) % FIELDS_XY};
- }
- }
- void Simulator::decode(Program& program, Task& task, int& v, int*& var_v, int param) {
- var_v = nullptr;
- switch(param) {
- case Local_1 : v = program.vars[0]; var_v = &program.vars[0]; break;
- case Local_2 : v = program.vars[1]; var_v = &program.vars[1]; break;
- case Local_3 : v = program.vars[2]; var_v = &program.vars[2]; break;
- case Local_4 : v = program.vars[3]; var_v = &program.vars[3]; break;
- case Local_5 : v = program.vars[4]; var_v = &program.vars[4]; break;
- case Local_6 : v = program.vars[5]; var_v = &program.vars[5]; break;
- case Local_7 : v = program.vars[6]; var_v = &program.vars[6]; break;
- case Local_8 : v = program.vars[7]; var_v = &program.vars[7]; break;
- case Local_9 : v = program.vars[8]; var_v = &program.vars[8]; break;
- case Local_10: v = program.vars[9]; var_v = &program.vars[9]; break;
- case Local_11: v = program.vars[10]; var_v = &program.vars[10]; break;
- case Local_12: v = program.vars[11]; var_v = &program.vars[11]; break;
- case Local_13: v = program.vars[12]; var_v = &program.vars[12]; break;
- case Local_14: v = program.vars[13]; var_v = &program.vars[13]; break;
- case Local_15: v = program.vars[14]; var_v = &program.vars[14]; break;
- case Local_16: v = program.vars[15]; var_v = &program.vars[15]; break;
- case Local_17: v = program.vars[16]; var_v = &program.vars[16]; break;
- case Local_18: v = program.vars[17]; var_v = &program.vars[17]; break;
- case Local_19: v = program.vars[18]; var_v = &program.vars[18]; break;
- case Local_20: v = program.vars[19]; var_v = &program.vars[19]; break;
- case LocalActive:
- v = program.active;
- var_v = &program.active;
- break;
- case LocalBanks:
- v = program.banks.size();
- break;
- case LocalInstrSet:
- v = program.instructionSet;
- break;
- case LocalMobile:
- v = program.mobile;
- break;
- case LocalAge:
- v = cycle - program.creationCycle;
- break;
- case LocalTasks:
- v = program.tasks.size();
- break;
- case LocalGeneration:
- v = program.generation;
- break;
- case LocalId:
- v = program.team->id;
- break;
- case RemoteActive: {
- auto remotePosition = calcPosition(program.position, task.direction, 1);
- auto remoteProgram = findProgram(remotePosition);
- if(remoteProgram) {
- v = remoteProgram->active;
- var_v = &remoteProgram->active;
- }
- else {
- v = 0;
- var_v = nullptr;
- }
- break;
- }
- case RemoteBanks: {
- auto remotePosition = calcPosition(program.position, task.direction, 1);
- auto remoteProgram = findProgram(remotePosition);
- v = remoteProgram ? remoteProgram->banks.size() : 0;
- break;
- }
- case RemoteInstrSet: {
- auto remotePosition = calcPosition(program.position, task.direction, 1);
- auto remoteProgram = findProgram(remotePosition);
- v = remoteProgram ? remoteProgram->instructionSet : 0;
- break;
- }
- case RemoteMobile: {
- auto remotePosition = calcPosition(program.position, task.direction, 1);
- auto remoteProgram = findProgram(remotePosition);
- v = remoteProgram ? remoteProgram->mobile: 0;
- break;
- }
- case RemoteAge: {
- auto remotePosition = calcPosition(program.position, task.direction, 1);
- auto remoteProgram = findProgram(remotePosition);
- v = remoteProgram ? (cycle - remoteProgram->creationCycle) : 0;
- break;
- }
- case RemoteTasks: {
- auto remotePosition = calcPosition(program.position, task.direction, 1);
- auto remoteProgram = findProgram(remotePosition);
- v = remoteProgram ? remoteProgram->tasks.size() : 0;
- break;
- }
- case RemoteGeneration: {
- auto remotePosition = calcPosition(program.position, task.direction, 1);
- auto remoteProgram = findProgram(remotePosition);
- v = remoteProgram ? remoteProgram->generation : 0;
- break;
- }
- case GlobalPub:
- v = pub;
- var_v = &pub;
- break;
- case GlobalTeam:
- v = program.team->var;
- var_v = &program.team->var;
- break;
- case GlobalOwn:
- v = program.team->programCount;
- break;
- case GlobalOthers:
- v = 0;
- for(auto& team : teams) {
- if(team != program.team) {
- v += team->programCount;
- }
- }
- break;
- case GlobalFields:
- v = FIELDS_XY * FIELDS_XY;
- break;
- case GlobalTime:
- v = cycle;
- break;
- case GlobalTimeout:
- v = CYCLE_TIMEOUT;
- break;
- }
- }
- void Simulator::decodeInstructionParameters(Program& program, Task& task, const Instruction& instruction) {
- task.a = instruction.a;
- task.b = instruction.b;
- task.c = instruction.c;
- task.var_a = nullptr;
- task.var_b = nullptr;
- task.var_c = nullptr;
- switch(instruction.params) {
- case N:
- break;
- case L:
- task.a = instruction.a;
- break;
- case V:
- decode(program, task, task.a, task.var_a, instruction.a);
- break;
- case LL:
- task.a = instruction.a;
- task.b = instruction.b;
- break;
- case LV:
- task.a = instruction.a;
- decode(program, task, task.b, task.var_b, instruction.b);
- break;
- case VL:
- decode(program, task, task.a, task.var_a, instruction.a);
- task.b = instruction.b;
- break;
- case VV:
- decode(program, task, task.a, task.var_a, instruction.a);
- decode(program, task, task.b, task.var_b, instruction.b);
- break;
- case LLL:
- task.a = instruction.a;
- task.b = instruction.b;
- task.c = instruction.c;
- break;
- case LLV:
- task.a = instruction.a;
- task.b = instruction.b;
- decode(program, task, task.c, task.var_c, instruction.c);
- break;
- case LVL:
- task.a = instruction.a;
- decode(program, task, task.b, task.var_b, instruction.b);
- task.c = instruction.c;
- break;
- case LVV:
- task.a = instruction.a;
- decode(program, task, task.b, task.var_b, instruction.b);
- decode(program, task, task.c, task.var_c, instruction.c);
- break;
- case VLL:
- decode(program, task, task.a, task.var_a, instruction.a);
- task.b = instruction.b;
- task.c = instruction.c;
- break;
- case VLV:
- decode(program, task, task.a, task.var_a, instruction.a);
- task.b = instruction.b;
- decode(program, task, task.c, task.var_c, instruction.c);
- break;
- case VVL:
- decode(program, task, task.a, task.var_a, instruction.a);
- decode(program, task, task.b, task.var_b, instruction.b);
- task.c = instruction.c;
- break;
- case VVV:
- decode(program, task, task.a, task.var_a, instruction.a);
- decode(program, task, task.b, task.var_b, instruction.b);
- decode(program, task, task.c, task.var_c, instruction.c);
- break;
- }
- }
- Program* Simulator::findProgram(Position position) {
- for(auto& program : programs) {
- if(program.position.x == position.x && program.position.y == position.y && program.error == NoError) {
- return &program;
- }
- }
- return nullptr;
- }
- void Simulator::removeErroneousPrograms() {
- auto it = std::remove_if(programs.begin(), programs.end(), [](const Program& program){ return program.error != NoError; });
- for(auto itr = it; itr != programs.end(); ++itr) {
- --(itr->team->programCount);
- }
- programs.erase(it, programs.end());
- }
- void Simulator::simulate() {
- removeErroneousPrograms();
- for (auto& program : programs) {
- auto& taskIndex = program.taskIndex;
- // do nothing if not active
- if(!program.active) {
- continue;
- }
- // error if no active task exists
- if(find_if(program.tasks.begin(), program.tasks.end(), [](const Task& task){ return !task.paused; }) == program.tasks.end()) {
- program.error = Unemployment;
- continue;
- }
- // switch to next unpasued task
- do {
- taskIndex = (taskIndex + 1) % program.tasks.size();
- } while(program.tasks[taskIndex].paused);
- // check if we are still executing an instruction
- auto& task = program.tasks[taskIndex];
- if(task.remainingCycles > 0) {
- --task.remainingCycles;
- continue;
- }
- else {
- endInstruction(program, task);
- beginInstruction(program, task);
- }
- }
- ++cycle;
- }
- void Simulator::beginInstruction(Program& program, Task& task) {
- // handle invalid bank number
- if(program.banks.empty() || task.bankIndex >= program.banks.size()) {
- program.error = InvalidBankNumber;
- return;
- }
- // handle autoreset to bank 0,0 if instructionIndex is out of banks bound or bank is empty
- if(!program.banks[task.bankIndex] || task.instIndex >= program.banks[task.bankIndex]->instructions.size()) {
- task.bankIndex = 0;
- task.instIndex = 0;
- }
- // handle data hunger
- if(task.bankIndex == 0 && !program.banks[0]) {
- program.error = DataHunger;
- return;
- }
- task.execBank = program.banks[task.bankIndex];
- auto& instruction = program.banks[task.bankIndex]->instructions[task.instIndex];
- // decode instruction parameters
- decodeInstructionParameters(program, task, instruction);
- // calculate cycle durations and check preconditions
- switch(instruction.command) {
- case CREATE:
- if(program.instructionSet < 2) {
- program.error = HigherInstructionSetRequired;
- break;
- }
- if(task.a < 0 || task.a > 2 || task.b < 1 || task.b > 50 || task.c < 0 || task.c > 1) {
- program.error = InvalidParameter;
- break;
- }
- task.remainingCycles = 100 + 50 * task.a + 25 * task.b + 120 * task.c;
- break;
- case MOVE:
- if(program.mobile < 1) {
- program.error = MobilityRequired;
- break;
- }
- task.remainingCycles = 20;
- break;
- case DIE:
- task.remainingCycles = 1;
- break;
- case TRANS: {
- int ar = task.a - 1;
- int br = task.b - 1;
- if(program.instructionSet < 1) {
- program.error = HigherInstructionSetRequired;
- break;
- }
- if(ar < 0 || ar >= program.banks.size()) {
- program.error = InvalidBankNumber;
- break;
- }
- const auto& bank = program.banks[ar];
- task.remainingCycles = 14 + (bank ? bank->instructions.size() : 0);
- break;
- }
- case RTRANS: {
- int ar = task.a - 1;
- int br = task.b - 1;
- if(program.instructionSet < 1) {
- program.error = HigherInstructionSetRequired;
- break;
- }
- if(ar < 0 || ar >= 50 || br < 0 || br >= program.banks.size()) {
- program.error = InvalidBankNumber;
- break;
- }
- auto remotePosition = calcPosition(program.position, task.direction, 1);
- auto remoteProgram = findProgram(remotePosition);
- task.remainingCycles = 14 + remoteProgram ? (ar < remoteProgram->banks.size() ? (remoteProgram->banks[ar] ? remoteProgram->banks[ar]->instructions.size() : 0): 0): 0;
- break;
- }
- case TURN:
- task.remainingCycles = 8;
- break;
- case JUMP:
- task.remainingCycles = 1;
- break;
- case AJUMP:
- task.remainingCycles = 1;
- break;
- case BJUMP:
- task.remainingCycles = 2;
- break;
- case SCAN:
- if(program.instructionSet < 1) {
- program.error = HigherInstructionSetRequired;
- break;
- }
- task.remainingCycles = 8;
- break;
- case FARSCAN:
- if(program.instructionSet < 1) {
- program.error = HigherInstructionSetRequired;
- break;
- }
- task.remainingCycles = 10 + 3 * task.c;
- break;
- case SET:
- task.remainingCycles = 2;
- break;
- case ADD:
- task.remainingCycles = 2;
- break;
- case SUB:
- task.remainingCycles = 2;
- break;
- case MUL:
- task.remainingCycles = 2;
- break;
- case DIV:
- task.remainingCycles = 2;
- break;
- case MOD:
- task.remainingCycles = 2;
- break;
- case MIN:
- task.remainingCycles = 2;
- break;
- case MAX:
- task.remainingCycles = 2;
- break;
- case RANDOM:
- if(task.b > task.c) {
- program.error = InvalidParameter;
- break;
- }
- task.remainingCycles = 1;
- break;
- case IF:
- task.remainingCycles = 2;
- break;
- case IFN:
- task.remainingCycles = 2;
- break;
- case IFG:
- task.remainingCycles = 2;
- break;
- case IFL:
- task.remainingCycles = 2;
- break;
- case IFGE:
- task.remainingCycles = 2;
- break;
- case IFLE:
- task.remainingCycles = 2;
- break;
- case INIT:
- task.remainingCycles = 2;
- break;
- case BREAK:
- task.remainingCycles = 1;
- break;
- case RESUME:
- task.remainingCycles = 1;
- break;
- case SEIZE:
- task.remainingCycles = 1;
- break;
- case SLEEP:
- if(task.a > 2000) {
- program.error = InvalidParameter;
- break;
- }
- task.remainingCycles = task.a;
- break;
- case QUIT:
- task.remainingCycles = 1;
- break;
- }
- }
- void Simulator::endInstruction(Program& program, Task& task) {
- // we are not executing yet
- if(!task.execBank || program.error != NoError) {
- return;
- }
- // check if bank is overwritten, skip execution of current command and begin new bank at instruction 0
- if(task.execBank != program.banks[task.bankIndex]) {
- task.instIndex = 0;
- return;
- }
- // execute command
- auto& instruction = task.execBank->instructions[task.instIndex];
- switch(instruction.command) {
- case CREATE: {
- auto remotePosition = calcPosition(program.position, task.direction, 1);
- auto remoteProgram = findProgram(remotePosition);
- if(!remoteProgram) {
- programs.push_back(Program(program.team, task.direction, remotePosition, task.a, task.b, task.c));
- ++program.team->programCount;
- }
- task.instIndex += 1;
- break;
- }
- case MOVE: {
- auto remotePosition = calcPosition(program.position, task.direction, 1);
- auto remoteProgram = findProgram(remotePosition);
- if(!remoteProgram) {
- program.position = remotePosition;
- }
- task.instIndex += 1;
- break;
- }
- case DIE: {
- program.error = DieExecuted;
- task.instIndex += 1;
- break;
- }
- case TRANS: {
- int ar = task.a - 1;
- int br = task.b - 1;
- auto remotePosition = calcPosition(program.position, task.direction, 1);
- auto remoteProgram = findProgram(remotePosition);
- if(remoteProgram && br < remoteProgram->banks.size() && ar < program.banks.size()) {
- remoteProgram->banks[br] = program.banks[ar];
- }
- task.instIndex += 1;
- break;
- }
- case RTRANS: {
- int ar = task.a - 1;
- int br = task.b - 1;
- auto remotePosition = calcPosition(program.position, task.direction, 1);
- auto remoteProgram = findProgram(remotePosition);
- if(remoteProgram && ar < remoteProgram->banks.size() && br < program.banks.size()) {
- program.banks[br] = remoteProgram->banks[ar];
- }
- task.instIndex += 1;
- break;
- }
- case TURN: {
- task.direction = static_cast<Direction>(qMax(0, (task.direction + ((task.a >= 0) ? 1 : -1)) % 4));
- task.instIndex += 1;
- break;
- }
- case JUMP: {
- task.instIndex += task.a;
- break;
- }
- case AJUMP: {
- task.instIndex = task.a - 1;
- break;
- }
- case BJUMP: {
- task.bankIndex = task.a - 1;
- task.instIndex = task.b - 1;
- break;
- }
- case SCAN: {
- // Scans a field, result in #a
- // #a=0 ...empty.
- // #a=1 ...enemy
- // #a=2 ...friend
- auto remotePosition = calcPosition(program.position, task.direction, 1);
- auto remoteProgram = findProgram(remotePosition);
- *task.var_a = !remoteProgram ? 0 : remoteProgram->team == program.team ? 2: 1;
- task.instIndex += 1;
- break;
- }
- case FARSCAN: {
- // Scans up to c fields straight in front of the bot.
- // The nearest bot's type is stored in #a:
- // #a=0 ...empty.
- // #a=1 ...enemy
- // #a=2 ...friend
- // Its distance is stored in #b.
- *task.var_a = 0;
- *task.var_b = 0;
- for(int i = 0; i < task.c; ++i) {
- auto remotePosition = calcPosition(program.position, task.direction, i + 1);
- auto remoteProgram = findProgram(remotePosition);
- if(remoteProgram) {
- *task.var_a = remoteProgram->team == program.team ? 2: 1;
- *task.var_b = i;
- break;
- }
- }
- task.instIndex += 1;
- break;
- }
- case SET:
- *task.var_a = task.b;
- task.instIndex += 1;
- break;
- case ADD:
- *task.var_a += task.b;
- task.instIndex += 1;
- break;
- case SUB:
- *task.var_a -= task.b;
- task.instIndex += 1;
- break;
- case MUL:
- *task.var_a *= task.b;
- task.instIndex += 1;
- break;
- case DIV:
- if(task.b == 0) {
- program.error = DivisionByZero;
- break;
- }
- *task.var_a /= task.b;
- task.instIndex += 1;
- break;
- case MOD:
- if(task.b == 0) {
- program.error = DivisionByZero;
- break;
- }
- *task.var_a %= task.b;
- task.instIndex += 1;
- break;
- case MIN:
- *task.var_a = qMin(task.a, task.b);
- task.instIndex += 1;
- break;
- case MAX:
- *task.var_a = qMax(task.a, task.b);
- task.instIndex += 1;
- break;
- case RANDOM:
- *task.var_a = task.b + (rand() % (task.c - task.b + 1));
- task.instIndex += 1;
- break;
- case IF:
- task.instIndex += ((task.a == task.b) ? 1 : 2);
- break;
- case IFN:
- task.instIndex += ((task.a != task.b) ? 1 : 2);
- break;
- case IFG:
- task.instIndex += ((task.a > task.b) ? 1 : 2);
- break;
- case IFL:
- task.instIndex += ((task.a < task.b) ? 1 : 2);
- break;
- case IFGE:
- task.instIndex += ((task.a >= task.b) ? 1 : 2);
- break;
- case IFLE:
- task.instIndex += ((task.a <= task.b) ? 1 : 2);
- break;
- case INIT:
- task.instIndex += 1;
- break;
- case BREAK:
- task.instIndex += 1;
- break;
- case RESUME:
- task.instIndex += 1;
- break;
- case SEIZE:
- task.instIndex += 1;
- break;
- case SLEEP:
- task.instIndex += 1;
- break;
- case QUIT:
- task.instIndex += 1;
- break;
- default:
- task.instIndex += 1;
- break;
- }
- }
|