Can you get an advantage in Baccarat from knowing the burn card?

Can you get an advantage in Baccarat from knowing the burn card?

In todays issue we'll be exploring whether we can gain advantage in Baccarat just by knowing what the burn card is. This turns into a bit of a rabbit hole, with some very surprising results!

Theoretically, the removal of a few cards should affect the game, and by knowing what the burn card is we can infer that the odds of the game have changed.

What is the burn card?

The burn card is a card drawn at the beginning of each new shoe in baccarat. The dealer will draw the first card after the shuffle, and whatever the value of that card is, they will pull that many additional cards from the shoe and discard them. If the first card out is an Ace, then the dealer will remove one additional card. If it's a 10, J, Q, K then they will remove an additional 10 cards for discard.

This has essentially the same effect as increasing the depth of the cut card. If the cur card is 14 cards from the back, and the burn card is a 10, the cut card is now 25 (14 + 1 + 10).

The Experiment

We'll have a look at how each burn card value affects the expected value of each of the main wagers in baccarat and EZ baccarat.

All the wins will be tracked sorted by burn card value 0 - 9. 0 value cards represent 10, J, Q, K since they're worth 0 in the game, and 1- 9 represents cards A through 9.

We'll be running 100M shoes for this experiment.

The setup

The normal simulation constants

# Game Constants
EZ_BAC = True
NUM_DECKS = 8
NUM_SHOES = 100000000
CUT_CARD = 14

BANKER_PAYOUT = 0.95
if EZ_BAC:
    BANKER_PAYOUT = 1
PLAYER_PAYOUT = 1
TIE_PAYOUT = 8
DRAGON_PAYOUT = 40

I'll define some new constants to make tracking and saving cleaner and easier to read

# Burn card tracking index constants
PLAYER_W = 0
BANKER_W = 1
DRAGON_W = 2
TIE_W = 3
TOTAL = 4

Create a nested numpy array to store the wins

burn_card_tracking = np.zeros((10,5), dtype=np.int32)

At the beginning of each shoe the variables are reset, and a card is burnt

for _ in range(NUM_SHOES):
        dragon_wins = 0
        total_hands = 0
        banker_wins = 0
        player_wins = 0
        tie_wins = 0
        
        burn_card = deck[0]
        if burn_card == 0:
            indx = 11
        else:
            indx = burn_card + 1

And at the end of each shoe those wins are sorted by burn card value and saved

for _ in range(NUM_SHOES):
        dragon_wins = 0
        total_hands = 0
        banker_wins = 0
        player_wins = 0
        tie_wins = 0
        
        burn_card = deck[0]
        if burn_card == 0:
            indx = 11
        else:
            indx = burn_card + 1
          
        # Rest of game code
burn_card_tracking[burn_card][BANKER_W] += banker_wins
burn_card_tracking[burn_card][PLAYER_W] += player_wins
burn_card_tracking[burn_card][DRAGON_W] += dragon_wins
burn_card_tracking[burn_card][TIE_W] += tie_wins
burn_card_tracking[burn_card][TOTAL] += total_hands

And then finally after all shoes have completed the stats are calculated

burn_card_tracking = baccarat()
    for rank in range(10):
        player_wins = burn_card_tracking[rank][PLAYER_W]
        banker_wins = burn_card_tracking[rank][BANKER_W]
        tie_wins = burn_card_tracking[rank][TIE_W]
        dragon_wins = burn_card_tracking[rank][DRAGON_W]
        total_hands = burn_card_tracking[rank][TOTAL]
        burn_card_results[rank] = calculate_stats(player_wins, banker_wins, tie_wins, dragon_wins, total_hands)

After running the code for EZ Baccarat, I got some interesting results

[[ 1092811263  1067819277    55237962   233202626 -1845896168]]
burn_card = 0
{'EZ_BAC': True,
 'banker_ev': 1.353921549502879,
 'banker_wins': -57.848285050451445,
 'banker_wins_no_tie': -51.359717974036776,
 'dragon_he': -222.69143201341754,
 'player_ev': 1.6385524020438913,
 'player_wins': -59.20220659995432,
 'player_wins_no_tie': -52.56177658097376,
 'tie_ev': -213.70215022841955,
 'tie_wins': -12.633572247602173}

