deck.cpp 21 KB

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