gtheler 5 лет назад
Родитель
Сommit
dae9ddb57a
4 измененных файлов: 105 добавлений и 46 удалений
  1. +8
    -10
      src/base.h
  2. +44
    -13
      src/blackjack.cpp
  3. +5
    -0
      src/blackjack.h
  4. +48
    -23
      src/internal.cpp

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

public: public:
Card(unsigned int); Card(unsigned int);
~Card() { }; ~Card() { };
// TODO: delete copy & move
// TODO: decidir si conviene usar getters o public members
Libreblackjack::Suit getSuit() { return suit; };
unsigned int getNumber() { return number; };
unsigned int getValue() { return value; };
Libreblackjack::Suit getSuit() { return suit; };
unsigned int getNumber() { return number; };
unsigned int getValue() { return value; };


std::string getNumberASCII() { return numberASCII; };
std::string getSuitUTF8() { return suitUTF8; };
std::string getNumberASCII() { return numberASCII; };
std::string getSuitUTF8() { return suitUTF8; };
Libreblackjack::Suit suit; Libreblackjack::Suit suit;
unsigned int number; unsigned int number;
unsigned int value; unsigned int value;
std::string ascii() {
return numberASCII + suitASCII;
}
std::string ascii() { return numberASCII + suitASCII; };
std::string utf8(bool single = false) { std::string utf8(bool single = false) {
return single ? singleUTF8 : numberASCII + suitUTF8; return single ? singleUTF8 : numberASCII + suitUTF8;
} }


int dealerValue = 0; int dealerValue = 0;
int playerValue = 0; int playerValue = 0;
bool canDouble = false;
bool canSplit = false;
bool verbose = false; bool verbose = false;
bool flat_bet = false; bool flat_bet = false;

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

} }


info(Libreblackjack::Info::NewHand, n_hand, 1e3*playerStats.bankroll); info(Libreblackjack::Info::NewHand, n_hand, 1e3*playerStats.bankroll);
// std::cout << "new hand #" << n_hand << std::endl;
#ifdef BJDEBUG
std::cout << "new hand #" << n_hand << std::endl;
#endif
if (player->flat_bet) { if (player->flat_bet) {
// step 3. deal the first card to each player // step 3. deal the first card to each player
playerFirstCard = drawCard(&(*playerStats.currentHand)); playerFirstCard = drawCard(&(*playerStats.currentHand));
info(Libreblackjack::Info::CardPlayer, playerFirstCard); info(Libreblackjack::Info::CardPlayer, playerFirstCard);
// std::cout << "first card " << card[playerFirstCard].utf8() << std::endl;
#ifdef BJDEBUG
std::cout << "first card " << card[playerFirstCard].utf8() << std::endl;
#endif
// step 4. show dealer's upcard // step 4. show dealer's upcard
upCard = drawCard(&hand); upCard = drawCard(&hand);
info(Libreblackjack::Info::CardDealer, upCard); info(Libreblackjack::Info::CardDealer, upCard);
// std::cout << "up card " << card[upCard].utf8() << std::endl;
#ifdef BJDEBUG
std::cout << "up card " << card[upCard].utf8() << std::endl;
#endif
player->dealerValue = hand.value(); player->dealerValue = hand.value();


// step 5. deal the second card to each player // step 5. deal the second card to each player
playerSecondCard = drawCard(&(*playerStats.currentHand)); playerSecondCard = drawCard(&(*playerStats.currentHand));
info(Libreblackjack::Info::CardPlayer, playerSecondCard); info(Libreblackjack::Info::CardPlayer, playerSecondCard);
player->playerValue = playerStats.currentHand->value(); player->playerValue = playerStats.currentHand->value();
// std::cout << "second card " << card[playerSecondCard].utf8() << std::endl;
#ifdef BJDEBUG
std::cout << "second card " << card[playerSecondCard].utf8() << std::endl;
#endif
// step 6. deal the dealer's hole card // step 6. deal the dealer's hole card
holeCard = drawCard(&hand); holeCard = drawCard(&hand);
} }


