1
1

simulator.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722
  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_1 : v = program.vars[0]; var_v = &program.vars[0]; break;
  19. case Local_2 : v = program.vars[1]; var_v = &program.vars[1]; break;
  20. case Local_3 : v = program.vars[2]; var_v = &program.vars[2]; break;
  21. case Local_4 : v = program.vars[3]; var_v = &program.vars[3]; break;
  22. case Local_5 : v = program.vars[4]; var_v = &program.vars[4]; break;
  23. case Local_6 : v = program.vars[5]; var_v = &program.vars[5]; break;
  24. case Local_7 : v = program.vars[6]; var_v = &program.vars[6]; break;
  25. case Local_8 : v = program.vars[7]; var_v = &program.vars[7]; break;
  26. case Local_9 : v = program.vars[8]; var_v = &program.vars[8]; break;
  27. case Local_10: v = program.vars[9]; var_v = &program.vars[9]; break;
  28. case Local_11: v = program.vars[10]; var_v = &program.vars[10]; break;
  29. case Local_12: v = program.vars[11]; var_v = &program.vars[11]; break;
  30. case Local_13: v = program.vars[12]; var_v = &program.vars[12]; break;
  31. case Local_14: v = program.vars[13]; var_v = &program.vars[13]; break;
  32. case Local_15: v = program.vars[14]; var_v = &program.vars[14]; break;
  33. case Local_16: v = program.vars[15]; var_v = &program.vars[15]; break;
  34. case Local_17: v = program.vars[16]; var_v = &program.vars[16]; break;
  35. case Local_18: v = program.vars[17]; var_v = &program.vars[17]; break;
  36. case Local_19: v = program.vars[18]; var_v = &program.vars[18]; break;
  37. case Local_20: 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. Program* Simulator::findProgram(Position position) {
  217. for(auto& program : programs) {
  218. if(program.position.x == position.x && program.position.y == position.y && program.error == NoError) {
  219. return &program;
  220. }
  221. }
  222. return nullptr;
  223. }
  224. void Simulator::removeErroneousPrograms() {
  225. auto it = std::remove_if(programs.begin(), programs.end(), [](const Program& program){ return program.error != NoError; });
  226. for(auto itr = it; itr != programs.end(); ++itr) {
  227. --(itr->team->programCount);
  228. }
  229. programs.erase(it, programs.end());
  230. }
  231. void Simulator::simulate() {
  232. removeErroneousPrograms();
  233. for (auto& program : programs) {
  234. auto& taskIndex = program.taskIndex;
  235. // do nothing if not active
  236. if(!program.active) {
  237. continue;
  238. }
  239. // error if no active task exists
  240. if(find_if(program.tasks.begin(), program.tasks.end(), [](const Task& task){ return !task.paused; }) == program.tasks.end()) {
  241. program.error = Unemployment;
  242. continue;
  243. }
  244. // switch to next unpasued task
  245. do {
  246. taskIndex = (taskIndex + 1) % program.tasks.size();
  247. } while(program.tasks[taskIndex].paused);
  248. // check if we are still executing an instruction
  249. auto& task = program.tasks[taskIndex];
  250. if(task.remainingCycles > 0) {
  251. --task.remainingCycles;
  252. continue;
  253. }
  254. else {
  255. endInstruction(program, task);
  256. beginInstruction(program, task);
  257. }
  258. }
  259. ++cycle;
  260. }
  261. void Simulator::beginInstruction(Program& program, Task& task) {
  262. // handle invalid bank number
  263. if(program.banks.empty() || task.bankIndex >= program.banks.size()) {
  264. program.error = InvalidBankNumber;
  265. return;
  266. }
  267. // handle autoreset to bank 0,0 if instructionIndex is out of banks bound or bank is empty
  268. if(!program.banks[task.bankIndex] || task.instIndex >= program.banks[task.bankIndex]->instructions.size()) {
  269. task.bankIndex = 0;
  270. task.instIndex = 0;
  271. }
  272. // handle data hunger
  273. if(task.bankIndex == 0 && !program.banks[0]) {
  274. program.error = DataHunger;
  275. return;
  276. }
  277. task.execBank = program.banks[task.bankIndex];
  278. auto& instruction = program.banks[task.bankIndex]->instructions[task.instIndex];
  279. // decode instruction parameters
  280. decodeInstructionParameters(program, task, instruction);
  281. // calculate cycle durations and check preconditions
  282. switch(instruction.command) {
  283. case CREATE:
  284. if(program.instructionSet < 2) {
  285. program.error = HigherInstructionSetRequired;
  286. break;
  287. }
  288. if(task.a < 0 || task.a > 2 || task.b < 1 || task.b > 50 || task.c < 0 || task.c > 1) {
  289. program.error = InvalidParameter;
  290. break;
  291. }
  292. task.remainingCycles = 100 + 50 * task.a + 25 * task.b + 120 * task.c;
  293. break;
  294. case MOVE:
  295. if(program.mobile < 1) {
  296. program.error = MobilityRequired;
  297. break;
  298. }
  299. task.remainingCycles = 20;
  300. break;
  301. case DIE:
  302. task.remainingCycles = 1;
  303. break;
  304. case TRANS: {
  305. int ar = task.a - 1;
  306. int br = task.b - 1;
  307. if(program.instructionSet < 1) {
  308. program.error = HigherInstructionSetRequired;
  309. break;
  310. }
  311. if(ar < 0 || ar >= program.banks.size()) {
  312. program.error = InvalidBankNumber;
  313. break;
  314. }
  315. const auto& bank = program.banks[ar];
  316. task.remainingCycles = 14 + (bank ? bank->instructions.size() : 0);
  317. break;
  318. }
  319. case RTRANS: {
  320. int ar = task.a - 1;
  321. int br = task.b - 1;
  322. if(program.instructionSet < 1) {
  323. program.error = HigherInstructionSetRequired;
  324. break;
  325. }
  326. if(ar < 0 || ar >= 50 || br < 0 || br >= program.banks.size()) {
  327. program.error = InvalidBankNumber;
  328. break;
  329. }
  330. auto remotePosition = calcPosition(program.position, task.direction, 1);
  331. auto remoteProgram = findProgram(remotePosition);
  332. task.remainingCycles = 14 + remoteProgram ? (ar < remoteProgram->banks.size() ? (remoteProgram->banks[ar] ? remoteProgram->banks[ar]->instructions.size() : 0): 0): 0;
  333. break;
  334. }
  335. case TURN:
  336. task.remainingCycles = 8;
  337. break;
  338. case JUMP:
  339. task.remainingCycles = 1;
  340. break;
  341. case AJUMP:
  342. task.remainingCycles = 1;
  343. break;
  344. case BJUMP:
  345. task.remainingCycles = 2;
  346. break;
  347. case SCAN:
  348. if(program.instructionSet < 1) {
  349. program.error = HigherInstructionSetRequired;
  350. break;
  351. }
  352. task.remainingCycles = 8;
  353. break;
  354. case FARSCAN:
  355. if(program.instructionSet < 1) {
  356. program.error = HigherInstructionSetRequired;
  357. break;
  358. }
  359. task.remainingCycles = 10 + 3 * task.c;
  360. break;
  361. case SET:
  362. task.remainingCycles = 2;
  363. break;
  364. case ADD:
  365. task.remainingCycles = 2;
  366. break;
  367. case SUB:
  368. task.remainingCycles = 2;
  369. break;
  370. case MUL:
  371. task.remainingCycles = 2;
  372. break;
  373. case DIV:
  374. task.remainingCycles = 2;
  375. break;
  376. case MOD:
  377. task.remainingCycles = 2;
  378. break;
  379. case MIN:
  380. task.remainingCycles = 2;
  381. break;
  382. case MAX:
  383. task.remainingCycles = 2;
  384. break;
  385. case RANDOM:
  386. if(task.b > task.c) {
  387. program.error = InvalidParameter;
  388. break;
  389. }
  390. task.remainingCycles = 1;
  391. break;
  392. case IF:
  393. task.remainingCycles = 2;
  394. break;
  395. case IFN:
  396. task.remainingCycles = 2;
  397. break;
  398. case IFG:
  399. task.remainingCycles = 2;
  400. break;
  401. case IFL:
  402. task.remainingCycles = 2;
  403. break;
  404. case IFGE:
  405. task.remainingCycles = 2;
  406. break;
  407. case IFLE:
  408. task.remainingCycles = 2;
  409. break;
  410. case INIT:
  411. task.remainingCycles = 2;
  412. break;
  413. case BREAK:
  414. task.remainingCycles = 1;
  415. break;
  416. case RESUME:
  417. task.remainingCycles = 1;
  418. break;
  419. case SEIZE:
  420. task.remainingCycles = 1;
  421. break;
  422. case SLEEP:
  423. if(task.a > 2000) {
  424. program.error = InvalidParameter;
  425. break;
  426. }
  427. task.remainingCycles = task.a;
  428. break;
  429. case QUIT:
  430. task.remainingCycles = 1;
  431. break;
  432. }
  433. }
  434. void Simulator::endInstruction(Program& program, Task& task) {
  435. // we are not executing yet
  436. if(!task.execBank || program.error != NoError) {
  437. return;
  438. }
  439. // check if bank is overwritten, skip execution of current command and begin new bank at instruction 0
  440. if(task.execBank != program.banks[task.bankIndex]) {
  441. task.instIndex = 0;
  442. return;
  443. }
  444. // execute command
  445. auto& instruction = task.execBank->instructions[task.instIndex];
  446. switch(instruction.command) {
  447. case CREATE: {
  448. auto remotePosition = calcPosition(program.position, task.direction, 1);
  449. auto remoteProgram = findProgram(remotePosition);
  450. if(!remoteProgram) {
  451. programs.push_back(Program(program.team, task.direction, remotePosition, task.a, task.b, task.c));
  452. ++program.team->programCount;
  453. }
  454. task.instIndex += 1;
  455. break;
  456. }
  457. case MOVE: {
  458. auto remotePosition = calcPosition(program.position, task.direction, 1);
  459. auto remoteProgram = findProgram(remotePosition);
  460. if(!remoteProgram) {
  461. program.position = remotePosition;
  462. }
  463. task.instIndex += 1;
  464. break;
  465. }
  466. case DIE: {
  467. program.error = DieExecuted;
  468. task.instIndex += 1;
  469. break;
  470. }
  471. case TRANS: {
  472. int ar = task.a - 1;
  473. int br = task.b - 1;
  474. auto remotePosition = calcPosition(program.position, task.direction, 1);
  475. auto remoteProgram = findProgram(remotePosition);
  476. if(remoteProgram && br < remoteProgram->banks.size() && ar < program.banks.size()) {
  477. remoteProgram->banks[br] = program.banks[ar];
  478. }
  479. task.instIndex += 1;
  480. break;
  481. }
  482. case RTRANS: {
  483. int ar = task.a - 1;
  484. int br = task.b - 1;
  485. auto remotePosition = calcPosition(program.position, task.direction, 1);
  486. auto remoteProgram = findProgram(remotePosition);
  487. if(remoteProgram && ar < remoteProgram->banks.size() && br < program.banks.size()) {
  488. program.banks[br] = remoteProgram->banks[ar];
  489. }
  490. task.instIndex += 1;
  491. break;
  492. }
  493. case TURN: {
  494. task.direction = static_cast<Direction>(qMax(0, (task.direction + ((task.a >= 0) ? 1 : -1)) % 4));
  495. task.instIndex += 1;
  496. break;
  497. }
  498. case JUMP: {
  499. task.instIndex += task.a;
  500. break;
  501. }
  502. case AJUMP: {
  503. task.instIndex = task.a - 1;
  504. break;
  505. }
  506. case BJUMP: {
  507. task.bankIndex = task.a - 1;
  508. task.instIndex = task.b - 1;
  509. break;
  510. }
  511. case SCAN: {
  512. // Scans a field, result in #a
  513. // #a=0 ...empty.
  514. // #a=1 ...enemy
  515. // #a=2 ...friend
  516. auto remotePosition = calcPosition(program.position, task.direction, 1);
  517. auto remoteProgram = findProgram(remotePosition);
  518. *task.var_a = !remoteProgram ? 0 : remoteProgram->team == program.team ? 2: 1;
  519. task.instIndex += 1;
  520. break;
  521. }
  522. case FARSCAN: {
  523. // Scans up to c fields straight in front of the bot.
  524. // The nearest bot's type is stored in #a:
  525. // #a=0 ...empty.
  526. // #a=1 ...enemy
  527. // #a=2 ...friend
  528. // Its distance is stored in #b.
  529. *task.var_a = 0;
  530. *task.var_b = 0;
  531. for(int i = 0; i < task.c; ++i) {
  532. auto remotePosition = calcPosition(program.position, task.direction, i + 1);
  533. auto remoteProgram = findProgram(remotePosition);
  534. if(remoteProgram) {
  535. *task.var_a = remoteProgram->team == program.team ? 2: 1;
  536. *task.var_b = i;
  537. break;
  538. }
  539. }
  540. task.instIndex += 1;
  541. break;
  542. }
  543. case SET:
  544. *task.var_a = task.b;
  545. task.instIndex += 1;
  546. break;
  547. case ADD:
  548. *task.var_a += task.b;
  549. task.instIndex += 1;
  550. break;
  551. case SUB:
  552. *task.var_a -= task.b;
  553. task.instIndex += 1;
  554. break;
  555. case MUL:
  556. *task.var_a *= task.b;
  557. task.instIndex += 1;
  558. break;
  559. case DIV:
  560. if(task.b == 0) {
  561. program.error = DivisionByZero;
  562. break;
  563. }
  564. *task.var_a /= task.b;
  565. task.instIndex += 1;
  566. break;
  567. case MOD:
  568. if(task.b == 0) {
  569. program.error = DivisionByZero;
  570. break;
  571. }
  572. *task.var_a %= task.b;
  573. task.instIndex += 1;
  574. break;
  575. case MIN:
  576. *task.var_a = qMin(task.a, task.b);
  577. task.instIndex += 1;
  578. break;
  579. case MAX:
  580. *task.var_a = qMax(task.a, task.b);
  581. task.instIndex += 1;
  582. break;
  583. case RANDOM:
  584. *task.var_a = task.b + (rand() % (task.c - task.b + 1));
  585. task.instIndex += 1;
  586. break;
  587. case IF:
  588. task.instIndex += ((task.a == task.b) ? 1 : 2);
  589. break;
  590. case IFN:
  591. task.instIndex += ((task.a != task.b) ? 1 : 2);
  592. break;
  593. case IFG:
  594. task.instIndex += ((task.a > task.b) ? 1 : 2);
  595. break;
  596. case IFL:
  597. task.instIndex += ((task.a < task.b) ? 1 : 2);
  598. break;
  599. case IFGE:
  600. task.instIndex += ((task.a >= task.b) ? 1 : 2);
  601. break;
  602. case IFLE:
  603. task.instIndex += ((task.a <= task.b) ? 1 : 2);
  604. break;
  605. case INIT:
  606. task.instIndex += 1;
  607. break;
  608. case BREAK:
  609. task.instIndex += 1;
  610. break;
  611. case RESUME:
  612. task.instIndex += 1;
  613. break;
  614. case SEIZE:
  615. task.instIndex += 1;
  616. break;
  617. case SLEEP:
  618. task.instIndex += 1;
  619. break;
  620. case QUIT:
  621. task.instIndex += 1;
  622. break;
  623. default:
  624. task.instIndex += 1;
  625. break;
  626. }
  627. }