Skip to content

Commit 8049acf

Browse files
committed
option to keep drawing even if the player busted
1 parent 9732ac0 commit 8049acf

5 files changed

Lines changed: 79 additions & 61 deletions

File tree

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
rules = s17
2-
hands = 1e5
3-
rng_seed = 12345
2+
hands = 1e6
3+
# rng_seed = 12345
4+
decks = 0
5+

src/blackjack.cpp

Lines changed: 52 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ Blackjack::Blackjack(Configuration &conf) : Dealer(conf), rng(dev_random()), fif
202202
///conf+quit_when_arranged_cards_run_out+example quit_when_arranged_cards_run_out = false
203203
///conf+quit_when_arranged_cards_run_out+example quit_when_arranged_cards_run_out = true
204204
conf.set(&quit_when_arranged_cards_run_out, {"quit_when_arranged_cards_run_out"});
205-
205+
206206
///conf+new_hand_reset_cards+usage `new_hand_reset_cards_out = ` $b$
207207
///conf+new_hand_reset_cards+details If the are arranged cards (either with `cards` or `cards_file`) and $b$ is `true`
208208
///conf+new_hand_reset_cards+details then when a hand is finished, the next hand starts with the arranged cards from the very beginning.
@@ -226,6 +226,19 @@ Blackjack::Blackjack(Configuration &conf) : Dealer(conf), rng(dev_random()), fif
226226
///conf+new_hand_reset_cards+example new_hand_reset_cards = true
227227
conf.set(&new_hand_reset_cards, {"new_hand_reset_cards"});
228228

