/*------------ -------------- -------- --- ----- --- -- - - * Libre Blackjack - base classes * * Copyright (C) 2020 jeremy theler * * This file is part of Libre Blackjack. * * Libre Blackjack is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Libre Blackjack is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Libre Blackjack. If not, see . *------------------- ------------ ---- -------- -- - - - */ #ifndef BASE_H #define BASE_H #include #include #include #include namespace Libreblackjack { void shortversion(void); void help(const char *); void copyright(void); } // TODO: namespace enum class DealerAction { None, StartNewHand, AskForBets, DealPlayerFirstCard, AskForInsurance, CheckforBlackjacks, AskForPlay, MoveOnToNextHand, HitDealerHand, }; enum class PlayerActionRequired { None, Bet, Insurance, Play }; enum class PlayerActionTaken { None, // common Quit, Help, Count, UpcardValue, Bankroll, Hands, Table, // particular Bet, Insure, DontInsure, Stand, Double, Split, Hit, }; enum class Info { None, InvalidBet, NewHand, Shuffle, CardPlayer, CardDealer, CardDealerRevealsHole, DealerBlackjack, PlayerWinsInsurance, PlayerBlackjackAlso, PlayerPushes, PlayerLosses, PlayerBlackjack, PlayerWins, NoBlackjacks, PlayerBustsAllHands, DealerBusts, Help, Bye, }; // alphabetically-sorted enum class Suit { Clubs = 0, Diamonds = 1, Hearts = 2, Spades = 3 }; class Card { public: Card(unsigned int); ~Card() { }; // TODO: delete copy & move // TODO: decidir si conviene usar getters o public members Suit getSuit() { return suit; }; unsigned int getNumber() { return number; }; unsigned int getValue() { return value; }; std::string getNumberASCII() { return numberASCII; }; std::string getSuitUTF8() { return suitUTF8; }; Suit suit; unsigned int number; unsigned int value; std::string ascii() { return numberASCII + suitASCII; } std::string utf8(bool single = false) { return single ? singleUTF8 : numberASCII + suitUTF8; } std::string text(); private: std::string numberASCII; std::string suitASCII; std::string suitUTF8; std::string suitName; std::string singleUTF8; }; // TODO: static inside a class extern Card card[52]; class Hand { public: std::list cards; // inline on purpose int total() { unsigned int soft = 0; unsigned int n = 0; unsigned int value = 0; for (auto tag : cards) { value = card[tag].value; n += value; soft += (value == 11); } // this loop should be only executed once if everything works fine while (n > 21 && soft > 0){ n -= 10; soft--; } return (soft)?(-n):(n); }; // inline on purpose bool blackjack() { return (std::abs(total()) == 21 && cards.size() == 2); }; // inline on purpose bool busted() { return (std::abs(total()) > 21); } }; class PlayerHand : public Hand { public: int bet = 0; int id = 0; bool insured = false; bool doubled = false; }; class Player { public: Player() = default; virtual ~Player() = default; // delete copy and move constructors Player(Player&) = delete; Player(const Player&) = delete; Player(Player &&) = delete; Player(const Player &&) = delete; virtual int play() = 0; virtual void info(Info = Info::None, int = 0) = 0; PlayerActionRequired actionRequired = PlayerActionRequired::None; PlayerActionTaken actionTaken = PlayerActionTaken::None; bool bustedAllHands = false; unsigned int currentSplits = 0; unsigned int currentBet = 0; unsigned int n_hands = 0; // this is different from the dealer's due to splitting unsigned int handsInsured = 0; unsigned int handsDoubled = 0; unsigned int blackjacksPlayer = 0; unsigned int blackjacksDealer = 0; unsigned int bustsPlayer = 0; unsigned int bustsDealer = 0; unsigned int wins = 0; unsigned int winsInsured = 0; unsigned int winsDoubled = 0; unsigned int winsBlackjack = 0; unsigned int pushes = 0; unsigned int losses = 0; // TODO: blackjack_pushes? unsigned int flat_bet = 1; bool no_insurance = false; bool always_insure = false; double bankroll = 0; double worst_bankroll = 0; double total_money_waged = 0; double current_result = 0; double mean = 0; double M2 = 0; double variance = 0; std::list hands; std::list::iterator currentHand; Hand dealerHand; }; class Dealer { public: Dealer() = default; virtual ~Dealer() = default; // delete copy and move constructors Dealer(Dealer&) = delete; Dealer(const Dealer&) = delete; Dealer(Dealer &&) = delete; Dealer(const Dealer &&) = delete; // maybe this first one does not need to be deleted virtual void shuffle() = 0; virtual void deal(Player *) = 0; virtual unsigned int drawCard(Hand * = nullptr) = 0; virtual int process(Player *) = 0; /* void setNextAction(DealerAction a) { next_action = a; } void getNextAction(DealerAction a) { next_action = a; } */ bool finished(void) { return done; } bool finished(bool d) { return (done = d); } bool done = false; DealerAction nextAction = DealerAction::None; // TODO: most of the games will have a single element, but maybe // there are games where the dealer has more than one hand // std::list hands; Hand hand; }; #endif