| * version and copyright | |||||
| * messages implemented on the player's side | |||||
| * arranged shoes | |||||
| * handle no readline | |||||
| * to_string() para floats | |||||
| * max_splits through conf (default 3) | |||||
| * DAS | |||||
| * shoes (and arranged shoes) | |||||
| * name of the game the dealer deals | * name of the game the dealer deals | ||||
| * name of the games the player can play | * name of the games the player can play | ||||
| * delays? | |||||
| * dealers | * dealers | ||||
| * ENHC | * ENHC | ||||
| * blackjack switch | * blackjack switch | ||||
| * multithreading | * multithreading | ||||
| * use of const and restrict | * use of const and restrict | ||||
| # flat_bet = 1 | |||||
| # max_bet = 2 | |||||
| arranged_cards = 9,8,13,12 | |||||
| delay = 0 | |||||
| ; flat_bet = 1 | |||||
| ; arranged_cards = 3,8,3,13,4,13,11,7 | |||||
| ; delay = 0 | |||||
| PlayerBlackjack, | PlayerBlackjack, | ||||
| PlayerWins, | PlayerWins, | ||||
| NoBlackjacks, | NoBlackjacks, | ||||
| PlayerBustsAllHands, | |||||
| // PlayerBustsAllHands, | |||||
| DealerBusts, | DealerBusts, | ||||
| Help, | Help, | ||||
| Bye, | Bye, | ||||
| Spades = 3 | Spades = 3 | ||||
| }; | }; | ||||
| enum class Color { | |||||
| Black, | |||||
| Red | |||||
| }; | |||||
| class Card { | class Card { | ||||
| public: | public: | ||||
| class Hand { | class Hand { | ||||
| public: | public: | ||||
| std::list<int> cards; | |||||
| std::list<unsigned int> cards; | |||||
| // inline on purpose | // inline on purpose | ||||
| int total() { | int total() { | ||||
| Player(const Player &&) = delete; | Player(const Player &&) = delete; | ||||
| virtual int play() = 0; | virtual int play() = 0; | ||||
| virtual void info(Info = Info::None, int = 0) = 0; | |||||
| virtual void info(Info = Info::None, int = 0, int = 0) = 0; | |||||
| PlayerActionRequired actionRequired = PlayerActionRequired::None; | PlayerActionRequired actionRequired = PlayerActionRequired::None; | ||||
| PlayerActionTaken actionTaken = PlayerActionTaken::None; | PlayerActionTaken actionTaken = PlayerActionTaken::None; |
| } | } | ||||
| player->info(Info::NewHand, player->bankroll); | |||||
| player->info(Info::NewHand, n_hand, 1e3*player->bankroll); | |||||
| return; | return; | ||||
| break; | break; | ||||
| // step 6. deal the dealer's hole card | // step 6. deal the dealer's hole card | ||||
| holeCard = drawCard(&hand); | holeCard = drawCard(&hand); | ||||
| player->info(Info::CardDealer, -1); | |||||
| player->info(Info::CardDealer); | |||||
| // step 7.a. if the upcard is an ace ask for insurance | // step 7.a. if the upcard is an ace ask for insurance | ||||
| if (card[upCard].value == 11) { | if (card[upCard].value == 11) { | ||||
| player->blackjacksDealer++; | player->blackjacksDealer++; | ||||
| if (player->currentHand->insured) { | if (player->currentHand->insured) { | ||||
| player->info(Info::PlayerWinsInsurance, player->currentHand->bet); | |||||
| player->info(Info::PlayerWinsInsurance, 1e3*player->currentHand->bet); | |||||
| player->current_result += player->currentHand->bet; | player->current_result += player->currentHand->bet; | ||||
| player->bankroll += player->currentHand->bet; | player->bankroll += player->currentHand->bet; | ||||
| player->winsInsured++; | player->winsInsured++; | ||||
| if (playerBlackack) { | if (playerBlackack) { | ||||
| player->info(Info::PlayerBlackjackAlso); | player->info(Info::PlayerBlackjackAlso); | ||||
| player->info(Info::PlayerPushes); | |||||
| player->info(Info::PlayerPushes, 1e3*player->currentHand->bet); | |||||
| player->blackjacksPlayer++; | player->blackjacksPlayer++; | ||||
| player->pushes++; | player->pushes++; | ||||
| } else { | } else { | ||||
| player->info(Info::PlayerLosses); | |||||
| player->info(Info::PlayerLosses, 1e3*player->currentHand->bet); | |||||
| player->current_result -= player->currentHand->bet; | player->current_result -= player->currentHand->bet; | ||||
| player->bankroll -= player->currentHand->bet; | player->bankroll -= player->currentHand->bet; | ||||
| if (player->bankroll < player->worst_bankroll) { | if (player->bankroll < player->worst_bankroll) { | ||||
| player->bankroll += blackjack_pays * player->currentHand->bet; | player->bankroll += blackjack_pays * player->currentHand->bet; | ||||
| player->blackjacksPlayer++; | player->blackjacksPlayer++; | ||||
| player->info(Info::PlayerWins, blackjack_pays * player->currentHand->bet); | |||||
| player->info(Info::PlayerWins, 1e3 * blackjack_pays*player->currentHand->bet); | |||||
| player->wins++; | player->wins++; | ||||
| player->winsBlackjack++; | player->winsBlackjack++; | ||||
| } | } | ||||
| if (player->bustedAllHands) { | if (player->bustedAllHands) { | ||||
| player->info(Info::PlayerBustsAllHands); | |||||
| player->info(Info::CardDealerRevealsHole, holeCard); | player->info(Info::CardDealerRevealsHole, holeCard); | ||||
| // TODO: no tengo que sacarle todo el dinero? | |||||
| player->actionRequired = PlayerActionRequired::None; | player->actionRequired = PlayerActionRequired::None; | ||||
| nextAction = DealerAction::StartNewHand; | nextAction = DealerAction::StartNewHand; | ||||
| player->info(Info::CardDealerRevealsHole, holeCard); | player->info(Info::CardDealerRevealsHole, holeCard); | ||||
| // hit if count is less than 17 (or equalt to soft 17 if hit_soft_17 is true) | |||||
| // hit while count is less than 17 (or equal to soft 17 if hit_soft_17 is true) | |||||
| dealerTotal = hand.total(); | dealerTotal = hand.total(); | ||||
| while ((std::abs(dealerTotal) < 17 || (hit_soft_17 && dealerTotal == -17)) && hand.busted() == 0) { | while ((std::abs(dealerTotal) < 17 || (hit_soft_17 && dealerTotal == -17)) && hand.busted() == 0) { | ||||
| unsigned int dealerCard = drawCard(&hand); | unsigned int dealerCard = drawCard(&hand); | ||||
| player->info(Info::CardDealer, dealerCard); | player->info(Info::CardDealer, dealerCard); | ||||
| dealerTotal = hand.total(); | |||||
| } | |||||
| dealerTotal = std::abs(hand.total()); | |||||
| if (hand.busted()) { | |||||
| player->info(Info::DealerBusts); | |||||
| player->bustsDealer++; | |||||
| for (auto playerHand : player->hands) { | |||||
| if (playerHand.busted() == false) { | |||||
| player->info(Info::PlayerWins, playerHand.bet); | |||||
| if (hand.busted()) { | |||||
| player->info(Info::DealerBusts, dealerTotal); | |||||
| player->bustsDealer++; | |||||
| for (auto playerHand : player->hands) { | |||||
| if (playerHand.busted() == false) { | |||||
| player->info(Info::PlayerWins, 1e3*playerHand.bet); | |||||
| player->current_result += playerHand.bet; | |||||
| player->bankroll += playerHand.bet; | |||||
| player->wins++; | |||||
| player->winsDoubled += playerHand.doubled; | |||||
| } | |||||
| } | |||||
| } else { | |||||
| for (auto playerHand : player->hands) { | |||||
| if (playerHand.busted() == false) { // busted hands have already been solved | |||||
| playerTotal = std::abs(playerHand.total()); | |||||
| if (dealerTotal > playerTotal) { | |||||
| player->info(Info::PlayerLosses, 1e3*playerHand.bet, playerTotal); | |||||
| player->bankroll -= playerHand.bet; | |||||
| if (player->bankroll < player->worst_bankroll) { | |||||
| player->worst_bankroll = player->bankroll; | |||||
| } | |||||
| player->losses++; | |||||
| } else if (dealerTotal == playerTotal) { | |||||
| player->info(Info::PlayerPushes, 1e3*playerHand.bet); | |||||
| player->pushes++; | |||||
| } else { | |||||
| player->info(Info::PlayerWins, 1e3*playerHand.bet, playerTotal); | |||||
| player->current_result += playerHand.bet; | player->current_result += playerHand.bet; | ||||
| player->bankroll += playerHand.bet; | player->bankroll += playerHand.bet; | ||||
| player->wins++; | player->wins++; | ||||
| if (playerHand.doubled) { | if (playerHand.doubled) { | ||||
| player->winsDoubled++; | player->winsDoubled++; | ||||
| } else { | } else { | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } else { | |||||
| for (auto playerHand : player->hands) { | |||||
| if (playerHand.busted() == false) { // busted hands have already been solved | |||||
| playerTotal = std::abs(playerHand.total()); | |||||
| if (dealerTotal > playerTotal) { | |||||
| player->info(Info::PlayerLosses, playerHand.bet); | |||||
| player->bankroll -= playerHand.bet; | |||||
| if (player->bankroll < player->worst_bankroll) { | |||||
| player->worst_bankroll = player->bankroll; | |||||
| } | |||||
| player->losses++; | |||||
| } else if (dealerTotal == playerTotal) { | |||||
| player->info(Info::PlayerPushes, playerHand.bet); | |||||
| player->pushes++; | |||||
| } else { | |||||
| player->info(Info::PlayerWins, playerHand.bet); | |||||
| player->current_result += playerHand.bet; | |||||
| player->bankroll += playerHand.bet; | |||||
| player->wins++; | |||||
| if (playerHand.doubled) { | |||||
| player->winsDoubled++; | |||||
| } else { | |||||
| player->wins++; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| switch (player->actionTaken) { | switch (player->actionTaken) { | ||||
| // TODO: maybe we have to call a basic method with common commands? | |||||
| // we first check common commands | // we first check common commands | ||||
| ///ig+quit+name quit | ///ig+quit+name quit | ||||
| ///ig+quit+desc Finish the game | ///ig+quit+desc Finish the game | ||||
| player->info(Info::Help); | player->info(Info::Help); | ||||
| return 0; | return 0; | ||||
| break; | break; | ||||
| case PlayerActionTaken::Count: | |||||
| std::cout << "count " << (*player->currentHand).total() <<std::endl; | |||||
| return 0; | |||||
| break; | |||||
| case PlayerActionTaken::UpcardValue: | |||||
| std::cout << "upcard " << card[upCard].utf8() <<std::endl; | |||||
| return 0; | |||||
| break; | |||||
| case PlayerActionTaken::Bankroll: | |||||
| std::cout << "bankroll " << player->bankroll <<std::endl; | |||||
| return 0; | |||||
| break; | |||||
| case PlayerActionTaken::None: | case PlayerActionTaken::None: | ||||
| return 0; | return 0; | ||||
| break; | break; | ||||
| ///ip+double+detail This command can be abbreviated as `d`. | ///ip+double+detail This command can be abbreviated as `d`. | ||||
| case PlayerActionTaken::Double: | case PlayerActionTaken::Double: | ||||
| if (player->currentHand->cards.size() == 2) { | if (player->currentHand->cards.size() == 2) { | ||||
| std::cout << "double_down" << std::endl; | |||||
| // TODO: check bankroll | // TODO: check bankroll | ||||
| player->total_money_waged += player->currentHand->bet; | |||||
| player->total_money_waged += player->currentHand->bet; | |||||
| player->currentHand->bet *= 2; | player->currentHand->bet *= 2; | ||||
| player->currentHand->doubled = true; | |||||
| player->currentHand->doubled = true; | |||||
| player->handsDoubled++; | player->handsDoubled++; | ||||
| playerCard = drawCard(&(*player->currentHand)); | playerCard = drawCard(&(*player->currentHand)); | ||||
| unsigned int playerTotal = player->currentHand->total(); | unsigned int playerTotal = player->currentHand->total(); | ||||
| std::cout << "card_player" << card[playerCard].utf8() << std::endl; | |||||
| std::cout << "player_total " << playerTotal << std::endl; | |||||
| player->info(Info::CardPlayer, playerCard); | |||||
| if (player->currentHand->busted()) { | if (player->currentHand->busted()) { | ||||
| std::cout << "player_busted" << std::endl; | |||||
| player->info(Info::PlayerLosses, 1e3*player->currentHand->bet, playerTotal); | |||||
| player->current_result -= player->currentHand->bet; | player->current_result -= player->currentHand->bet; | ||||
| player->bankroll -= player->currentHand->bet; | player->bankroll -= player->currentHand->bet; | ||||
| player->bustsPlayer++; | player->bustsPlayer++; | ||||
| secondCard = *(++player->currentHand->cards.begin()); | secondCard = *(++player->currentHand->cards.begin()); | ||||
| // up to three splits (i.e. four hands) | // up to three splits (i.e. four hands) | ||||
| // TODO: choose | |||||
| if (player->currentSplits < 3 && player->currentHand->cards.size() == 2 && | |||||
| card[firstCard].value == card[secondCard].value) { | |||||
| // TODO: choose through conf | |||||
| // TODO: check bankroll to see if player can split | |||||
| if (player->currentSplits < 3 && player->currentHand->cards.size() == 2 && card[firstCard].value == card[secondCard].value) { | |||||
| // mark that we split to put ids in the hands and to limi the number of spltis | // mark that we split to put ids in the hands and to limi the number of spltis | ||||
| player->currentSplits++; | player->currentSplits++; | ||||
| // create a new hand | // create a new hand | ||||
| PlayerHand newHand; | PlayerHand newHand; | ||||
| newHand.id = player->currentHand->id + 1; | newHand.id = player->currentHand->id + 1; | ||||
| // TODO: check bankroll | |||||
| newHand.bet = player->currentHand->bet; | newHand.bet = player->currentHand->bet; | ||||
| player->total_money_waged += player->currentHand->bet; | player->total_money_waged += player->currentHand->bet; | ||||
| ///ip+hit+detail | ///ip+hit+detail | ||||
| ///ip+hit+detail This command can be abbreviated as `h`. | ///ip+hit+detail This command can be abbreviated as `h`. | ||||
| playerCard = drawCard(&(*player->currentHand)); | playerCard = drawCard(&(*player->currentHand)); | ||||
| std::cout << "card_player " << card[playerCard].utf8() << std::endl; | |||||
| player->info(Info::CardPlayer, playerCard); | |||||
| if (player->currentHand->busted()) { | if (player->currentHand->busted()) { | ||||
| std::cout << "busted_player " << player->currentHand->total() << std::endl; | |||||
| player->info(Info::PlayerLosses, 1e3*player->currentHand->bet); | |||||
| player->current_result -= player->currentHand->bet; | player->current_result -= player->currentHand->bet; | ||||
| player->bankroll -= player->currentHand->bet; | player->bankroll -= player->currentHand->bet; | ||||
| player->bustsPlayer++; | player->bustsPlayer++; |
| while (!dealer->finished()) { | while (!dealer->finished()) { | ||||
| dealer->deal(player); | dealer->deal(player); | ||||
| if (player->actionRequired != PlayerActionRequired::None) { | if (player->actionRequired != PlayerActionRequired::None) { | ||||
| unknownCommands = 0; | |||||
| do { | do { | ||||
| if (unknownCommands++ > conf.max_incorrect_commands) { | if (unknownCommands++ > conf.max_incorrect_commands) { | ||||
| std::cerr << "Too many unknown commands." << std::endl; | std::cerr << "Too many unknown commands." << std::endl; |
| StdInOut::StdInOut(void) { | StdInOut::StdInOut(void) { | ||||
| } | } | ||||
| void StdInOut::info(Info msg, int data) { | |||||
| void StdInOut::info(Info msg, int p1, int p2) { | |||||
| return; | return; | ||||
| } | } | ||||
| ~StdInOut() { }; | ~StdInOut() { }; | ||||
| int play(void) override; | int play(void) override; | ||||
| void info(Info = Info::None, int = 0) override; | |||||
| void info(Info = Info::None, int = 0, int = 0) override; | |||||
| private: | private: | ||||
| std::string input_buffer; | std::string input_buffer; |
| return; | return; | ||||
| } | } | ||||
| void Tty::info(Info msg, int p) { | |||||
| void Tty::info(Info msg, int p1, int p2) { | |||||
| std::string s; | std::string s; | ||||
| bool render = false; | |||||
| // TODO: choose utf8 or other representation | // TODO: choose utf8 or other representation | ||||
| switch (msg) { | switch (msg) { | ||||
| case Info::InvalidBet: | case Info::InvalidBet: | ||||
| if (p < 0) { | |||||
| if (p1 < 0) { | |||||
| // s = "bet_negative"; | // s = "bet_negative"; | ||||
| s = "Your bet is negative (" + std::to_string(p) + ")"; | |||||
| } else if (p > 0) { | |||||
| s = "Your bet is negative (" + std::to_string(p1) + ")"; | |||||
| } else if (p1 > 0) { | |||||
| // s = "bet_maximum"; | // s = "bet_maximum"; | ||||
| s = "Your bet is larger than the maximum allowed (" + std::to_string(p) + ")"; | |||||
| s = "Your bet is larger than the maximum allowed (" + std::to_string(p1) + ")"; | |||||
| } else { | } else { | ||||
| // s = "bet_zero"; | // s = "bet_zero"; | ||||
| s = "Your bet is zero"; | s = "Your bet is zero"; | ||||
| case Info::NewHand: | case Info::NewHand: | ||||
| // s = "new_hand"; | // s = "new_hand"; | ||||
| std::cout << std::endl; | std::cout << std::endl; | ||||
| s = "Starting new hand, bankroll " + std::to_string(p); | |||||
| s = "Starting new hand #" + std::to_string(p1) + " with bankroll " + std::to_string(1e-3*p2); | |||||
| dealerHand.cards.clear(); | dealerHand.cards.clear(); | ||||
| break; | break; | ||||
| case Info::Shuffle: | case Info::Shuffle: | ||||
| // TODO: ask the user to cut | |||||
| // s = "shuffle"; | // s = "shuffle"; | ||||
| s = "Deck needs to be shuffled."; | s = "Deck needs to be shuffled."; | ||||
| break; | break; | ||||
| switch (currentHand->cards.size()) { | switch (currentHand->cards.size()) { | ||||
| case 1: | case 1: | ||||
| // s = "card_player_first"; | // s = "card_player_first"; | ||||
| s = "Player's first card is " + card[p].utf8(); | |||||
| s = "Player's first card is " + card[p1].utf8(); | |||||
| break; | break; | ||||
| case 2: | case 2: | ||||
| // s = "card_player_second"; | // s = "card_player_second"; | ||||
| s = "Player's second card is " + card[p].utf8(); | |||||
| s = "Player's second card is " + card[p1].utf8(); | |||||
| break; | break; | ||||
| default: | default: | ||||
| // s = "card_player"; | // s = "card_player"; | ||||
| s = "Player's card is " + card[p].utf8(); | |||||
| s = "Player's card is " + card[p1].utf8(); | |||||
| break; | break; | ||||
| } | } | ||||
| break; | break; | ||||
| case Info::CardDealer: | case Info::CardDealer: | ||||
| if (p != -1) { | |||||
| if (p1 > 0) { | |||||
| switch (dealerHand.cards.size()) { | switch (dealerHand.cards.size()) { | ||||
| case 0: | case 0: | ||||
| // s = "card_dealer_up"; | // s = "card_dealer_up"; | ||||
| s = "Dealer's up card is " + card[p].utf8(); | |||||
| s = "Dealer's up card is " + card[p1].utf8(); | |||||
| break; | break; | ||||
| default: | default: | ||||
| // s = "card_dealer"; | // s = "card_dealer"; | ||||
| s = "Dealer's card is " + card[p].utf8(); | |||||
| s = "Dealer's card is " + card[p1].utf8(); | |||||
| break; | break; | ||||
| } | } | ||||
| } else { | } else { | ||||
| s = "Dealer's hole card is dealt"; | s = "Dealer's hole card is dealt"; | ||||
| } | } | ||||
| dealerHand.cards.push_back(p); | |||||
| dealerHand.cards.push_back(p1); | |||||
| break; | break; | ||||
| case Info::CardDealerRevealsHole: | case Info::CardDealerRevealsHole: | ||||
| // s = "card_dealer_hole"; | // s = "card_dealer_hole"; | ||||
| s = "Dealer's hole card was " + card[p].utf8(); | |||||
| *(++(dealerHand.cards.begin())) = p; | |||||
| // renderTable(); | |||||
| s = "Dealer's hole card was " + card[p1].utf8(); | |||||
| *(++(dealerHand.cards.begin())) = p1; | |||||
| break; | break; | ||||
| case Info::DealerBlackjack: | case Info::DealerBlackjack: | ||||
| case Info::PlayerBlackjackAlso: | case Info::PlayerBlackjackAlso: | ||||
| // s = "player_blackjack_also"; | // s = "player_blackjack_also"; | ||||
| s = "Player also has Blackjack"; | s = "Player also has Blackjack"; | ||||
| renderTable(); | |||||
| render = true; | |||||
| break; | break; | ||||
| case Info::PlayerNextHand: | case Info::PlayerNextHand: | ||||
| // s = "player_pushes"; | |||||
| s = "Playing next hand #" + std::to_string(p); | |||||
| renderTable(); | |||||
| // s = "player_next_hand"; | |||||
| s = "Playing next hand #" + std::to_string(p1); | |||||
| render = true; | |||||
| break; | break; | ||||
| case Info::PlayerPushes: | case Info::PlayerPushes: | ||||
| // s = "player_pushes"; | // s = "player_pushes"; | ||||
| s = "Player pushes"; | |||||
| renderTable(); | |||||
| s = "Player pushes " + std::to_string(1e-3*p1) + ((p2 > 0) ? (" with " + std::to_string(p2)) : ""); | |||||
| render = true; | |||||
| break; | break; | ||||
| case Info::PlayerLosses: | case Info::PlayerLosses: | ||||
| // s = "player_losses"; | // s = "player_losses"; | ||||
| s = "Player losses"; | |||||
| renderTable(); | |||||
| s = "Player losses " + std::to_string(1e-3*p1) + ((p2 > 0) ? (" with " + std::to_string(p2)) : ""); | |||||
| render = true; | |||||
| break; | break; | ||||
| case Info::PlayerBlackjack: | case Info::PlayerBlackjack: | ||||
| // s = "blackjack_player"; | // s = "blackjack_player"; | ||||
| s = "Player has Blackjack"; | s = "Player has Blackjack"; | ||||
| renderTable(); | |||||
| render = true; | |||||
| break; | break; | ||||
| case Info::PlayerWins: | case Info::PlayerWins: | ||||
| // s = "player_wins"; | // s = "player_wins"; | ||||
| s = "Player wins " + std::to_string(p); | |||||
| renderTable(); | |||||
| s = "Player wins " + std::to_string(1e-3*p1) + ((p2 > 0) ? (" with " + std::to_string(p2)) : ""); | |||||
| render = true; | |||||
| break; | break; | ||||
| case Info::NoBlackjacks: | case Info::NoBlackjacks: | ||||
| // s = "no_blackjacks"; | // s = "no_blackjacks"; | ||||
| s = "No blackjacks"; | s = "No blackjacks"; | ||||
| break; | break; | ||||
| /* | |||||
| case Info::PlayerBustsAllHands: | case Info::PlayerBustsAllHands: | ||||
| // s = "player_busted_all_hands"; | // s = "player_busted_all_hands"; | ||||
| if (hands.size() == 1) { | if (hands.size() == 1) { | ||||
| } | } | ||||
| renderTable(); | renderTable(); | ||||
| break; | break; | ||||
| */ | |||||
| case Info::DealerBusts: | case Info::DealerBusts: | ||||
| // s = "no_blackjacks"; | // s = "no_blackjacks"; | ||||
| s = "Dealer busts!"; | |||||
| renderTable(); | |||||
| s = "Dealer busts with " + std::to_string(p1); | |||||
| break; | break; | ||||
| case Info::Help: | case Info::Help: | ||||
| std::this_thread::sleep_for(std::chrono::milliseconds(delay)); | std::this_thread::sleep_for(std::chrono::milliseconds(delay)); | ||||
| } | } | ||||
| std::cout << green << s << reset << std::endl; | std::cout << green << s << reset << std::endl; | ||||
| if (render) { | |||||
| renderTable(); | |||||
| } | |||||
| return; | return; | ||||
| } | } | ||||
| // TODO: better solution | // TODO: better solution | ||||
| std::string command = input_buffer; | std::string command = input_buffer; | ||||
| free(input_buffer); | |||||
| trim(command); | trim(command); | ||||
| switch (actionRequired) { | switch (actionRequired) { | ||||
| case PlayerActionRequired::Bet: | case PlayerActionRequired::Bet: | ||||
| currentBet = std::stoi(input_buffer); | |||||
| currentBet = std::stoi(command); | |||||
| actionTaken = PlayerActionTaken::Bet; | actionTaken = PlayerActionTaken::Bet; | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| free(input_buffer); | |||||
| } | } | ||||
| #else | #else | ||||
| void Tty::renderHand(Hand *hand) { | void Tty::renderHand(Hand *hand) { | ||||
| std::string ansiColor; | |||||
| std::string ansiReset; | |||||
| for (unsigned int i = 0; i < hand->cards.size(); i++) { | for (unsigned int i = 0; i < hand->cards.size(); i++) { | ||||
| std::cout << " _____ "; | std::cout << " _____ "; | ||||
| } | } | ||||
| std::cout << std::endl; | std::cout << std::endl; | ||||
| unsigned int i = 0; | |||||
| for (auto it : hand->cards) { | |||||
| if (it >= 0) { | |||||
| std::cout << "|" << card[it].getNumberASCII() << ((card[it].number != 10)?" ":"") << " | "; | |||||
| for (auto c : hand->cards) { | |||||
| if (color && (card[c].suit == Suit::Diamonds || card[c].suit == Suit::Hearts)) { | |||||
| ansiColor = red; | |||||
| ansiReset = reset; | |||||
| } else { | |||||
| ansiColor = ""; | |||||
| ansiReset = ""; | |||||
| } | |||||
| if (c > 0) { | |||||
| std::cout << "|" << ansiColor << card[c].getNumberASCII() << ((card[c].number != 10)?" ":"") << ansiReset << " | "; | |||||
| } else { | } else { | ||||
| std::cout << "|#####| "; | std::cout << "|#####| "; | ||||
| } | } | ||||
| i++; | |||||
| } | } | ||||
| std::cout << std::endl; | std::cout << std::endl; | ||||
| i = 0; | |||||
| for (auto it : hand->cards) { | |||||
| if (it >= 0) { | |||||
| for (auto c : hand->cards) { | |||||
| if (c > 0) { | |||||
| std::cout << "| | "; | std::cout << "| | "; | ||||
| } else { | } else { | ||||
| std::cout << "|#####| "; | std::cout << "|#####| "; | ||||
| } | } | ||||
| i++; | |||||
| } | } | ||||
| std::cout << std::endl; | std::cout << std::endl; | ||||
| i = 0; | |||||
| for (auto it : hand->cards) { | |||||
| if (it >= 0) { | |||||
| std::cout << "| " << card[it].getSuitUTF8() << " | "; | |||||
| for (auto c : hand->cards) { | |||||
| if (color && (card[c].suit == Suit::Diamonds || card[c].suit == Suit::Hearts)) { | |||||
| ansiColor = red; | |||||
| ansiReset = reset; | |||||
| } else { | |||||
| ansiColor = ""; | |||||
| ansiReset = ""; | |||||
| } | |||||
| if (c > 0) { | |||||
| std::cout << "| " << ansiColor << card[c].getSuitUTF8() << ansiReset << " | "; | |||||
| } else { | } else { | ||||
| std::cout << "|#####| "; | std::cout << "|#####| "; | ||||
| } | } | ||||
| i++; | |||||
| } | } | ||||
| std::cout << std::endl; | std::cout << std::endl; | ||||
| i = 0; | |||||
| for (auto it : hand->cards) { | |||||
| if (it >= 0) { | |||||
| for (auto c : hand->cards) { | |||||
| if (c > 0) { | |||||
| std::cout << "| | "; | std::cout << "| | "; | ||||
| } else { | } else { | ||||
| std::cout << "|#####| "; | std::cout << "|#####| "; | ||||
| } | } | ||||
| i++; | |||||
| } | } | ||||
| std::cout << std::endl; | std::cout << std::endl; | ||||
| i = 0; | |||||
| for (auto it : hand->cards) { | |||||
| if (it >= 0) { | |||||
| std::cout << "|___" << ((card[it].number != 10)?"_":"") << card[it].getNumberASCII() << "| "; | |||||
| for (auto c : hand->cards) { | |||||
| if (color && (card[c].suit == Suit::Diamonds || card[c].suit == Suit::Hearts)) { | |||||
| ansiColor = red; | |||||
| ansiReset = reset; | |||||
| } else { | |||||
| ansiColor = ""; | |||||
| ansiReset = ""; | |||||
| } | |||||
| if (c > 0) { | |||||
| std::cout << "|___" << ansiColor << ((card[c].number != 10)?"_":"") << card[c].getNumberASCII() << ansiReset<< "| "; | |||||
| } else { | } else { | ||||
| std::cout << "|#####| "; | std::cout << "|#####| "; | ||||
| } | } | ||||
| i++; | |||||
| } | } | ||||
| std::cout << std::endl; | std::cout << std::endl; | ||||
| ~Tty() { }; | ~Tty() { }; | ||||
| int play() override; | int play() override; | ||||
| void info(Info = Info::None, int = 0) override; | |||||
| void info(Info = Info::None, int = 0, int = 0) override; | |||||
| // for readline's autocompletion | // for readline's autocompletion | ||||
| static char *rl_command_generator(const char *, int); | static char *rl_command_generator(const char *, int); |