Specifically, we can see that the Banker and Player EV are positive. But there's a problem and after looking at the tracking data I realised that I am getting what's called integer overflow. The problem stems from when I defined the burn_card_tracking array with dtype=np.int32. So it'll need to be defined as np.int64 to avoid this. We can tell because the value of total_hands is -1845896168 - which clearly isnt correct.

After fixing this bug, and re-running the code we have our results

Simulation Results

Raw Data

Here's the raw data used to derive these statistics. The lists are indexed by the burn card (0 index is 10 value cards, 1 - 9 as normal):

# Burn card tracking index key
PLAYER_W = 0
BANKER_W = 1
DRAGON_W = 2
TIE_W = 3
TOTAL = 4

EZ Baccarat:

[[1092642239 1067649291   55239095  233121629 2448652254]
 [ 279468428  273100930   14127194   59598235  626294787]
 [ 278823193  272501229   14074179   59437055  624835656]
 [ 277821597  271576193   14012648   59231505  622641943]
 [ 277388731  271150566   13972212   59125958  621637467]
 [ 276797547  270463127   13939745   59002051  620202470]
 [ 276109295  269766504   13884547   58781918  618542264]
 [ 275410333  269149360   13850417   58668522  617078632]
 [ 274392101  268033913   13937087   58568073  614931174]
 [ 273677223  267329757   13892241   58383089  613282310]]

Standard Baccarat:

[[1092845556 1123057994          0  233188359 2449091909]
 [ 279384597  287170339          0   59609605  626164541]
 [ 278612883  286388779          0   59411148  624412810]
 [ 277973758  285723255          0   59263479  622960492]
 [ 277331841  285114058          0   59133201  621579100]
 [ 276664101  284234157          0   58960525  619858783]
 [ 276079710  283659478          0   58781902  618521090]
 [ 275185496  282739732          0   58600112  616525340]
 [ 274566738  282129020          0   58590445  615286203]
 [ 273827160  281433354          0   58418145  613678659]]

EZ Baccarat

Burn Card Banker EV (%) Banker Wins (%) Player EV (%) Player Wins (%) Tie EV (%) Tie Wins (%) Dragon HE (%)
Baseline -1.0184 43.6058 -1.2362 44.6242 -14.3614 9.5154 -7.5595
0 -1.0207 43.6015 -1.2352 44.6222 -14.3163 9.5204 -7.5082
1 -1.0167 43.6058 -1.2390 44.6225 -14.3560 9.5160 -7.5172
2 -1.0118 43.6117 -1.2407 44.6234 -14.3881 9.5124 -7.6491
3 -1.0030 43.6168 -1.2475 44.6198 -14.3836 9.5129 -7.7289
4 -1.0035 43.6188 -1.2441 44.6223 -14.3981 9.5113 -7.8465
5 -1.0213 43.6088 -1.2263 44.6302 -14.3798 9.5134 -7.8479
6 -1.0254 43.6133 -1.2193 44.6387 -14.4703 9.5033 -7.9664
7 -1.0146 43.6167 -1.2299 44.6313 -14.4328 9.5075 -7.9749
8 -1.0340 43.5876 -1.2325 44.6216 -14.2810 9.5243 -7.0757
9 -1.0350 43.5900 -1.2302 44.6250 -14.3220 9.5198 -7.1257

Standard Baccarat

