1
1

simulator.cpp 23 KB

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