// step 7.c. ask the player to play // step 7.c. ask the player to play
player->canDouble = true;
player->canSplit = card[playerFirstCard].value == card[playerSecondCard].value;
player->actionRequired = Libreblackjack::PlayerActionRequired::Play; player->actionRequired = Libreblackjack::PlayerActionRequired::Play;
nextAction = Libreblackjack::DealerAction::AskForPlay; nextAction = Libreblackjack::DealerAction::AskForPlay;
return; return;
if (hand.blackjack()) { if (hand.blackjack()) {
info(Libreblackjack::Info::CardDealerRevealsHole, holeCard); info(Libreblackjack::Info::CardDealerRevealsHole, holeCard);
info(Libreblackjack::Info::DealerBlackjack); info(Libreblackjack::Info::DealerBlackjack);
// std::cout << "dealer blakjack " << card[holeCard].utf8() << std::endl;
#ifdef BJDEBUG
std::cout << "dealer blakjack " << card[holeCard].utf8() << std::endl;
#endif
playerStats.blackjacksDealer++; playerStats.blackjacksDealer++;


if (playerStats.currentHand->insured) { if (playerStats.currentHand->insured) {


if (playerBlackjack) { if (playerBlackjack) {
info(Libreblackjack::Info::PlayerBlackjackAlso); info(Libreblackjack::Info::PlayerBlackjackAlso);
// std::cout << "both blackjack " << card[holeCard].utf8() << std::endl;
#ifdef BJDEBUG
std::cout << "both blackjack " << card[holeCard].utf8() << std::endl;
#endif


// give him his (her her) money back // give him his (her her) money back
playerStats.bankroll += playerStats.currentHand->bet; playerStats.bankroll += playerStats.currentHand->bet;
info(Libreblackjack::Info::NoBlackjacks); info(Libreblackjack::Info::NoBlackjacks);
} }
canDoubleSplit();
nextAction = Libreblackjack::DealerAction::AskForPlay; nextAction = Libreblackjack::DealerAction::AskForPlay;
player->actionRequired = Libreblackjack::PlayerActionRequired::Play; player->actionRequired = Libreblackjack::PlayerActionRequired::Play;
return; return;
break; break;
case Libreblackjack::DealerAction::AskForPlay: case Libreblackjack::DealerAction::AskForPlay:
#ifdef BJDEBUG
std::cout << "pistola" << std::endl;
#endif
canDoubleSplit();
player->actionRequired = Libreblackjack::PlayerActionRequired::Play; player->actionRequired = Libreblackjack::PlayerActionRequired::Play;
nextAction = Libreblackjack::DealerAction::AskForPlay; nextAction = Libreblackjack::DealerAction::AskForPlay;
return; return;
unsigned int playerCard = drawCard(&(*playerStats.currentHand)); unsigned int playerCard = drawCard(&(*playerStats.currentHand));
player->playerValue = playerStats.currentHand->value(); player->playerValue = playerStats.currentHand->value();
info(Libreblackjack::Info::CardPlayer, playerCard, playerStats.currentHand->id); info(Libreblackjack::Info::CardPlayer, playerCard, playerStats.currentHand->id);
// std::cout << "card player " << card[playerCard].utf8() << std::endl;
#ifdef BJDEBUG
std::cout << "card player " << card[playerCard].utf8() << std::endl;
#endif


if (std::abs(player->playerValue) == 21) { if (std::abs(player->playerValue) == 21) {
player->actionRequired = Libreblackjack::PlayerActionRequired::None; player->actionRequired = Libreblackjack::PlayerActionRequired::None;
nextAction = Libreblackjack::DealerAction::MoveOnToNextHand; nextAction = Libreblackjack::DealerAction::MoveOnToNextHand;
return; return;
} else { } else {
canDoubleSplit();
player->actionRequired = Libreblackjack::PlayerActionRequired::Play; player->actionRequired = Libreblackjack::PlayerActionRequired::Play;
nextAction = Libreblackjack::DealerAction::AskForPlay; nextAction = Libreblackjack::DealerAction::AskForPlay;
return; return;


if (bustedAllHands) { if (bustedAllHands) {
info(Libreblackjack::Info::CardDealerRevealsHole, holeCard); info(Libreblackjack::Info::CardDealerRevealsHole, holeCard);
// std::cout << "hole " << card[holeCard].utf8() << std::endl;
#ifdef BJDEBUG
std::cout << "hole " << card[holeCard].utf8() << std::endl;
#endif
player->actionRequired = Libreblackjack::PlayerActionRequired::None; player->actionRequired = Libreblackjack::PlayerActionRequired::None;
nextAction = Libreblackjack::DealerAction::StartNewHand; nextAction = Libreblackjack::DealerAction::StartNewHand;
case Libreblackjack::DealerAction::HitDealerHand: case Libreblackjack::DealerAction::HitDealerHand:
info(Libreblackjack::Info::CardDealerRevealsHole, holeCard); info(Libreblackjack::Info::CardDealerRevealsHole, holeCard);
// std::cout << "hole " << card[holeCard].utf8() << std::endl;
#ifdef BJDEBUG
std::cout << "hole " << card[holeCard].utf8() << std::endl;
#endif


// hit while count is less than 17 (or equal 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)
player->dealerValue = hand.value(); player->dealerValue = hand.value();
while ((std::abs(player->dealerValue) < 17 || (hit_soft_17 && player->dealerValue == -17)) && hand.busted() == 0) { while ((std::abs(player->dealerValue) < 17 || (hit_soft_17 && player->dealerValue == -17)) && hand.busted() == 0) {
unsigned int dealerCard = drawCard(&hand); unsigned int dealerCard = drawCard(&hand);
info(Libreblackjack::Info::CardDealer, dealerCard); info(Libreblackjack::Info::CardDealer, dealerCard);
// std::cout << "dealer " << card[dealerCard].utf8() << std::endl;
#ifdef BJDEBUG
std::cout << "dealer " << card[dealerCard].utf8() << std::endl;
#endif
player->dealerValue = hand.value(); player->dealerValue = hand.value();
} }
secondCard = *(++playerStats.currentHand->cards.begin()); secondCard = *(++playerStats.currentHand->cards.begin());
// up to three splits (i.e. four hands) // up to three splits (i.e. four hands)
// TODO: choose through conf
// TODO: choose through conf how many max splits are available
// TODO: check bankroll to see if player can split // TODO: check bankroll to see if player can split
if (playerStats.splits < 3 && playerStats.currentHand->cards.size() == 2 && card[firstCard].value == card[secondCard].value) {
// if (playerStats.splits < 3 && playerStats.currentHand->cards.size() == 2 && card[firstCard].value == card[secondCard].value) {
if (playerStats.currentHand->cards.size() == 2 && card[firstCard].value == card[secondCard].value) {
// take player's money // take player's money
playerStats.bankroll -= playerStats.currentHand->bet; playerStats.bankroll -= playerStats.currentHand->bet;
nextAction = Libreblackjack::DealerAction::MoveOnToNextHand; nextAction = Libreblackjack::DealerAction::MoveOnToNextHand;
return 1; return 1;
} else { } else {
canDoubleSplit();
player->actionRequired = Libreblackjack::PlayerActionRequired::Play; player->actionRequired = Libreblackjack::PlayerActionRequired::Play;
nextAction = Libreblackjack::DealerAction::AskForPlay; nextAction = Libreblackjack::DealerAction::AskForPlay;
return 1; return 1;
return 1; return 1;
} }
} else { } else {
canDoubleSplit();
player->actionRequired = Libreblackjack::PlayerActionRequired::Play; player->actionRequired = Libreblackjack::PlayerActionRequired::Play;
nextAction = Libreblackjack::DealerAction::AskForPlay; nextAction = Libreblackjack::DealerAction::AskForPlay;
return 1; return 1;
} else { } else {
canDoubleSplit();
player->actionRequired = Libreblackjack::PlayerActionRequired::Play; player->actionRequired = Libreblackjack::PlayerActionRequired::Play;
nextAction = Libreblackjack::DealerAction::AskForPlay; nextAction = Libreblackjack::DealerAction::AskForPlay;
return 1; return 1;

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

double penetration = 0.75; double penetration = 0.75;
double penetration_sigma = 0; double penetration_sigma = 0;
void canDoubleSplit(void) {
player->canDouble = playerStats.currentHand->cards.size() == 2;
player->canSplit = player->canDouble && (card[*(playerStats.currentHand->cards.begin())].value == card[*(++playerStats.currentHand->cards.begin())].value);
return;
}
}; };
#endif #endif

+ 48
- 23
src/internal.cpp Просмотреть файл

hard.resize(21); // 4--20 hard.resize(21); // 4--20
soft.resize(21); // 12--20 soft.resize(21); // 12--20
pair.resize(12); // 2--11
pair.resize(21); // 2*(2--10) + 11
for (int value = 0; value < 21; value++) { for (int value = 0; value < 21; value++) {
hard[value].resize(12); hard[value].resize(12);
soft[value].resize(12); soft[value].resize(12);
if (value < 12) {
pair[value].resize(12);
}
pair[value].resize(12);

for (int upcard = 0; upcard < 12; upcard++) { for (int upcard = 0; upcard < 12; upcard++) {
hard[value][upcard] = Libreblackjack::PlayerActionTaken::None; hard[value][upcard] = Libreblackjack::PlayerActionTaken::None;
soft[value][upcard] = Libreblackjack::PlayerActionTaken::None; soft[value][upcard] = Libreblackjack::PlayerActionTaken::None;
if (value < 12) {
pair[value][upcard] = Libreblackjack::PlayerActionTaken::None;
}
pair[value][upcard] = Libreblackjack::PlayerActionTaken::None;
} }
} }
// TODO: read a default basic strategy // TODO: read a default basic strategy
break; break;
case 'p': case 'p':
strategy = &pair; strategy = &pair;
// see below how we handle these two cases
if (token[1] == 'A') { if (token[1] == 'A') {
value = 11; value = 11;
} else if (token[1] == 'T') { } else if (token[1] == 'T') {
} else if (token == "d") { } else if (token == "d") {
(*strategy)[value][upcard] = Libreblackjack::PlayerActionTaken::Double; (*strategy)[value][upcard] = Libreblackjack::PlayerActionTaken::Double;
} else if (token == "y") { } else if (token == "y") {
(*strategy)[value][upcard] = Libreblackjack::PlayerActionTaken::Split;
// the pair data is different as it is not written as a function of the value
// but of the value of the individual cards,
// i.e. p8 means split a pair of eights and not a hand with two fours
// to avoid clashing a pair of aces with a pair of sixes, we treat the former differently
if (value != 11) {
(*strategy)[2*value][upcard] = Libreblackjack::PlayerActionTaken::Split;
} else {
(*strategy)[11][upcard] = Libreblackjack::PlayerActionTaken::Split;
}
} else if (token == "n") { } else if (token == "n") {
(*strategy)[value][upcard] = Libreblackjack::PlayerActionTaken::None;
if (value != 11) {
(*strategy)[2*value][upcard] = Libreblackjack::PlayerActionTaken::None;
} else {
(*strategy)[11][upcard] = Libreblackjack::PlayerActionTaken::None;
}
} }
} }
} }


int Internal::play() { int Internal::play() {


std::size_t value;
std::size_t upcard;
switch (actionRequired) { switch (actionRequired) {
case Libreblackjack::PlayerActionRequired::Bet: case Libreblackjack::PlayerActionRequired::Bet:
currentBet = 1; currentBet = 1;
case Libreblackjack::PlayerActionRequired::Play: case Libreblackjack::PlayerActionRequired::Play:


// std::cout << "player " << playerValue << " dealer " << dealerValue << std::endl;
// TODO: split
// soft
{
std::size_t value = std::abs(playerValue);
std::size_t upcard = std::abs(dealerValue);
#ifdef BJDEBUG
std::cout << "player " << playerValue << " dealer " << dealerValue << std::endl;
#endif
value = std::abs(playerValue);
upcard = std::abs(dealerValue);
// first, we see if we can and shold split
if (canSplit &&
((playerValue == -12 && pair[11][upcard] == Libreblackjack::PlayerActionTaken::Split) ||
pair[value][upcard] == Libreblackjack::PlayerActionTaken::Split)) {
actionTaken = Libreblackjack::PlayerActionTaken::Split;

} else {
actionTaken = (playerValue < 0) ? soft[value][upcard] : hard[value][upcard]; actionTaken = (playerValue < 0) ? soft[value][upcard] : hard[value][upcard];
// TODO: double
if (actionTaken == Libreblackjack::PlayerActionTaken::Double) {
actionTaken = Libreblackjack::PlayerActionTaken::Hit;
if (canDouble == false) {
if (actionTaken == Libreblackjack::PlayerActionTaken::Double) {
actionTaken = Libreblackjack::PlayerActionTaken::Hit;
}
} }
}
/*
}
#ifdef BJDEBUG
if (actionTaken == Libreblackjack::PlayerActionTaken::Hit) { if (actionTaken == Libreblackjack::PlayerActionTaken::Hit) {
std::cout << "hit" << std::endl; std::cout << "hit" << std::endl;
} else if (actionTaken == Libreblackjack::PlayerActionTaken::Stand) { } else if (actionTaken == Libreblackjack::PlayerActionTaken::Stand) {
std::cout << "stand" << std::endl; std::cout << "stand" << std::endl;
} else if (actionTaken == Libreblackjack::PlayerActionTaken::Split) {
std::cout << "split" << std::endl;
} else { } else {
std::cout << "none" << std::endl; std::cout << "none" << std::endl;
} }
*/
#endif
break; break;
case Libreblackjack::PlayerActionRequired::None: case Libreblackjack::PlayerActionRequired::None:

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