229+
///conf+dealer_draws_even_if_player_busted+usage `dealer_draws_even_if_player_busted = ` $b$
230+
///conf+dealer_draws_even_if_player_busted+details The usual rule in casinos is that if all player busted all hands (including split hands),
231+
///conf+dealer_draws_even_if_player_busted+details the dealer does not have to draw until sixteen (or soft seventeen) but the hand is finihsed
232+
///conf+dealer_draws_even_if_player_busted+details and the next card in the shoe (or shuffler) is the player's first card of the next hand.
233+
///conf+dealer_draws_even_if_player_busted+details Yet, this rule may distort some statistics such as dealer's bust rate because for sure
234+
///conf+dealer_draws_even_if_player_busted+details he will not bust that hand.
235+
///conf+dealer_draws_even_if_player_busted+details This flag can modify the dealer's behavior and, if true, the dealer will draw cards
236+
///conf+dealer_draws_even_if_player_busted+details as normal even if the player had busted all her hands.
237+
///conf+dealer_draws_even_if_player_busted+default `false`
238+
///conf+dealer_draws_even_if_player_busted+example dealer_draws_even_if_player_busted = false
239+
///conf+dealer_draws_even_if_player_busted+example dealer_draws_even_if_player_busted = true
240+
conf.set(&dealer_draws_even_if_player_busted, {"dealer_draws_even_if_player_busted"});
241+
229242
// read arranged cards
230243
///conf+cards+usage `cards = ` $\text{list of cards}$
231244
///conf+cards+details If this option is given, the dealer draws the cards specified on the list.
@@ -249,10 +262,14 @@ Blackjack::Blackjack(Configuration &conf) : Dealer(conf), rng(dev_random()), fif
249262
///conf+cards+details ii. a set of infinite cards , if `decks` is zero.
250263
///conf+cards+details b. the hand is over and `new_hand_reset_cards` is `true`, or
251264
///conf+cards+details c. `quit_when_arranged_cards_run_out` is true, in which case the program exits.
265+
///conf+cards+details @
266+
///conf+cards+details A zero or `XX` means a placeholder for an actual random card. So for example `JS XX AC` will give
267+
///conf+cards+details the Jack of Spades, a random card and te Ace of Clubs.
268+
///conf+cards+details @
252269
///conf+cards+default Empty list
253270
///conf+cards+example cards = TH JD 6C
254-
///conf+cards+example cards = 2S 5D QS AC
255-
///conf+cards+example cards = 8D QH TC 2C KD 7S 8S TD AH 5C
271+
///conf+cards+example cards = 2S XX QS AC
272+
///conf+cards+example cards = 8D QH XX 2C KD 7S XX TD AH 5C
256273
if (conf.exists("cards")) {
257274
if (conf.exists("cards_file")) {
258275
std::cerr << "error: cannot have both cards and cards_file" << std::endl;
@@ -373,25 +390,27 @@ int Blackjack::read_arranged_cards(std::istringstream iss) {
373390
if (rank == 'X') { // placeholder for random
374391
n = 0;
375392
} else if (rank == 'A') {
376-
n = 1;
393+
n = 1;
377394
} else if (rank == 'T') {
378-
n = 10;
395+
n = 10;
379396
} else if (rank == 'J') {
380-
n = 11;
397+
n = 11;
381398
} else if (rank == 'Q') {
382-
n = 12;
399+
n = 12;
383400
} else if (rank == 'K') {
384-
n = 13;
401+
n = 13;
385402
} else {
386403
n = rank - '0';
387404
}
388-
if (n < 1 || n > 13) {
405+
if (n < 0 || n > 13) {
389406
std::cerr << "error: invalid ASCII card rank " << token << std::endl;
390407
return 1;
391408
}
392409

393410
if (suit != '\0') {
394-
if (suit == 'C') {
411+
if (suit == 'X') {
412+
n += 0;
413+
} else if (suit == 'C') {
395414
n += static_cast<int>(lbj::Suit::Clubs) * 13;
396415
} else if (suit == 'D') {
397416
n += static_cast<int>(lbj::Suit::Diamonds) * 13;
@@ -699,38 +718,42 @@ void Blackjack::deal(void) {
699718
} else {
700719
// assume the player busted in all the hands
701720
bool player_busted_all_hands = true;
702-
for (auto playerHand = playerStats.hands.begin(); playerHand != playerStats.hands.end(); playerHand++) {
721+
for (const auto &player_hand : playerStats.hands) {
703722
// if he (she) did not bust, set to false
704-
if (playerHand->busted() == false) {
723+
if (player_hand.busted() == false) {
705724
player_busted_all_hands = false;
706725
break;
707726
}
708727
}
709728

710729
if (player_busted_all_hands) {
711-
if (enhc == false) {
730+
if (enhc == false) {
712731
info(lbj::Info::CardDealerRevealsHole, dealer_hole_card);
713732
#ifdef BJDEBUG
714733
std::cout << "hole " << card[dealer_hole_card].utf8() << std::endl;
715734
#endif
716735
}
717-
// } else {
718-
playerStats.bustsPlayerAllHands++;
719-
// }
720-
721-
player->actionRequired = lbj::PlayerActionRequired::None;
722-
nextAction = lbj::DealerAction::StartNewHand;
723-
return;
736+
playerStats.bustsPlayerAllHands++;
737+
738+
if (dealer_draws_even_if_player_busted) {
739+
player->actionRequired = lbj::PlayerActionRequired::None;
740+
nextAction = lbj::DealerAction::HitDealerHand;
741+
return;
742+
} else {
743+
player->actionRequired = lbj::PlayerActionRequired::None;
744+
nextAction = lbj::DealerAction::StartNewHand;
745+
return;
746+
}
724747
} else {
725748
player->actionRequired = lbj::PlayerActionRequired::None;
726749
nextAction = lbj::DealerAction::HitDealerHand;
727750
return;
728751
}
729-
}
752+
}
730753
break;
731-
754+
732755
case lbj::DealerAction::HitDealerHand:
733-
756+
734757
if (enhc == false) {
735758
info(lbj::Info::CardDealerRevealsHole, dealer_hole_card);
736759
#ifdef BJDEBUG
@@ -740,11 +763,12 @@ void Blackjack::deal(void) {
740763

741764
// hit while count is less than 17 (or equal to soft 17 if hit_soft_17 is true)
742765
player->value_dealer = hand.value();
743-
while ((std::abs(player->value_dealer) < 17 || (h17 && player->value_dealer == -17)) && hand.busted() == 0) {
744-
unsigned int dealerCard = draw(&hand);
745-
info(lbj::Info::CardDealer, dealerCard);
766+
// while ((std::abs(dealer_value) < 17 || (h17 && dealer_value == -17)) && hand.busted() == false) {
767+
while (std::abs(player->value_dealer) < 17 || (h17 && player->value_dealer == -17)) {
768+
unsigned int dealer_card = draw(&hand);
769+
info(lbj::Info::CardDealer, dealer_card);
746770
#ifdef BJDEBUG
747-
std::cout << "dealer " << card[dealerCard].utf8() << std::endl;
771+
std::cout << "dealer " << card[dealer_card].utf8() << std::endl;
748772
#endif
749773
player->value_dealer = hand.value();
750774
}
@@ -780,7 +804,7 @@ void Blackjack::deal(void) {
780804
if (hand.busted()) {
781805
info(lbj::Info::DealerBusts, player->value_dealer);
782806
playerStats.bustsDealer++;
783-
for (auto playerHand : playerStats.hands) {
807+
for (const auto &playerHand : playerStats.hands) {
784808
if (playerHand.busted() == false) {
785809
// pay him (her)
786810
playerStats.bankroll += 2 * playerHand.bet;

src/blackjack.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ class Blackjack : public Dealer {
6565
bool shuffle_every_hand = false;
6666
bool quit_when_arranged_cards_run_out = false;
6767
bool new_hand_reset_cards = true;
68+
bool dealer_draws_even_if_player_busted = false;
6869

6970
std::vector<int> arranged_cards;
7071
size_t n_arranged_cards = 0; // just to prevent calling size() each time we draw a card

src/dealer.h

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -154,36 +154,36 @@ class Hand {
154154
std::list<unsigned int> cards;
155155

156156
// inline on purpose
157-
int value() {
157+
int value() const {
158158
unsigned int soft = 0;
159159
unsigned int n = 0;
160160
unsigned int value = 0;
161-
for (auto tag : cards) {
161+
for (const auto &tag : cards) {
162162
value = card[tag].value;
163163
n += value;
164164
soft += (value == 11);
165165
}
166-
166+
167167
// this loop should be only executed once if everything works fine
168168
while (n > 21 && soft > 0){
169169
n -= 10;
170170
soft--;
171171
}
172-
172+
173173
return (soft)?(-n):(n);
174174
};
175-
175+
176176
// inline on purpose
177-
bool blackjack() {
177+
bool blackjack() const {
178178
return (std::abs(value()) == 21 && cards.size() == 2);
179179
};
180-
180+
181181
// inline on purpose
182-
bool busted() {
182+
bool busted() const {
183183
return (std::abs(value()) > 21);
184184
}
185-
};
186-
185+
};
186+
187187
class PlayerHand : public Hand {
188188
public:
189189
PlayerHand(std::size_t i = 0) : id(i) { };

src/report.cpp

Lines changed: 12 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -66,35 +66,26 @@ void Dealer::prepareReport(void) {
6666

6767
report.push_back(reportItem(3, "busts_player_n", playerStats.bustsPlayer));
6868
report.push_back(reportItem(3, "busts_dealer_n", playerStats.bustsDealer));
69-
69+
7070
report.push_back(reportItem(3, "busts_player", playerStats.bustsPlayer / total));
71-
report.push_back(reportItem(3, "busts_player_nobj", playerStats.bustsPlayer / (total - playerStats.blackjacksPlayer)));
71+
report.push_back(reportItem(3, "busts_player_all", playerStats.bustsPlayerAllHands / total));
72+
report.push_back(reportItem(3, "busts_dealer", playerStats.bustsDealer / total));
7273

73-
double b1 = playerStats.bustsDealer / total;
74-
double b2 = playerStats.bustsDealer / (total - playerStats.bustsPlayerAllHands);
75-
double b3 = playerStats.bustsDealer / (total - playerStats.blackjacksDealer);
76-
double b4 = playerStats.bustsDealer / (total - playerStats.bustsPlayerAllHands - playerStats.blackjacksDealer);
77-
78-
// double b2 = b1 * (1 + (double)playerStats.bustsPlayerAllHands/total);
79-
// double b3 = b2 * (1 + (double)playerStats.blackjacksDealer/total);
80-
report.push_back(reportItem(3, "busts_dealer1", b1));
81-
// report.push_back(reportItem(3, "busts_dealer2old", playerStats.bustsDealer / (double) (n_hand - playerStats.bustsPlayerAllHands)));
82-
report.push_back(reportItem(3, "busts_dealer2", b2));
83-
// report.push_back(reportItem(3, "busts_dealer3old", playerStats.bustsDealer / (double) (n_hand - playerStats.bustsPlayerAllHands - playerStats.blackjacksDealer)));
84-
report.push_back(reportItem(3, "busts_dealer3", b3));
85-
report.push_back(reportItem(3, "busts_dealer3", b4));
74+
report.push_back(reportItem(3, "busts_player_nobust", playerStats.bustsPlayer / (total - playerStats.blackjacksDealer)));
75+
report.push_back(reportItem(3, "busts_dealer_nobust", playerStats.bustsDealer / (total - playerStats.blackjacksPlayer)));
76+
77+
report.push_back(reportItem(4, "blackjacks_player", playerStats.blackjacksPlayer / total));
78+
report.push_back(reportItem(4, "blackjacks_dealer", playerStats.blackjacksDealer / total));
79+
// if (playerStats.bustsPlayerAllHands != 0) {
80+
// report.push_back(reportItem(4, "blackjacks_dealer_real1", playerStats.blackjacksDealer / (double) (n_hand - playerStats.bustsPlayerAllHands)));
81+
// report.push_back(reportItem(4, "blackjacks_dealer_real2", playerStats.blackjacksDealer / (double) (n_hand - playerStats.bustsPlayer)));
82+
// }
8683

8784
report.push_back(reportItem(3, "wins", playerStats.wins / total));
8885
report.push_back(reportItem(3, "pushes", playerStats.pushes / total));
8986
report.push_back(reportItem(3, "losses", playerStats.losses / total));
9087

9188
report.push_back(reportItem(4, "total_money_waged", playerStats.totalMoneyWaged));
92-
report.push_back(reportItem(4, "blackjacks_player", playerStats.blackjacksPlayer / total));
93-
report.push_back(reportItem(4, "blackjacks_dealer", playerStats.blackjacksDealer / total));
94-
// if (playerStats.bustsPlayerAllHands != 0) {
95-
report.push_back(reportItem(4, "blackjacks_dealer_real1", playerStats.blackjacksDealer / (double) (n_hand - playerStats.bustsPlayerAllHands)));
96-
report.push_back(reportItem(4, "blackjacks_dealer_real2", playerStats.blackjacksDealer / (double) (n_hand - playerStats.bustsPlayer)));
97-
// }
9889

9990
report.push_back(reportItem(5, "variance", playerStats.variance));
10091
report.push_back(reportItem(5, "deviation", sqrt(playerStats.variance)));

0 commit comments

Comments
 (0)