deck.cpp 19 KB

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