Burn Card Banker EV (%) Banker Wins (%) Player EV (%) Player Wins (%) Tie EV (%) Tie Wins (%) Dragon HE (%)
Baseline -1.0600 45.8598 -1.2330 44.6268 -14.3790 9.5134 -100.0000
0 -1.0592 45.8561 -1.2336 44.6225 -14.3072 9.5214 -100.0000
1 -1.0497 45.8618 -1.2434 44.6184 -14.3218 9.5198 -100.0000
2 -1.0480 45.8653 -1.2453 44.6200 -14.3675 9.5147 -100.0000
3 -1.0493 45.8654 -1.2440 44.6214 -14.3812 9.5132 -100.0000
4 -1.0415 45.8693 -1.2520 44.6173 -14.3796 9.5134 -100.0000
5 -1.0715 45.8547 -1.2213 44.6334 -14.3926 9.5119 -100.0000
6 -1.0676 45.8609 -1.2255 44.6355 -14.4674 9.5036 -100.0000
7 -1.0677 45.8602 -1.2253 44.6349 -14.4559 9.5049 -100.0000
8 -1.0636 45.8533 -1.2291 44.6242 -14.2978 9.5225 -100.0000
9 -1.0536 45.8601 -1.2394 44.6206 -14.3260 9.5193 -100.0000

Notes:

  • EV = Expected Value (house edge)
  • Dragon HE shows -100.0000% for Standard Baccarat (bet not available)

Baccarat Expected Value Charts

Baccarat Expected Value Analysis

Impact of Card Removal on Bet Expected Values

EZ Baccarat
Banker (Left Axis)
Player (Left Axis)
Tie (Right Axis)
Dragon (Right Axis)
Standard Baccarat
Banker (Left Axis)
Player (Left Axis)
Tie (Right Axis)

Analyzing the Results

Ok, to be honest I did not expect these results. At the beginning of this experiment I did not think that there'd be any real detectable results and if there were, they'd be linearly scaled by burn card value.

But what we're actually seeing is that EV is increasing for the banker bet when 4 and 5 total cards are burnt. That's where our best gain is. We're seeing a parabolic ev curve based on the burn card, and similar results for the other bets. This is odd.

Now, I was a bit skeptical so I did a bit of math. I wasn't convinced that my sample size was large enough so I used the Margin of Error formula to get a confidence interval based on sample size n.

Margin of Error = z × √(σ²/n)

Where:
σ² = variance of outcomes
n = sample size
z = confidence level z-score

Using burn card 3 for our calculations, we'll need to calculate the variance.

Var(X) = E[X²] - (E[X])²

We need the Expected value of the squared outcomes E[X²] and the expected value, then squared (E[X])²

EV = (Probability of Win * Payout) - (Probability of Loss * Bet)

We only count winning or losing bets.

E[X] = 0.436168×(+1) + 0.446198×(-1) + 0.1176×(0) = -0.01003

And we get the same EV as in the chart. Now we'll calculate the total number of hands that are won or lost.

E[X²] = 0.436168×(1)² + 0.446198×(-1)² + 0.1176×(0)² = 0.882366
σ² = E[X²] - (E[X])²
σ² = 0.882366 - (-0.01003)²
σ² = 0.882366 - 0.0001 = 0.882266

The margin of error at 99% confidence is:

Margin of Error = z × √(σ²/n)
= 2.576 × √(0.882266/620M)
= 2.576 × 0.0000377
= 0.00009717 × 100
= 0.009717%

Our observed difference for EZ Baccarat using burn card 3 banker EV and baseline banker EV is 1.0184 - 1.0030 = 0.0154%

Our EV range from the baseline should be 1.008683 - 1.028117%

Confidence Level Z-Score Margin of Error Observed Effect vs Margin
90% 1.645 ±0.0062% 2.5x
95% 1.96 ±0.0074% 2.1x
99% 2.576 ±0.0097% 1.6x
99.9% 3.29 ±0.0124% 1.2x
99.99% 3.89 ±0.0147% 1.0x

Our observed difference is statistically significant up to 99% confidence, after that it becomes borderline.

In order to find the number of hands required for a confidence interval of 99.9% we can select a very precise margin of error of 0.00005 and use the following formula.

n = z² × σ² / d²
n = (3.29)² × 0.882266 / (0.00005)²
n = 10.82 × 0.882266 / 0.0000000025
n = 9.546 / 0.0000000025
n = 3,818,400,000 hands

