gtheler 5 лет назад
Родитель
Сommit
ed3beb27fa
7 измененных файлов: 250 добавлений и 108 удалений
  1. +1
    -1
      src/base.cpp
  2. +25
    -17
      src/base.h
  3. +176
    -50
      src/blackjack.cpp
  4. +1
    -0
      src/blackjack.h
  5. +1
    -1
      src/main.cpp
  6. +43
    -38
      src/tty.cpp
  7. +3
    -1
      src/tty.h

+ 1
- 1
src/base.cpp Просмотреть файл

#include <iostream> #include <iostream>
#include "base.h" #include "base.h"


void Hand::draw(bool holeCardShown) {
void Hand::render(bool holeCardShown) {
for (auto it : cards) { for (auto it : cards) {
std::cout << " _____ "; std::cout << " _____ ";

+ 25
- 17
src/base.h Просмотреть файл

DealPlayerFirstCard, DealPlayerFirstCard,
AskForInsurance, AskForInsurance,
CheckforBlackjacks, CheckforBlackjacks,
PayOrTakeInsuranceBets,
AskForPlay, AskForPlay,
MoveOnToNextHand, MoveOnToNextHand,
HitDealerHand, HitDealerHand,
// inline on purpose // inline on purpose
bool blackjack() { bool blackjack() {
return (total() == 21 && cards.size() == 2);
return (abs(total()) == 21 && cards.size() == 2);
}; };
// inline on purpose // inline on purpose
bool busted() { bool busted() {
return (total() > 21);
return (abs(total()) > 21);
} }
void draw(bool = true);
void render(bool = true);
}; };
class PlayerHand : public Hand { class PlayerHand : public Hand {
int bet = 0; int bet = 0;
int id = 0; int id = 0;
bool insured = false; bool insured = false;
bool doubled = false;
}; };


class DealerHand : public Hand { class DealerHand : public Hand {
class Player { class Player {
public: public:
Player() = default; Player() = default;
~Player() = default;
virtual ~Player() = default;
// delete copy and move constructors // delete copy and move constructors
Player(Player&) = delete; Player(Player&) = delete;
Player(const Player&) = delete; Player(const Player&) = delete;
bool hasSplit = false; bool hasSplit = false;
bool hasDoubled = false; bool hasDoubled = false;
bool bustedAllHands = false;


unsigned int flatBet = 0;
unsigned int flatBet = 1;
unsigned int currentBet = 0; unsigned int currentBet = 0;
unsigned int n_hands = 0; // this is different from the dealer's due to splitting unsigned int n_hands = 0; // this is different from the dealer's due to splitting
unsigned int n_insured_hands = 0;
unsigned int player_blackjacks = 0;
unsigned int handsInsured = 0;
unsigned int blackjacksPlayer = 0;
unsigned int blackjacksDealer = 0;


unsigned int dealer_blackjacks = 0;
unsigned int insured_wins = 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 pushes = 0;
unsigned int losses = 0; unsigned int losses = 0;
unsigned int wins = 0;
unsigned int blackjack_wins = 0;
// TODO: blackjack_pushes? // TODO: blackjack_pushes?
bool no_insurance = false; bool no_insurance = false;


class Dealer { class Dealer {
public: public:
Dealer() {};
~Dealer() {};
Dealer() = default;
virtual ~Dealer() = default;
// delete copy and move constructors // delete copy and move constructors
Dealer(Dealer&) = delete; Dealer(Dealer&) = delete;
Dealer(const Dealer&) = delete; Dealer(const Dealer&) = delete;
void getNextAction(DealerAction a) { void getNextAction(DealerAction a) {
next_action = a; next_action = a;
} }

/*
bool getInputNeeded(void) { bool getInputNeeded(void) {
return input_needed; return input_needed;
} }
void setInputNeeded(bool flag) { void setInputNeeded(bool flag) {
input_needed = flag; input_needed = flag;
} }
*/
bool finished(void) { bool finished(void) {
return done; return done;
} }

+ 176
- 50
src/blackjack.cpp Просмотреть файл

void Blackjack::deal(Player *player) { void Blackjack::deal(Player *player) {
int playerTotal = 0; int playerTotal = 0;
int dealerTotal = 0;
bool playerBlackack = false; bool playerBlackack = false;
// let's start by assuming the player does not need to do anything // let's start by assuming the player does not need to do anything
setInputNeeded(false);
player->actionRequired = PlayerActionRequired::None;
switch(next_action) { switch(next_action) {
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
if (lastPass) { if (lastPass) {
// TODO: send informative messages to the player // TODO: send informative messages to the player
// tell people we are shuffling // tell people we are shuffling
// bjcall (blackjack.current_player->write (player, "shuffling"));
// bjcall (blackjack.current_player->write (player, "shuffling"));
// shuffle the cards // shuffle the cards
shuffle();
shuffle();
// TODO: reset card counting systems
// burn as many cards as asked
for (int i = 0; i < number_of_burnt_cards; i++) {
// TODO: reset card counting systems
// burn as many cards as asked
for (int i = 0; i < number_of_burnt_cards; i++) {
// dealCard(); // dealCard();
}
lastPass = false;
}
lastPass = false;
} }
if (player->flatBet) { if (player->flatBet) {
std::cout << "bet?" << std::endl; std::cout << "bet?" << std::endl;
// TODO: setter // TODO: setter
player->actionRequired = PlayerActionRequired::Bet; player->actionRequired = PlayerActionRequired::Bet;
setInputNeeded(true);
return; return;
break; break;


case DealerAction::DealPlayerFirstCard: case DealerAction::DealPlayerFirstCard:
// where's step 2? <- probably that's the player's bet // where's step 2? <- probably that's the player's bet
// step 3. deal the first card to each player // step 3. deal the first card to each player
player->n_hands++; // splits are counted as a single hand
player->n_hands++; // splits are counted as a single hand
player->total_money_waged += player->currentHand->bet; player->total_money_waged += player->currentHand->bet;


playerFirstCard = dealCard(&(*player->currentHand)); playerFirstCard = dealCard(&(*player->currentHand));
holeCard = dealCard(&hand); holeCard = dealCard(&hand);
std::cout << "card_dealer_hole" << std::endl; std::cout << "card_dealer_hole" << std::endl;


hand.draw(hand.holeCardShown);
player->currentHand->draw();
hand.render(hand.holeCardShown);
player->currentHand->render();


// 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) {
if (player->no_insurance == false && player->always_insure == false) { if (player->no_insurance == false && player->always_insure == false) {
player->actionRequired = PlayerActionRequired::Insurance; player->actionRequired = PlayerActionRequired::Insurance;
setNextAction(DealerAction::AskForInsurance); setNextAction(DealerAction::AskForInsurance);
setInputNeeded(true);
std::cout << "next ask insurance" << std::endl; std::cout << "next ask insurance" << std::endl;
return; return;
// TODO: allow insurance for less than one half of the original bet // TODO: allow insurance for less than one half of the original bet
player->current_result -= 0.5 * player->currentHand->bet; player->current_result -= 0.5 * player->currentHand->bet;
player->bankroll -= 0.5 * player->currentHand->bet; player->bankroll -= 0.5 * player->currentHand->bet;
player->n_insured_hands++;
player->handsInsured++;
player->actionRequired = PlayerActionRequired::None; player->actionRequired = PlayerActionRequired::None;
setNextAction(DealerAction::CheckforBlackjacks); setNextAction(DealerAction::CheckforBlackjacks);
setInputNeeded(false);
return; return;
} }
} }
if ((card[upCard].value == 10 || card[upCard].value == 11) || playerTotal == 21) { if ((card[upCard].value == 10 || card[upCard].value == 11) || playerTotal == 21) {
player->actionRequired = PlayerActionRequired::None; player->actionRequired = PlayerActionRequired::None;
setNextAction(DealerAction::CheckforBlackjacks); setNextAction(DealerAction::CheckforBlackjacks);
setInputNeeded(false);
std::cout << "next check BJs" << std::endl; std::cout << "next check BJs" << std::endl;
return; return;
} }
// step 7.c. ask the player to play // step 7.c. ask the player to play
player->actionRequired = PlayerActionRequired::Play; player->actionRequired = PlayerActionRequired::Play;
setNextAction(DealerAction::AskForPlay); setNextAction(DealerAction::AskForPlay);
setInputNeeded(true);
std::cout << "dealer upcard is " << card[upCard].utf8() << std::endl; std::cout << "dealer upcard is " << card[upCard].utf8() << std::endl;
std::cout << "your total is " << playerTotal << std::endl; std::cout << "your total is " << playerTotal << std::endl;
std::cout << "play please" << std::endl; std::cout << "play please" << std::endl;
if (hand.blackjack()) { if (hand.blackjack()) {
std::cout << "card_dealer_hole" << card[holeCard].utf8() << std::endl; std::cout << "card_dealer_hole" << card[holeCard].utf8() << std::endl;
std::cout << "blackjack_dealer" << std::endl; std::cout << "blackjack_dealer" << std::endl;
player->dealer_blackjacks++;
player->blackjacksDealer++;
// print_hand_art (blackjack.dealer_hand); // print_hand_art (blackjack.dealer_hand);


if (player->currentHand->insured) { if (player->currentHand->insured) {
std::cout << "player_wins_insurance " << player->currentHand->bet << std::endl; std::cout << "player_wins_insurance " << player->currentHand->bet << std::endl;
player->current_result += player->currentHand->bet; player->current_result += player->currentHand->bet;
player->bankroll += player->currentHand->bet; player->bankroll += player->currentHand->bet;
player->insured_wins++;
}
player->winsInsured++;
}


if (playerBlackack) {
if (playerBlackack) {
std::cout << "blackjack_player_also" << std::endl; std::cout << "blackjack_player_also" << std::endl;
player->player_blackjacks++;
if (player->hasSplit) {
player->blackjacksPlayer++;
if (player->hasSplit) {
std::cout << "player_pushes " << player->currentHand->bet << " #" << player->currentHand->id << std::endl; std::cout << "player_pushes " << player->currentHand->bet << " #" << player->currentHand->id << std::endl;
} else { } else {
std::cout << "player_pushes " << player->currentHand->bet << std::endl; std::cout << "player_pushes " << player->currentHand->bet << std::endl;
// print_hand_art (player->current_hand); // print_hand_art (player->current_hand);
} else { } else {
if (player->hasSplit) {
if (player->hasSplit) {
std::cout << "player_losses " << player->currentHand->bet << " #" << player->currentHand->id << std::endl; std::cout << "player_losses " << player->currentHand->bet << " #" << player->currentHand->id << std::endl;
} else { } else {
std::cout << "player_losses " << player->currentHand->bet << std::endl; std::cout << "player_losses " << player->currentHand->bet << std::endl;
} }
player->current_result -= player->currentHand->bet;
player->bankroll -= player->currentHand->bet;
if (player->bankroll < player->worst_bankroll) {
player->current_result -= player->currentHand->bet;
player->bankroll -= player->currentHand->bet;
if (player->bankroll < player->worst_bankroll) {
player->worst_bankroll = player->bankroll; player->worst_bankroll = player->bankroll;
}
player->losses++;
}
}
player->losses++;
}


setNextAction(DealerAction::StartNewHand); setNextAction(DealerAction::StartNewHand);
player->actionRequired = PlayerActionRequired::None; player->actionRequired = PlayerActionRequired::None;
setInputNeeded(false);
std::cout << "next start a new hand" << std::endl; std::cout << "next start a new hand" << std::endl;
return; return;
} else if (playerBlackack) { } else if (playerBlackack) {
std::cout << "blackjack_player" << std::endl;
player->current_result += blackjack_pays * player->currentHand->bet;
player->bankroll += blackjack_pays * player->currentHand->bet;
player->player_blackjacks++;
std::cout << "blackjack_player" << std::endl;
player->current_result += blackjack_pays * player->currentHand->bet;
player->bankroll += blackjack_pays * player->currentHand->bet;
player->blackjacksPlayer++;
std::cout << "player_wins " << blackjack_pays * player->currentHand->bet << std::endl;
player->wins++;
player->blackjack_wins++;
std::cout << "player_wins " << blackjack_pays * player->currentHand->bet << std::endl;
player->wins++;
player->winsBlackjack++;


setNextAction(DealerAction::StartNewHand); setNextAction(DealerAction::StartNewHand);
player->actionRequired = PlayerActionRequired::None; player->actionRequired = PlayerActionRequired::None;
setInputNeeded(false);
std::cout << "next start a new hand" << std::endl; std::cout << "next start a new hand" << std::endl;
return; return;
} else { } else {
// only if the dealer had the chance to have a blackjack we say "no_blackjacks"
if (card[upCard].value == 10 || card[upCard].value == 11) {
// only if the dealer had the chance to have a blackjack we say "no_blackjacks"
if (card[upCard].value == 10 || card[upCard].value == 11) {
std::cout << "no_blackjacks" << std::endl; std::cout << "no_blackjacks" << std::endl;
} }
setNextAction(DealerAction::AskForPlay); setNextAction(DealerAction::AskForPlay);
player->actionRequired = PlayerActionRequired::Play; player->actionRequired = PlayerActionRequired::Play;
setInputNeeded(true);
std::cout << "prepare to play" << std::endl; std::cout << "prepare to play" << std::endl;
return; return;
} }
/* /*
case DealerAction::PayOrTakeInsuranceBets: case DealerAction::PayOrTakeInsuranceBets:
break; break;
*/
case DealerAction::AskForPlay: case DealerAction::AskForPlay:
std::cout << "Here are your cards" << std::endl;
setInputNeeded(true);

player->actionRequired = PlayerActionRequired::Play;
setNextAction(DealerAction::AskForPlay);
hand.render(hand.holeCardShown);
player->currentHand->render();
std::cout << "dealer upcard is " << card[upCard].utf8() << std::endl;
std::cout << "your total is " << playerTotal << std::endl;
std::cout << "play please" << std::endl;
return;
break; break;
case DealerAction::MoveOnToNextHand: case DealerAction::MoveOnToNextHand:
// see if we finished all the player's hands
if (++player->currentHand != player->hands.end()) {
unsigned int playerCard = dealCard(&(*player->currentHand));
if (player->hasSplit && player->currentHand->cards.size() == 2) {
std::cout << "card_player_second " << card[playerCard].utf8() << std::endl;
} else {
std::cout << "card_player " << card[playerCard].utf8() << std::endl;
}
player->currentHand->render();

if (player->currentHand->total() == 21) {
player->actionRequired = PlayerActionRequired::None;
setNextAction(DealerAction::MoveOnToNextHand);
return;
} else {
player->actionRequired = PlayerActionRequired::Play;
setNextAction(DealerAction::AskForPlay);
return;
}
} else {
// assume the player busted in all the hands
player->bustedAllHands = true;
for (auto playerHand : player->hands) {
// if she did not bust, set zero
if (playerHand.busted() == false) {
player->bustedAllHands = false;
}
}

if (player->bustedAllHands) {
std::cout << "player_bustd_all_hands" << std::endl;
std::cout << "card_dealer_hole " << card[holeCard].utf8() << std::endl;
hand.holeCardShown = true;
std::cout << "dealer_hand" << std::endl;
hand.render(hand.holeCardShown);
// TODO: no tengo que sacarle todo el dinero?
player->actionRequired = PlayerActionRequired::None;
setNextAction(DealerAction::StartNewHand);
return;
} else {
player->actionRequired = PlayerActionRequired::None;
setNextAction(DealerAction::HitDealerHand);
return;
}
}
break; break;
case DealerAction::HitDealerHand: case DealerAction::HitDealerHand:
std::cout << "card_dealer_hole" << card[holeCard].utf8() << std::endl;
hand.holeCardShown = true;

hand.render(hand.holeCardShown);

// TODO: print "soft"
std::cout << "dealer_count " << hand.total() << std::endl;

// hit if count is less than 17 (or equalt to soft 17 if hit_soft_17 is true)
dealerTotal = hand.total();
while (((abs(dealerTotal) < 17 || (hit_soft_17 && dealerTotal == -17))) && hand.busted() == 0) {
unsigned int dealerCard = dealCard(&hand);
std::cout << "card_dealer " << card[dealerCard].utf8() << std::endl;
hand.render(hand.holeCardShown);
dealerTotal = abs(hand.total());
std::cout << "dealer_count " << dealerTotal << std::endl;

if (hand.busted()) {
std::cout << "busted_dealer " << dealerTotal << std::endl;
player->bustsDealer++;
for (auto playerHand : player->hands) {
if (playerHand.busted() == false) {
// TODO: split
std::cout << "player_wins " << playerHand.bet << std::endl;
player->current_result += playerHand.bet;
player->bankroll += playerHand.bet;
player->wins++;
if (playerHand.doubled) {
player->winsDoubled++;
} else {
player->wins++;
}
}
}
} else {
for (auto playerHand : player->hands) {
if (playerHand.busted() == false) { // busted hands have already been solved
unsigned int playerTotal = abs(playerHand.total());
if (dealerTotal > playerTotal) {
std::cout << "player_losses " << playerHand.bet << std::endl;
player->bankroll -= playerHand.bet;
if (player->bankroll < player->worst_bankroll) {
player->worst_bankroll = player->bankroll;
}
player->losses++;
} else if (dealerTotal == playerTotal) {
std::cout << "player_pushes " << playerHand.bet << std::endl;
player->pushes++;
} else {
std::cout << "player_wins " << playerHand.bet << std::endl;
player->current_result += playerHand.bet;
player->bankroll += playerHand.bet;
player->wins++;

if (playerHand.doubled) {
player->winsDoubled++;
} else {
player->wins++;
}
}
}
}
}
}

player->actionRequired = PlayerActionRequired::None;
setNextAction(DealerAction::StartNewHand);
return;
break; break;
case DealerAction::Payout:
break;

case DealerAction::None: case DealerAction::None:
break; break;
*/
} }
} }
player->currentHand->insured = true; player->currentHand->insured = true;
player->current_result -= 0.5 * player->currentHand->bet; player->current_result -= 0.5 * player->currentHand->bet;
player->bankroll -= 0.5 * player->currentHand->bet; player->bankroll -= 0.5 * player->currentHand->bet;
player->n_insured_hands++;
player->handsInsured++;
player->actionRequired = PlayerActionRequired::None; player->actionRequired = PlayerActionRequired::None;
setNextAction(DealerAction::CheckforBlackjacks); setNextAction(DealerAction::CheckforBlackjacks);
setInputNeeded(false);
return 1; return 1;
break; break;


player->currentHand->insured = false; player->currentHand->insured = false;
player->actionRequired = PlayerActionRequired::None; player->actionRequired = PlayerActionRequired::None;
setNextAction(DealerAction::CheckforBlackjacks); setNextAction(DealerAction::CheckforBlackjacks);
setInputNeeded(false);
return 1; return 1;
break; break;

+ 1
- 0
src/blackjack.h Просмотреть файл

unsigned int max_bet = 0; unsigned int max_bet = 0;
unsigned int number_of_burnt_cards = 0; unsigned int number_of_burnt_cards = 0;
unsigned int infinite_decks_card_number_for_arranged_ones = 0; unsigned int infinite_decks_card_number_for_arranged_ones = 0;
bool hit_soft_17 = true;
double insurance = 0; double insurance = 0;
double blackjack_pays = 1.5; double blackjack_pays = 1.5;

+ 1
- 1
src/main.cpp Просмотреть файл

while (!dealer->finished()) { while (!dealer->finished()) {
dealer->deal(player); dealer->deal(player);
if (dealer->getInputNeeded()) {
if (player->actionRequired != PlayerActionRequired::None) {
do { do {
// TODO: check for too many errors meaning dealer and player do not understand each other // TODO: check for too many errors meaning dealer and player do not understand each other
player->play(); player->play();

+ 43
- 38
src/tty.cpp Просмотреть файл

#ifdef HAVE_LIBREADLINE #ifdef HAVE_LIBREADLINE
if ((input_buffer = readline(prompt.c_str())) != nullptr) {
add_history(input_buffer);
}
if ((input_buffer = readline(prompt.c_str())) == nullptr) {
// EOF means "quit"
actionTaken = PlayerActionTaken::Quit;
std::cout << std::endl;
} else {


// TODO: check EOF
// TODO: esto puede ir en algo comun para tty y stdout
switch (actionRequired) {
add_history(input_buffer);
case PlayerActionRequired::Bet:
// TODO: both as parameters or both as class members
currentBet = atoi(input_buffer);
actionTaken = PlayerActionTaken::Bet;
break;
// TODO: convertir a string y usar algo comun para non-readline
switch (actionRequired) {
case PlayerActionRequired::Bet:
currentBet = atoi(input_buffer);
actionTaken = PlayerActionTaken::Bet;
break;
case PlayerActionRequired::Insurance:
if (strcmp(input_buffer, "y") == 0 || strcmp(input_buffer, "yes") == 0) {
actionTaken = PlayerActionTaken::Insure;
} else if (strcmp(input_buffer, "n") == 0 || strcmp(input_buffer, "no") == 0) {
actionTaken = PlayerActionTaken::DontInsure;
} else {
// TODO: chosse if we allow not(yes) == no
actionTaken = PlayerActionTaken::None;
}
break;
case PlayerActionRequired::Insurance:
if (strcmp(input_buffer, "y") == 0 || strcmp(input_buffer, "yes") == 0) {
actionTaken = PlayerActionTaken::Insure;
} else if (strcmp(input_buffer, "n") == 0 || strcmp(input_buffer, "no") == 0) {
actionTaken = PlayerActionTaken::DontInsure;
} else {
// TODO: chosse if we allow not(yes) == no
actionTaken = PlayerActionTaken::None;
}
break;
case PlayerActionRequired::Play:
case PlayerActionRequired::Play:
// TODO: sort by higher-expected response first
if (strcmp(input_buffer, "h") == 0 || strcmp(input_buffer, "hit") == 0) {
actionTaken = PlayerActionTaken::Hit;
} else if (strcmp(input_buffer, "s") == 0 || strcmp(input_buffer, "stand") == 0) {
actionTaken = PlayerActionTaken::Stand;
} else if (strcmp(input_buffer, "d") == 0 || strcmp(input_buffer, "double") == 0) {
actionTaken = PlayerActionTaken::Stand;
} else if (strcmp(input_buffer, "p") == 0 || strcmp(input_buffer, "pair") == 0 || strcmp(input_buffer, "split") == 0) {
actionTaken = PlayerActionTaken::Split;
} else {
actionTaken = PlayerActionTaken::None;
}
break;
// TODO: sort by higher-expected response first
if (strcmp(input_buffer, "h") == 0 || strcmp(input_buffer, "hit") == 0) {
actionTaken = PlayerActionTaken::Hit;
} else if (strcmp(input_buffer, "s") == 0 || strcmp(input_buffer, "stand") == 0) {
actionTaken = PlayerActionTaken::Stand;
} else if (strcmp(input_buffer, "d") == 0 || strcmp(input_buffer, "double") == 0) {
actionTaken = PlayerActionTaken::Stand;
} else if (strcmp(input_buffer, "p") == 0 || strcmp(input_buffer, "pair") == 0 || strcmp(input_buffer, "split") == 0) {
actionTaken = PlayerActionTaken::Split;
} else {
actionTaken = PlayerActionTaken::None;
}
break;
free(input_buffer);
}
} }
free(input_buffer);
#else #else



+ 3
- 1
src/tty.h Просмотреть файл

class Tty : public Player { class Tty : public Player {
public: public:
Tty(); Tty();
~Tty() { };
~Tty() {
std::cout << "bye!" << std::endl;
};
int play() override; int play() override;

Загрузка…
Отмена
Сохранить