|  | @@ -0,0 +1,1206 @@
 | 
											
												
													
														|  | 
 |  | +#include "play.h"
 | 
											
												
													
														|  | 
 |  | +#include "db.h"
 | 
											
												
													
														|  | 
 |  | +#include "deck.h"
 | 
											
												
													
														|  | 
 |  | +#include "version.h"
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +#include <iomanip> // put_time
 | 
											
												
													
														|  | 
 |  | +#include <sstream>
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +static std::function<std::ofstream &(void)> get_logger;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +static int press_a_key(door::Door &door) {
 | 
											
												
													
														|  | 
 |  | +  door << door::reset << "Press a key to continue...";
 | 
											
												
													
														|  | 
 |  | +  int r = door.sleep_key(door.inactivity);
 | 
											
												
													
														|  | 
 |  | +  door << door::nl;
 | 
											
												
													
														|  | 
 |  | +  return r;
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +/*
 | 
											
												
													
														|  | 
 |  | +In the future, this will probably check to see if they can play today or not, as
 | 
											
												
													
														|  | 
 |  | +well as displaying a calendar to show what days are available to be played.
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +For now, it will play today.
 | 
											
												
													
														|  | 
 |  | +*/
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +PlayCards::PlayCards(door::Door &d, DBData &dbd, std::mt19937 &r)
 | 
											
												
													
														|  | 
 |  | +    : door{d}, db{dbd}, rng{r} {
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  init_values();
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  spaceAceTriPeaks = make_tripeaks();
 | 
											
												
													
														|  | 
 |  | +  score_panel = make_score_panel();
 | 
											
												
													
														|  | 
 |  | +  streak_panel = make_streak_panel();
 | 
											
												
													
														|  | 
 |  | +  left_panel = make_left_panel();
 | 
											
												
													
														|  | 
 |  | +  cmd_panel = make_command_panel();
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  int mx = door.width;
 | 
											
												
													
														|  | 
 |  | +  int my = door.height;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  play_day = std::chrono::system_clock::now();
 | 
											
												
													
														|  | 
 |  | +  get_logger = [this]() -> ofstream & { return door.log(); };
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +PlayCards::~PlayCards() { get_logger = nullptr; }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +void PlayCards::init_values(void) {
 | 
											
												
													
														|  | 
 |  | +  hand = 1;
 | 
											
												
													
														|  | 
 |  | +  total_hands = 3;
 | 
											
												
													
														|  | 
 |  | +  card_number = 28;
 | 
											
												
													
														|  | 
 |  | +  current_streak = 0;
 | 
											
												
													
														|  | 
 |  | +  best_streak = 0;
 | 
											
												
													
														|  | 
 |  | +  active_card = 23;
 | 
											
												
													
														|  | 
 |  | +  score = 0;
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +int PlayCards::play_cards(void) {
 | 
											
												
													
														|  | 
 |  | +  play_day = std::chrono::system_clock::now();
 | 
											
												
													
														|  | 
 |  | +  init_values();
 | 
											
												
													
														|  | 
 |  | +  std::string currentDefault = db.getSetting("DeckColor", "ALL");
 | 
											
												
													
														|  | 
 |  | +  get_logger() << "DeckColor shows as " << currentDefault << std::endl;
 | 
											
												
													
														|  | 
 |  | +  deck_color = from_string(currentDefault);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  dp = Deck(deck_color);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  // Calculate the game size
 | 
											
												
													
														|  | 
 |  | +  int game_width;
 | 
											
												
													
														|  | 
 |  | +  int game_height = 20;
 | 
											
												
													
														|  | 
 |  | +  {
 | 
											
												
													
														|  | 
 |  | +    int cx, cy, level;
 | 
											
												
													
														|  | 
 |  | +    cardgo(27, cx, cy, level);
 | 
											
												
													
														|  | 
 |  | +    game_width = cx + 5;
 | 
											
												
													
														|  | 
 |  | +  }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  int mx = door.width;
 | 
											
												
													
														|  | 
 |  | +  int my = door.height;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  off_x = (mx - game_width) / 2;
 | 
											
												
													
														|  | 
 |  | +  off_y = (my - game_height) / 2;
 | 
											
												
													
														|  | 
 |  | +  int true_off_y = off_y;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  // we can now position things properly centered
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  int tp_off_x = (mx - spaceAceTriPeaks->getWidth()) / 2;
 | 
											
												
													
														|  | 
 |  | +  spaceAceTriPeaks->set(tp_off_x, off_y);
 | 
											
												
													
														|  | 
 |  | +  off_y += 3; // adjust for tripeaks panel
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +next_hand:
 | 
											
												
													
														|  | 
 |  | +  card_number = 28;
 | 
											
												
													
														|  | 
 |  | +  active_card = 23;
 | 
											
												
													
														|  | 
 |  | +  score = 0;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  // Use play_day to seed the rng
 | 
											
												
													
														|  | 
 |  | +  {
 | 
											
												
													
														|  | 
 |  | +    time_t tt = std::chrono::system_clock::to_time_t(play_day);
 | 
											
												
													
														|  | 
 |  | +    tm local_tm = *localtime(&tt);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    std::seed_seq seq{local_tm.tm_year + 1900, local_tm.tm_mon + 1,
 | 
											
												
													
														|  | 
 |  | +                      local_tm.tm_mday, hand};
 | 
											
												
													
														|  | 
 |  | +    deck = card_shuffle(seq, 1);
 | 
											
												
													
														|  | 
 |  | +    state = card_states();
 | 
											
												
													
														|  | 
 |  | +  }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  /*
 | 
											
												
													
														|  | 
 |  | +    door::Panel score_panel = make_score_panel();
 | 
											
												
													
														|  | 
 |  | +    door::Panel streak_panel = make_streak_panel();
 | 
											
												
													
														|  | 
 |  | +    door::Panel left_panel = make_left_panel();
 | 
											
												
													
														|  | 
 |  | +    door::Panel cmd_panel = make_command_panel();
 | 
											
												
													
														|  | 
 |  | +  */
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  {
 | 
											
												
													
														|  | 
 |  | +    int off_yp = off_y + 11;
 | 
											
												
													
														|  | 
 |  | +    int cxp, cyp, levelp;
 | 
											
												
													
														|  | 
 |  | +    int left_panel_x, right_panel_x;
 | 
											
												
													
														|  | 
 |  | +    // find position of card, to position the panels
 | 
											
												
													
														|  | 
 |  | +    cardgo(18, cxp, cyp, levelp);
 | 
											
												
													
														|  | 
 |  | +    left_panel_x = cxp;
 | 
											
												
													
														|  | 
 |  | +    cardgo(15, cxp, cyp, levelp);
 | 
											
												
													
														|  | 
 |  | +    right_panel_x = cxp;
 | 
											
												
													
														|  | 
 |  | +    score_panel->set(left_panel_x + off_x, off_yp);
 | 
											
												
													
														|  | 
 |  | +    streak_panel->set(right_panel_x + off_x, off_yp);
 | 
											
												
													
														|  | 
 |  | +    cmd_panel->set(left_panel_x + off_x, off_yp + 5);
 | 
											
												
													
														|  | 
 |  | +  }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  bool dealing = true;
 | 
											
												
													
														|  | 
 |  | +  int r = 0;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  redraw(dealing);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  dealing = false;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  left_panel->update(door);
 | 
											
												
													
														|  | 
 |  | +  door << door::reset;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  door::Panel *c;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  bool in_game = true;
 | 
											
												
													
														|  | 
 |  | +  while (in_game) {
 | 
											
												
													
														|  | 
 |  | +    // time might have updated, so update score panel too.
 | 
											
												
													
														|  | 
 |  | +    score_panel->update(door);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    r = door.sleep_key(door.inactivity);
 | 
											
												
													
														|  | 
 |  | +    if (r > 0) {
 | 
											
												
													
														|  | 
 |  | +      // not a timeout or expire.
 | 
											
												
													
														|  | 
 |  | +      if (r < 0x1000) // not a function key
 | 
											
												
													
														|  | 
 |  | +        r = std::toupper(r);
 | 
											
												
													
														|  | 
 |  | +      switch (r) {
 | 
											
												
													
														|  | 
 |  | +      case '\x0d':
 | 
											
												
													
														|  | 
 |  | +        if (card_number < 51) {
 | 
											
												
													
														|  | 
 |  | +          card_number++;
 | 
											
												
													
														|  | 
 |  | +          current_streak = 0;
 | 
											
												
													
														|  | 
 |  | +          streak_panel->update(door);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +          // Ok, deal next card from the pile.
 | 
											
												
													
														|  | 
 |  | +          int cx, cy, level;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +          if (card_number == 51) {
 | 
											
												
													
														|  | 
 |  | +            cardgo(29, cx, cy, level);
 | 
											
												
													
														|  | 
 |  | +            level = 0; // out of cards
 | 
											
												
													
														|  | 
 |  | +            c = dp.back(level);
 | 
											
												
													
														|  | 
 |  | +            c->set(cx + off_x, cy + off_y);
 | 
											
												
													
														|  | 
 |  | +            door << *c;
 | 
											
												
													
														|  | 
 |  | +          }
 | 
											
												
													
														|  | 
 |  | +          cardgo(28, cx, cy, level);
 | 
											
												
													
														|  | 
 |  | +          c = dp.card(deck.at(card_number));
 | 
											
												
													
														|  | 
 |  | +          c->set(cx + off_x, cy + off_y);
 | 
											
												
													
														|  | 
 |  | +          door << *c;
 | 
											
												
													
														|  | 
 |  | +          // update the cards left_panel
 | 
											
												
													
														|  | 
 |  | +          left_panel->update(door);
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  | 
 |  | +        break;
 | 
											
												
													
														|  | 
 |  | +      case 'R':
 | 
											
												
													
														|  | 
 |  | +        // now_what = false;
 | 
											
												
													
														|  | 
 |  | +        redraw(false);
 | 
											
												
													
														|  | 
 |  | +        break;
 | 
											
												
													
														|  | 
 |  | +      case 'Q':
 | 
											
												
													
														|  | 
 |  | +        in_game = false;
 | 
											
												
													
														|  | 
 |  | +        break;
 | 
											
												
													
														|  | 
 |  | +      case ' ':
 | 
											
												
													
														|  | 
 |  | +      case '5':
 | 
											
												
													
														|  | 
 |  | +        // can we play this card?
 | 
											
												
													
														|  | 
 |  | +        /*
 | 
											
												
													
														|  | 
 |  | +        get_logger() << "can_play( " << active_card << ":"
 | 
											
												
													
														|  | 
 |  | +                     << deck1.at(active_card) << "/"
 | 
											
												
													
														|  | 
 |  | +                     << d.is_rank(deck1.at(active_card)) << " , "
 | 
											
												
													
														|  | 
 |  | +                     << card_number << "/" <<
 | 
											
												
													
														|  | 
 |  | +        d.is_rank(deck1.at(card_number))
 | 
											
												
													
														|  | 
 |  | +                     << ") = "
 | 
											
												
													
														|  | 
 |  | +                     << d.can_play(deck1.at(active_card),
 | 
											
												
													
														|  | 
 |  | +                                   deck1.at(card_number))
 | 
											
												
													
														|  | 
 |  | +                     << std::endl;
 | 
											
												
													
														|  | 
 |  | +                     */
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +        if (dp.can_play(deck.at(active_card), deck.at(card_number))) {
 | 
											
												
													
														|  | 
 |  | +          // if (true) {
 | 
											
												
													
														|  | 
 |  | +          // yes we can.
 | 
											
												
													
														|  | 
 |  | +          ++current_streak;
 | 
											
												
													
														|  | 
 |  | +          if (current_streak > best_streak)
 | 
											
												
													
														|  | 
 |  | +            best_streak = current_streak;
 | 
											
												
													
														|  | 
 |  | +          streak_panel->update(door);
 | 
											
												
													
														|  | 
 |  | +          score += 10;
 | 
											
												
													
														|  | 
 |  | +          if (current_streak > 2)
 | 
											
												
													
														|  | 
 |  | +            score += 5;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +          // play card!
 | 
											
												
													
														|  | 
 |  | +          state.at(active_card) = 2;
 | 
											
												
													
														|  | 
 |  | +          {
 | 
											
												
													
														|  | 
 |  | +            // swap the active card with card_number (play card)
 | 
											
												
													
														|  | 
 |  | +            int temp = deck.at(active_card);
 | 
											
												
													
														|  | 
 |  | +            deck.at(active_card) = deck.at(card_number);
 | 
											
												
													
														|  | 
 |  | +            deck.at(card_number) = temp;
 | 
											
												
													
														|  | 
 |  | +            // active_card is -- invalidated here!  find "new" card.
 | 
											
												
													
														|  | 
 |  | +            int cx, cy, level;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +            // erase/clear active_card
 | 
											
												
													
														|  | 
 |  | +            std::vector<int> check = dp.unblocks(active_card);
 | 
											
												
													
														|  | 
 |  | +            bool left = false, right = false;
 | 
											
												
													
														|  | 
 |  | +            for (const int c : check) {
 | 
											
												
													
														|  | 
 |  | +              std::pair<int, int> blockers = dp.blocks[c];
 | 
											
												
													
														|  | 
 |  | +              if (blockers.first == active_card)
 | 
											
												
													
														|  | 
 |  | +                right = true;
 | 
											
												
													
														|  | 
 |  | +              if (blockers.second == active_card)
 | 
											
												
													
														|  | 
 |  | +                left = true;
 | 
											
												
													
														|  | 
 |  | +            }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +            dp.remove_card(door, active_card, off_x, off_y, left, right);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +            /*   // old way of doing this that leaves holes.
 | 
											
												
													
														|  | 
 |  | +            cardgo(active_card, cx, cy, level);
 | 
											
												
													
														|  | 
 |  | +            c = d.back(0);
 | 
											
												
													
														|  | 
 |  | +            c->set(cx + off_x, cy + off_y);
 | 
											
												
													
														|  | 
 |  | +            door << *c;
 | 
											
												
													
														|  | 
 |  | +            */
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +            // redraw play card #28. (Which is the "old" active_card)
 | 
											
												
													
														|  | 
 |  | +            cardgo(28, cx, cy, level);
 | 
											
												
													
														|  | 
 |  | +            c = dp.card(deck.at(card_number));
 | 
											
												
													
														|  | 
 |  | +            c->set(cx + off_x, cy + off_y);
 | 
											
												
													
														|  | 
 |  | +            door << *c;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +            // Did we unhide a card here?
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +            // std::vector<int> check = d.unblocks(active_card);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +            /*
 | 
											
												
													
														|  | 
 |  | +            get_logger() << "active_card = " << active_card
 | 
											
												
													
														|  | 
 |  | +                         << " unblocks: " << check.size() << std::endl;
 | 
											
												
													
														|  | 
 |  | +            */
 | 
											
												
													
														|  | 
 |  | +            int new_card_shown = -1;
 | 
											
												
													
														|  | 
 |  | +            if (!check.empty()) {
 | 
											
												
													
														|  | 
 |  | +              for (const int to_check : check) {
 | 
											
												
													
														|  | 
 |  | +                std::pair<int, int> blockers = dp.blocks[to_check];
 | 
											
												
													
														|  | 
 |  | +                /*
 | 
											
												
													
														|  | 
 |  | +                get_logger()
 | 
											
												
													
														|  | 
 |  | +                    << "Check: " << to_check << " " << blockers.first << ","
 | 
											
												
													
														|  | 
 |  | +                    << blockers.second << " " << state.at(blockers.first)
 | 
											
												
													
														|  | 
 |  | +                    << "," << state.at(blockers.second) << std::endl;
 | 
											
												
													
														|  | 
 |  | +                    */
 | 
											
												
													
														|  | 
 |  | +                if ((state.at(blockers.first) == 2) and
 | 
											
												
													
														|  | 
 |  | +                    (state.at(blockers.second) == 2)) {
 | 
											
												
													
														|  | 
 |  | +                  // WOOT!  Card uncovered.
 | 
											
												
													
														|  | 
 |  | +                  /*
 | 
											
												
													
														|  | 
 |  | +                  get_logger() << "showing: " << to_check << std::endl;
 | 
											
												
													
														|  | 
 |  | +                  */
 | 
											
												
													
														|  | 
 |  | +                  state.at(to_check) = 1;
 | 
											
												
													
														|  | 
 |  | +                  cardgo(to_check, cx, cy, level);
 | 
											
												
													
														|  | 
 |  | +                  c = dp.card(deck.at(to_check));
 | 
											
												
													
														|  | 
 |  | +                  c->set(cx + off_x, cy + off_y);
 | 
											
												
													
														|  | 
 |  | +                  door << *c;
 | 
											
												
													
														|  | 
 |  | +                  new_card_shown = to_check;
 | 
											
												
													
														|  | 
 |  | +                }
 | 
											
												
													
														|  | 
 |  | +              }
 | 
											
												
													
														|  | 
 |  | +            } else {
 | 
											
												
													
														|  | 
 |  | +              // this would be a "top" card.  Should set status = 4 and
 | 
											
												
													
														|  | 
 |  | +              // display something here?
 | 
											
												
													
														|  | 
 |  | +              get_logger() << "top card cleared?" << std::endl;
 | 
											
												
													
														|  | 
 |  | +              // display something at active_card position
 | 
											
												
													
														|  | 
 |  | +              int cx, cy, level;
 | 
											
												
													
														|  | 
 |  | +              cardgo(active_card, cx, cy, level);
 | 
											
												
													
														|  | 
 |  | +              door << door::Goto(cx + off_x, cy + off_y) << door::reset
 | 
											
												
													
														|  | 
 |  | +                   << "BONUS";
 | 
											
												
													
														|  | 
 |  | +              score += 100;
 | 
											
												
													
														|  | 
 |  | +              state.at(active_card) = 3; // handle this in the "redraw"
 | 
											
												
													
														|  | 
 |  | +            }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +            // Find new "number" for active_card to be.
 | 
											
												
													
														|  | 
 |  | +            if (new_card_shown != -1) {
 | 
											
												
													
														|  | 
 |  | +              active_card = new_card_shown;
 | 
											
												
													
														|  | 
 |  | +            } else {
 | 
											
												
													
														|  | 
 |  | +              // active_card++;
 | 
											
												
													
														|  | 
 |  | +              int new_active = find_next_closest(state, active_card);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +              if (new_active != -1) {
 | 
											
												
													
														|  | 
 |  | +                active_card = new_active;
 | 
											
												
													
														|  | 
 |  | +              } else {
 | 
											
												
													
														|  | 
 |  | +                get_logger() << "This looks like END OF GAME." << std::endl;
 | 
											
												
													
														|  | 
 |  | +                // bonus for cards left
 | 
											
												
													
														|  | 
 |  | +                press_a_key(door);
 | 
											
												
													
														|  | 
 |  | +                if (hand < total_hands) {
 | 
											
												
													
														|  | 
 |  | +                  hand++;
 | 
											
												
													
														|  | 
 |  | +                  door << door::reset << door::cls;
 | 
											
												
													
														|  | 
 |  | +                  goto next_hand;
 | 
											
												
													
														|  | 
 |  | +                }
 | 
											
												
													
														|  | 
 |  | +                r = 'Q';
 | 
											
												
													
														|  | 
 |  | +                in_game = false;
 | 
											
												
													
														|  | 
 |  | +              }
 | 
											
												
													
														|  | 
 |  | +            }
 | 
											
												
													
														|  | 
 |  | +            // update the active_card marker!
 | 
											
												
													
														|  | 
 |  | +            cardgo(active_card, cx, cy, level);
 | 
											
												
													
														|  | 
 |  | +            c = dp.marker(1);
 | 
											
												
													
														|  | 
 |  | +            c->set(cx + off_x + 2, cy + off_y + 2);
 | 
											
												
													
														|  | 
 |  | +            door << *c;
 | 
											
												
													
														|  | 
 |  | +          }
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  | 
 |  | +        break;
 | 
											
												
													
														|  | 
 |  | +      case XKEY_LEFT_ARROW:
 | 
											
												
													
														|  | 
 |  | +      case '4': {
 | 
											
												
													
														|  | 
 |  | +        int new_active = find_next(true, state, active_card);
 | 
											
												
													
														|  | 
 |  | +        /*
 | 
											
												
													
														|  | 
 |  | +        int new_active = active_card - 1;
 | 
											
												
													
														|  | 
 |  | +        while (new_active >= 0) {
 | 
											
												
													
														|  | 
 |  | +          if (state.at(new_active) == 1)
 | 
											
												
													
														|  | 
 |  | +            break;
 | 
											
												
													
														|  | 
 |  | +          --new_active;
 | 
											
												
													
														|  | 
 |  | +        }*/
 | 
											
												
													
														|  | 
 |  | +        if (new_active >= 0) {
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +          int cx, cy, level;
 | 
											
												
													
														|  | 
 |  | +          cardgo(active_card, cx, cy, level);
 | 
											
												
													
														|  | 
 |  | +          c = dp.marker(0);
 | 
											
												
													
														|  | 
 |  | +          c->set(cx + off_x + 2, cy + off_y + 2);
 | 
											
												
													
														|  | 
 |  | +          door << *c;
 | 
											
												
													
														|  | 
 |  | +          active_card = new_active;
 | 
											
												
													
														|  | 
 |  | +          cardgo(active_card, cx, cy, level);
 | 
											
												
													
														|  | 
 |  | +          c = dp.marker(1);
 | 
											
												
													
														|  | 
 |  | +          c->set(cx + off_x + 2, cy + off_y + 2);
 | 
											
												
													
														|  | 
 |  | +          door << *c;
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  | 
 |  | +      } break;
 | 
											
												
													
														|  | 
 |  | +      case XKEY_RIGHT_ARROW:
 | 
											
												
													
														|  | 
 |  | +      case '6': {
 | 
											
												
													
														|  | 
 |  | +        int new_active = find_next(false, state, active_card);
 | 
											
												
													
														|  | 
 |  | +        /*
 | 
											
												
													
														|  | 
 |  | +        int new_active = active_card + 1;
 | 
											
												
													
														|  | 
 |  | +        while (new_active < 28) {
 | 
											
												
													
														|  | 
 |  | +          if (state.at(new_active) == 1)
 | 
											
												
													
														|  | 
 |  | +            break;
 | 
											
												
													
														|  | 
 |  | +          ++new_active;
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  | 
 |  | +        */
 | 
											
												
													
														|  | 
 |  | +        if (new_active >= 0) { //(new_active < 28) {
 | 
											
												
													
														|  | 
 |  | +          int cx, cy, level;
 | 
											
												
													
														|  | 
 |  | +          cardgo(active_card, cx, cy, level);
 | 
											
												
													
														|  | 
 |  | +          c = dp.marker(0);
 | 
											
												
													
														|  | 
 |  | +          c->set(cx + off_x + 2, cy + off_y + 2);
 | 
											
												
													
														|  | 
 |  | +          door << *c;
 | 
											
												
													
														|  | 
 |  | +          active_card = new_active;
 | 
											
												
													
														|  | 
 |  | +          cardgo(active_card, cx, cy, level);
 | 
											
												
													
														|  | 
 |  | +          c = dp.marker(1);
 | 
											
												
													
														|  | 
 |  | +          c->set(cx + off_x + 2, cy + off_y + 2);
 | 
											
												
													
														|  | 
 |  | +          door << *c;
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  | 
 |  | +      }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +      break;
 | 
											
												
													
														|  | 
 |  | +      }
 | 
											
												
													
														|  | 
 |  | +    } else
 | 
											
												
													
														|  | 
 |  | +      in_game = false;
 | 
											
												
													
														|  | 
 |  | +  }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  if (r == 'Q') {
 | 
											
												
													
														|  | 
 |  | +    // continue with hand, or quit?
 | 
											
												
													
														|  | 
 |  | +  }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  return r;
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +void PlayCards::redraw(bool dealing) {
 | 
											
												
													
														|  | 
 |  | +  door::Panel *c;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  door << door::reset << door::cls;
 | 
											
												
													
														|  | 
 |  | +  door << *spaceAceTriPeaks;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  {
 | 
											
												
													
														|  | 
 |  | +    // step 1:
 | 
											
												
													
														|  | 
 |  | +    // draw the deck "source"
 | 
											
												
													
														|  | 
 |  | +    int cx, cy, level;
 | 
											
												
													
														|  | 
 |  | +    cardgo(29, cx, cy, level);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    if (card_number == 51)
 | 
											
												
													
														|  | 
 |  | +      level = 0; // out of cards!
 | 
											
												
													
														|  | 
 |  | +    c = dp.back(level);
 | 
											
												
													
														|  | 
 |  | +    c->set(cx + off_x, cy + off_y);
 | 
											
												
													
														|  | 
 |  | +    // p3 is heigh below
 | 
											
												
													
														|  | 
 |  | +    left_panel->set(cx + off_x, cy + off_y + height);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    // how do I update these? (hand >1)
 | 
											
												
													
														|  | 
 |  | +    score_panel->update();
 | 
											
												
													
														|  | 
 |  | +    left_panel->update();
 | 
											
												
													
														|  | 
 |  | +    streak_panel->update();
 | 
											
												
													
														|  | 
 |  | +    cmd_panel->update();
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    door << *score_panel << *left_panel << *streak_panel << *cmd_panel;
 | 
											
												
													
														|  | 
 |  | +    door << *c;
 | 
											
												
													
														|  | 
 |  | +    if (dealing)
 | 
											
												
													
														|  | 
 |  | +      std::this_thread::sleep_for(std::chrono::seconds(1));
 | 
											
												
													
														|  | 
 |  | +  }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  for (int x = 0; x < (dealing ? 28 : 29); x++) {
 | 
											
												
													
														|  | 
 |  | +    int cx, cy, level;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    cardgo(x, cx, cy, level);
 | 
											
												
													
														|  | 
 |  | +    // This is hardly visible.
 | 
											
												
													
														|  | 
 |  | +    // door << door::Goto(cx + off_x - 1, cy + off_y + 1);
 | 
											
												
													
														|  | 
 |  | +    if (dealing)
 | 
											
												
													
														|  | 
 |  | +      std::this_thread::sleep_for(std::chrono::milliseconds(75));
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    if (dealing) {
 | 
											
												
													
														|  | 
 |  | +      c = dp.back(level);
 | 
											
												
													
														|  | 
 |  | +      c->set(cx + off_x, cy + off_y);
 | 
											
												
													
														|  | 
 |  | +      door << *c;
 | 
											
												
													
														|  | 
 |  | +    } else {
 | 
											
												
													
														|  | 
 |  | +      // redrawing -- draw the cards with their correct "state"
 | 
											
												
													
														|  | 
 |  | +      int s = state.at(x);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +      switch (s) {
 | 
											
												
													
														|  | 
 |  | +      case 0:
 | 
											
												
													
														|  | 
 |  | +        c = dp.back(level);
 | 
											
												
													
														|  | 
 |  | +        c->set(cx + off_x, cy + off_y);
 | 
											
												
													
														|  | 
 |  | +        door << *c;
 | 
											
												
													
														|  | 
 |  | +        break;
 | 
											
												
													
														|  | 
 |  | +      case 1:
 | 
											
												
													
														|  | 
 |  | +        // cardgo(x, space, height, cx, cy, level);
 | 
											
												
													
														|  | 
 |  | +        if (x == 28)
 | 
											
												
													
														|  | 
 |  | +          c = dp.card(deck.at(card_number));
 | 
											
												
													
														|  | 
 |  | +        else
 | 
											
												
													
														|  | 
 |  | +          c = dp.card(deck.at(x));
 | 
											
												
													
														|  | 
 |  | +        c->set(cx + off_x, cy + off_y);
 | 
											
												
													
														|  | 
 |  | +        door << *c;
 | 
											
												
													
														|  | 
 |  | +        break;
 | 
											
												
													
														|  | 
 |  | +      case 2:
 | 
											
												
													
														|  | 
 |  | +        // no card to draw.  :)
 | 
											
												
													
														|  | 
 |  | +        break;
 | 
											
												
													
														|  | 
 |  | +      }
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +  }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  if (dealing)
 | 
											
												
													
														|  | 
 |  | +    for (int x = 18; x < 29; x++) {
 | 
											
												
													
														|  | 
 |  | +      int cx, cy, level;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +      state.at(x) = 1;
 | 
											
												
													
														|  | 
 |  | +      cardgo(x, cx, cy, level);
 | 
											
												
													
														|  | 
 |  | +      // door << door::Goto(cx + off_x - 1, cy + off_y + 1);
 | 
											
												
													
														|  | 
 |  | +      std::this_thread::sleep_for(std::chrono::milliseconds(200));
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +      c = dp.card(deck.at(x));
 | 
											
												
													
														|  | 
 |  | +      c->set(cx + off_x, cy + off_y);
 | 
											
												
													
														|  | 
 |  | +      door << *c;
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  {
 | 
											
												
													
														|  | 
 |  | +    int cx, cy, level;
 | 
											
												
													
														|  | 
 |  | +    cardgo(active_card, cx, cy, level);
 | 
											
												
													
														|  | 
 |  | +    c = dp.marker(1);
 | 
											
												
													
														|  | 
 |  | +    c->set(cx + off_x + 2, cy + off_y + 2);
 | 
											
												
													
														|  | 
 |  | +    door << *c;
 | 
											
												
													
														|  | 
 |  | +  }
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +door::renderFunction PlayCards::statusValue(door::ANSIColor status,
 | 
											
												
													
														|  | 
 |  | +                                            door::ANSIColor value) {
 | 
											
												
													
														|  | 
 |  | +  door::renderFunction rf = [status,
 | 
											
												
													
														|  | 
 |  | +                             value](const std::string &txt) -> door::Render {
 | 
											
												
													
														|  | 
 |  | +    door::Render r(txt);
 | 
											
												
													
														|  | 
 |  | +    door::ColorOutput co;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    co.pos = 0;
 | 
											
												
													
														|  | 
 |  | +    co.len = 0;
 | 
											
												
													
														|  | 
 |  | +    co.c = status;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    size_t pos = txt.find(':');
 | 
											
												
													
														|  | 
 |  | +    if (pos == std::string::npos) {
 | 
											
												
													
														|  | 
 |  | +      // failed to find :, render digits/numbers in value color
 | 
											
												
													
														|  | 
 |  | +      int tpos = 0;
 | 
											
												
													
														|  | 
 |  | +      for (char const &c : txt) {
 | 
											
												
													
														|  | 
 |  | +        if (std::isdigit(c)) {
 | 
											
												
													
														|  | 
 |  | +          if (co.c != value) {
 | 
											
												
													
														|  | 
 |  | +            r.outputs.push_back(co);
 | 
											
												
													
														|  | 
 |  | +            co.reset();
 | 
											
												
													
														|  | 
 |  | +            co.pos = tpos;
 | 
											
												
													
														|  | 
 |  | +            co.c = value;
 | 
											
												
													
														|  | 
 |  | +          }
 | 
											
												
													
														|  | 
 |  | +        } else {
 | 
											
												
													
														|  | 
 |  | +          if (co.c != status) {
 | 
											
												
													
														|  | 
 |  | +            r.outputs.push_back(co);
 | 
											
												
													
														|  | 
 |  | +            co.reset();
 | 
											
												
													
														|  | 
 |  | +            co.pos = tpos;
 | 
											
												
													
														|  | 
 |  | +            co.c = status;
 | 
											
												
													
														|  | 
 |  | +          }
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  | 
 |  | +        co.len++;
 | 
											
												
													
														|  | 
 |  | +        tpos++;
 | 
											
												
													
														|  | 
 |  | +      }
 | 
											
												
													
														|  | 
 |  | +      if (co.len != 0)
 | 
											
												
													
														|  | 
 |  | +        r.outputs.push_back(co);
 | 
											
												
													
														|  | 
 |  | +    } else {
 | 
											
												
													
														|  | 
 |  | +      pos++; // Have : in status color
 | 
											
												
													
														|  | 
 |  | +      co.len = pos;
 | 
											
												
													
														|  | 
 |  | +      r.outputs.push_back(co);
 | 
											
												
													
														|  | 
 |  | +      co.reset();
 | 
											
												
													
														|  | 
 |  | +      co.pos = pos;
 | 
											
												
													
														|  | 
 |  | +      co.c = value;
 | 
											
												
													
														|  | 
 |  | +      co.len = txt.length() - pos;
 | 
											
												
													
														|  | 
 |  | +      r.outputs.push_back(co);
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    return r;
 | 
											
												
													
														|  | 
 |  | +  };
 | 
											
												
													
														|  | 
 |  | +  return rf;
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +std::unique_ptr<door::Panel> PlayCards::make_score_panel() {
 | 
											
												
													
														|  | 
 |  | +  const int W = 25;
 | 
											
												
													
														|  | 
 |  | +  std::unique_ptr<door::Panel> p = std::make_unique<door::Panel>(W);
 | 
											
												
													
														|  | 
 |  | +  p->setStyle(door::BorderStyle::NONE);
 | 
											
												
													
														|  | 
 |  | +  door::ANSIColor statusColor(door::COLOR::WHITE, door::COLOR::BLUE,
 | 
											
												
													
														|  | 
 |  | +                              door::ATTR::BOLD);
 | 
											
												
													
														|  | 
 |  | +  door::ANSIColor valueColor(door::COLOR::YELLOW, door::COLOR::BLUE,
 | 
											
												
													
														|  | 
 |  | +                             door::ATTR::BOLD);
 | 
											
												
													
														|  | 
 |  | +  door::renderFunction svRender = statusValue(statusColor, valueColor);
 | 
											
												
													
														|  | 
 |  | +  // or use renderStatus as defined above.
 | 
											
												
													
														|  | 
 |  | +  // We'll stick with these for now.
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  {
 | 
											
												
													
														|  | 
 |  | +    std::string userString = "Name: ";
 | 
											
												
													
														|  | 
 |  | +    userString += door.username;
 | 
											
												
													
														|  | 
 |  | +    door::Line username(userString, W);
 | 
											
												
													
														|  | 
 |  | +    username.setRender(svRender);
 | 
											
												
													
														|  | 
 |  | +    p->addLine(std::make_unique<door::Line>(username));
 | 
											
												
													
														|  | 
 |  | +  }
 | 
											
												
													
														|  | 
 |  | +  {
 | 
											
												
													
														|  | 
 |  | +    door::updateFunction scoreUpdate = [this](void) -> std::string {
 | 
											
												
													
														|  | 
 |  | +      std::string text = "Score: ";
 | 
											
												
													
														|  | 
 |  | +      text.append(std::to_string(score));
 | 
											
												
													
														|  | 
 |  | +      return text;
 | 
											
												
													
														|  | 
 |  | +    };
 | 
											
												
													
														|  | 
 |  | +    std::string scoreString = scoreUpdate();
 | 
											
												
													
														|  | 
 |  | +    door::Line score(scoreString, W);
 | 
											
												
													
														|  | 
 |  | +    score.setRender(svRender);
 | 
											
												
													
														|  | 
 |  | +    score.setUpdater(scoreUpdate);
 | 
											
												
													
														|  | 
 |  | +    p->addLine(std::make_unique<door::Line>(score));
 | 
											
												
													
														|  | 
 |  | +  }
 | 
											
												
													
														|  | 
 |  | +  {
 | 
											
												
													
														|  | 
 |  | +    door::updateFunction timeUpdate = [this](void) -> std::string {
 | 
											
												
													
														|  | 
 |  | +      std::stringstream ss;
 | 
											
												
													
														|  | 
 |  | +      std::string text;
 | 
											
												
													
														|  | 
 |  | +      ss << "Time used: " << setw(3) << door.time_used << " / " << setw(3)
 | 
											
												
													
														|  | 
 |  | +         << door.time_left;
 | 
											
												
													
														|  | 
 |  | +      text = ss.str();
 | 
											
												
													
														|  | 
 |  | +      return text;
 | 
											
												
													
														|  | 
 |  | +    };
 | 
											
												
													
														|  | 
 |  | +    std::string timeString = timeUpdate();
 | 
											
												
													
														|  | 
 |  | +    door::Line time(timeString, W);
 | 
											
												
													
														|  | 
 |  | +    time.setRender(svRender);
 | 
											
												
													
														|  | 
 |  | +    time.setUpdater(timeUpdate);
 | 
											
												
													
														|  | 
 |  | +    p->addLine(std::make_unique<door::Line>(time));
 | 
											
												
													
														|  | 
 |  | +  }
 | 
											
												
													
														|  | 
 |  | +  {
 | 
											
												
													
														|  | 
 |  | +    door::updateFunction handUpdate = [this](void) -> std::string {
 | 
											
												
													
														|  | 
 |  | +      std::string text = "Playing Hand ";
 | 
											
												
													
														|  | 
 |  | +      text.append(std::to_string(hand));
 | 
											
												
													
														|  | 
 |  | +      text.append(" of ");
 | 
											
												
													
														|  | 
 |  | +      text.append(std::to_string(total_hands));
 | 
											
												
													
														|  | 
 |  | +      return text;
 | 
											
												
													
														|  | 
 |  | +    };
 | 
											
												
													
														|  | 
 |  | +    std::string handString = handUpdate();
 | 
											
												
													
														|  | 
 |  | +    door::Line hands(handString, W);
 | 
											
												
													
														|  | 
 |  | +    hands.setRender(svRender);
 | 
											
												
													
														|  | 
 |  | +    hands.setUpdater(handUpdate);
 | 
											
												
													
														|  | 
 |  | +    p->addLine(std::make_unique<door::Line>(hands));
 | 
											
												
													
														|  | 
 |  | +  }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  return p;
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +std::unique_ptr<door::Panel> PlayCards::make_streak_panel(void) {
 | 
											
												
													
														|  | 
 |  | +  const int W = 20;
 | 
											
												
													
														|  | 
 |  | +  std::unique_ptr<door::Panel> p = std::make_unique<door::Panel>(W);
 | 
											
												
													
														|  | 
 |  | +  p->setStyle(door::BorderStyle::NONE);
 | 
											
												
													
														|  | 
 |  | +  door::ANSIColor statusColor(door::COLOR::WHITE, door::COLOR::BLUE,
 | 
											
												
													
														|  | 
 |  | +                              door::ATTR::BOLD);
 | 
											
												
													
														|  | 
 |  | +  door::ANSIColor valueColor(door::COLOR::YELLOW, door::COLOR::BLUE,
 | 
											
												
													
														|  | 
 |  | +                             door::ATTR::BOLD);
 | 
											
												
													
														|  | 
 |  | +  door::renderFunction svRender = statusValue(statusColor, valueColor);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  {
 | 
											
												
													
														|  | 
 |  | +    std::string text = "Playing: ";
 | 
											
												
													
														|  | 
 |  | +    auto in_time_t = std::chrono::system_clock::to_time_t(play_day);
 | 
											
												
													
														|  | 
 |  | +    std::stringstream ss;
 | 
											
												
													
														|  | 
 |  | +    ss << std::put_time(std::localtime(&in_time_t), "%B %d");
 | 
											
												
													
														|  | 
 |  | +    text.append(ss.str());
 | 
											
												
													
														|  | 
 |  | +    door::Line current(text, W);
 | 
											
												
													
														|  | 
 |  | +    current.setRender(svRender);
 | 
											
												
													
														|  | 
 |  | +    p->addLine(std::make_unique<door::Line>(current));
 | 
											
												
													
														|  | 
 |  | +  }
 | 
											
												
													
														|  | 
 |  | +  {
 | 
											
												
													
														|  | 
 |  | +    door::updateFunction currentUpdate = [this](void) -> std::string {
 | 
											
												
													
														|  | 
 |  | +      std::string text = "Current Streak: ";
 | 
											
												
													
														|  | 
 |  | +      text.append(std::to_string(current_streak));
 | 
											
												
													
														|  | 
 |  | +      return text;
 | 
											
												
													
														|  | 
 |  | +    };
 | 
											
												
													
														|  | 
 |  | +    std::string currentString = currentUpdate();
 | 
											
												
													
														|  | 
 |  | +    door::Line current(currentString, W);
 | 
											
												
													
														|  | 
 |  | +    current.setRender(svRender);
 | 
											
												
													
														|  | 
 |  | +    current.setUpdater(currentUpdate);
 | 
											
												
													
														|  | 
 |  | +    p->addLine(std::make_unique<door::Line>(current));
 | 
											
												
													
														|  | 
 |  | +  }
 | 
											
												
													
														|  | 
 |  | +  {
 | 
											
												
													
														|  | 
 |  | +    door::updateFunction currentUpdate = [this](void) -> std::string {
 | 
											
												
													
														|  | 
 |  | +      std::string text = "Longest Streak: ";
 | 
											
												
													
														|  | 
 |  | +      text.append(std::to_string(best_streak));
 | 
											
												
													
														|  | 
 |  | +      return text;
 | 
											
												
													
														|  | 
 |  | +    };
 | 
											
												
													
														|  | 
 |  | +    std::string currentString = currentUpdate();
 | 
											
												
													
														|  | 
 |  | +    door::Line current(currentString, W);
 | 
											
												
													
														|  | 
 |  | +    current.setRender(svRender);
 | 
											
												
													
														|  | 
 |  | +    current.setUpdater(currentUpdate);
 | 
											
												
													
														|  | 
 |  | +    p->addLine(std::make_unique<door::Line>(current));
 | 
											
												
													
														|  | 
 |  | +  }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  return p;
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +std::unique_ptr<door::Panel> PlayCards::make_left_panel(void) {
 | 
											
												
													
														|  | 
 |  | +  const int W = 13;
 | 
											
												
													
														|  | 
 |  | +  std::unique_ptr<door::Panel> p = std::make_unique<door::Panel>(W);
 | 
											
												
													
														|  | 
 |  | +  p->setStyle(door::BorderStyle::NONE);
 | 
											
												
													
														|  | 
 |  | +  door::ANSIColor statusColor(door::COLOR::WHITE, door::COLOR::BLUE,
 | 
											
												
													
														|  | 
 |  | +                              door::ATTR::BOLD);
 | 
											
												
													
														|  | 
 |  | +  door::ANSIColor valueColor(door::COLOR::YELLOW, door::COLOR::BLUE,
 | 
											
												
													
														|  | 
 |  | +                             door::ATTR::BOLD);
 | 
											
												
													
														|  | 
 |  | +  door::renderFunction svRender = statusValue(statusColor, valueColor);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  {
 | 
											
												
													
														|  | 
 |  | +    door::updateFunction cardsleftUpdate = [this](void) -> std::string {
 | 
											
												
													
														|  | 
 |  | +      std::string text = "Cards left:";
 | 
											
												
													
														|  | 
 |  | +      text.append(std::to_string(51 - card_number));
 | 
											
												
													
														|  | 
 |  | +      return text;
 | 
											
												
													
														|  | 
 |  | +    };
 | 
											
												
													
														|  | 
 |  | +    std::string cardsleftString = "Cards left:--";
 | 
											
												
													
														|  | 
 |  | +    door::Line cardsleft(cardsleftString, W);
 | 
											
												
													
														|  | 
 |  | +    cardsleft.setRender(svRender);
 | 
											
												
													
														|  | 
 |  | +    cardsleft.setUpdater(cardsleftUpdate);
 | 
											
												
													
														|  | 
 |  | +    p->addLine(std::make_unique<door::Line>(cardsleft));
 | 
											
												
													
														|  | 
 |  | +  }
 | 
											
												
													
														|  | 
 |  | +  return p;
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +door::renderFunction PlayCards::commandLineRender(door::ANSIColor bracket,
 | 
											
												
													
														|  | 
 |  | +                                                  door::ANSIColor inner,
 | 
											
												
													
														|  | 
 |  | +                                                  door::ANSIColor outer) {
 | 
											
												
													
														|  | 
 |  | +  door::renderFunction rf = [bracket, inner,
 | 
											
												
													
														|  | 
 |  | +                             outer](const std::string &txt) -> door::Render {
 | 
											
												
													
														|  | 
 |  | +    door::Render r(txt);
 | 
											
												
													
														|  | 
 |  | +    door::ColorOutput co;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    co.pos = 0;
 | 
											
												
													
														|  | 
 |  | +    co.len = 0;
 | 
											
												
													
														|  | 
 |  | +    co.c = outer;
 | 
											
												
													
														|  | 
 |  | +    bool inOuter = true;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    int tpos = 0;
 | 
											
												
													
														|  | 
 |  | +    for (char const &c : txt) {
 | 
											
												
													
														|  | 
 |  | +      if (inOuter) {
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +        // we're in the outer text
 | 
											
												
													
														|  | 
 |  | +        if (co.c != outer) {
 | 
											
												
													
														|  | 
 |  | +          if (co.len != 0) {
 | 
											
												
													
														|  | 
 |  | +            r.outputs.push_back(co);
 | 
											
												
													
														|  | 
 |  | +            co.reset();
 | 
											
												
													
														|  | 
 |  | +            co.pos = tpos;
 | 
											
												
													
														|  | 
 |  | +          }
 | 
											
												
													
														|  | 
 |  | +          co.c = outer;
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +        // check for [
 | 
											
												
													
														|  | 
 |  | +        if (c == '[') {
 | 
											
												
													
														|  | 
 |  | +          if (co.len != 0) {
 | 
											
												
													
														|  | 
 |  | +            r.outputs.push_back(co);
 | 
											
												
													
														|  | 
 |  | +            co.reset();
 | 
											
												
													
														|  | 
 |  | +            co.pos = tpos;
 | 
											
												
													
														|  | 
 |  | +          }
 | 
											
												
													
														|  | 
 |  | +          inOuter = false;
 | 
											
												
													
														|  | 
 |  | +          co.c = bracket;
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  | 
 |  | +      } else {
 | 
											
												
													
														|  | 
 |  | +        // We're not in the outer.
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +        if (co.c != inner) {
 | 
											
												
													
														|  | 
 |  | +          if (co.len != 0) {
 | 
											
												
													
														|  | 
 |  | +            r.outputs.push_back(co);
 | 
											
												
													
														|  | 
 |  | +            co.reset();
 | 
											
												
													
														|  | 
 |  | +            co.pos = tpos;
 | 
											
												
													
														|  | 
 |  | +          }
 | 
											
												
													
														|  | 
 |  | +          co.c = inner;
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +        if (c == ']') {
 | 
											
												
													
														|  | 
 |  | +          if (co.len != 0) {
 | 
											
												
													
														|  | 
 |  | +            r.outputs.push_back(co);
 | 
											
												
													
														|  | 
 |  | +            co.reset();
 | 
											
												
													
														|  | 
 |  | +            co.pos = tpos;
 | 
											
												
													
														|  | 
 |  | +          }
 | 
											
												
													
														|  | 
 |  | +          inOuter = true;
 | 
											
												
													
														|  | 
 |  | +          co.c = bracket;
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  | 
 |  | +      }
 | 
											
												
													
														|  | 
 |  | +      co.len++;
 | 
											
												
													
														|  | 
 |  | +      tpos++;
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +    if (co.len != 0)
 | 
											
												
													
														|  | 
 |  | +      r.outputs.push_back(co);
 | 
											
												
													
														|  | 
 |  | +    return r;
 | 
											
												
													
														|  | 
 |  | +  };
 | 
											
												
													
														|  | 
 |  | +  return rf;
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +std::unique_ptr<door::Panel> PlayCards::make_command_panel(void) {
 | 
											
												
													
														|  | 
 |  | +  const int W = 76;
 | 
											
												
													
														|  | 
 |  | +  std::unique_ptr<door::Panel> p = make_unique<door::Panel>(W);
 | 
											
												
													
														|  | 
 |  | +  p->setStyle(door::BorderStyle::NONE);
 | 
											
												
													
														|  | 
 |  | +  std::string commands;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  if (door::unicode) {
 | 
											
												
													
														|  | 
 |  | +    commands = "[4/\u25c4] Left [6/\u25ba] Right [Space] Play Card [Enter] "
 | 
											
												
													
														|  | 
 |  | +               "Draw [Q]uit "
 | 
											
												
													
														|  | 
 |  | +               "[R]edraw [H]elp";
 | 
											
												
													
														|  | 
 |  | +  } else {
 | 
											
												
													
														|  | 
 |  | +    commands =
 | 
											
												
													
														|  | 
 |  | +        "[4/\x11] Left [6/\x10] Right [Space] Play Card [Enter] Draw [Q]uit "
 | 
											
												
													
														|  | 
 |  | +        "[R]edraw [H]elp";
 | 
											
												
													
														|  | 
 |  | +  }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  door::ANSIColor bracketColor(door::COLOR::YELLOW, door::COLOR::BLUE,
 | 
											
												
													
														|  | 
 |  | +                               door::ATTR::BOLD);
 | 
											
												
													
														|  | 
 |  | +  door::ANSIColor innerColor(door::COLOR::CYAN, door::COLOR::BLUE,
 | 
											
												
													
														|  | 
 |  | +                             door::ATTR::BOLD);
 | 
											
												
													
														|  | 
 |  | +  door::ANSIColor outerColor(door::COLOR::GREEN, door::COLOR::BLUE,
 | 
											
												
													
														|  | 
 |  | +                             door::ATTR::BOLD);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  door::renderFunction cmdRender =
 | 
											
												
													
														|  | 
 |  | +      commandLineRender(bracketColor, innerColor, outerColor);
 | 
											
												
													
														|  | 
 |  | +  door::Line cmd(commands, W);
 | 
											
												
													
														|  | 
 |  | +  cmd.setRender(cmdRender);
 | 
											
												
													
														|  | 
 |  | +  p->addLine(std::make_unique<door::Line>(cmd));
 | 
											
												
													
														|  | 
 |  | +  return p;
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +std::unique_ptr<door::Panel> PlayCards::make_tripeaks(void) {
 | 
											
												
													
														|  | 
 |  | +  std::string tripeaksText(" " SPACEACE
 | 
											
												
													
														|  | 
 |  | +                           " - Tri-Peaks Solitaire v" SPACEACE_VERSION " ");
 | 
											
												
													
														|  | 
 |  | +  std::unique_ptr<door::Panel> spaceAceTriPeaks =
 | 
											
												
													
														|  | 
 |  | +      std::make_unique<door::Panel>(tripeaksText.size());
 | 
											
												
													
														|  | 
 |  | +  spaceAceTriPeaks->setStyle(door::BorderStyle::SINGLE);
 | 
											
												
													
														|  | 
 |  | +  spaceAceTriPeaks->setColor(
 | 
											
												
													
														|  | 
 |  | +      door::ANSIColor(door::COLOR::CYAN, door::COLOR::BLACK));
 | 
											
												
													
														|  | 
 |  | +  spaceAceTriPeaks->addLine(
 | 
											
												
													
														|  | 
 |  | +      std::make_unique<door::Line>(tripeaksText, tripeaksText.size()));
 | 
											
												
													
														|  | 
 |  | +  return spaceAceTriPeaks;
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +#ifdef OLD_WAY
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +int play_cards(door::Door &door, DBData &db, std::mt19937 &rng) {
 | 
											
												
													
														|  | 
 |  | +  int mx = door.width;
 | 
											
												
													
														|  | 
 |  | +  int my = door.height;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  // init these values:
 | 
											
												
													
														|  | 
 |  | +  card_number = 28;
 | 
											
												
													
														|  | 
 |  | +  active_card = 23;
 | 
											
												
													
														|  | 
 |  | +  hand = 1;
 | 
											
												
													
														|  | 
 |  | +  score = 0;
 | 
											
												
													
														|  | 
 |  | +  play_day = std::chrono::system_clock::now();
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  // cards color --
 | 
											
												
													
														|  | 
 |  | +  // configured by the player.
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  door::ANSIColor deck_color;
 | 
											
												
													
														|  | 
 |  | +  // std::string key("DeckColor");
 | 
											
												
													
														|  | 
 |  | +  const char *key = "DeckColor";
 | 
											
												
													
														|  | 
 |  | +  std::string currentDefault = db.getSetting(key, "ALL");
 | 
											
												
													
														|  | 
 |  | +  door.log() << key << " shows as " << currentDefault << std::endl;
 | 
											
												
													
														|  | 
 |  | +  deck_color = from_string(currentDefault);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  const int height = 3;
 | 
											
												
													
														|  | 
 |  | +  Deck d(deck_color); // , height);
 | 
											
												
													
														|  | 
 |  | +  door::Panel *c;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  // This displays the cards in the upper left corner.
 | 
											
												
													
														|  | 
 |  | +  // We want them center, and down some.
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  // const int space = 3;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  // int cards_dealt_width = 59; int cards_dealt_height = 9;
 | 
											
												
													
														|  | 
 |  | +  int game_width;
 | 
											
												
													
														|  | 
 |  | +  int game_height = 20; // 13; // 9;
 | 
											
												
													
														|  | 
 |  | +  {
 | 
											
												
													
														|  | 
 |  | +    int cx, cy, level;
 | 
											
												
													
														|  | 
 |  | +    cardgo(27, cx, cy, level);
 | 
											
												
													
														|  | 
 |  | +    game_width = cx + 5; // card width
 | 
											
												
													
														|  | 
 |  | +  }
 | 
											
												
													
														|  | 
 |  | +  int off_x = (mx - game_width) / 2;
 | 
											
												
													
														|  | 
 |  | +  int off_y = (my - game_height) / 2;
 | 
											
												
													
														|  | 
 |  | +  int true_off_y = off_y;
 | 
											
												
													
														|  | 
 |  | +  // The idea is to see the cards with <<Something Unique to the card game>>,
 | 
											
												
													
														|  | 
 |  | +  // Year, Month, Day, and game (like 1 of 3).
 | 
											
												
													
														|  | 
 |  | +  // This will make the games the same/fair for everyone.
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +next_hand:
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  card_number = 28;
 | 
											
												
													
														|  | 
 |  | +  active_card = 23;
 | 
											
												
													
														|  | 
 |  | +  score = 0;
 | 
											
												
													
														|  | 
 |  | +  off_y = true_off_y;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  door::Panel spaceAceTriPeaks = make_tripeaks();
 | 
											
												
													
														|  | 
 |  | +  int tp_off_x = (mx - spaceAceTriPeaks.getWidth()) / 2;
 | 
											
												
													
														|  | 
 |  | +  spaceAceTriPeaks.set(tp_off_x, off_y);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  off_y += 3;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  // figure out what date we're playing / what game we're playing
 | 
											
												
													
														|  | 
 |  | +  time_t tt = std::chrono::system_clock::to_time_t(play_day);
 | 
											
												
													
														|  | 
 |  | +  tm local_tm = *localtime(&tt);
 | 
											
												
													
														|  | 
 |  | +  /*
 | 
											
												
													
														|  | 
 |  | +  std::cout << utc_tm.tm_year + 1900 << '-';
 | 
											
												
													
														|  | 
 |  | +  std::cout << utc_tm.tm_mon + 1 << '-';
 | 
											
												
													
														|  | 
 |  | +  std::cout << utc_tm.tm_mday << ' ';
 | 
											
												
													
														|  | 
 |  | +  std::cout << utc_tm.tm_hour << ':';
 | 
											
												
													
														|  | 
 |  | +  std::cout << utc_tm.tm_min << ':';
 | 
											
												
													
														|  | 
 |  | +  std::cout << utc_tm.tm_sec << '\n';
 | 
											
												
													
														|  | 
 |  | +  */
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  std::seed_seq s1{local_tm.tm_year + 1900, local_tm.tm_mon + 1,
 | 
											
												
													
														|  | 
 |  | +                   local_tm.tm_mday, hand};
 | 
											
												
													
														|  | 
 |  | +  cards deck1 = card_shuffle(s1, 1);
 | 
											
												
													
														|  | 
 |  | +  cards state = card_states();
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  door::Panel score_panel = make_score_panel(door);
 | 
											
												
													
														|  | 
 |  | +  door::Panel streak_panel = make_streak_panel();
 | 
											
												
													
														|  | 
 |  | +  door::Panel left_panel = make_left_panel();
 | 
											
												
													
														|  | 
 |  | +  door::Panel cmd_panel = make_command_panel();
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  {
 | 
											
												
													
														|  | 
 |  | +    int off_yp = off_y + 11;
 | 
											
												
													
														|  | 
 |  | +    int cxp, cyp, levelp;
 | 
											
												
													
														|  | 
 |  | +    int left_panel_x, right_panel_x;
 | 
											
												
													
														|  | 
 |  | +    // find position of card, to position the panels
 | 
											
												
													
														|  | 
 |  | +    cardgo(18, cxp, cyp, levelp);
 | 
											
												
													
														|  | 
 |  | +    left_panel_x = cxp;
 | 
											
												
													
														|  | 
 |  | +    cardgo(15, cxp, cyp, levelp);
 | 
											
												
													
														|  | 
 |  | +    right_panel_x = cxp;
 | 
											
												
													
														|  | 
 |  | +    score_panel.set(left_panel_x + off_x, off_yp);
 | 
											
												
													
														|  | 
 |  | +    streak_panel.set(right_panel_x + off_x, off_yp);
 | 
											
												
													
														|  | 
 |  | +    cmd_panel.set(left_panel_x + off_x, off_yp + 5);
 | 
											
												
													
														|  | 
 |  | +  }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  bool dealing = true;
 | 
											
												
													
														|  | 
 |  | +  int r = 0;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  while ((r >= 0) and (r != 'Q')) {
 | 
											
												
													
														|  | 
 |  | +    // REDRAW everything
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    door << door::reset << door::cls;
 | 
											
												
													
														|  | 
 |  | +    door << spaceAceTriPeaks;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    {
 | 
											
												
													
														|  | 
 |  | +      // step 1:
 | 
											
												
													
														|  | 
 |  | +      // draw the deck "source"
 | 
											
												
													
														|  | 
 |  | +      int cx, cy, level;
 | 
											
												
													
														|  | 
 |  | +      cardgo(29, cx, cy, level);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +      if (card_number == 51)
 | 
											
												
													
														|  | 
 |  | +        level = 0; // out of cards!
 | 
											
												
													
														|  | 
 |  | +      c = d.back(level);
 | 
											
												
													
														|  | 
 |  | +      c->set(cx + off_x, cy + off_y);
 | 
											
												
													
														|  | 
 |  | +      // p3 is heigh below
 | 
											
												
													
														|  | 
 |  | +      left_panel.set(cx + off_x, cy + off_y + height);
 | 
											
												
													
														|  | 
 |  | +      door << score_panel << left_panel << streak_panel << cmd_panel;
 | 
											
												
													
														|  | 
 |  | +      door << *c;
 | 
											
												
													
														|  | 
 |  | +      if (dealing)
 | 
											
												
													
														|  | 
 |  | +        std::this_thread::sleep_for(std::chrono::seconds(1));
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    // I tried setting the cursor before the delay and before displaying the
 | 
											
												
													
														|  | 
 |  | +    // card. It is very hard to see / just about useless.  Not worth the effort.
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    for (int x = 0; x < (dealing ? 28 : 29); x++) {
 | 
											
												
													
														|  | 
 |  | +      int cx, cy, level;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +      cardgo(x, cx, cy, level);
 | 
											
												
													
														|  | 
 |  | +      // This is hardly visible.
 | 
											
												
													
														|  | 
 |  | +      // door << door::Goto(cx + off_x - 1, cy + off_y + 1);
 | 
											
												
													
														|  | 
 |  | +      if (dealing)
 | 
											
												
													
														|  | 
 |  | +        std::this_thread::sleep_for(std::chrono::milliseconds(75));
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +      if (dealing) {
 | 
											
												
													
														|  | 
 |  | +        c = d.back(level);
 | 
											
												
													
														|  | 
 |  | +        c->set(cx + off_x, cy + off_y);
 | 
											
												
													
														|  | 
 |  | +        door << *c;
 | 
											
												
													
														|  | 
 |  | +      } else {
 | 
											
												
													
														|  | 
 |  | +        // redrawing -- draw the cards with their correct "state"
 | 
											
												
													
														|  | 
 |  | +        int s = state.at(x);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +        switch (s) {
 | 
											
												
													
														|  | 
 |  | +        case 0:
 | 
											
												
													
														|  | 
 |  | +          c = d.back(level);
 | 
											
												
													
														|  | 
 |  | +          c->set(cx + off_x, cy + off_y);
 | 
											
												
													
														|  | 
 |  | +          door << *c;
 | 
											
												
													
														|  | 
 |  | +          break;
 | 
											
												
													
														|  | 
 |  | +        case 1:
 | 
											
												
													
														|  | 
 |  | +          // cardgo(x, space, height, cx, cy, level);
 | 
											
												
													
														|  | 
 |  | +          if (x == 28)
 | 
											
												
													
														|  | 
 |  | +            c = d.card(deck1.at(card_number));
 | 
											
												
													
														|  | 
 |  | +          else
 | 
											
												
													
														|  | 
 |  | +            c = d.card(deck1.at(x));
 | 
											
												
													
														|  | 
 |  | +          c->set(cx + off_x, cy + off_y);
 | 
											
												
													
														|  | 
 |  | +          door << *c;
 | 
											
												
													
														|  | 
 |  | +          break;
 | 
											
												
													
														|  | 
 |  | +        case 2:
 | 
											
												
													
														|  | 
 |  | +          // no card to draw.  :)
 | 
											
												
													
														|  | 
 |  | +          break;
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  | 
 |  | +      }
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    if (dealing)
 | 
											
												
													
														|  | 
 |  | +      for (int x = 18; x < 29; x++) {
 | 
											
												
													
														|  | 
 |  | +        int cx, cy, level;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +        state.at(x) = 1;
 | 
											
												
													
														|  | 
 |  | +        cardgo(x, cx, cy, level);
 | 
											
												
													
														|  | 
 |  | +        // door << door::Goto(cx + off_x - 1, cy + off_y + 1);
 | 
											
												
													
														|  | 
 |  | +        std::this_thread::sleep_for(std::chrono::milliseconds(200));
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +        c = d.card(deck1.at(x));
 | 
											
												
													
														|  | 
 |  | +        c->set(cx + off_x, cy + off_y);
 | 
											
												
													
														|  | 
 |  | +        door << *c;
 | 
											
												
													
														|  | 
 |  | +      }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    {
 | 
											
												
													
														|  | 
 |  | +      int cx, cy, level;
 | 
											
												
													
														|  | 
 |  | +      cardgo(active_card, cx, cy, level);
 | 
											
												
													
														|  | 
 |  | +      c = d.marker(1);
 | 
											
												
													
														|  | 
 |  | +      c->set(cx + off_x + 2, cy + off_y + 2);
 | 
											
												
													
														|  | 
 |  | +      door << *c;
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    dealing = false;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    left_panel.update(door);
 | 
											
												
													
														|  | 
 |  | +    door << door::reset;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    bool now_what = true;
 | 
											
												
													
														|  | 
 |  | +    while (now_what) {
 | 
											
												
													
														|  | 
 |  | +      // time might have updated, so update score panel too.
 | 
											
												
													
														|  | 
 |  | +      score_panel.update(door);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +      r = door.sleep_key(door.inactivity);
 | 
											
												
													
														|  | 
 |  | +      if (r > 0) {
 | 
											
												
													
														|  | 
 |  | +        // They didn't timeout/expire.  They didn't press a function key.
 | 
											
												
													
														|  | 
 |  | +        if (r < 0x1000)
 | 
											
												
													
														|  | 
 |  | +          r = std::toupper(r);
 | 
											
												
													
														|  | 
 |  | +        switch (r) {
 | 
											
												
													
														|  | 
 |  | +        case '\x0d':
 | 
											
												
													
														|  | 
 |  | +          if (card_number < 51) {
 | 
											
												
													
														|  | 
 |  | +            card_number++;
 | 
											
												
													
														|  | 
 |  | +            current_streak = 0;
 | 
											
												
													
														|  | 
 |  | +            streak_panel.update(door);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +            // Ok, deal next card from the pile.
 | 
											
												
													
														|  | 
 |  | +            int cx, cy, level;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +            if (card_number == 51) {
 | 
											
												
													
														|  | 
 |  | +              cardgo(29, cx, cy, level);
 | 
											
												
													
														|  | 
 |  | +              level = 0; // out of cards
 | 
											
												
													
														|  | 
 |  | +              c = d.back(level);
 | 
											
												
													
														|  | 
 |  | +              c->set(cx + off_x, cy + off_y);
 | 
											
												
													
														|  | 
 |  | +              door << *c;
 | 
											
												
													
														|  | 
 |  | +            }
 | 
											
												
													
														|  | 
 |  | +            cardgo(28, cx, cy, level);
 | 
											
												
													
														|  | 
 |  | +            c = d.card(deck1.at(card_number));
 | 
											
												
													
														|  | 
 |  | +            c->set(cx + off_x, cy + off_y);
 | 
											
												
													
														|  | 
 |  | +            door << *c;
 | 
											
												
													
														|  | 
 |  | +            // update the cards left_panel
 | 
											
												
													
														|  | 
 |  | +            left_panel.update(door);
 | 
											
												
													
														|  | 
 |  | +          }
 | 
											
												
													
														|  | 
 |  | +          break;
 | 
											
												
													
														|  | 
 |  | +        case 'R':
 | 
											
												
													
														|  | 
 |  | +          now_what = false;
 | 
											
												
													
														|  | 
 |  | +          break;
 | 
											
												
													
														|  | 
 |  | +        case 'Q':
 | 
											
												
													
														|  | 
 |  | +          now_what = false;
 | 
											
												
													
														|  | 
 |  | +          break;
 | 
											
												
													
														|  | 
 |  | +        case ' ':
 | 
											
												
													
														|  | 
 |  | +        case '5':
 | 
											
												
													
														|  | 
 |  | +          // can we play this card?
 | 
											
												
													
														|  | 
 |  | +          /*
 | 
											
												
													
														|  | 
 |  | +          get_logger() << "can_play( " << active_card << ":"
 | 
											
												
													
														|  | 
 |  | +                       << deck1.at(active_card) << "/"
 | 
											
												
													
														|  | 
 |  | +                       << d.is_rank(deck1.at(active_card)) << " , "
 | 
											
												
													
														|  | 
 |  | +                       << card_number << "/" << d.is_rank(deck1.at(card_number))
 | 
											
												
													
														|  | 
 |  | +                       << ") = "
 | 
											
												
													
														|  | 
 |  | +                       << d.can_play(deck1.at(active_card),
 | 
											
												
													
														|  | 
 |  | +                                     deck1.at(card_number))
 | 
											
												
													
														|  | 
 |  | +                       << std::endl;
 | 
											
												
													
														|  | 
 |  | +                       */
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +          if (d.can_play(deck1.at(active_card), deck1.at(card_number))) {
 | 
											
												
													
														|  | 
 |  | +            // if (true) {
 | 
											
												
													
														|  | 
 |  | +            // yes we can.
 | 
											
												
													
														|  | 
 |  | +            ++current_streak;
 | 
											
												
													
														|  | 
 |  | +            if (current_streak > best_streak)
 | 
											
												
													
														|  | 
 |  | +              best_streak = current_streak;
 | 
											
												
													
														|  | 
 |  | +            streak_panel.update(door);
 | 
											
												
													
														|  | 
 |  | +            score += 10;
 | 
											
												
													
														|  | 
 |  | +            if (current_streak > 2)
 | 
											
												
													
														|  | 
 |  | +              score += 5;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +            // play card!
 | 
											
												
													
														|  | 
 |  | +            state.at(active_card) = 2;
 | 
											
												
													
														|  | 
 |  | +            {
 | 
											
												
													
														|  | 
 |  | +              // swap the active card with card_number (play card)
 | 
											
												
													
														|  | 
 |  | +              int temp = deck1.at(active_card);
 | 
											
												
													
														|  | 
 |  | +              deck1.at(active_card) = deck1.at(card_number);
 | 
											
												
													
														|  | 
 |  | +              deck1.at(card_number) = temp;
 | 
											
												
													
														|  | 
 |  | +              // active_card is -- invalidated here!  find "new" card.
 | 
											
												
													
														|  | 
 |  | +              int cx, cy, level;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +              // erase/clear active_card
 | 
											
												
													
														|  | 
 |  | +              std::vector<int> check = d.unblocks(active_card);
 | 
											
												
													
														|  | 
 |  | +              bool left = false, right = false;
 | 
											
												
													
														|  | 
 |  | +              for (const int c : check) {
 | 
											
												
													
														|  | 
 |  | +                std::pair<int, int> blockers = d.blocks[c];
 | 
											
												
													
														|  | 
 |  | +                if (blockers.first == active_card)
 | 
											
												
													
														|  | 
 |  | +                  right = true;
 | 
											
												
													
														|  | 
 |  | +                if (blockers.second == active_card)
 | 
											
												
													
														|  | 
 |  | +                  left = true;
 | 
											
												
													
														|  | 
 |  | +              }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +              d.remove_card(door, active_card, off_x, off_y, left, right);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +              /*   // old way of doing this that leaves holes.
 | 
											
												
													
														|  | 
 |  | +              cardgo(active_card, cx, cy, level);
 | 
											
												
													
														|  | 
 |  | +              c = d.back(0);
 | 
											
												
													
														|  | 
 |  | +              c->set(cx + off_x, cy + off_y);
 | 
											
												
													
														|  | 
 |  | +              door << *c;
 | 
											
												
													
														|  | 
 |  | +              */
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +              // redraw play card #28. (Which is the "old" active_card)
 | 
											
												
													
														|  | 
 |  | +              cardgo(28, cx, cy, level);
 | 
											
												
													
														|  | 
 |  | +              c = d.card(deck1.at(card_number));
 | 
											
												
													
														|  | 
 |  | +              c->set(cx + off_x, cy + off_y);
 | 
											
												
													
														|  | 
 |  | +              door << *c;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +              // Did we unhide a card here?
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +              // std::vector<int> check = d.unblocks(active_card);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +              /*
 | 
											
												
													
														|  | 
 |  | +              get_logger() << "active_card = " << active_card
 | 
											
												
													
														|  | 
 |  | +                           << " unblocks: " << check.size() << std::endl;
 | 
											
												
													
														|  | 
 |  | +              */
 | 
											
												
													
														|  | 
 |  | +              int new_card_shown = -1;
 | 
											
												
													
														|  | 
 |  | +              if (!check.empty()) {
 | 
											
												
													
														|  | 
 |  | +                for (const int to_check : check) {
 | 
											
												
													
														|  | 
 |  | +                  std::pair<int, int> blockers = d.blocks[to_check];
 | 
											
												
													
														|  | 
 |  | +                  /*
 | 
											
												
													
														|  | 
 |  | +                  get_logger()
 | 
											
												
													
														|  | 
 |  | +                      << "Check: " << to_check << " " << blockers.first << ","
 | 
											
												
													
														|  | 
 |  | +                      << blockers.second << " " << state.at(blockers.first)
 | 
											
												
													
														|  | 
 |  | +                      << "," << state.at(blockers.second) << std::endl;
 | 
											
												
													
														|  | 
 |  | +                      */
 | 
											
												
													
														|  | 
 |  | +                  if ((state.at(blockers.first) == 2) and
 | 
											
												
													
														|  | 
 |  | +                      (state.at(blockers.second) == 2)) {
 | 
											
												
													
														|  | 
 |  | +                    // WOOT!  Card uncovered.
 | 
											
												
													
														|  | 
 |  | +                    /*
 | 
											
												
													
														|  | 
 |  | +                    get_logger() << "showing: " << to_check << std::endl;
 | 
											
												
													
														|  | 
 |  | +                    */
 | 
											
												
													
														|  | 
 |  | +                    state.at(to_check) = 1;
 | 
											
												
													
														|  | 
 |  | +                    cardgo(to_check, cx, cy, level);
 | 
											
												
													
														|  | 
 |  | +                    c = d.card(deck1.at(to_check));
 | 
											
												
													
														|  | 
 |  | +                    c->set(cx + off_x, cy + off_y);
 | 
											
												
													
														|  | 
 |  | +                    door << *c;
 | 
											
												
													
														|  | 
 |  | +                    new_card_shown = to_check;
 | 
											
												
													
														|  | 
 |  | +                  }
 | 
											
												
													
														|  | 
 |  | +                }
 | 
											
												
													
														|  | 
 |  | +              } else {
 | 
											
												
													
														|  | 
 |  | +                // this would be a "top" card.  Should set status = 4 and
 | 
											
												
													
														|  | 
 |  | +                // display something here?
 | 
											
												
													
														|  | 
 |  | +                get_logger() << "top card cleared?" << std::endl;
 | 
											
												
													
														|  | 
 |  | +                // display something at active_card position
 | 
											
												
													
														|  | 
 |  | +                int cx, cy, level;
 | 
											
												
													
														|  | 
 |  | +                cardgo(active_card, cx, cy, level);
 | 
											
												
													
														|  | 
 |  | +                door << door::Goto(cx + off_x, cy + off_y) << door::reset
 | 
											
												
													
														|  | 
 |  | +                     << "BONUS";
 | 
											
												
													
														|  | 
 |  | +                score += 100;
 | 
											
												
													
														|  | 
 |  | +                state.at(active_card) = 3; // handle this in the "redraw"
 | 
											
												
													
														|  | 
 |  | +              }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +              // Find new "number" for active_card to be.
 | 
											
												
													
														|  | 
 |  | +              if (new_card_shown != -1) {
 | 
											
												
													
														|  | 
 |  | +                active_card = new_card_shown;
 | 
											
												
													
														|  | 
 |  | +              } else {
 | 
											
												
													
														|  | 
 |  | +                // active_card++;
 | 
											
												
													
														|  | 
 |  | +                int new_active = find_next_closest(state, active_card);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +                if (new_active != -1) {
 | 
											
												
													
														|  | 
 |  | +                  active_card = new_active;
 | 
											
												
													
														|  | 
 |  | +                } else {
 | 
											
												
													
														|  | 
 |  | +                  get_logger() << "This looks like END OF GAME." << std::endl;
 | 
											
												
													
														|  | 
 |  | +                  // bonus for cards left
 | 
											
												
													
														|  | 
 |  | +                  press_a_key(door);
 | 
											
												
													
														|  | 
 |  | +                  if (hand < total_hands) {
 | 
											
												
													
														|  | 
 |  | +                    hand++;
 | 
											
												
													
														|  | 
 |  | +                    door << door::reset << door::cls;
 | 
											
												
													
														|  | 
 |  | +                    goto next_hand;
 | 
											
												
													
														|  | 
 |  | +                  }
 | 
											
												
													
														|  | 
 |  | +                  r = 'Q';
 | 
											
												
													
														|  | 
 |  | +                  now_what = false;
 | 
											
												
													
														|  | 
 |  | +                }
 | 
											
												
													
														|  | 
 |  | +              }
 | 
											
												
													
														|  | 
 |  | +              // update the active_card marker!
 | 
											
												
													
														|  | 
 |  | +              cardgo(active_card, cx, cy, level);
 | 
											
												
													
														|  | 
 |  | +              c = d.marker(1);
 | 
											
												
													
														|  | 
 |  | +              c->set(cx + off_x + 2, cy + off_y + 2);
 | 
											
												
													
														|  | 
 |  | +              door << *c;
 | 
											
												
													
														|  | 
 |  | +            }
 | 
											
												
													
														|  | 
 |  | +          }
 | 
											
												
													
														|  | 
 |  | +          break;
 | 
											
												
													
														|  | 
 |  | +        case XKEY_LEFT_ARROW:
 | 
											
												
													
														|  | 
 |  | +        case '4': {
 | 
											
												
													
														|  | 
 |  | +          int new_active = find_next(true, state, active_card);
 | 
											
												
													
														|  | 
 |  | +          /*
 | 
											
												
													
														|  | 
 |  | +          int new_active = active_card - 1;
 | 
											
												
													
														|  | 
 |  | +          while (new_active >= 0) {
 | 
											
												
													
														|  | 
 |  | +            if (state.at(new_active) == 1)
 | 
											
												
													
														|  | 
 |  | +              break;
 | 
											
												
													
														|  | 
 |  | +            --new_active;
 | 
											
												
													
														|  | 
 |  | +          }*/
 | 
											
												
													
														|  | 
 |  | +          if (new_active >= 0) {
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +            int cx, cy, level;
 | 
											
												
													
														|  | 
 |  | +            cardgo(active_card, cx, cy, level);
 | 
											
												
													
														|  | 
 |  | +            c = d.marker(0);
 | 
											
												
													
														|  | 
 |  | +            c->set(cx + off_x + 2, cy + off_y + 2);
 | 
											
												
													
														|  | 
 |  | +            door << *c;
 | 
											
												
													
														|  | 
 |  | +            active_card = new_active;
 | 
											
												
													
														|  | 
 |  | +            cardgo(active_card, cx, cy, level);
 | 
											
												
													
														|  | 
 |  | +            c = d.marker(1);
 | 
											
												
													
														|  | 
 |  | +            c->set(cx + off_x + 2, cy + off_y + 2);
 | 
											
												
													
														|  | 
 |  | +            door << *c;
 | 
											
												
													
														|  | 
 |  | +          }
 | 
											
												
													
														|  | 
 |  | +        } break;
 | 
											
												
													
														|  | 
 |  | +        case XKEY_RIGHT_ARROW:
 | 
											
												
													
														|  | 
 |  | +        case '6': {
 | 
											
												
													
														|  | 
 |  | +          int new_active = find_next(false, state, active_card);
 | 
											
												
													
														|  | 
 |  | +          /*
 | 
											
												
													
														|  | 
 |  | +          int new_active = active_card + 1;
 | 
											
												
													
														|  | 
 |  | +          while (new_active < 28) {
 | 
											
												
													
														|  | 
 |  | +            if (state.at(new_active) == 1)
 | 
											
												
													
														|  | 
 |  | +              break;
 | 
											
												
													
														|  | 
 |  | +            ++new_active;
 | 
											
												
													
														|  | 
 |  | +          }
 | 
											
												
													
														|  | 
 |  | +          */
 | 
											
												
													
														|  | 
 |  | +          if (new_active >= 0) { //(new_active < 28) {
 | 
											
												
													
														|  | 
 |  | +            int cx, cy, level;
 | 
											
												
													
														|  | 
 |  | +            cardgo(active_card, cx, cy, level);
 | 
											
												
													
														|  | 
 |  | +            c = d.marker(0);
 | 
											
												
													
														|  | 
 |  | +            c->set(cx + off_x + 2, cy + off_y + 2);
 | 
											
												
													
														|  | 
 |  | +            door << *c;
 | 
											
												
													
														|  | 
 |  | +            active_card = new_active;
 | 
											
												
													
														|  | 
 |  | +            cardgo(active_card, cx, cy, level);
 | 
											
												
													
														|  | 
 |  | +            c = d.marker(1);
 | 
											
												
													
														|  | 
 |  | +            c->set(cx + off_x + 2, cy + off_y + 2);
 | 
											
												
													
														|  | 
 |  | +            door << *c;
 | 
											
												
													
														|  | 
 |  | +          }
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +        break;
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  | 
 |  | +      } else
 | 
											
												
													
														|  | 
 |  | +        now_what = false;
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +  }
 | 
											
												
													
														|  | 
 |  | +  if (r == 'Q') {
 | 
											
												
													
														|  | 
 |  | +    // continue with hand or quit?
 | 
											
												
													
														|  | 
 |  | +    if (hand < total_hands) {
 | 
											
												
													
														|  | 
 |  | +      press_a_key(door);
 | 
											
												
													
														|  | 
 |  | +      hand++;
 | 
											
												
													
														|  | 
 |  | +      door << door::reset << door::cls;
 | 
											
												
													
														|  | 
 |  | +      goto next_hand;
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +  }
 | 
											
												
													
														|  | 
 |  | +  return r;
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +#endif
 |