deck.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870
  1. #include "deck.h"
  2. #include <algorithm>
  3. #include <map>
  4. #include <sstream>
  5. Deck::Deck(int size) {
  6. cardback = door::ANSIColor(door::COLOR::RED);
  7. card_height = size;
  8. init();
  9. }
  10. Deck::Deck(door::ANSIColor backcolor, int size) : cardback{backcolor} {
  11. card_height = size;
  12. init();
  13. }
  14. void Deck::init(void) {
  15. if (card_height != 3) {
  16. if (card_height != 5) {
  17. card_height = 3;
  18. }
  19. }
  20. for (int i = 0; i < 52; ++i) {
  21. cards.push_back(card_of(i));
  22. }
  23. // 0 = BLANK, 1-4 levels
  24. for (int i = 0; i < 5; ++i) {
  25. backs.push_back(back_of(i));
  26. }
  27. mark.push_back(mark_of(0));
  28. mark.push_back(mark_of(1));
  29. }
  30. Deck::~Deck() {
  31. for (auto c : cards) {
  32. delete c;
  33. }
  34. cards.clear();
  35. for (auto b : backs) {
  36. delete b;
  37. }
  38. backs.clear();
  39. for (auto m : mark) {
  40. delete m;
  41. }
  42. mark.clear();
  43. }
  44. Deck::Deck(Deck &&ref) {
  45. cardback = ref.cardback;
  46. for (auto c : cards)
  47. delete c;
  48. cards.clear();
  49. cards = ref.cards;
  50. ref.cards.clear();
  51. for (auto b : backs)
  52. delete b;
  53. backs.clear();
  54. backs = ref.backs;
  55. ref.backs.clear();
  56. for (auto m : mark)
  57. delete m;
  58. mark.clear();
  59. mark = ref.mark;
  60. ref.mark.clear();
  61. card_height = ref.card_height;
  62. };
  63. Deck &Deck::operator=(Deck &&ref) {
  64. cardback = ref.cardback;
  65. for (auto c : cards)
  66. delete c;
  67. cards.clear();
  68. cards = ref.cards;
  69. ref.cards.clear();
  70. for (auto b : backs)
  71. delete b;
  72. backs.clear();
  73. backs = ref.backs;
  74. ref.backs.clear();
  75. for (auto m : mark)
  76. delete m;
  77. mark.clear();
  78. mark = ref.mark;
  79. ref.mark.clear();
  80. card_height = ref.card_height;
  81. return *this;
  82. }
  83. int Deck::is_deck(int c) { return c / 52; }
  84. int Deck::is_suit(int c) { return (c % 52) / 13; }
  85. int Deck::is_rank(int c) { return (c % 52) % 13; }
  86. char Deck::rank_symbol(int c) {
  87. const char symbols[] = "A23456789TJQK";
  88. return symbols[c];
  89. }
  90. std::string Deck::suit_symbol(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. door::Panel *Deck::card_of(int c) {
  132. int suit = is_suit(c);
  133. int rank = is_rank(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. door::Panel *p = new door::Panel(0, 0, 5);
  142. // setColor sets border_color. NOT WHAT I WANT.
  143. // p->setColor(color);
  144. char r = rank_symbol(rank);
  145. std::string s = suit_symbol(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::back_char(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. door::Panel *Deck::back_of(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. door::Panel *p = new door::Panel(0, 0, 5);
  213. std::string c = back_char(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, cardback));
  217. };
  218. // p->addLine(std::make_unique<door::Line>(l, 5, cardback));
  219. // p->addLine(std::make_unique<door::Line>(l, 5, cardback));
  220. return p;
  221. }
  222. door::Panel *Deck::mark_of(int c) {
  223. door::Panel *p = new 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. void Deck::part(int x, int y, door::Door &d, int level, bool left) {
  240. // Render part of the back of a card.
  241. y += 2;
  242. if (!left) {
  243. x += 2;
  244. }
  245. std::string c = back_char(level);
  246. std::string l = c + c + c;
  247. door::Goto g(x, y);
  248. d << g << cardback << l;
  249. }
  250. door::Panel *Deck::card(int c) { return cards[c]; }
  251. /**
  252. * @brief Return panel for back of card.
  253. *
  254. * 0 = Blank
  255. * 1 = level 1 (furthest/darkest)
  256. * 2 = level 2
  257. * 3 = level 3
  258. * 4 = level 4 (closest/lightest)
  259. *
  260. * 5 = left (fills with left corner in place)
  261. * 6 = right (fills right corner)
  262. * 7 = both (fills both corners)
  263. *
  264. * @param level
  265. * @return door::Panel*
  266. */
  267. door::Panel *Deck::back(int level) { return backs[level]; }
  268. const std::array<std::pair<int, int>, 18> Deck::blocks = {
  269. make_pair(3, 4), make_pair(5, 6), make_pair(7, 8), // end row 1
  270. make_pair(9, 10), make_pair(10, 11), make_pair(12, 13),
  271. make_pair(13, 14), make_pair(15, 16), make_pair(16, 17),
  272. make_pair(18, 19), // end row 2
  273. make_pair(19, 20), make_pair(20, 21), make_pair(21, 22),
  274. make_pair(22, 23), make_pair(23, 24), make_pair(24, 25),
  275. make_pair(25, 26), make_pair(26, 27) // 27
  276. };
  277. /**
  278. * @brief Which card (if any) is unblocked by this card
  279. *
  280. * @param card
  281. * @return * int
  282. */
  283. std::vector<int> Deck::unblocks(int card) {
  284. std::vector<int> result;
  285. for (size_t i = 0; i < blocks.size(); ++i) {
  286. if ((blocks.at(i).first == card) || (blocks.at(i).second == card)) {
  287. result.push_back(i);
  288. }
  289. }
  290. return result;
  291. }
  292. /**
  293. * @brief Can this card play on this other card?
  294. *
  295. * @param card1
  296. * @param card2
  297. * @return true
  298. * @return false
  299. */
  300. bool Deck::can_play(int card1, int card2) {
  301. int rank1, rank2;
  302. rank1 = is_rank(card1);
  303. rank2 = is_rank(card2);
  304. // this works %13 handles wrap-around for us.
  305. if ((rank1 + 1) % 13 == rank2)
  306. return true;
  307. if (rank1 == 0) {
  308. rank1 += 13;
  309. }
  310. if (rank1 - 1 == rank2)
  311. return true;
  312. return false;
  313. }
  314. /**
  315. * @brief Returns marker
  316. *
  317. * 0 = blank
  318. * 1 = [] symbol thing \xfe ■
  319. *
  320. * @param c
  321. * @return door::Panel*
  322. */
  323. door::Panel *Deck::marker(int c) { return mark[c]; }
  324. /**
  325. * @brief remove_card
  326. *
  327. * This removes a card at a given position (c).
  328. * It needs to know if there are cards underneath
  329. * to the left or right. (If so, we restore those missing parts.)
  330. *
  331. * @param door
  332. * @param c
  333. * @param off_x
  334. * @param off_y
  335. * @param left
  336. * @param right
  337. */
  338. void Deck::remove_card(door::Door &door, int c, int off_x, int off_y, bool left,
  339. bool right) {
  340. int cx, cy, level;
  341. cardgo(c, cx, cy, level);
  342. if (level > 1)
  343. --level;
  344. std::string cstr = back_char(level);
  345. door::Goto g(cx + off_x, cy + off_y);
  346. door << g << cardback;
  347. if (left)
  348. door << cstr;
  349. else
  350. door << " ";
  351. door << " ";
  352. if (right)
  353. door << cstr;
  354. else
  355. door << " ";
  356. g.set(cx + off_x, cy + off_y + 1);
  357. door << g << " ";
  358. g.set(cx + off_x, cy + off_y + 2);
  359. door << g << " ";
  360. }
  361. /*
  362. Layout spacing 1:
  363. 1 2 3 4 5 6
  364. 123456789012345678901234567890123456789012345678901234567890
  365. ░░░░░ ░░░░░ ░░░░░
  366. ░░░░░ ░░░░░ ░░░░░
  367. ▒▒▒▒▒░▒▒▒▒▒ #####░##### #####░#####
  368. ▒▒▒▒▒ ▒▒▒▒▒ ##### ##### ##### #####
  369. ▓▓▓▓▓▒▓▓▓▓▓▒▓▓▓▓▓ #####=#####=##### #####=#####=#####
  370. ▓▓▓▓▓ ▓▓▓▓▓ ▓▓▓▓▓ ##### ##### ##### ##### ##### #####
  371. █████▓█████▓█████▓#####=#####=#####=#####=#####=#####=#####
  372. █████ █████ █████ ##### ##### ##### ##### ##### ##### #####
  373. █████ █████ █████ ##### ##### ##### ##### ##### ##### #####
  374. width = 5 * 10 + (1*9) = 59 OK!
  375. Layout with spacing = 2:
  376. EEEEE
  377. ZZZZZ
  378. yyyyyZZZyyyyy
  379. yyyyy yyyyy
  380. XXXXXyyyXXXXXyyyXXXXX
  381. XXXXX XXXXX XXXXX
  382. width = 5 * 10 + (2 * 9) = 50+18 = 68 ! I could do that!
  383. */
  384. /**
  385. * @brief Where does this card go in relation to everything else?
  386. *
  387. * This function is deprecated, see the other cardgo.
  388. *
  389. * @param pos
  390. * @param space
  391. * @param h
  392. * @param x
  393. * @param y
  394. * @param level
  395. */
  396. void cardgo(int pos, int space, int h, int &x, int &y, int &level) {
  397. // special cases here
  398. if (pos == 28) {
  399. // cardgo(23, space, h, x, y, level);
  400. cardgo(23, x, y, level);
  401. y += h + 1;
  402. --level;
  403. return;
  404. } else {
  405. if (pos == 29) {
  406. // cardgo(22, space, h, x, y, level);
  407. cardgo(22, x, y, level);
  408. y += h + 1;
  409. --level;
  410. return;
  411. }
  412. }
  413. const int CARD_WIDTH = 5;
  414. int HALF_WIDTH = 3;
  415. // space = 1 or 3
  416. // int space = 1;
  417. // space = 3;
  418. HALF_WIDTH += space / 2;
  419. /*
  420. int levels[4] = {3, 6, 9, 10};
  421. for (level = 0; level < 4; ++level) {
  422. if (pos < levels[level]) {
  423. level++;
  424. // we're here
  425. y = (level -1) * 2 + 1;
  426. } else {
  427. pos -= levels[level];
  428. }
  429. }
  430. */
  431. int between = CARD_WIDTH + space;
  432. if (pos < 3) {
  433. // top
  434. level = 1;
  435. y = (level - 1) * (h - 1) + 1;
  436. x = pos * (between * 3) + between + HALF_WIDTH + space; // 10
  437. return;
  438. } else {
  439. pos -= 3;
  440. }
  441. if (pos < 6) {
  442. level = 2;
  443. y = (level - 1) * (h - 1) + 1;
  444. int group = (pos) / 2;
  445. x = pos * between + (group * between) + CARD_WIDTH + space * 2;
  446. return;
  447. } else {
  448. pos -= 6;
  449. }
  450. if (pos < 9) {
  451. level = 3;
  452. y = (level - 1) * (h - 1) + 1;
  453. x = pos * between + HALF_WIDTH + space;
  454. return;
  455. } else {
  456. pos -= 9;
  457. }
  458. if (pos < 10) {
  459. level = 4;
  460. y = (level - 1) * (h - 1) + 1;
  461. x = (pos)*between + space;
  462. return;
  463. } else {
  464. // something is wrong.
  465. y = -1;
  466. x = -1;
  467. level = -1;
  468. }
  469. }
  470. /**
  471. * @brief Given card pos, calculate x, y, and level values.
  472. *
  473. * level is used to determine the card background gradient.
  474. *
  475. * @param pos
  476. * @param x
  477. * @param y
  478. * @param level
  479. */
  480. void cardgo(int pos, int &x, int &y, int &level) {
  481. const int space = 3;
  482. const int h = 3;
  483. // special cases here
  484. if (pos == 28) {
  485. cardgo(23, x, y, level);
  486. y += h + 1;
  487. --level;
  488. return;
  489. } else {
  490. if (pos == 29) {
  491. cardgo(22, x, y, level);
  492. y += h + 1;
  493. --level;
  494. return;
  495. }
  496. }
  497. const int CARD_WIDTH = 5;
  498. int HALF_WIDTH = 3;
  499. HALF_WIDTH += space / 2;
  500. int between = CARD_WIDTH + space;
  501. if (pos < 3) {
  502. // top
  503. level = 1;
  504. y = (level - 1) * (h - 1) + 1;
  505. x = pos * (between * 3) + between + HALF_WIDTH + space; // 10
  506. return;
  507. } else {
  508. pos -= 3;
  509. }
  510. if (pos < 6) {
  511. level = 2;
  512. y = (level - 1) * (h - 1) + 1;
  513. int group = (pos) / 2;
  514. x = pos * between + (group * between) + CARD_WIDTH + space * 2;
  515. return;
  516. } else {
  517. pos -= 6;
  518. }
  519. if (pos < 9) {
  520. level = 3;
  521. y = (level - 1) * (h - 1) + 1;
  522. x = pos * between + HALF_WIDTH + space;
  523. return;
  524. } else {
  525. pos -= 9;
  526. }
  527. if (pos < 10) {
  528. level = 4;
  529. y = (level - 1) * (h - 1) + 1;
  530. x = (pos)*between + space;
  531. return;
  532. } else {
  533. // something is wrong.
  534. y = -1;
  535. x = -1;
  536. level = -1;
  537. }
  538. }
  539. /**
  540. * @brief shuffle deck of cards
  541. *
  542. * example of seeding the deck for a given date 2/27/2021 game 1
  543. * std::seed_seq s1{2021, 2, 27, 1};
  544. * vector<int> deck1 = card_shuffle(s1, 1);
  545. * @param seed
  546. * @param decks
  547. * @return vector<int>
  548. */
  549. cards card_shuffle(std::seed_seq &seed, int decks) {
  550. std::mt19937 gen;
  551. // build deck of cards
  552. int size = decks * 52;
  553. std::vector<int> deck;
  554. deck.reserve(size);
  555. for (int x = 0; x < size; ++x) {
  556. deck.push_back(x);
  557. }
  558. // repeatable, but random
  559. gen.seed(seed);
  560. std::shuffle(deck.begin(), deck.end(), gen);
  561. return deck;
  562. }
  563. /**
  564. * @brief generate a vector of ints to track card states.
  565. *
  566. * This initializes everything to 0.
  567. *
  568. * @param decks
  569. * @return cards
  570. */
  571. cards card_states(int decks) {
  572. // auto states = std::unique_ptr<std::vector<int>>(); // (decks * 52, 0)>;
  573. std::vector<int> states;
  574. states.assign(decks * 52, 0);
  575. return states;
  576. }
  577. /**
  578. * @brief Find the next card we can move the marker to.
  579. *
  580. * if left, look in the left - direction, otherwise the right + direction.
  581. * current is the current active card.
  582. * states is the card states (0 = down, 1 = in play, 2 = removed)
  583. *
  584. * updated: If we can't go any further left (or right), then
  585. * roll around to the other side.
  586. *
  587. * @param left
  588. * @param states
  589. * @param current
  590. * @return int
  591. */
  592. int find_next(bool left, const cards &states, int current) {
  593. int cx, cy, level;
  594. int current_x;
  595. cardgo(current, cx, cy, level);
  596. current_x = cx;
  597. int x;
  598. int pos = -1;
  599. int pos_x;
  600. int max_pos = -1;
  601. int max_x = -1;
  602. int min_pos = -1;
  603. int min_x = 100;
  604. if (left)
  605. pos_x = 0;
  606. else
  607. pos_x = 100;
  608. for (x = 0; x < 28; x++) {
  609. if (states.at(x) == 1) {
  610. // possible location
  611. if (x == current)
  612. continue;
  613. cardgo(x, cx, cy, level);
  614. // find max and min while we're iterating here
  615. if (cx < min_x) {
  616. min_pos = x;
  617. min_x = cx;
  618. }
  619. if (cx > max_x) {
  620. max_pos = x;
  621. max_x = cx;
  622. }
  623. if (left) {
  624. if ((cx < current_x) and (cx > pos_x)) {
  625. pos_x = cx;
  626. pos = x;
  627. }
  628. } else {
  629. if ((cx > current_x) and (cx < pos_x)) {
  630. pos_x = cx;
  631. pos = x;
  632. }
  633. }
  634. }
  635. }
  636. if (pos == -1) {
  637. // we couldn't find one
  638. if (left) {
  639. // use max -- roll around to the right
  640. pos = max_pos;
  641. } else {
  642. // use min -- roll around to the left
  643. pos = min_pos;
  644. }
  645. }
  646. return pos;
  647. }
  648. /**
  649. * @brief Find the next closest card to move to.
  650. *
  651. * Given the card states, this finds the next closest card.
  652. * Uses current.
  653. *
  654. * return -1 there's no options to go to. (END OF GAME)
  655. * @param states
  656. * @param current
  657. * @return int
  658. */
  659. int find_next_closest(const cards &states, int current) {
  660. int cx, cy, level;
  661. int current_x;
  662. cardgo(current, cx, cy, level);
  663. current_x = cx;
  664. int x;
  665. int pos = -1;
  666. int pos_x = -1;
  667. for (x = 0; x < 28; x++) {
  668. if (states.at(x) == 1) {
  669. // possible location
  670. if (x == current)
  671. continue;
  672. cardgo(x, cx, cy, level);
  673. if (pos == -1) {
  674. pos = x;
  675. pos_x = cx;
  676. } else {
  677. if (abs(current_x - cx) < abs(current_x - pos_x)) {
  678. pos = x;
  679. pos_x = cx;
  680. }
  681. }
  682. }
  683. }
  684. return pos;
  685. }
  686. vector<std::string> deck_colors = {std::string("All"), std::string("Blue"),
  687. std::string("Cyan"), std::string("Green"),
  688. std::string("Magenta"), std::string("Red")};
  689. /**
  690. * @brief menu render that sets the text color based on the color found in the
  691. * text itself.
  692. *
  693. * @param c1 [] brackets
  694. * @param c2 text within brackets
  695. * @param c3 base color give (we set the FG, we use the BG)
  696. * @return door::renderFunction
  697. */
  698. door::renderFunction makeColorRender(door::ANSIColor c1, door::ANSIColor c2,
  699. door::ANSIColor c3) {
  700. door::renderFunction render = [c1, c2,
  701. c3](const std::string &txt) -> door::Render {
  702. door::Render r(txt);
  703. bool option = true;
  704. door::ColorOutput co;
  705. // I need this mutable
  706. door::ANSIColor textColor = c3;
  707. // Color update:
  708. {
  709. std::string found;
  710. for (auto &dc : deck_colors) {
  711. if (txt.find(dc) != string::npos) {
  712. found = dc;
  713. break;
  714. }
  715. }
  716. if (!found.empty()) {
  717. if (found == "All") {
  718. // handle this some other way.
  719. textColor.setFg(door::COLOR::WHITE);
  720. } else {
  721. door::ANSIColor c = from_string(found);
  722. textColor.setFg(c.getFg());
  723. }
  724. }
  725. }
  726. co.pos = 0;
  727. co.len = 0;
  728. co.c = c1;
  729. int tpos = 0;
  730. for (char const &c : txt) {
  731. if (option) {
  732. if (c == '[' or c == ']') {
  733. if (co.c != c1)
  734. if (co.len != 0) {
  735. r.outputs.push_back(co);
  736. co.reset();
  737. co.pos = tpos;
  738. }
  739. co.c = c1;
  740. if (c == ']')
  741. option = false;
  742. } else {
  743. if (co.c != c2)
  744. if (co.len != 0) {
  745. r.outputs.push_back(co);
  746. co.reset();
  747. co.pos = tpos;
  748. }
  749. co.c = c2;
  750. }
  751. } else {
  752. if (co.c != textColor)
  753. if (co.len != 0) {
  754. r.outputs.push_back(co);
  755. co.reset();
  756. co.pos = tpos;
  757. }
  758. co.c = textColor;
  759. }
  760. co.len++;
  761. tpos++;
  762. }
  763. if (co.len != 0) {
  764. r.outputs.push_back(co);
  765. }
  766. return r;
  767. };
  768. return render;
  769. }
  770. // convert a string to an option
  771. // an option to the string to store
  772. // This needs to be updated to use deck_colors.
  773. door::ANSIColor from_string(std::string colorCode) {
  774. std::map<std::string, door::ANSIColor> codeMap = {
  775. {std::string("BLUE"), door::ANSIColor(door::COLOR::BLUE)},
  776. {std::string("RED"), door::ANSIColor(door::COLOR::RED)},
  777. {std::string("CYAN"), door::ANSIColor(door::COLOR::CYAN)},
  778. {std::string("GREEN"), door::ANSIColor(door::COLOR::GREEN)},
  779. {std::string("MAGENTA"), door::ANSIColor(door::COLOR::MAGENTA)}};
  780. std::string code = colorCode;
  781. string_toupper(code);
  782. auto iter = codeMap.find(code);
  783. if (iter != codeMap.end()) {
  784. return iter->second;
  785. }
  786. // And if it doesn't match, and isn't ALL ... ?
  787. // if (code.compare("ALL") == 0) {
  788. std::random_device dev;
  789. std::mt19937_64 rng(dev());
  790. std::uniform_int_distribution<size_t> idDist(0, codeMap.size() - 1);
  791. iter = codeMap.begin();
  792. std::advance(iter, idDist(rng));
  793. return iter->second;
  794. // }
  795. }
  796. std::string from_color_option(int opt) { return deck_colors[opt]; }
  797. void string_toupper(std::string &str) {
  798. std::transform(str.begin(), str.end(), str.begin(), ::toupper);
  799. }