Where:
d = desired margin of error
n = number of trials

This tells us that for each burn card we'd need to track 3.8B hands for the most precise results.

I think having a 99% confidence interval with our margin of error is acceptable.

I've organized all our results in the charts below. I've subtracted the newly calculated house edge (or ev) from the known baseline house edge of the particular wager, and listed the difference in the column beside it.

A positive difference means that burn card is good for the player, and a negative difference means that it's worse for the player.

EZ Baccarat Burn Card EVs and Differences

CardBanker EVBanker DiffPlayer EVPlayer DiffTie EVTie DiffDragon EVDragon Diff
Baseline-1.01840.0000-1.23620.0000-14.36140.0000-7.55950.0000
0-1.0207-0.0023-1.23520.0010-14.31630.0451-7.50820.0513
1-1.01670.0017-1.2390-0.0028-14.35600.0054-7.51720.0423
2-1.01180.0066-1.2407-0.0045-14.3881-0.0267-7.6491-0.0896
3-1.00300.0154-1.2475-0.0113-14.3836-0.0222-7.7289-0.1694
4-1.00350.0149-1.2441-0.0079-14.3981-0.0367-7.8465-0.2870
5-1.0213-0.0029-1.22630.0099-14.3798-0.0184-7.8479-0.2884
6-1.0254-0.0070-1.21930.0169-14.4703-0.1089-7.9664-0.4069
7-1.01460.0038-1.22990.0063-14.4328-0.0714-7.9749-0.4154
8-1.0340-0.0156-1.23250.0037-14.28100.0804-7.07570.4838
9-1.0350-0.0166-1.23020.0060-14.32200.0394-7.12570.4338
Raw Sum-0.00200.0173-0.1140-0.6455
Absolute Sum0.08680.07030.45462.6679

Standard Baccarat Burn Card EVs and Differences

CardBanker EVBanker DiffPlayer EVPlayer DiffTie EVTie Diff
Baseline-1.06000.0000-1.23300.0000-14.37900.0000
0-1.05920.0008-1.2336-0.0006-14.30720.0718
1-1.04970.0103-1.2434-0.0104-14.32180.0572
2-1.04800.0120-1.2453-0.0123-14.36750.0115
3-1.04930.0107-1.2440-0.0110-14.3812-0.0022
4-1.04150.0185-1.2520-0.0190-14.3796-0.0006
5-1.0715-0.0115-1.22130.0117-14.3926-0.0136
6-1.0676-0.0076-1.22550.0075-14.4674-0.0884
7-1.0677-0.0077-1.22530.0077-14.4559-0.0769
8-1.0636-0.0036-1.22910.0039-14.29780.0812
9-1.05360.0064-1.2394-0.0064-14.32600.0530
Raw Sum0.0283-0.02890.0930
Absolute Sum0.08910.09050.4564

I also added raw sum and absolute sum to the bottoms of the tables. The raw sum is all the differences summed, and the absolute sum is the sum of all differences as if they were all positive.

The raw sum tells us that the net analysis either has a more positive effect or negative effect. As in if the raw sum is positive, that means the bet has a more positive sensitivity to the cards being burnt. So the dragon has a negative raw sum because most of the burn cards produce a negative outcome for the bet.

The absolute sum tells us the sensitivity to the burn cards effects. Again, the dragon seems like it has a quite high sensitivity compared to the other bets.

All this is to say that in the end, yes we can gain an advantage just by knowing the burn card.

For all the EZ baccarat bets: the banker bet, if the burn card is a 3 or 4, we gain the largest reduction in the house edge by ~0.015% and a 0.0169% reduction in the house edge for the player bet when the cut card is a 6. The dragon bet's house edge is reduced the most - by 0.48% - when the burn card is an 8. The best burn card for the tie bet is an 8, reducing the house edge by 0.08%

The banker, tie and dragon bets have the least amount of helpful burn cards, while the player has the most.

While these burn cards provide a more advantageous situation we're not actually gaining a winning advantage, but rather a reduction in the house edge.