#ifndef SIMULATOR_H #define SIMULATOR_H #include #include #include #include #include using namespace std; struct Position { size_t x = 0; size_t y = 0; Position() : x(0) , y(0) {} Position(size_t _x, size_t _y) : x(_x) , y(_y) {} Position(const Position& _pos) : x(_pos.x) , y(_pos.y) {} }; enum Direction { Right, Down, Left, Up, }; enum Command : uint16_t { NOP, CREATE, MOVE, DIE, TRANS, RTRANS, TURN, JUMP, AJUMP, BJUMP, SCAN, FARSCAN, SET, ADD, SUB, MUL, DIV, MOD, MIN, MAX, RANDOM, IF, IFN, IFG, IFL, IFGE, IFLE, // INIT, // BREAK, // RESUME, // SEIZE, // SLEEP, // QUIT, }; enum Params : uint16_t { LLL, LLV, LVL, LVV, VLL, VLV, VVL, VVV, N = LLL, L = LLL, V = VLL, LL = LLL, LV = LVL, VL = VLL, VV = VVV, }; enum Variables { LocalVar_0 = 0, LocalVar_20 = 19, PubVar, TeamVar, LocalActiveVar, RemoteActiveVar, LocalBanks, RemoteBanks, LocalInstrSet, RemoteInstrSet, LocalMobile, RemoteMobile, LocalAge, RemoteAge, Own, Others, Fields, LocalGeneration, TeamId, InstrPos, Time, Timeout, LocalTasks, RemoteTasks, }; enum Error { NoError, // No error EliminationTrigger, // Elimination Trigger released DataHunger, // Data Hunger (Bank 1 empty and executed) DivisionByZero, // Division by zero InvalidBankNumber, // Invalid bank number (e.g. in TRANS or BJUMP) HigherInstructionSetRequired, // Higher Instruction Set required MobilityRequired, // Mobility required DieExecuted, // DIE executed InvalidParameter , // Invalid parameter (e.g. CREATE x, -1, x) Unemployment, // No more tasks left in a robot (Unemployment) InstructionDurationTooHigh, // Instruction duration too high (i.e. > MaxInstrDur) }; using Parameter = int32_t; struct Instruction { Command command = NOP; Params params = N; Parameter a = 0; Parameter b = 0; Parameter c = 0; Instruction(Command _command, Params _params = N, Parameter _a = 0, Parameter _b = 0, Parameter _c = 0) : command(_command) , params(_params) , a(_a) , b(_b) , c(_c) { } }; using Bank = shared_ptr>; using BankIndex = size_t; using InstIndex = size_t; using TaskIndex = size_t; struct Task { Direction direction = Right; BankIndex bankIndex = 0; InstIndex instIndex = 0; }; struct Program { Error error = NoError; QColor color; Position position; vector tasks; TaskIndex taskIndex = 0; vector banks; array vars{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}; Program(QColor _color, Position _position, int32_t instructionSet, int32_t slotCount, int32_t mobile) { color = _color; position = _position; banks.resize(slotCount); tasks.resize(1); } }; struct Field { Program* program = nullptr; }; struct Simulator { size_t cycle = 0; vector programs; size_t size = 0; Simulator() { size = 20; programs.reserve(size * size); // std::srand(std::time(0)); std::srand(0); } Position calcPosition(Position position, Direction direction, int32_t distance) { switch(direction) { case Right: return Position{(position.x + distance) % size, position.y}; case Down: return Position{position.x, (position.y + distance) % size}; case Left: return Position{(position.x - distance) % size, position.y}; case Up: return Position{position.x, (position.y - distance) % size}; } } void loadProgram(QColor color, size_t x, size_t y) { programs.push_back(Program(color, Position{x, y}, 2, 50, 1)); { Bank bank = make_shared>(); bank->push_back(Instruction(BJUMP, LL, 1, 0)); programs.back().banks[0] = bank; } { Bank bank = make_shared>(); bank->push_back(Instruction(SCAN, V, 1)); bank->push_back(Instruction(CREATE, LLL, 2, 50, 1)); bank->push_back(Instruction(TRANS, LL, 0, 0)); bank->push_back(Instruction(TRANS, LL, 1, 1)); bank->push_back(Instruction(RANDOM, VLL, 5, -5, 5)); bank->push_back(Instruction(TURN, V, 5)); bank->push_back(Instruction(ADD, VL, 6, 1)); // bank->push_back(Instruction(IFG, VL, 6, 5)); // bank->push_back(Instruction(DIE)); bank->push_back(Instruction(AJUMP, L, 0)); programs.back().banks[1] = bank; } } Program* 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 simulate() { for (auto& program : programs) { auto& taskIndex = program.taskIndex; if(program.error != NoError) { continue; } if(program.tasks.empty()) { continue; } taskIndex = (taskIndex + 1) % program.tasks.size(); if (taskIndex < program.tasks.size()) { auto& task = program.tasks[taskIndex]; if(task.bankIndex >= program.banks.size()) { continue; } const auto bank_ptr = program.banks[task.bankIndex].get(); if(bank_ptr == nullptr || task.instIndex >= bank_ptr->size()) { continue; } const auto& bank = *bank_ptr; const auto& inst = bank[task.instIndex]; //prevent overrideing of instuctions... int32_t a_safe = inst.a; int32_t b_safe = inst.b; int32_t c_safe = inst.c; int32_t* a = &a_safe; int32_t* b = &b_safe; int32_t* c = &c_safe; auto decode = [&](int*& v) { if(*v >= VAR_0 && *v <= VAR_20) { v = &program.vars[*v]; return; } switch(*v) { case 21: break; } }; switch(inst.params) { case LLL: { break; } case LLV: { decode(c); break; } case LVL: { decode(b); break; } case LVV: { decode(b); decode(c); break; } case VLL: { decode(a); break; } case VLV: { decode(a); decode(c); break; } case VVL: { decode(a); decode(b); break; } case VVV: { decode(a); decode(b); decode(c); break; } } switch(inst.command) { case CREATE: { auto remotePosition = calcPosition(program.position, task.direction, 1); auto remoteProgram = findProgram(remotePosition); if(!remoteProgram) { programs.push_back(Program(program.color, remotePosition, *a, *b, *c)); } 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: { auto remotePosition = calcPosition(program.position, task.direction, 1); auto remoteProgram = findProgram(remotePosition); if(remoteProgram && *b < remoteProgram->banks.size() && *a < program.banks.size()) { remoteProgram->banks[*b] = program.banks[*a]; } task.instIndex += 1; break; } case RTRANS: { auto remotePosition = calcPosition(program.position, task.direction, 1); auto remoteProgram = findProgram(remotePosition); if(remoteProgram && *a < remoteProgram->banks.size() && *b < program.banks.size()) { program.banks[*b] = remoteProgram->banks[*a]; } task.instIndex += 1; break; } case TURN: { task.direction = static_cast(qMax(0, (task.direction + ((*a >= 0) ? 1 : -1)) % 4)); task.instIndex += 1; break; } case JUMP: { task.instIndex += *a; break; } case AJUMP: { task.instIndex = *a; break; } case BJUMP: { task.bankIndex = *a; task.instIndex = *b; 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); *a = !remoteProgram ? 0 : remoteProgram->color == program.color ? 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. *a = 0; *b = 0; for(int i = 0; i < *c; ++i) { auto remotePosition = calcPosition(program.position, task.direction, i + 1); auto remoteProgram = findProgram(remotePosition); if(remoteProgram) { *a = remoteProgram->color == program.color ? 2: 1; *b = i; break; } } task.instIndex += 1; break; } case SET: *a = *b; task.instIndex += 1; break; case ADD: *a += *b; task.instIndex += 1; break; case SUB: *a -= *b; task.instIndex += 1; break; case MUL: *a *= *b; task.instIndex += 1; break; case DIV: *a /= *b; task.instIndex += 1; break; case MOD: *a %= *b; task.instIndex += 1; break; case MIN: *a = qMin(*a, *b); task.instIndex += 1; break; case MAX: *a = qMax(*a, *b); task.instIndex += 1; break; case RANDOM: *a = *b + (rand() % (*c - *b + 1)); task.instIndex += 1; break; case IF: task.instIndex += ((*a == *b) ? 1 : 2); break; case IFN: task.instIndex += ((*a != *b) ? 1 : 2); break; case IFG: task.instIndex += ((*a > *b) ? 1 : 2); break; case IFL: task.instIndex += ((*a < *b) ? 1 : 2); break; case IFGE: task.instIndex += ((*a >= *b) ? 1 : 2); break; case IFLE: task.instIndex += ((*a <= *b) ? 1 : 2); break; default: task.instIndex += 1; break; } } } ++cycle; } }; #endif // SIMULATOR_H