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 Просмотреть файл

@@ -1,7 +1,7 @@
#include <iostream>
#include "base.h"

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

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

@@ -36,7 +36,6 @@ enum class DealerAction {
DealPlayerFirstCard,
AskForInsurance,
CheckforBlackjacks,
PayOrTakeInsuranceBets,
AskForPlay,
MoveOnToNextHand,
HitDealerHand,
@@ -144,15 +143,15 @@ class Hand {
// inline on purpose
bool blackjack() {
return (total() == 21 && cards.size() == 2);
return (abs(total()) == 21 && cards.size() == 2);
};
// inline on purpose
bool busted() {
return (total() > 21);
return (abs(total()) > 21);
}
void draw(bool = true);
void render(bool = true);
};
class PlayerHand : public Hand {
@@ -161,6 +160,7 @@ class PlayerHand : public Hand {
int bet = 0;
int id = 0;
bool insured = false;
bool doubled = false;
};

class DealerHand : public Hand {
@@ -173,7 +173,7 @@ class DealerHand : public Hand {
class Player {
public:
Player() = default;
~Player() = default;
virtual ~Player() = default;
// delete copy and move constructors
Player(Player&) = delete;
Player(const Player&) = delete;
@@ -196,19 +196,26 @@ class Player {
bool hasSplit = false;
bool hasDoubled = false;
bool bustedAllHands = false;

unsigned int flatBet = 0;
unsigned int flatBet = 1;
unsigned int currentBet = 0;
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 losses = 0;
unsigned int wins = 0;
unsigned int blackjack_wins = 0;
// TODO: blackjack_pushes?
bool no_insurance = false;
@@ -228,8 +235,8 @@ class Player {

class Dealer {
public:
Dealer() {};
~Dealer() {};
Dealer() = default;
virtual ~Dealer() = default;
// delete copy and move constructors
Dealer(Dealer&) = delete;
Dealer(const Dealer&) = delete;
@@ -250,15 +257,16 @@ class Dealer {
void getNextAction(DealerAction a) {
next_action = a;
}

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

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

@@ -45,9 +45,10 @@ Blackjack::~Blackjack() {
void Blackjack::deal(Player *player) {
int playerTotal = 0;
int dealerTotal = 0;
bool playerBlackack = false;
// let's start by assuming the player does not need to do anything
setInputNeeded(false);
player->actionRequired = PlayerActionRequired::None;
switch(next_action) {
// -------------------------------------------------------------------------
@@ -90,17 +91,17 @@ void Blackjack::deal(Player *player) {
if (lastPass) {
// TODO: send informative messages to the player
// tell people we are shuffling
// bjcall (blackjack.current_player->write (player, "shuffling"));
// bjcall (blackjack.current_player->write (player, "shuffling"));
// 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();
}
lastPass = false;
}
lastPass = false;
}
if (player->flatBet) {
@@ -123,14 +124,13 @@ void Blackjack::deal(Player *player) {
std::cout << "bet?" << std::endl;
// TODO: setter
player->actionRequired = PlayerActionRequired::Bet;
setInputNeeded(true);
return;
break;

case DealerAction::DealPlayerFirstCard:
// where's step 2? <- probably that's the player's bet
// 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;

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

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

if (playerBlackack) {
if (playerBlackack) {
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;
} else {
std::cout << "player_pushes " << player->currentHand->bet << std::endl;
@@ -230,50 +226,47 @@ void Blackjack::deal(Player *player) {
// print_hand_art (player->current_hand);
} else {
if (player->hasSplit) {
if (player->hasSplit) {
std::cout << "player_losses " << player->currentHand->bet << " #" << player->currentHand->id << std::endl;
} else {
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->losses++;
}
}
player->losses++;
}

setNextAction(DealerAction::StartNewHand);
player->actionRequired = PlayerActionRequired::None;
setInputNeeded(false);
std::cout << "next start a new hand" << std::endl;
return;
} 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);
player->actionRequired = PlayerActionRequired::None;
setInputNeeded(false);
std::cout << "next start a new hand" << std::endl;
return;
} 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;
}
setNextAction(DealerAction::AskForPlay);
player->actionRequired = PlayerActionRequired::Play;
setInputNeeded(true);
std::cout << "prepare to play" << std::endl;
return;
}
@@ -282,19 +275,154 @@ void Blackjack::deal(Player *player) {
/*
case DealerAction::PayOrTakeInsuranceBets:
break;
*/
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;
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;
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;
case DealerAction::Payout:
break;

case DealerAction::None:
break;
*/
}
}
@@ -371,11 +499,10 @@ int Blackjack::process(Player *player) {
player->currentHand->insured = true;
player->current_result -= 0.5 * player->currentHand->bet;
player->bankroll -= 0.5 * player->currentHand->bet;
player->n_insured_hands++;
player->handsInsured++;
player->actionRequired = PlayerActionRequired::None;
setNextAction(DealerAction::CheckforBlackjacks);
setInputNeeded(false);
return 1;
break;

@@ -383,7 +510,6 @@ int Blackjack::process(Player *player) {
player->currentHand->insured = false;
player->actionRequired = PlayerActionRequired::None;
setNextAction(DealerAction::CheckforBlackjacks);
setInputNeeded(false);
return 1;
break;

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

@@ -53,6 +53,7 @@ class Blackjack : public Dealer {
unsigned int max_bet = 0;
unsigned int number_of_burnt_cards = 0;
unsigned int infinite_decks_card_number_for_arranged_ones = 0;
bool hit_soft_17 = true;
double insurance = 0;
double blackjack_pays = 1.5;

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

@@ -47,7 +47,7 @@ int main(int argc, char **argv) {
while (!dealer->finished()) {
dealer->deal(player);
if (dealer->getInputNeeded()) {
if (player->actionRequired != PlayerActionRequired::None) {
do {
// TODO: check for too many errors meaning dealer and player do not understand each other
player->play();

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

@@ -19,50 +19,55 @@ int Tty::play() {
#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


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

@@ -5,7 +5,9 @@
class Tty : public Player {
public:
Tty();
~Tty() { };
~Tty() {
std::cout << "bye!" << std::endl;
};
int play() override;

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