|
@@ -28,8 +28,7 @@ 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} {
|
|
|
+PlayCards::PlayCards(door::Door &d, DBData &dbd) : door{d}, db{dbd} {
|
|
|
get_logger = [this]() -> ofstream & { return door.log(); };
|
|
|
init_values();
|
|
|
|
|
@@ -846,440 +845,3 @@ std::unique_ptr<door::Panel> PlayCards::make_tripeaks(void) {
|
|
|
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
|