simulator.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713
  1. #include "simulator.h"
  2. Simulator::Simulator() {
  3. programs.reserve(FIELDS_XY * FIELDS_XY);
  4. // std::srand(std::time(0));
  5. std::srand(0);
  6. }
  7. Position Simulator::calcPosition(Position position, Direction direction, int32_t distance) {
  8. switch(direction) {
  9. case Right: return Position{(position.x + distance) % FIELDS_XY, position.y};
  10. case Down: return Position{position.x, (position.y + distance) % FIELDS_XY};
  11. case Left: return Position{(position.x - distance) % FIELDS_XY, position.y};
  12. case Up: return Position{position.x, (position.y - distance) % FIELDS_XY};
  13. }
  14. }
  15. void Simulator::decode(Program& program, Task& task, int& v, int*& var_v, int param) {
  16. var_v = nullptr;
  17. switch(param) {
  18. case Local_0: v = program.vars[0]; var_v = &program.vars[0]; break;
  19. case Local_1: v = program.vars[1]; var_v = &program.vars[1]; break;
  20. case Local_2: v = program.vars[2]; var_v = &program.vars[2]; break;
  21. case Local_3: v = program.vars[3]; var_v = &program.vars[3]; break;
  22. case Local_4: v = program.vars[4]; var_v = &program.vars[4]; break;
  23. case Local_5: v = program.vars[5]; var_v = &program.vars[5]; break;
  24. case Local_6: v = program.vars[6]; var_v = &program.vars[6]; break;
  25. case Local_7: v = program.vars[7]; var_v = &program.vars[7]; break;
  26. case Local_8: v = program.vars[8]; var_v = &program.vars[8]; break;
  27. case Local_9: v = program.vars[9]; var_v = &program.vars[9]; break;
  28. case Local_10: v = program.vars[10]; var_v = &program.vars[10]; break;
  29. case Local_11: v = program.vars[11]; var_v = &program.vars[11]; break;
  30. case Local_12: v = program.vars[12]; var_v = &program.vars[12]; break;
  31. case Local_13: v = program.vars[13]; var_v = &program.vars[13]; break;
  32. case Local_14: v = program.vars[14]; var_v = &program.vars[14]; break;
  33. case Local_15: v = program.vars[15]; var_v = &program.vars[15]; break;
  34. case Local_16: v = program.vars[16]; var_v = &program.vars[16]; break;
  35. case Local_17: v = program.vars[17]; var_v = &program.vars[17]; break;
  36. case Local_18: v = program.vars[18]; var_v = &program.vars[18]; break;
  37. case Local_19: v = program.vars[19]; var_v = &program.vars[19]; break;
  38. case LocalActive:
  39. v = program.active;
  40. var_v = &program.active;
  41. break;
  42. case LocalBanks:
  43. v = program.banks.size();
  44. break;
  45. case LocalInstrSet:
  46. v = program.instructionSet;
  47. break;
  48. case LocalMobile:
  49. v = program.mobile;
  50. break;
  51. case LocalAge:
  52. v = cycle - program.creationCycle;
  53. break;
  54. case LocalTasks:
  55. v = program.tasks.size();
  56. break;
  57. case LocalGeneration:
  58. v = program.generation;
  59. break;
  60. case LocalId:
  61. v = program.team->id;
  62. break;
  63. case RemoteActive: {
  64. auto remotePosition = calcPosition(program.position, task.direction, 1);
  65. auto remoteProgram = findProgram(remotePosition);
  66. if(remoteProgram) {
  67. v = remoteProgram->active;
  68. var_v = &remoteProgram->active;
  69. }
  70. else {
  71. v = 0;
  72. var_v = nullptr;
  73. }
  74. break;
  75. }
  76. case RemoteBanks: {
  77. auto remotePosition = calcPosition(program.position, task.direction, 1);
  78. auto remoteProgram = findProgram(remotePosition);
  79. v = remoteProgram ? remoteProgram->banks.size() : 0;
  80. break;
  81. }
  82. case RemoteInstrSet: {
  83. auto remotePosition = calcPosition(program.position, task.direction, 1);
  84. auto remoteProgram = findProgram(remotePosition);
  85. v = remoteProgram ? remoteProgram->instructionSet : 0;
  86. break;
  87. }
  88. case RemoteMobile: {
  89. auto remotePosition = calcPosition(program.position, task.direction, 1);
  90. auto remoteProgram = findProgram(remotePosition);
  91. v = remoteProgram ? remoteProgram->mobile: 0;
  92. break;
  93. }
  94. case RemoteAge: {
  95. auto remotePosition = calcPosition(program.position, task.direction, 1);
  96. auto remoteProgram = findProgram(remotePosition);
  97. v = remoteProgram ? (cycle - remoteProgram->creationCycle) : 0;
  98. break;
  99. }
  100. case RemoteTasks: {
  101. auto remotePosition = calcPosition(program.position, task.direction, 1);
  102. auto remoteProgram = findProgram(remotePosition);
  103. v = remoteProgram ? remoteProgram->tasks.size() : 0;
  104. break;
  105. }
  106. case RemoteGeneration: {
  107. auto remotePosition = calcPosition(program.position, task.direction, 1);
  108. auto remoteProgram = findProgram(remotePosition);
  109. v = remoteProgram ? remoteProgram->generation : 0;
  110. break;
  111. }
  112. case GlobalPub:
  113. v = pub;
  114. var_v = &pub;
  115. break;
  116. case GlobalTeam:
  117. v = program.team->var;
  118. var_v = &program.team->var;
  119. break;
  120. case GlobalOwn:
  121. v = program.team->programCount;
  122. break;
  123. case GlobalOthers:
  124. v = 0;
  125. for(auto& team : teams) {
  126. if(team != program.team) {
  127. v += team->programCount;
  128. }
  129. }
  130. break;
  131. case GlobalFields:
  132. v = FIELDS_XY * FIELDS_XY;
  133. break;
  134. case GlobalTime:
  135. v = cycle;
  136. break;
  137. case GlobalTimeout:
  138. v = CYCLE_TIMEOUT;
  139. break;
  140. }
  141. }
  142. void Simulator::decodeInstructionParameters(Program& program, Task& task, const Instruction& instruction) {
  143. task.a = instruction.a;
  144. task.b = instruction.b;
  145. task.c = instruction.c;
  146. task.var_a = nullptr;
  147. task.var_b = nullptr;
  148. task.var_c = nullptr;
  149. switch(instruction.params) {
  150. case N:
  151. break;
  152. case L:
  153. task.a = instruction.a;
  154. break;
  155. case V:
  156. decode(program, task, task.a, task.var_a, instruction.a);
  157. break;
  158. case LL:
  159. task.a = instruction.a;
  160. task.b = instruction.b;
  161. break;
  162. case LV:
  163. task.a = instruction.a;
  164. decode(program, task, task.b, task.var_b, instruction.b);
  165. break;
  166. case VL:
  167. decode(program, task, task.a, task.var_a, instruction.a);
  168. task.b = instruction.b;
  169. break;
  170. case VV:
  171. decode(program, task, task.a, task.var_a, instruction.a);
  172. decode(program, task, task.b, task.var_b, instruction.b);
  173. break;
  174. case LLL:
  175. task.a = instruction.a;
  176. task.b = instruction.b;
  177. task.c = instruction.c;
  178. break;
  179. case LLV:
  180. task.a = instruction.a;
  181. task.b = instruction.b;
  182. decode(program, task, task.c, task.var_c, instruction.c);
  183. break;
  184. case LVL:
  185. task.a = instruction.a;
  186. decode(program, task, task.b, task.var_b, instruction.b);
  187. task.c = instruction.c;
  188. break;
  189. case LVV:
  190. task.a = instruction.a;
  191. decode(program, task, task.b, task.var_b, instruction.b);
  192. decode(program, task, task.c, task.var_c, instruction.c);
  193. break;
  194. case VLL:
  195. decode(program, task, task.a, task.var_a, instruction.a);
  196. task.b = instruction.b;
  197. task.c = instruction.c;
  198. break;
  199. case VLV:
  200. decode(program, task, task.a, task.var_a, instruction.a);
  201. task.b = instruction.b;
  202. decode(program, task, task.c, task.var_c, instruction.c);
  203. break;
  204. case VVL:
  205. decode(program, task, task.a, task.var_a, instruction.a);
  206. decode(program, task, task.b, task.var_b, instruction.b);
  207. task.c = instruction.c;
  208. break;
  209. case VVV:
  210. decode(program, task, task.a, task.var_a, instruction.a);
  211. decode(program, task, task.b, task.var_b, instruction.b);
  212. decode(program, task, task.c, task.var_c, instruction.c);
  213. break;
  214. }
  215. }
  216. void Simulator::loadProgram(QColor color, size_t x, size_t y) {
  217. shared_ptr<Team> team = make_shared<Team>(color);
  218. teams.push_back(team);
  219. programs.push_back(Program(team, Right, Position{x, y}, 2, 50, 1));
  220. ++team->programCount;
  221. programs.back().banks[0] = make_shared<Bank>(team, vector<Instruction>{
  222. Instruction(BJUMP, LL, 1, 0)
  223. });
  224. programs.back().banks[1] = make_shared<Bank>(team, vector<Instruction>{
  225. Instruction(SCAN, V, 1),
  226. Instruction(CREATE, LLL, 2, 50, 1),
  227. Instruction(TRANS, LL, 0, 0),
  228. Instruction(TRANS, LL, 1, 1),
  229. Instruction(SET, VL, RemoteActive, 1),
  230. Instruction(TURN, L, 0),
  231. Instruction(AJUMP, L, 0)
  232. });
  233. programs.back().active = team->id;
  234. }
  235. Program* Simulator::findProgram(Position position) {
  236. for(auto& program : programs) {
  237. if(program.position.x == position.x && program.position.y == position.y && program.error == NoError) {
  238. return &program;
  239. }
  240. }
  241. return nullptr;
  242. }
  243. void Simulator::removeErroneousPrograms() {
  244. auto it = std::remove_if(programs.begin(), programs.end(), [](const Program& program){ return program.error != NoError; });
  245. for(auto itr = it; itr != programs.end(); ++itr) {
  246. --(itr->team->programCount);
  247. }
  248. programs.erase(it, programs.end());
  249. }
  250. void Simulator::simulate() {
  251. removeErroneousPrograms();
  252. for (auto& program : programs) {
  253. auto& taskIndex = program.taskIndex;
  254. // do nothing if not active
  255. if(!program.active) {
  256. continue;
  257. }
  258. // error if no active task exists
  259. if(find_if(program.tasks.begin(), program.tasks.end(), [](const Task& task){ return !task.paused; }) == program.tasks.end()) {
  260. program.error = Unemployment;
  261. continue;
  262. }
  263. // switch to next unpasued task
  264. do {
  265. taskIndex = (taskIndex + 1) % program.tasks.size();
  266. } while(program.tasks[taskIndex].paused);
  267. // check if we are still executing an instruction
  268. auto& task = program.tasks[taskIndex];
  269. if(task.remainingCycles > 0) {
  270. --task.remainingCycles;
  271. continue;
  272. }
  273. else {
  274. endInstruction(program, task);
  275. beginInstruction(program, task);
  276. }
  277. }
  278. ++cycle;
  279. }
  280. void Simulator::beginInstruction(Program& program, Task& task) {
  281. // handle invalid bank number
  282. if(program.banks.empty() || task.bankIndex >= program.banks.size()) {
  283. program.error = InvalidBankNumber;
  284. return;
  285. }
  286. // handle autoreset to bank 0,0 if instructionIndex is out of banks bound or bank is empty
  287. if(!program.banks[task.bankIndex] || task.instIndex >= program.banks[task.bankIndex]->instructions.size()) {
  288. task.bankIndex = 0;
  289. task.instIndex = 0;
  290. }
  291. // handle data hunger
  292. if(task.bankIndex == 0 && !program.banks[0]) {
  293. program.error = DataHunger;
  294. return;
  295. }
  296. task.execBank = program.banks[task.bankIndex];
  297. auto& instruction = program.banks[task.bankIndex]->instructions[task.instIndex];
  298. // decode instruction parameters
  299. decodeInstructionParameters(program, task, instruction);
  300. // calculate cycle durations and check preconditions
  301. switch(instruction.command) {
  302. case CREATE:
  303. if(program.instructionSet < 2) {
  304. program.error = HigherInstructionSetRequired;
  305. break;
  306. }
  307. if(task.a < 0 || task.a > 2 || task.b < 1 || task.b > 50 || task.c < 0 || task.c > 1) {
  308. program.error = InvalidParameter;
  309. break;
  310. }
  311. task.remainingCycles = 100 + 50 * task.a + 25 * task.b + 120 * task.c;
  312. break;
  313. case MOVE:
  314. if(program.mobile < 1) {
  315. program.error = MobilityRequired;
  316. break;
  317. }
  318. task.remainingCycles = 20;
  319. break;
  320. case DIE:
  321. task.remainingCycles = 1;
  322. break;
  323. case TRANS: {
  324. if(program.instructionSet < 1) {
  325. program.error = HigherInstructionSetRequired;
  326. break;
  327. }
  328. if(task.a < 0 || task.a >= program.banks.size()) {
  329. program.error = InvalidBankNumber;
  330. break;
  331. }
  332. const auto& bank = program.banks[task.a];
  333. task.remainingCycles = 14 + (bank ? bank->instructions.size() : 0);
  334. break;
  335. }
  336. case RTRANS: {
  337. if(program.instructionSet < 1) {
  338. program.error = HigherInstructionSetRequired;
  339. break;
  340. }
  341. if(task.a < 0 || task.a >= 50 || task.b < 0 || task.b >= program.banks.size()) {
  342. program.error = InvalidBankNumber;
  343. break;
  344. }
  345. auto remotePosition = calcPosition(program.position, task.direction, 1);
  346. auto remoteProgram = findProgram(remotePosition);
  347. task.remainingCycles = 14 + remoteProgram ? (task.a < remoteProgram->banks.size() ? (remoteProgram->banks[task.a] ? remoteProgram->banks[task.a]->instructions.size() : 0): 0): 0;
  348. break;
  349. }
  350. case TURN:
  351. task.remainingCycles = 8;
  352. break;
  353. case JUMP:
  354. task.remainingCycles = 1;
  355. break;
  356. case AJUMP:
  357. task.remainingCycles = 1;
  358. break;
  359. case BJUMP:
  360. task.remainingCycles = 2;
  361. break;
  362. case SCAN:
  363. if(program.instructionSet < 1) {
  364. program.error = HigherInstructionSetRequired;
  365. break;
  366. }
  367. task.remainingCycles = 8;
  368. break;
  369. case FARSCAN:
  370. if(program.instructionSet < 1) {
  371. program.error = HigherInstructionSetRequired;
  372. break;
  373. }
  374. task.remainingCycles = 10 + 3 * task.c;
  375. break;
  376. case SET:
  377. task.remainingCycles = 2;
  378. break;
  379. case ADD:
  380. task.remainingCycles = 2;
  381. break;
  382. case SUB:
  383. task.remainingCycles = 2;
  384. break;
  385. case MUL:
  386. task.remainingCycles = 2;
  387. break;
  388. case DIV:
  389. task.remainingCycles = 2;
  390. break;
  391. case MOD:
  392. task.remainingCycles = 2;
  393. break;
  394. case MIN:
  395. task.remainingCycles = 2;
  396. break;
  397. case MAX:
  398. task.remainingCycles = 2;
  399. break;
  400. case RANDOM:
  401. if(task.b > task.c) {
  402. program.error = InvalidParameter;
  403. break;
  404. }
  405. task.remainingCycles = 1;
  406. break;
  407. case IF:
  408. task.remainingCycles = 2;
  409. break;
  410. case IFN:
  411. task.remainingCycles = 2;
  412. break;
  413. case IFG:
  414. task.remainingCycles = 2;
  415. break;
  416. case IFL:
  417. task.remainingCycles = 2;
  418. break;
  419. case IFGE:
  420. task.remainingCycles = 2;
  421. break;
  422. case IFLE:
  423. task.remainingCycles = 2;
  424. break;
  425. case INIT:
  426. task.remainingCycles = 2;
  427. break;
  428. case BREAK:
  429. task.remainingCycles = 1;
  430. break;
  431. case RESUME:
  432. task.remainingCycles = 1;
  433. break;
  434. case SEIZE:
  435. task.remainingCycles = 1;
  436. break;
  437. case SLEEP:
  438. if(task.a > 2000) {
  439. program.error = InvalidParameter;
  440. break;
  441. }
  442. task.remainingCycles = task.a;
  443. break;
  444. case QUIT:
  445. task.remainingCycles = 1;
  446. break;
  447. }
  448. }
  449. void Simulator::endInstruction(Program& program, Task& task) {
  450. // we are not executing yet
  451. if(!task.execBank || program.error != NoError) {
  452. return;
  453. }
  454. // check if bank is overwritten, skip execution of current command and begin new bank at instruction 0
  455. if(task.execBank != program.banks[task.bankIndex]) {
  456. task.instIndex = 0;
  457. return;
  458. }
  459. // execute command
  460. auto& instruction = task.execBank->instructions[task.instIndex];
  461. switch(instruction.command) {
  462. case CREATE: {
  463. auto remotePosition = calcPosition(program.position, task.direction, 1);
  464. auto remoteProgram = findProgram(remotePosition);
  465. if(!remoteProgram) {
  466. programs.push_back(Program(program.team, task.direction, remotePosition, task.a, task.b, task.c));
  467. ++program.team->programCount;
  468. }
  469. task.instIndex += 1;
  470. break;
  471. }
  472. case MOVE: {
  473. auto remotePosition = calcPosition(program.position, task.direction, 1);
  474. auto remoteProgram = findProgram(remotePosition);
  475. if(!remoteProgram) {
  476. program.position = remotePosition;
  477. }
  478. task.instIndex += 1;
  479. break;
  480. }
  481. case DIE: {
  482. program.error = DieExecuted;
  483. task.instIndex += 1;
  484. break;
  485. }
  486. case TRANS: {
  487. auto remotePosition = calcPosition(program.position, task.direction, 1);
  488. auto remoteProgram = findProgram(remotePosition);
  489. if(remoteProgram && task.b < remoteProgram->banks.size() && task.a < program.banks.size()) {
  490. remoteProgram->banks[task.b] = program.banks[task.a];
  491. }
  492. task.instIndex += 1;
  493. break;
  494. }
  495. case RTRANS: {
  496. auto remotePosition = calcPosition(program.position, task.direction, 1);
  497. auto remoteProgram = findProgram(remotePosition);
  498. if(remoteProgram && task.a < remoteProgram->banks.size() && task.b < program.banks.size()) {
  499. program.banks[task.b] = remoteProgram->banks[task.a];
  500. }
  501. task.instIndex += 1;
  502. break;
  503. }
  504. case TURN: {
  505. task.direction = static_cast<Direction>(qMax(0, (task.direction + ((task.a >= 0) ? 1 : -1)) % 4));
  506. task.instIndex += 1;
  507. break;
  508. }
  509. case JUMP: {
  510. task.instIndex += task.a;
  511. break;
  512. }
  513. case AJUMP: {
  514. task.instIndex = task.a;
  515. break;
  516. }
  517. case BJUMP: {
  518. task.bankIndex = task.a;
  519. task.instIndex = task.b;
  520. break;
  521. }
  522. case SCAN: {
  523. // Scans a field, result in #a
  524. // #a=0 ...empty.
  525. // #a=1 ...enemy
  526. // #a=2 ...friend
  527. auto remotePosition = calcPosition(program.position, task.direction, 1);
  528. auto remoteProgram = findProgram(remotePosition);
  529. *task.var_a = !remoteProgram ? 0 : remoteProgram->team == program.team ? 2: 1;
  530. task.instIndex += 1;
  531. break;
  532. }
  533. case FARSCAN: {
  534. // Scans up to c fields straight in front of the bot.
  535. // The nearest bot's type is stored in #a:
  536. // #a=0 ...empty.
  537. // #a=1 ...enemy
  538. // #a=2 ...friend
  539. // Its distance is stored in #b.
  540. *task.var_a = 0;
  541. *task.var_b = 0;
  542. for(int i = 0; i < task.c; ++i) {
  543. auto remotePosition = calcPosition(program.position, task.direction, i + 1);
  544. auto remoteProgram = findProgram(remotePosition);
  545. if(remoteProgram) {
  546. *task.var_a = remoteProgram->team == program.team ? 2: 1;
  547. *task.var_b = i;
  548. break;
  549. }
  550. }
  551. task.instIndex += 1;
  552. break;
  553. }
  554. case SET:
  555. *task.var_a = task.b;
  556. task.instIndex += 1;
  557. break;
  558. case ADD:
  559. *task.var_a += task.b;
  560. task.instIndex += 1;
  561. break;
  562. case SUB:
  563. *task.var_a -= task.b;
  564. task.instIndex += 1;
  565. break;
  566. case MUL:
  567. *task.var_a *= task.b;
  568. task.instIndex += 1;
  569. break;
  570. case DIV:
  571. if(task.b == 0) {
  572. program.error = DivisionByZero;
  573. break;
  574. }
  575. *task.var_a /= task.b;
  576. task.instIndex += 1;
  577. break;
  578. case MOD:
  579. if(task.b == 0) {
  580. program.error = DivisionByZero;
  581. break;
  582. }
  583. *task.var_a %= task.b;
  584. task.instIndex += 1;
  585. break;
  586. case MIN:
  587. *task.var_a = qMin(task.a, task.b);
  588. task.instIndex += 1;
  589. break;
  590. case MAX:
  591. *task.var_a = qMax(task.a, task.b);
  592. task.instIndex += 1;
  593. break;
  594. case RANDOM:
  595. *task.var_a = task.b + (rand() % (task.c - task.b + 1));
  596. task.instIndex += 1;
  597. break;
  598. case IF:
  599. task.instIndex += ((task.a == task.b) ? 1 : 2);
  600. break;
  601. case IFN:
  602. task.instIndex += ((task.a != task.b) ? 1 : 2);
  603. break;
  604. case IFG:
  605. task.instIndex += ((task.a > task.b) ? 1 : 2);
  606. break;
  607. case IFL:
  608. task.instIndex += ((task.a < task.b) ? 1 : 2);
  609. break;
  610. case IFGE:
  611. task.instIndex += ((task.a >= task.b) ? 1 : 2);
  612. break;
  613. case IFLE:
  614. task.instIndex += ((task.a <= task.b) ? 1 : 2);
  615. break;
  616. default:
  617. task.instIndex += 1;
  618. break;
  619. }
  620. }