1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294 |
- #include "deck.h"
- #include "space.h"
- #include "utils.h"
- #include "version.h"
- #include <algorithm>
- #include <map>
- #include <sstream>
- Deck::Deck(door::ANSIColor backcolor) : card_back_color{backcolor} {
- for (int i = 0; i < 52; ++i) {
- cards.push_back(cardOf(i));
- }
- // 0 = BLANK, 1-4 levels
- for (int i = 0; i < 5; ++i) {
- backs.push_back(backOf(i));
- }
- mark.push_back(markOf(0));
- mark.push_back(markOf(1));
- }
- Deck::~Deck() {
- /*
- for (auto c : cards) {
- delete c;
- }
- cards.clear();
- for (auto b : backs) {
- delete b;
- }
- backs.clear();
- for (auto m : mark) {
- delete m;
- }
- mark.clear();
- */
- }
- Deck::Deck(Deck &&ref) {
- card_back_color = ref.card_back_color;
- /*
- for (auto c : cards)
- delete c;
- cards.clear();
- */
- cards = ref.cards;
- ref.cards.clear();
- /*
- for (auto b : backs)
- delete b;
- backs.clear();
- */
- backs = ref.backs;
- ref.backs.clear();
- /*
- for (auto m : mark)
- delete m;
- mark.clear();
- */
- mark = ref.mark;
- ref.mark.clear();
- // card_height = ref.card_height;
- };
- Deck &Deck::operator=(Deck &&ref) {
- card_back_color = ref.card_back_color;
- /*
- for (auto c : cards)
- delete c;
- cards.clear();
- */
- cards = ref.cards;
- ref.cards.clear();
- /*
- for (auto b : backs)
- delete b;
- backs.clear();
- */
- backs = ref.backs;
- ref.backs.clear();
- /*
- for (auto m : mark)
- delete m;
- mark.clear();
- */
- mark = ref.mark;
- ref.mark.clear();
- // card_height = ref.card_height;
- return *this;
- }
- int Deck::getDeck(int c) { return c / 52; }
- int Deck::getSuit(int c) { return (c % 52) / 13; }
- int Deck::getRank(int c) { return (c % 52) % 13; }
- char Deck::rankSymbol(int c) {
- const char symbols[] = "A23456789TJQK";
- return symbols[c];
- }
- std::string Deck::suitSymbol(int c) {
- // unicode
- if (door::unicode) {
- switch (c) {
- case 0:
- return std::string("\u2665");
- case 1:
- return std::string("\u2666");
- case 2:
- return std::string("\u2663");
- case 3:
- return std::string("\u2660");
- }
- } else {
- if (door::full_cp437) {
- switch (c) {
- case 0:
- return std::string(1, '\x03');
- case 1:
- return std::string(1, '\x04');
- case 2:
- return std::string(1, '\x05');
- case 3:
- return std::string(1, '\x06');
- }
- } else {
- // These look horrible!
- switch (c) {
- case 0:
- return std::string(1, '*'); // H
- case 1:
- return std::string(1, '^'); // D
- case 2:
- return std::string(1, '%'); // C
- case 3:
- return std::string(1, '$'); // S
- }
- }
- }
- return std::string("!", 1);
- }
- shared_panel Deck::cardOf(int c) {
- int suit = getSuit(c);
- int rank = getRank(c);
- bool is_red = (suit < 2);
- door::ANSIColor color;
- if (is_red) {
- color = door::ANSIColor(door::COLOR::RED, door::COLOR::WHITE);
- } else {
- color = door::ANSIColor(door::COLOR::BLACK, door::COLOR::WHITE);
- }
- shared_panel p = std::make_shared<door::Panel>(0, 0, 5);
- // setColor sets border_color. NOT WHAT I WANT.
- // p->setColor(color);
- char r = rankSymbol(rank);
- std::string s = suitSymbol(suit);
- // build lines
- std::ostringstream oss;
- oss << r << s << " ";
- std::string str = oss.str();
- p->addLine(std::make_unique<door::Line>(str, 5, color));
- oss.str(std::string());
- oss.clear();
- if (card_height == 5)
- p->addLine(std::make_unique<door::Line>(" ", 5, color));
- oss << " " << s << " ";
- str = oss.str();
- p->addLine(std::make_unique<door::Line>(str, 5, color));
- oss.str(std::string());
- oss.clear();
- if (card_height == 5)
- p->addLine(std::make_unique<door::Line>(" ", 5, color));
- oss << " " << s << r;
- str = oss.str();
- p->addLine(std::make_unique<door::Line>(str, 5, color));
- oss.str(std::string());
- oss.clear();
- return p;
- }
- std::string Deck::backSymbol(int level) {
- std::string c;
- if (level == 0) {
- c = ' ';
- return c;
- }
- if (door::unicode) {
- switch (level) {
- case 1:
- c = "\u2591";
- break;
- case 2:
- c = "\u2592";
- break;
- case 3:
- c = "\u2593";
- break;
- case 4:
- c = "\u2588";
- break;
- }
- } else {
- switch (level) {
- case 1:
- c = "\xb0";
- break;
- case 2:
- c = "\xb1";
- break;
- case 3:
- c = "\xb2";
- break;
- case 4:
- c = "\xdb";
- break;
- }
- }
- return c;
- }
- shared_panel Deck::backOf(int level) {
- // using: \xb0, 0xb1, 0xb2, 0xdb
- // OR: \u2591, \u2592, \u2593, \u2588
- // door::ANSIColor color(door::COLOR::RED, door::COLOR::BLACK);
- shared_panel p = std::make_shared<door::Panel>(0, 0, 5);
- std::string c = backSymbol(level);
- std::string l = c + c + c + c + c;
- for (int x = 0; x < card_height; ++x) {
- p->addLine(std::make_unique<door::Line>(l, 5, card_back_color));
- };
- // p->addLine(std::make_unique<door::Line>(l, 5, card_back_color));
- // p->addLine(std::make_unique<door::Line>(l, 5, card_back_color));
- return p;
- }
- shared_panel Deck::markOf(int c) {
- shared_panel p = std::make_shared<door::Panel>(1);
- door::ANSIColor color = door::ANSIColor(
- door::COLOR::BLUE, door::COLOR::WHITE); // , door::ATTR::BOLD);
- std::string m;
- if (c == 0)
- m = " ";
- else {
- if (door::unicode) {
- m = "\u25a0";
- } else {
- m = "\xfe";
- }
- }
- p->addLine(std::make_unique<door::Line>(m, 1, color));
- return p;
- }
- shared_panel Deck::card(int c) { return cards[c]; }
- /**
- * @brief Return panel for back of card.
- *
- * - 0 = Blank
- * - 1 = level 1 (furthest/darkest)
- * - 2 = level 2
- * - 3 = level 3
- * - 4 = level 4 (closest/lightest)
- *
- * @param level
- * @return door::Panel*
- */
- shared_panel Deck::back(int level) { return backs[level]; }
- const std::array<std::pair<int, int>, 18> Deck::blocks = {
- make_pair(3, 4), make_pair(5, 6), make_pair(7, 8), // end row 1
- make_pair(9, 10), make_pair(10, 11), make_pair(12, 13),
- make_pair(13, 14), make_pair(15, 16), make_pair(16, 17),
- make_pair(18, 19), // end row 2
- make_pair(19, 20), make_pair(20, 21), make_pair(21, 22),
- make_pair(22, 23), make_pair(23, 24), make_pair(24, 25),
- make_pair(25, 26), make_pair(26, 27) // 27
- };
- /**
- * @brief Which card(s) are unblocked by this card?
- *
- * @param card
- * @return * int
- */
- std::vector<int> Deck::unblocks(int card) {
- std::vector<int> result;
- for (size_t i = 0; i < blocks.size(); ++i) {
- if ((blocks.at(i).first == card) || (blocks.at(i).second == card)) {
- result.push_back(i);
- }
- }
- return result;
- }
- /**
- * @brief Can this card play on this other card?
- *
- * @param card1
- * @param card2
- * @return true
- * @return false
- */
- bool Deck::canPlay(int card1, int card2) {
- int rank1, rank2;
- rank1 = getRank(card1);
- rank2 = getRank(card2);
- // this works %13 handles wrap-around for us.
- if ((rank1 + 1) % 13 == rank2)
- return true;
- if (rank1 == 0) {
- rank1 += 13;
- }
- if (rank1 - 1 == rank2)
- return true;
- return false;
- }
- /**
- * @brief Returns marker
- *
- * 0 = blank
- * 1 = [] symbol thing \xfe ■
- *
- * @param c
- * @return door::Panel*
- */
- shared_panel Deck::marker(int c) { return mark[c]; }
- /**
- * @brief removeCard
- *
- * This removes a card at a given position (c).
- * It needs to know if there are cards underneath
- * to the left or right. (If so, we restore those missing parts.)
- *
- * @param door
- * @param c
- * @param off_x
- * @param off_y
- * @param left
- * @param right
- */
- void Deck::removeCard(door::Door &door, int c, int off_x, int off_y, bool left,
- bool right) {
- int cx, cy, level;
- cardPosLevel(c, cx, cy, level);
- if (level > 1)
- --level;
- std::string cstr = backSymbol(level);
- door::Goto g(cx + off_x, cy + off_y);
- door << g << card_back_color;
- if (left)
- door << cstr;
- else
- door << " ";
- door << " ";
- if (right)
- door << cstr;
- else
- door << " ";
- g.set(cx + off_x, cy + off_y + 1);
- door << g << " ";
- g.set(cx + off_x, cy + off_y + 2);
- door << g << " ";
- }
- /*
- Layout spacing 1:
- 1 2 3 4 5 6
- 123456789012345678901234567890123456789012345678901234567890
- ░░░░░ ░░░░░ ░░░░░
- ░░░░░ ░░░░░ ░░░░░
- ▒▒▒▒▒░▒▒▒▒▒ #####░##### #####░#####
- ▒▒▒▒▒ ▒▒▒▒▒ ##### ##### ##### #####
- ▓▓▓▓▓▒▓▓▓▓▓▒▓▓▓▓▓ #####=#####=##### #####=#####=#####
- ▓▓▓▓▓ ▓▓▓▓▓ ▓▓▓▓▓ ##### ##### ##### ##### ##### #####
- █████▓█████▓█████▓#####=#####=#####=#####=#####=#####=#####
- █████ █████ █████ ##### ##### ##### ##### ##### ##### #####
- █████ █████ █████ ##### ##### ##### ##### ##### ##### #####
- width = 5 * 10 + (1*9) = 59 OK!
- Layout with spacing = 2:
- EEEEE
- ZZZZZ
- yyyyyZZZyyyyy
- yyyyy yyyyy
- XXXXXyyyXXXXXyyyXXXXX
- XXXXX XXXXX XXXXX
- width = 5 * 10 + (2 * 9) = 50+18 = 68 ! I could do that!
- */
- #ifdef NO
- /**
- * @brief Where does this card go in relation to everything else?
- *
- * This function is deprecated, see the other cardgo.
- *
- * @param pos
- * @param space
- * @param h
- * @param x
- * @param y
- * @param level
- */
- void cardgo(int pos, int space, int h, int &x, int &y, int &level) {
- // special cases here
- if (pos == 28) {
- // cardgo(23, space, h, x, y, level);
- cardgo(23, x, y, level);
- y += h + 1;
- --level;
- return;
- } else {
- if (pos == 29) {
- // cardgo(22, space, h, x, y, level);
- cardgo(22, x, y, level);
- y += h + 1;
- --level;
- return;
- }
- }
- const int CARD_WIDTH = 5;
- int HALF_WIDTH = 3;
- // space = 1 or 3
- // int space = 1;
- // space = 3;
- HALF_WIDTH += space / 2;
- /*
- int levels[4] = {3, 6, 9, 10};
- for (level = 0; level < 4; ++level) {
- if (pos < levels[level]) {
- level++;
- // we're here
- y = (level -1) * 2 + 1;
- } else {
- pos -= levels[level];
- }
- }
- */
- int between = CARD_WIDTH + space;
- if (pos < 3) {
- // top
- level = 1;
- y = (level - 1) * (h - 1) + 1;
- x = pos * (between * 3) + between + HALF_WIDTH + space; // 10
- return;
- } else {
- pos -= 3;
- }
- if (pos < 6) {
- level = 2;
- y = (level - 1) * (h - 1) + 1;
- int group = (pos) / 2;
- x = pos * between + (group * between) + CARD_WIDTH + space * 2;
- return;
- } else {
- pos -= 6;
- }
- if (pos < 9) {
- level = 3;
- y = (level - 1) * (h - 1) + 1;
- x = pos * between + HALF_WIDTH + space;
- return;
- } else {
- pos -= 9;
- }
- if (pos < 10) {
- level = 4;
- y = (level - 1) * (h - 1) + 1;
- x = (pos)*between + space;
- return;
- } else {
- // something is wrong.
- y = -1;
- x = -1;
- level = -1;
- }
- }
- #endif
- void cardPos(int pos, int &x, int &y) {
- const int space = 3;
- const int height = 3;
- // special cases here
- if (pos == 28) {
- cardPos(23, x, y);
- y += height + 1;
- return;
- } else {
- if (pos == 29) {
- cardPos(22, x, y);
- y += height + 1;
- return;
- }
- }
- const int CARD_WIDTH = 5;
- int HALF_WIDTH = 3;
- HALF_WIDTH += space / 2;
- int between = CARD_WIDTH + space;
- int level; // I still need level in my calculations
- if (pos < 3) {
- // top
- level = 1;
- y = (level - 1) * (height - 1) + 1;
- x = pos * (between * 3) + between + HALF_WIDTH + space; // 10
- return;
- } else {
- pos -= 3;
- }
- if (pos < 6) {
- level = 2;
- y = (level - 1) * (height - 1) + 1;
- int group = (pos) / 2;
- x = pos * between + (group * between) + CARD_WIDTH + space * 2;
- return;
- } else {
- pos -= 6;
- }
- if (pos < 9) {
- level = 3;
- y = (level - 1) * (height - 1) + 1;
- x = pos * between + HALF_WIDTH + space;
- return;
- } else {
- pos -= 9;
- }
- if (pos < 10) {
- level = 4;
- y = (level - 1) * (height - 1) + 1;
- x = (pos)*between + space;
- return;
- } else {
- // something is wrong.
- y = -1;
- x = -1;
- level = -1;
- }
- }
- void cardLevel(int pos, int &level) {
- /*
- const int space = 3;
- const int height = 3;
- */
- // special cases here
- if (pos == 28) {
- cardLevel(23, level);
- --level;
- return;
- } else {
- if (pos == 29) {
- cardLevel(22, level);
- --level;
- return;
- }
- }
- /*
- const int CARD_WIDTH = 5;
- int HALF_WIDTH = 3;
- HALF_WIDTH += space / 2;
- int between = CARD_WIDTH + space;
- */
- if (pos < 3) {
- // top
- level = 1;
- return;
- } else {
- pos -= 3;
- }
- if (pos < 6) {
- level = 2;
- return;
- } else {
- pos -= 6;
- }
- if (pos < 9) {
- level = 3;
- return;
- } else {
- pos -= 9;
- }
- if (pos < 10) {
- level = 4;
- return;
- } else {
- // something is wrong.
- level = -1;
- }
- }
- /**
- * @brief Given card pos, calculate x, y, and level values.
- *
- * level is used to determine the card background gradient.
- *
- * @param pos
- * @param x
- * @param y
- * @param level
- */
- void cardPosLevel(int pos, int &x, int &y, int &level) {
- const int space = 3;
- const int height = 3;
- // special cases here
- if (pos == 28) {
- cardPosLevel(23, x, y, level);
- y += height + 1;
- --level;
- return;
- } else {
- if (pos == 29) {
- cardPosLevel(22, x, y, level);
- y += height + 1;
- --level;
- return;
- }
- }
- const int CARD_WIDTH = 5;
- int HALF_WIDTH = 3;
- HALF_WIDTH += space / 2;
- int between = CARD_WIDTH + space;
- if (pos < 3) {
- // top
- level = 1;
- y = (level - 1) * (height - 1) + 1;
- x = pos * (between * 3) + between + HALF_WIDTH + space; // 10
- return;
- } else {
- pos -= 3;
- }
- if (pos < 6) {
- level = 2;
- y = (level - 1) * (height - 1) + 1;
- int group = (pos) / 2;
- x = pos * between + (group * between) + CARD_WIDTH + space * 2;
- return;
- } else {
- pos -= 6;
- }
- if (pos < 9) {
- level = 3;
- y = (level - 1) * (height - 1) + 1;
- x = pos * between + HALF_WIDTH + space;
- return;
- } else {
- pos -= 9;
- }
- if (pos < 10) {
- level = 4;
- y = (level - 1) * (height - 1) + 1;
- x = (pos)*between + space;
- return;
- } else {
- // something is wrong.
- y = -1;
- x = -1;
- level = -1;
- }
- }
- /**
- * @brief shuffle deck of cards
- *
- * example of seeding the deck for a given date 2/27/2021 game 1
- * std::seed_seq s1{2021, 2, 27, 1};
- * vector<int> deck1 = shuffleCards(s1, 1);
- * @param seed
- * @param decks
- * @return vector<int>
- */
- cards shuffleCards(std::seed_seq &seed, int decks) {
- std::mt19937 gen;
- // build deck of cards
- int size = decks * 52;
- std::vector<int> deck;
- deck.reserve(size);
- for (int x = 0; x < size; ++x) {
- deck.push_back(x);
- }
- // repeatable, but random
- gen.seed(seed);
- std::shuffle(deck.begin(), deck.end(), gen);
- return deck;
- }
- /**
- * @brief generate a vector of ints to track card states.
- *
- * This initializes everything to 0.
- *
- * @param decks
- * @return cards
- */
- cards makeCardStates(int decks) {
- // auto states = std::unique_ptr<std::vector<int>>(); // (decks * 52, 0)>;
- std::vector<int> states;
- states.assign(decks * 52, 0);
- return states;
- }
- /**
- * @brief Find the next card we can move the marker to.
- *
- * if left, look in the left - direction, otherwise the right + direction.
- * current is the current active card.
- * states is the card states (0 = down, 1 = in play, 2 = removed)
- *
- * updated: If we can't go any further left (or right), then
- * roll around to the other side.
- *
- * @param left
- * @param states
- * @param current
- * @return int
- */
- int findNextActiveCard(bool left, const cards &states, int current) {
- int cx, cy;
- int current_x;
- cardPos(current, cx, cy);
- current_x = cx;
- int x;
- int pos = -1;
- int pos_x;
- int max_pos = -1;
- int max_x = -1;
- int min_pos = -1;
- int min_x = 100;
- if (left)
- pos_x = 0;
- else
- pos_x = 100;
- for (x = 0; x < 28; x++) {
- if (states.at(x) == 1) {
- // possible location
- if (x == current)
- continue;
- cardPos(x, cx, cy);
- // find max and min while we're iterating here
- if (cx < min_x) {
- min_pos = x;
- min_x = cx;
- }
- if (cx > max_x) {
- max_pos = x;
- max_x = cx;
- }
- if (left) {
- if ((cx < current_x) and (cx > pos_x)) {
- pos_x = cx;
- pos = x;
- }
- } else {
- if ((cx > current_x) and (cx < pos_x)) {
- pos_x = cx;
- pos = x;
- }
- }
- }
- }
- if (pos == -1) {
- // we couldn't find one
- if (left) {
- // use max -- roll around to the right
- pos = max_pos;
- } else {
- // use min -- roll around to the left
- pos = min_pos;
- }
- }
- return pos;
- }
- /**
- * @brief Find the next closest card to move to.
- *
- * Given the card states, this finds the next closest card.
- * Uses current.
- *
- * return -1 there's no options to go to. (END OF GAME)
- * @param states
- * @param current
- * @return int
- */
- int findClosestActiveCard(const cards &states, int current) {
- int cx, cy;
- int current_x;
- cardPos(current, cx, cy);
- current_x = cx;
- int x;
- int pos = -1;
- int pos_x = -1;
- for (x = 0; x < 28; x++) {
- if (states.at(x) == 1) {
- // possible location
- if (x == current)
- continue;
- cardPos(x, cx, cy);
- if (pos == -1) {
- pos = x;
- pos_x = cx;
- } else {
- if (abs(current_x - cx) < abs(current_x - pos_x)) {
- pos = x;
- pos_x = cx;
- }
- }
- }
- }
- return pos;
- }
- vector<std::string> deck_colors = {std::string("All"), std::string("Blue"),
- std::string("Cyan"), std::string("Green"),
- std::string("Magenta"), std::string("Red")};
- /**
- * @brief menu render that sets the text color based on the color found in the
- * text itself.
- *
- * @param c1 [] brackets
- * @param c2 text within brackets
- * @param c3 base color give (we set the FG, we use the BG)
- * @return door::renderFunction
- */
- door::renderFunction makeColorRender(door::ANSIColor c1, door::ANSIColor c2,
- door::ANSIColor c3) {
- door::renderFunction render = [c1, c2,
- c3](const std::string &txt) -> door::Render {
- door::Render r(txt);
- bool option = true;
- door::ColorOutput co;
- // I need this mutable
- door::ANSIColor textColor = c3;
- // Color update:
- {
- std::string found;
- for (auto &dc : deck_colors) {
- if (txt.find(dc) != string::npos) {
- found = dc;
- break;
- }
- }
- if (!found.empty()) {
- if (found == "All") {
- // handle this some other way.
- textColor.setFg(door::COLOR::WHITE);
- } else {
- door::ANSIColor c = stringToANSIColor(found);
- textColor.setFg(c.getFg());
- }
- }
- }
- co.pos = 0;
- co.len = 0;
- co.c = c1;
- int tpos = 0;
- for (char const &c : txt) {
- if (option) {
- if (c == '[' or c == ']') {
- if (co.c != c1)
- if (co.len != 0) {
- r.outputs.push_back(co);
- co.reset();
- co.pos = tpos;
- }
- co.c = c1;
- if (c == ']')
- option = false;
- } else {
- if (co.c != c2)
- if (co.len != 0) {
- r.outputs.push_back(co);
- co.reset();
- co.pos = tpos;
- }
- co.c = c2;
- }
- } else {
- if (co.c != textColor)
- if (co.len != 0) {
- r.outputs.push_back(co);
- co.reset();
- co.pos = tpos;
- }
- co.c = textColor;
- }
- co.len++;
- tpos++;
- }
- if (co.len != 0) {
- r.outputs.push_back(co);
- }
- return r;
- };
- return render;
- }
- // convert a string to an option
- // an option to the string to store
- // This needs to be updated to use deck_colors.
- door::ANSIColor stringToANSIColor(std::string colorCode) {
- std::map<std::string, door::ANSIColor> codeMap = {
- {std::string("BLUE"), door::ANSIColor(door::COLOR::BLUE)},
- {std::string("RED"), door::ANSIColor(door::COLOR::RED)},
- {std::string("CYAN"), door::ANSIColor(door::COLOR::CYAN)},
- {std::string("GREEN"), door::ANSIColor(door::COLOR::GREEN)},
- {std::string("MAGENTA"), door::ANSIColor(door::COLOR::MAGENTA)}};
- std::string code = colorCode;
- string_toupper(code);
- auto iter = codeMap.find(code);
- if (iter != codeMap.end()) {
- return iter->second;
- }
- // And if it doesn't match, and isn't ALL ... ?
- // if (code.compare("ALL") == 0) {
- std::random_device dev;
- std::mt19937_64 rng(dev());
- std::uniform_int_distribution<size_t> idDist(0, codeMap.size() - 1);
- iter = codeMap.begin();
- std::advance(iter, idDist(rng));
- return iter->second;
- // }
- }
- std::string stringFromColorOptions(int opt) { return deck_colors[opt]; }
- door::Panel make_about(void) {
- const int W = 60;
- door::Panel about(W);
- about.setStyle(door::BorderStyle::DOUBLE_SINGLE);
- about.setColor(door::ANSIColor(door::COLOR::YELLOW, door::COLOR::BLUE,
- door::ATTR::BOLD));
- about.addLine(std::make_unique<door::Line>("About This Door", W));
- about.addLine(std::make_unique<door::Line>(
- "---------------------------------", W,
- door::ANSIColor(door::COLOR::CYAN, door::COLOR::BLUE, door::ATTR::BOLD)));
- /*
- 123456789012345678901234567890123456789012345678901234567890-60
- This door was written by Bugz.
- It is written in c++, only supports Linux, and replaces
- opendoors.
- It's written in c++, and replaces the outdated opendoors
- library.
- */
- about.addLine(
- std::make_unique<door::Line>(SPACEACE " v" SPACEACE_VERSION, W));
- std::string copyright = SPACEACE_COPYRIGHT;
- if (door::unicode) {
- replace(copyright, "(C)", "\u00a9");
- }
- about.addLine(std::make_unique<door::Line>(copyright, W));
- about.addLine(std::make_unique<door::Line>("", W));
- about.addLine(
- std::make_unique<door::Line>("This door was written by Bugz.", W));
- about.addLine(std::make_unique<door::Line>("", W));
- about.addLine(std::make_unique<door::Line>(
- "It is written in door++, using c++, only support Linux.", W));
- /*
- door::updateFunction updater = [](void) -> std::string {
- std::string text = "Currently: ";
- text.append(return_current_time_and_date());
- return text;
- };
- std::string current = updater();
- door::Line active(current, 60);
- active.setUpdater(updater);
- active.setRender(statusValue(
- door::ANSIColor(door::COLOR::WHITE, door::COLOR::BLUE,
- door::ATTR::BOLD), door::ANSIColor(door::COLOR::YELLOW,
- door::COLOR::BLUE, door::ATTR::BOLD)));
- about.addLine(std::make_unique<door::Line>(active));
- */
- return about;
- }
- void display_starfield(door::Door &door, std::mt19937 &rng) {
- door << door::reset << door::cls;
- int mx = door.width;
- int my = door.height;
- // display starfield
- const char *stars[2];
- stars[0] = ".";
- if (door::unicode) {
- stars[1] = "\u2219"; // "\u00b7";
- } else {
- stars[1] = "\xf9"; // "\xfa";
- };
- {
- // Make uniform random distribution between 1 and MAX screen size X/Y
- std::uniform_int_distribution<int> uni_x(1, mx);
- std::uniform_int_distribution<int> uni_y(1, my);
- door::ANSIColor white(door::COLOR::WHITE);
- door::ANSIColor dark(door::COLOR::BLACK, door::ATTR::BRIGHT);
- // 10 is too many, 100 is too few. 40 looks ok.
- int MAX_STARS = ((mx * my) / 40);
- // door.log() << "Generating starmap using " << mx << "," << my << " : "
- // << MAX_STARS << " stars." << std::endl;
- for (int x = 0; x < MAX_STARS; x++) {
- door::Goto star_at(uni_x(rng), uni_y(rng));
- door << star_at;
- if (x % 5 < 2)
- door << dark;
- else
- door << white;
- if (x % 2 == 0)
- door << stars[0];
- else
- door << stars[1];
- }
- }
- }
- void display_space_ace(door::Door &door) {
- int mx = door.width;
- int my = door.height;
- // space_ace is 72 chars wide, 6 high
- int sa_x = (mx - 72) / 2;
- int sa_y = (my - 6) / 2;
- // output the SpaceAce logo -- centered!
- for (const auto s : space) {
- door::Goto sa_at(sa_x, sa_y);
- door << sa_at;
- if (door::unicode) {
- std::string unicode;
- door::cp437toUnicode(s, unicode);
- door << unicode; // << door::nl;
- } else
- door << s; // << door::nl;
- sa_y++;
- }
- // pause 5 seconds so they can enjoy our awesome logo -- if they want.
- door.sleep_key(5);
- }
- void display_starfield_space_ace(door::Door &door, std::mt19937 &rng) {
- // mx = door.width;
- // my = door.height;
- display_starfield(door, rng);
- display_space_ace(door);
- door << door::reset;
- }
- door::Panel make_timeout(int mx, int my) {
- door::ANSIColor yellowred =
- door::ANSIColor(door::COLOR::YELLOW, door::COLOR::RED, door::ATTR::BOLD);
- std::string line_text("Sorry, you've been inactive for too long.");
- int msgWidth = line_text.length() + (2 * 3); // + padding * 2
- door::Panel timeout((mx - (msgWidth)) / 2, my / 2 + 4, msgWidth);
- // place.setTitle(std::make_unique<door::Line>(title), 1);
- timeout.setStyle(door::BorderStyle::DOUBLE);
- timeout.setColor(yellowred);
- door::Line base(line_text);
- base.setColor(yellowred);
- std::string pad1(3, ' ');
- /*
- std::string pad1(3, '\xb0');
- if (door::unicode) {
- std::string unicode;
- door::cp437toUnicode(pad1.c_str(), unicode);
- pad1 = unicode;
- }
- */
- base.setPadding(pad1, yellowred);
- // base.setColor(door::ANSIColor(door::COLOR::GREEN, door::COLOR::BLACK));
- std::unique_ptr<door::Line> stuff = std::make_unique<door::Line>(base);
- timeout.addLine(std::make_unique<door::Line>(base));
- return timeout;
- }
- door::Panel make_notime(int mx, int my) {
- door::ANSIColor yellowred =
- door::ANSIColor(door::COLOR::YELLOW, door::COLOR::RED, door::ATTR::BOLD);
- std::string line_text("Sorry, you've used up all your time for today.");
- int msgWidth = line_text.length() + (2 * 3); // + padding * 2
- door::Panel timeout((mx - (msgWidth)) / 2, my / 2 + 4, msgWidth);
- timeout.setStyle(door::BorderStyle::DOUBLE);
- timeout.setColor(yellowred);
- door::Line base(line_text);
- base.setColor(yellowred);
- std::string pad1(3, ' ');
- /*
- std::string pad1(3, '\xb0');
- if (door::unicode) {
- std::string unicode;
- door::cp437toUnicode(pad1.c_str(), unicode);
- pad1 = unicode;
- }
- */
- base.setPadding(pad1, yellowred);
- std::unique_ptr<door::Line> stuff = std::make_unique<door::Line>(base);
- timeout.addLine(std::make_unique<door::Line>(base));
- return timeout;
- }
- door::Menu make_main_menu(void) {
- door::Menu m(5, 5, 25);
- door::Line mtitle(SPACEACE " Main Menu");
- door::ANSIColor border_color(door::COLOR::CYAN, door::COLOR::BLUE);
- door::ANSIColor title_color(door::COLOR::CYAN, door::COLOR::BLUE,
- door::ATTR::BOLD);
- m.setColor(border_color);
- mtitle.setColor(title_color);
- mtitle.setPadding(" ", title_color);
- m.setTitle(std::make_unique<door::Line>(mtitle), 1);
- // m.setColorizer(true,
- m.setRender(true, door::Menu::makeRender(
- door::ANSIColor(door::COLOR::CYAN, door::ATTR::BOLD),
- door::ANSIColor(door::COLOR::BLUE, door::ATTR::BOLD),
- door::ANSIColor(door::COLOR::CYAN, door::ATTR::BOLD),
- door::ANSIColor(door::COLOR::BLUE, door::ATTR::BOLD)));
- // m.setColorizer(false,
- m.setRender(false, door::Menu::makeRender(
- door::ANSIColor(door::COLOR::YELLOW, door::COLOR::BLUE,
- door::ATTR::BOLD),
- door::ANSIColor(door::COLOR::WHITE, door::COLOR::BLUE,
- door::ATTR::BOLD),
- door::ANSIColor(door::COLOR::YELLOW, door::COLOR::BLUE,
- door::ATTR::BOLD),
- door::ANSIColor(door::COLOR::CYAN, door::COLOR::BLUE,
- door::ATTR::BOLD)));
- m.addSelection('P', "Play Cards");
- m.addSelection('S', "View Scores");
- m.addSelection('C', "Configure");
- m.addSelection('H', "Help");
- m.addSelection('A', "About this game");
- m.addSelection('Q', "Quit");
- return m;
- }
- door::Menu make_config_menu(void) {
- door::Menu m(5, 5, 31);
- door::Line mtitle(SPACEACE " Configuration Menu");
- door::ANSIColor border_color(door::COLOR::CYAN, door::COLOR::BLUE);
- door::ANSIColor title_color(door::COLOR::CYAN, door::COLOR::BLUE,
- door::ATTR::BOLD);
- m.setColor(border_color);
- mtitle.setColor(title_color);
- mtitle.setPadding(" ", title_color);
- m.setTitle(std::make_unique<door::Line>(mtitle), 1);
- // m.setColorizer(true,
- m.setRender(true, door::Menu::makeRender(
- door::ANSIColor(door::COLOR::CYAN, door::ATTR::BOLD),
- door::ANSIColor(door::COLOR::BLUE, door::ATTR::BOLD),
- door::ANSIColor(door::COLOR::CYAN, door::ATTR::BOLD),
- door::ANSIColor(door::COLOR::BLUE, door::ATTR::BOLD)));
- // m.setColorizer(false,
- m.setRender(false, door::Menu::makeRender(
- door::ANSIColor(door::COLOR::YELLOW, door::COLOR::BLUE,
- door::ATTR::BOLD),
- door::ANSIColor(door::COLOR::WHITE, door::COLOR::BLUE,
- door::ATTR::BOLD),
- door::ANSIColor(door::COLOR::YELLOW, door::COLOR::BLUE,
- door::ATTR::BOLD),
- door::ANSIColor(door::COLOR::CYAN, door::COLOR::BLUE,
- door::ATTR::BOLD)));
- m.addSelection('D', "Deck Colors");
- m.addSelection('V', "View Settings");
- m.addSelection('Q', "Quit");
- return m;
- }
- /*
- // all the possible deck colors
- vector<std::string> deck_colors = {std::string("All"), std::string("Blue"),
- std::string("Cyan"), std::string("Green"),
- std::string("Magenta"), std::string("Red")};
- */
- door::Menu make_deck_menu(void) {
- door::Menu m(5, 5, 31);
- door::Line mtitle(SPACEACE " Deck Menu");
- door::ANSIColor border_color(door::COLOR::CYAN, door::COLOR::BLUE);
- door::ANSIColor title_color(door::COLOR::CYAN, door::COLOR::BLUE,
- door::ATTR::BOLD);
- m.setColor(border_color);
- mtitle.setColor(title_color);
- mtitle.setPadding(" ", title_color);
- m.setTitle(std::make_unique<door::Line>(mtitle), 1);
- m.setRender(true, makeColorRender(
- door::ANSIColor(door::COLOR::CYAN, door::ATTR::BOLD),
- door::ANSIColor(door::COLOR::BLUE, door::ATTR::BOLD),
- door::ANSIColor(door::COLOR::CYAN, door::ATTR::BOLD)));
- m.setRender(false, makeColorRender(
- door::ANSIColor(door::COLOR::YELLOW, door::COLOR::BLUE,
- door::ATTR::BOLD),
- door::ANSIColor(door::COLOR::WHITE, door::COLOR::BLUE,
- door::ATTR::BOLD),
- door::ANSIColor(door::COLOR::YELLOW, door::COLOR::BLUE,
- door::ATTR::BOLD)));
- // build the menu options from the colors. First character = single letter
- // option trigger.
- for (auto iter = deck_colors.begin(); iter != deck_colors.end(); ++iter) {
- char c = (*iter)[0];
- m.addSelection(c, (*iter).c_str());
- }
- /*
- m.addSelection('A', "All");
- m.addSelection('B', "Blue");
- m.addSelection('C', "Cyan");
- m.addSelection('G', "Green");
- m.addSelection('M', "Magenta");
- m.addSelection('R', "Red");
- */
- return m;
- }
|