deck.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977
  1. #include "deck.h"
  2. #include "utils.h"
  3. #include <algorithm>
  4. #include <map>
  5. #include <sstream>
  6. Deck::Deck(door::ANSIColor backcolor) : card_back_color{backcolor} {
  7. for (int i = 0; i < 52; ++i) {
  8. cards.push_back(cardOf(i));
  9. }
  10. // 0 = BLANK, 1-4 levels
  11. for (int i = 0; i < 5; ++i) {
  12. backs.push_back(backOf(i));
  13. }
  14. mark.push_back(markOf(0));
  15. mark.push_back(markOf(1));
  16. }
  17. Deck::~Deck() {
  18. /*
  19. for (auto c : cards) {
  20. delete c;
  21. }
  22. cards.clear();
  23. for (auto b : backs) {
  24. delete b;
  25. }
  26. backs.clear();
  27. for (auto m : mark) {
  28. delete m;
  29. }
  30. mark.clear();
  31. */
  32. }
  33. Deck::Deck(Deck &&ref) {
  34. card_back_color = ref.card_back_color;
  35. /*
  36. for (auto c : cards)
  37. delete c;
  38. cards.clear();
  39. */
  40. cards = ref.cards;
  41. ref.cards.clear();
  42. /*
  43. for (auto b : backs)
  44. delete b;
  45. backs.clear();
  46. */
  47. backs = ref.backs;
  48. ref.backs.clear();
  49. /*
  50. for (auto m : mark)
  51. delete m;
  52. mark.clear();
  53. */
  54. mark = ref.mark;
  55. ref.mark.clear();
  56. // card_height = ref.card_height;
  57. };
  58. Deck &Deck::operator=(Deck &&ref) {
  59. card_back_color = ref.card_back_color;
  60. /*
  61. for (auto c : cards)
  62. delete c;
  63. cards.clear();
  64. */
  65. cards = ref.cards;
  66. ref.cards.clear();
  67. /*
  68. for (auto b : backs)
  69. delete b;
  70. backs.clear();
  71. */
  72. backs = ref.backs;
  73. ref.backs.clear();
  74. /*
  75. for (auto m : mark)
  76. delete m;
  77. mark.clear();
  78. */
  79. mark = ref.mark;
  80. ref.mark.clear();
  81. // card_height = ref.card_height;
  82. return *this;
  83. }
  84. int Deck::getDeck(int c) { return c / 52; }
  85. int Deck::getSuit(int c) { return (c % 52) / 13; }
  86. int Deck::getRank(int c) { return (c % 52) % 13; }
  87. char Deck::rankSymbol(int c) {
  88. const char symbols[] = "A23456789TJQK";
  89. return symbols[c];
  90. }
  91. std::string Deck::suitSymbol(int c) {
  92. // unicode
  93. if (door::unicode) {
  94. switch (c) {
  95. case 0:
  96. return std::string("\u2665");
  97. case 1:
  98. return std::string("\u2666");
  99. case 2:
  100. return std::string("\u2663");
  101. case 3:
  102. return std::string("\u2660");
  103. }
  104. } else {
  105. if (door::full_cp437) {
  106. switch (c) {
  107. case 0:
  108. return std::string(1, '\x03');
  109. case 1:
  110. return std::string(1, '\x04');
  111. case 2:
  112. return std::string(1, '\x05');
  113. case 3:
  114. return std::string(1, '\x06');
  115. }
  116. } else {
  117. // These look horrible!
  118. switch (c) {
  119. case 0:
  120. return std::string(1, '*'); // H
  121. case 1:
  122. return std::string(1, '^'); // D
  123. case 2:
  124. return std::string(1, '%'); // C
  125. case 3:
  126. return std::string(1, '$'); // S
  127. }
  128. }
  129. }
  130. return std::string("!", 1);
  131. }
  132. shared_panel Deck::cardOf(int c) {
  133. int suit = getSuit(c);
  134. int rank = getRank(c);
  135. bool is_red = (suit < 2);
  136. door::ANSIColor color;
  137. if (is_red) {
  138. color = door::ANSIColor(door::COLOR::RED, door::COLOR::WHITE);
  139. } else {
  140. color = door::ANSIColor(door::COLOR::BLACK, door::COLOR::WHITE);
  141. }
  142. shared_panel p = std::make_shared<door::Panel>(0, 0, 5);
  143. // setColor sets border_color. NOT WHAT I WANT.
  144. // p->setColor(color);
  145. char r = rankSymbol(rank);
  146. std::string s = suitSymbol(suit);
  147. // build lines
  148. std::ostringstream oss;
  149. oss << r << s << " ";
  150. std::string str = oss.str();
  151. p->addLine(std::make_unique<door::Line>(str, 5, color));
  152. oss.str(std::string());
  153. oss.clear();
  154. if (card_height == 5)
  155. p->addLine(std::make_unique<door::Line>(" ", 5, color));
  156. oss << " " << s << " ";
  157. str = oss.str();
  158. p->addLine(std::make_unique<door::Line>(str, 5, color));
  159. oss.str(std::string());
  160. oss.clear();
  161. if (card_height == 5)
  162. p->addLine(std::make_unique<door::Line>(" ", 5, color));
  163. oss << " " << s << r;
  164. str = oss.str();
  165. p->addLine(std::make_unique<door::Line>(str, 5, color));
  166. oss.str(std::string());
  167. oss.clear();
  168. return p;
  169. }
  170. std::string Deck::backSymbol(int level) {
  171. std::string c;
  172. if (level == 0) {
  173. c = ' ';
  174. return c;
  175. }
  176. if (door::unicode) {
  177. switch (level) {
  178. case 1:
  179. c = "\u2591";
  180. break;
  181. case 2:
  182. c = "\u2592";
  183. break;
  184. case 3:
  185. c = "\u2593";
  186. break;
  187. case 4:
  188. c = "\u2588";
  189. break;
  190. }
  191. } else {
  192. switch (level) {
  193. case 1:
  194. c = "\xb0";
  195. break;
  196. case 2:
  197. c = "\xb1";
  198. break;
  199. case 3:
  200. c = "\xb2";
  201. break;
  202. case 4:
  203. c = "\xdb";
  204. break;
  205. }
  206. }
  207. return c;
  208. }
  209. shared_panel Deck::backOf(int level) {
  210. // using: \xb0, 0xb1, 0xb2, 0xdb
  211. // OR: \u2591, \u2592, \u2593, \u2588
  212. // door::ANSIColor color(door::COLOR::RED, door::COLOR::BLACK);
  213. shared_panel p = std::make_shared<door::Panel>(0, 0, 5);
  214. std::string c = backSymbol(level);
  215. std::string l = c + c + c + c + c;
  216. for (int x = 0; x < card_height; ++x) {
  217. p->addLine(std::make_unique<door::Line>(l, 5, card_back_color));
  218. };
  219. // p->addLine(std::make_unique<door::Line>(l, 5, card_back_color));
  220. // p->addLine(std::make_unique<door::Line>(l, 5, card_back_color));
  221. return p;
  222. }
  223. shared_panel Deck::markOf(int c) {
  224. shared_panel p = std::make_shared<door::Panel>(1);
  225. door::ANSIColor color = door::ANSIColor(
  226. door::COLOR::BLUE, door::COLOR::WHITE); // , door::ATTR::BOLD);
  227. std::string m;
  228. if (c == 0)
  229. m = " ";
  230. else {
  231. if (door::unicode) {
  232. m = "\u25a0";
  233. } else {
  234. m = "\xfe";
  235. }
  236. }
  237. p->addLine(std::make_unique<door::Line>(m, 1, color));
  238. return p;
  239. }
  240. shared_panel Deck::card(int c) { return cards[c]; }
  241. /**
  242. * @brief Return panel for back of card.
  243. *
  244. * - 0 = Blank
  245. * - 1 = level 1 (furthest/darkest)
  246. * - 2 = level 2
  247. * - 3 = level 3
  248. * - 4 = level 4 (closest/lightest)
  249. *
  250. * - 5 = left (fills with left corner in place)
  251. * - 6 = right (fills right corner)
  252. * - 7 = both (fills both corners)
  253. *
  254. * @param level
  255. * @return door::Panel*
  256. */
  257. shared_panel Deck::back(int level) { return backs[level]; }
  258. const std::array<std::pair<int, int>, 18> Deck::blocks = {
  259. make_pair(3, 4), make_pair(5, 6), make_pair(7, 8), // end row 1
  260. make_pair(9, 10), make_pair(10, 11), make_pair(12, 13),
  261. make_pair(13, 14), make_pair(15, 16), make_pair(16, 17),
  262. make_pair(18, 19), // end row 2
  263. make_pair(19, 20), make_pair(20, 21), make_pair(21, 22),
  264. make_pair(22, 23), make_pair(23, 24), make_pair(24, 25),
  265. make_pair(25, 26), make_pair(26, 27) // 27
  266. };
  267. /**
  268. * @brief Which card(s) are unblocked by this card?
  269. *
  270. * @param card
  271. * @return * int
  272. */
  273. std::vector<int> Deck::unblocks(int card) {
  274. std::vector<int> result;
  275. for (size_t i = 0; i < blocks.size(); ++i) {
  276. if ((blocks.at(i).first == card) || (blocks.at(i).second == card)) {
  277. result.push_back(i);
  278. }
  279. }
  280. return result;
  281. }
  282. /**
  283. * @brief Can this card play on this other card?
  284. *
  285. * @param card1
  286. * @param card2
  287. * @return true
  288. * @return false
  289. */
  290. bool Deck::canPlay(int card1, int card2) {
  291. int rank1, rank2;
  292. rank1 = getRank(card1);
  293. rank2 = getRank(card2);
  294. // this works %13 handles wrap-around for us.
  295. if ((rank1 + 1) % 13 == rank2)
  296. return true;
  297. if (rank1 == 0) {
  298. rank1 += 13;
  299. }
  300. if (rank1 - 1 == rank2)
  301. return true;
  302. return false;
  303. }
  304. /**
  305. * @brief Returns marker
  306. *
  307. * 0 = blank
  308. * 1 = [] symbol thing \xfe ■
  309. *
  310. * @param c
  311. * @return door::Panel*
  312. */
  313. shared_panel Deck::marker(int c) { return mark[c]; }
  314. /**
  315. * @brief removeCard
  316. *
  317. * This removes a card at a given position (c).
  318. * It needs to know if there are cards underneath
  319. * to the left or right. (If so, we restore those missing parts.)
  320. *
  321. * @param door
  322. * @param c
  323. * @param off_x
  324. * @param off_y
  325. * @param left
  326. * @param right
  327. */
  328. void Deck::removeCard(door::Door &door, int c, int off_x, int off_y, bool left,
  329. bool right) {
  330. int cx, cy, level;
  331. cardPosLevel(c, cx, cy, level);
  332. if (level > 1)
  333. --level;
  334. std::string cstr = backSymbol(level);
  335. door::Goto g(cx + off_x, cy + off_y);
  336. door << g << card_back_color;
  337. if (left)
  338. door << cstr;
  339. else
  340. door << " ";
  341. door << " ";
  342. if (right)
  343. door << cstr;
  344. else
  345. door << " ";
  346. g.set(cx + off_x, cy + off_y + 1);
  347. door << g << " ";
  348. g.set(cx + off_x, cy + off_y + 2);
  349. door << g << " ";
  350. }
  351. /*
  352. Layout spacing 1:
  353. 1 2 3 4 5 6
  354. 123456789012345678901234567890123456789012345678901234567890
  355. ░░░░░ ░░░░░ ░░░░░
  356. ░░░░░ ░░░░░ ░░░░░
  357. ▒▒▒▒▒░▒▒▒▒▒ #####░##### #####░#####
  358. ▒▒▒▒▒ ▒▒▒▒▒ ##### ##### ##### #####
  359. ▓▓▓▓▓▒▓▓▓▓▓▒▓▓▓▓▓ #####=#####=##### #####=#####=#####
  360. ▓▓▓▓▓ ▓▓▓▓▓ ▓▓▓▓▓ ##### ##### ##### ##### ##### #####
  361. █████▓█████▓█████▓#####=#####=#####=#####=#####=#####=#####
  362. █████ █████ █████ ##### ##### ##### ##### ##### ##### #####
  363. █████ █████ █████ ##### ##### ##### ##### ##### ##### #####
  364. width = 5 * 10 + (1*9) = 59 OK!
  365. Layout with spacing = 2:
  366. EEEEE
  367. ZZZZZ
  368. yyyyyZZZyyyyy
  369. yyyyy yyyyy
  370. XXXXXyyyXXXXXyyyXXXXX
  371. XXXXX XXXXX XXXXX
  372. width = 5 * 10 + (2 * 9) = 50+18 = 68 ! I could do that!
  373. */
  374. #ifdef NO
  375. /**
  376. * @brief Where does this card go in relation to everything else?
  377. *
  378. * This function is deprecated, see the other cardgo.
  379. *
  380. * @param pos
  381. * @param space
  382. * @param h
  383. * @param x
  384. * @param y
  385. * @param level
  386. */
  387. void cardgo(int pos, int space, int h, int &x, int &y, int &level) {
  388. // special cases here
  389. if (pos == 28) {
  390. // cardgo(23, space, h, x, y, level);
  391. cardgo(23, x, y, level);
  392. y += h + 1;
  393. --level;
  394. return;
  395. } else {
  396. if (pos == 29) {
  397. // cardgo(22, space, h, x, y, level);
  398. cardgo(22, x, y, level);
  399. y += h + 1;
  400. --level;
  401. return;
  402. }
  403. }
  404. const int CARD_WIDTH = 5;
  405. int HALF_WIDTH = 3;
  406. // space = 1 or 3
  407. // int space = 1;
  408. // space = 3;
  409. HALF_WIDTH += space / 2;
  410. /*
  411. int levels[4] = {3, 6, 9, 10};
  412. for (level = 0; level < 4; ++level) {
  413. if (pos < levels[level]) {
  414. level++;
  415. // we're here
  416. y = (level -1) * 2 + 1;
  417. } else {
  418. pos -= levels[level];
  419. }
  420. }
  421. */
  422. int between = CARD_WIDTH + space;
  423. if (pos < 3) {
  424. // top
  425. level = 1;
  426. y = (level - 1) * (h - 1) + 1;
  427. x = pos * (between * 3) + between + HALF_WIDTH + space; // 10
  428. return;
  429. } else {
  430. pos -= 3;
  431. }
  432. if (pos < 6) {
  433. level = 2;
  434. y = (level - 1) * (h - 1) + 1;
  435. int group = (pos) / 2;
  436. x = pos * between + (group * between) + CARD_WIDTH + space * 2;
  437. return;
  438. } else {
  439. pos -= 6;
  440. }
  441. if (pos < 9) {
  442. level = 3;
  443. y = (level - 1) * (h - 1) + 1;
  444. x = pos * between + HALF_WIDTH + space;
  445. return;
  446. } else {
  447. pos -= 9;
  448. }
  449. if (pos < 10) {
  450. level = 4;
  451. y = (level - 1) * (h - 1) + 1;
  452. x = (pos)*between + space;
  453. return;
  454. } else {
  455. // something is wrong.
  456. y = -1;
  457. x = -1;
  458. level = -1;
  459. }
  460. }
  461. #endif
  462. void cardPos(int pos, int &x, int &y) {
  463. const int space = 3;
  464. const int height = 3;
  465. // special cases here
  466. if (pos == 28) {
  467. cardPos(23, x, y);
  468. y += height + 1;
  469. return;
  470. } else {
  471. if (pos == 29) {
  472. cardPos(22, x, y);
  473. y += height + 1;
  474. return;
  475. }
  476. }
  477. const int CARD_WIDTH = 5;
  478. int HALF_WIDTH = 3;
  479. HALF_WIDTH += space / 2;
  480. int between = CARD_WIDTH + space;
  481. int level; // I still need level in my calculations
  482. if (pos < 3) {
  483. // top
  484. level = 1;
  485. y = (level - 1) * (height - 1) + 1;
  486. x = pos * (between * 3) + between + HALF_WIDTH + space; // 10
  487. return;
  488. } else {
  489. pos -= 3;
  490. }
  491. if (pos < 6) {
  492. level = 2;
  493. y = (level - 1) * (height - 1) + 1;
  494. int group = (pos) / 2;
  495. x = pos * between + (group * between) + CARD_WIDTH + space * 2;
  496. return;
  497. } else {
  498. pos -= 6;
  499. }
  500. if (pos < 9) {
  501. level = 3;
  502. y = (level - 1) * (height - 1) + 1;
  503. x = pos * between + HALF_WIDTH + space;
  504. return;
  505. } else {
  506. pos -= 9;
  507. }
  508. if (pos < 10) {
  509. level = 4;
  510. y = (level - 1) * (height - 1) + 1;
  511. x = (pos)*between + space;
  512. return;
  513. } else {
  514. // something is wrong.
  515. y = -1;
  516. x = -1;
  517. level = -1;
  518. }
  519. }
  520. void cardLevel(int pos, int &level) {
  521. /*
  522. const int space = 3;
  523. const int height = 3;
  524. */
  525. // special cases here
  526. if (pos == 28) {
  527. cardLevel(23, level);
  528. --level;
  529. return;
  530. } else {
  531. if (pos == 29) {
  532. cardLevel(22, level);
  533. --level;
  534. return;
  535. }
  536. }
  537. /*
  538. const int CARD_WIDTH = 5;
  539. int HALF_WIDTH = 3;
  540. HALF_WIDTH += space / 2;
  541. int between = CARD_WIDTH + space;
  542. */
  543. if (pos < 3) {
  544. // top
  545. level = 1;
  546. return;
  547. } else {
  548. pos -= 3;
  549. }
  550. if (pos < 6) {
  551. level = 2;
  552. return;
  553. } else {
  554. pos -= 6;
  555. }
  556. if (pos < 9) {
  557. level = 3;
  558. return;
  559. } else {
  560. pos -= 9;
  561. }
  562. if (pos < 10) {
  563. level = 4;
  564. return;
  565. } else {
  566. // something is wrong.
  567. level = -1;
  568. }
  569. }
  570. /**
  571. * @brief Given card pos, calculate x, y, and level values.
  572. *
  573. * level is used to determine the card background gradient.
  574. *
  575. * @param pos
  576. * @param x
  577. * @param y
  578. * @param level
  579. */
  580. void cardPosLevel(int pos, int &x, int &y, int &level) {
  581. const int space = 3;
  582. const int height = 3;
  583. // special cases here
  584. if (pos == 28) {
  585. cardPosLevel(23, x, y, level);
  586. y += height + 1;
  587. --level;
  588. return;
  589. } else {
  590. if (pos == 29) {
  591. cardPosLevel(22, x, y, level);
  592. y += height + 1;
  593. --level;
  594. return;
  595. }
  596. }
  597. const int CARD_WIDTH = 5;
  598. int HALF_WIDTH = 3;
  599. HALF_WIDTH += space / 2;
  600. int between = CARD_WIDTH + space;
  601. if (pos < 3) {
  602. // top
  603. level = 1;
  604. y = (level - 1) * (height - 1) + 1;
  605. x = pos * (between * 3) + between + HALF_WIDTH + space; // 10
  606. return;
  607. } else {
  608. pos -= 3;
  609. }
  610. if (pos < 6) {
  611. level = 2;
  612. y = (level - 1) * (height - 1) + 1;
  613. int group = (pos) / 2;
  614. x = pos * between + (group * between) + CARD_WIDTH + space * 2;
  615. return;
  616. } else {
  617. pos -= 6;
  618. }
  619. if (pos < 9) {
  620. level = 3;
  621. y = (level - 1) * (height - 1) + 1;
  622. x = pos * between + HALF_WIDTH + space;
  623. return;
  624. } else {
  625. pos -= 9;
  626. }
  627. if (pos < 10) {
  628. level = 4;
  629. y = (level - 1) * (height - 1) + 1;
  630. x = (pos)*between + space;
  631. return;
  632. } else {
  633. // something is wrong.
  634. y = -1;
  635. x = -1;
  636. level = -1;
  637. }
  638. }
  639. /**
  640. * @brief shuffle deck of cards
  641. *
  642. * example of seeding the deck for a given date 2/27/2021 game 1
  643. * std::seed_seq s1{2021, 2, 27, 1};
  644. * vector<int> deck1 = shuffleCards(s1, 1);
  645. * @param seed
  646. * @param decks
  647. * @return vector<int>
  648. */
  649. cards shuffleCards(std::seed_seq &seed, int decks) {
  650. std::mt19937 gen;
  651. // build deck of cards
  652. int size = decks * 52;
  653. std::vector<int> deck;
  654. deck.reserve(size);
  655. for (int x = 0; x < size; ++x) {
  656. deck.push_back(x);
  657. }
  658. // repeatable, but random
  659. gen.seed(seed);
  660. std::shuffle(deck.begin(), deck.end(), gen);
  661. return deck;
  662. }
  663. /**
  664. * @brief generate a vector of ints to track card states.
  665. *
  666. * This initializes everything to 0.
  667. *
  668. * @param decks
  669. * @return cards
  670. */
  671. cards makeCardStates(int decks) {
  672. // auto states = std::unique_ptr<std::vector<int>>(); // (decks * 52, 0)>;
  673. std::vector<int> states;
  674. states.assign(decks * 52, 0);
  675. return states;
  676. }
  677. /**
  678. * @brief Find the next card we can move the marker to.
  679. *
  680. * if left, look in the left - direction, otherwise the right + direction.
  681. * current is the current active card.
  682. * states is the card states (0 = down, 1 = in play, 2 = removed)
  683. *
  684. * updated: If we can't go any further left (or right), then
  685. * roll around to the other side.
  686. *
  687. * @param left
  688. * @param states
  689. * @param current
  690. * @return int
  691. */
  692. int findNextActiveCard(bool left, const cards &states, int current) {
  693. int cx, cy;
  694. int current_x;
  695. cardPos(current, cx, cy);
  696. current_x = cx;
  697. int x;
  698. int pos = -1;
  699. int pos_x;
  700. int max_pos = -1;
  701. int max_x = -1;
  702. int min_pos = -1;
  703. int min_x = 100;
  704. if (left)
  705. pos_x = 0;
  706. else
  707. pos_x = 100;
  708. for (x = 0; x < 28; x++) {
  709. if (states.at(x) == 1) {
  710. // possible location
  711. if (x == current)
  712. continue;
  713. cardPos(x, cx, cy);
  714. // find max and min while we're iterating here
  715. if (cx < min_x) {
  716. min_pos = x;
  717. min_x = cx;
  718. }
  719. if (cx > max_x) {
  720. max_pos = x;
  721. max_x = cx;
  722. }
  723. if (left) {
  724. if ((cx < current_x) and (cx > pos_x)) {
  725. pos_x = cx;
  726. pos = x;
  727. }
  728. } else {
  729. if ((cx > current_x) and (cx < pos_x)) {
  730. pos_x = cx;
  731. pos = x;
  732. }
  733. }
  734. }
  735. }
  736. if (pos == -1) {
  737. // we couldn't find one
  738. if (left) {
  739. // use max -- roll around to the right
  740. pos = max_pos;
  741. } else {
  742. // use min -- roll around to the left
  743. pos = min_pos;
  744. }
  745. }
  746. return pos;
  747. }
  748. /**
  749. * @brief Find the next closest card to move to.
  750. *
  751. * Given the card states, this finds the next closest card.
  752. * Uses current.
  753. *
  754. * return -1 there's no options to go to. (END OF GAME)
  755. * @param states
  756. * @param current
  757. * @return int
  758. */
  759. int findClosestActiveCard(const cards &states, int current) {
  760. int cx, cy;
  761. int current_x;
  762. cardPos(current, cx, cy);
  763. current_x = cx;
  764. int x;
  765. int pos = -1;
  766. int pos_x = -1;
  767. for (x = 0; x < 28; x++) {
  768. if (states.at(x) == 1) {
  769. // possible location
  770. if (x == current)
  771. continue;
  772. cardPos(x, cx, cy);
  773. if (pos == -1) {
  774. pos = x;
  775. pos_x = cx;
  776. } else {
  777. if (abs(current_x - cx) < abs(current_x - pos_x)) {
  778. pos = x;
  779. pos_x = cx;
  780. }
  781. }
  782. }
  783. }
  784. return pos;
  785. }
  786. vector<std::string> deck_colors = {std::string("All"), std::string("Blue"),
  787. std::string("Cyan"), std::string("Green"),
  788. std::string("Magenta"), std::string("Red")};
  789. /**
  790. * @brief menu render that sets the text color based on the color found in the
  791. * text itself.
  792. *
  793. * @param c1 [] brackets
  794. * @param c2 text within brackets
  795. * @param c3 base color give (we set the FG, we use the BG)
  796. * @return door::renderFunction
  797. */
  798. door::renderFunction makeColorRender(door::ANSIColor c1, door::ANSIColor c2,
  799. door::ANSIColor c3) {
  800. door::renderFunction render = [c1, c2,
  801. c3](const std::string &txt) -> door::Render {
  802. door::Render r(txt);
  803. bool option = true;
  804. door::ColorOutput co;
  805. // I need this mutable
  806. door::ANSIColor textColor = c3;
  807. // Color update:
  808. {
  809. std::string found;
  810. for (auto &dc : deck_colors) {
  811. if (txt.find(dc) != string::npos) {
  812. found = dc;
  813. break;
  814. }
  815. }
  816. if (!found.empty()) {
  817. if (found == "All") {
  818. // handle this some other way.
  819. textColor.setFg(door::COLOR::WHITE);
  820. } else {
  821. door::ANSIColor c = stringToANSIColor(found);
  822. textColor.setFg(c.getFg());
  823. }
  824. }
  825. }
  826. co.pos = 0;
  827. co.len = 0;
  828. co.c = c1;
  829. int tpos = 0;
  830. for (char const &c : txt) {
  831. if (option) {
  832. if (c == '[' or c == ']') {
  833. if (co.c != c1)
  834. if (co.len != 0) {
  835. r.outputs.push_back(co);
  836. co.reset();
  837. co.pos = tpos;
  838. }
  839. co.c = c1;
  840. if (c == ']')
  841. option = false;
  842. } else {
  843. if (co.c != c2)
  844. if (co.len != 0) {
  845. r.outputs.push_back(co);
  846. co.reset();
  847. co.pos = tpos;
  848. }
  849. co.c = c2;
  850. }
  851. } else {
  852. if (co.c != textColor)
  853. if (co.len != 0) {
  854. r.outputs.push_back(co);
  855. co.reset();
  856. co.pos = tpos;
  857. }
  858. co.c = textColor;
  859. }
  860. co.len++;
  861. tpos++;
  862. }
  863. if (co.len != 0) {
  864. r.outputs.push_back(co);
  865. }
  866. return r;
  867. };
  868. return render;
  869. }
  870. // convert a string to an option
  871. // an option to the string to store
  872. // This needs to be updated to use deck_colors.
  873. door::ANSIColor stringToANSIColor(std::string colorCode) {
  874. std::map<std::string, door::ANSIColor> codeMap = {
  875. {std::string("BLUE"), door::ANSIColor(door::COLOR::BLUE)},
  876. {std::string("RED"), door::ANSIColor(door::COLOR::RED)},
  877. {std::string("CYAN"), door::ANSIColor(door::COLOR::CYAN)},
  878. {std::string("GREEN"), door::ANSIColor(door::COLOR::GREEN)},
  879. {std::string("MAGENTA"), door::ANSIColor(door::COLOR::MAGENTA)}};
  880. std::string code = colorCode;
  881. string_toupper(code);
  882. auto iter = codeMap.find(code);
  883. if (iter != codeMap.end()) {
  884. return iter->second;
  885. }
  886. // And if it doesn't match, and isn't ALL ... ?
  887. // if (code.compare("ALL") == 0) {
  888. std::random_device dev;
  889. std::mt19937_64 rng(dev());
  890. std::uniform_int_distribution<size_t> idDist(0, codeMap.size() - 1);
  891. iter = codeMap.begin();
  892. std::advance(iter, idDist(rng));
  893. return iter->second;
  894. // }
  895. }
  896. std::string stringFromColorOptions(int opt) { return deck_colors[opt]; }