Work the Shell

Baccarat Punto Banco, Part II

Issue #161, September 2007

Remember that Baccarat hands can't go to 11 or even 10 for that matter.

Last month, we visited the rarefied climes of the expensive private player rooms at Monte Carlo to learn about the elite gambling game Baccarat. The game is straightforward, but it's governed by a fairly complicated set of rules.

At its most rudimentary though, Baccarat has two players: a Banker and a Player, and each is dealt two cards, the rank of which are summed up to calculate the winning hand.

Any hand worth 10 or more is divided by 10, so a 9 + 6 isn't 15, but 5, and a hand of 3 + 4 = 7 would indeed beat it.

It gets complicated in the case of whether the Banker should draw a third card. The Player can draw one card only on any two-card point value of less than six, but the Banker can draw based only on the Player's initial hand, the card the Player drew and the Banker's hand value. It works like this:

1. If the Player didn't draw a card, the Banker draws a card on 0–5 and stands otherwise.

2. If the Player drew a 2 or 3 and the Banker has a total of 0–4, the Banker draws a card.

3. If the Player drew a 4 or 5 and the Banker has a total of 0–5, the Banker draws a card.

4. If the Player drew a 6 or 7 and the Banker has a total of 0–6, the Banker draws a card.

5. If the Player drew an 8 and the Banker has a total of 0–2, the Banker draws a card.

6. If the Player drew a 9, 10, face card or ace and the Banker has a total of 0–3, the Banker draws a card.

In all situations not detailed above, the Banker cannot draw a card, and the Baccarat hand will end either with the Player winning, the Banker wining or an égalité, or tie.

As you can see, it's a set of rules that apparently could be loved only by a computer programmer, so it looks perfect for us to expand the baccarat.sh game in this direction.

On to the Script

Last month's Baccarat game took everything into account up to, but not including, the Banker picking a third card, with all the complicated rules detailed above.

Running it as is, here's a typical sequence:

```\$ sh baccarat.sh

Welcome to Baccarat. You can choose to either
stake the player or dealer to win this game.
Remember, face cards are worthless and all point values
are modulo 10, with '9' the best possible hand value.
We're using Punto Banco rules with this simulation,

** Player was dealt: 3 of Hearts, 10 of Clubs (hand value = 3)
** Dealer was dealt: 4 of Clubs, 10 of Spades (hand value = 4)

Player takes a card: 6 of Hearts (hand value = 12)

** Banker play rules yet to come...game ends inconclusively.
```

As you can see, instead of capturing the rules, I just have a “coming soon” stub. Think of it as, um, early alpha so far.

In fact, it's sufficiently in alpha that there's a bug displayed in the above sequence. Can you see it? How can the Player have a hand value of 12?

Fortunately, it's straightforward to see the problem:

```playerhandvalue=\$(( \$playerhandvalue +
\$handvalue ))
```

This is just plain wrong. Because the line above hands all three Player cards to the handValue function, all this needs to be is the simpler:

```playerhandvalue=\$handvalue
```

Phew. Easily fixed. Now, where were we?

One thing that we need to ascertain easily is whether the Player took a card. This can be done by actually testing the number of cards in the Player hand, but instead I simply create a new variable, playerDrewCard, setting it to zero on initial deal and flipping it to one if the Player takes another card.

Now, the first rule can be captured like this:

```if [ \$playerDrewCard -eq 0 ] ; then
if [ \$bankerhandvalue -lt 6 ] ; then
# Banker draws a card
banker[\$nextbankercard]=\${newdeck[\$nextcard]}

handValue \${banker[1]} \${banker[2]}
\${banker[3]}
bankerhandvalue=\$handvalue

echo -n "Banker takes a card: "
showCard \${banker[\$nextbankercard]}
echo "\$cardname (hand value =
\$bankerhandvalue)"
fi
else
```

Notice here that if the Player drew a card and the Banker's hand is worth six or more, there is no else clause, and correctly, there is no additional action before the end-game winner is determined.

The else at the bottom, however, is our gateway to the situation where neither the Banker nor Player has an 8 or 9 (which is already captured in the game) and where the Player took another card. Now, it's just a set of conditionals.

To make things easy though, let's have the Player's drawn card's rank handy:

```pdcRank=\$(( \${player[3]} % 13 ))
```

Unfortunately, although the man page for test indicates that you can group complicated tests logically with parentheses, pragmatic reality demonstrates that it's far less portable than we might desire, so instead of a nice (A or B) and C statement, we'll break each rule into two if statements, like this:

```if [ \$pdcRank -eq 2 -o \$pdcRank -eq 3 ] ; then
if [ \$bankerhandvalue -lt 5 ]; then
```

In this case, we're testing the card the Player took (card #3) and testing that the Banker's hand is below a certain value. If both are true, we have condition #2, above.

Now, it's just a matter of having a sequence of these tests in a row to build all the rules necessary for Punto Banco Baccarat.

In all its crazy-nested-if-statement glory:

```if [ \$pdcRank -eq 2 -o \$pdcRank -eq 3 ] ; then
if [ \$bankerhandvalue -lt 5 ]; then
dealBanker;
fi
elif [ \$pdcRank -eq 4 -o \$pdcRank -eq 5 ] ; then
if [ \$bankerhandvalue -lt 6 ] ; then
dealBanker;
fi
elif [ \$pdcRank -eq 6 -o \$pdcRank -eq 7 ] ; then
if [ \$bankerhandvalue -lt 7 ] ; then
dealBanker;
fi
elif [ \$pdcRank -eq 8 -a \$bankerhandvalue -lt 3 ]
then
dealBanker;
elif [ \$pdcRank -eq 9 -o \$pdcRank -eq 0 ] ; then
if [ \$bankerhandvalue -lt 4 ] ; then
dealBanker;
fi
fi
```

Finally, we can play Baccarat on our handy Linux box:

```> sh baccarat.sh

Welcome to Baccarat. You can choose to either stake
the player or banker to win this game. Remember, face
cards are worthless and all point values are modulo 10,
with '9' the best possible hand value. We're using Punto
Banco rules with this simulation, if you're already an expert...

** Player was dealt: 6 of Clubs, 8 of Hearts (hand value = 4)
** Banker was dealt: King of Spades, Ace of Hearts (hand value = 1)

Player takes a card: 9 of Hearts (hand value = 3)
Banker takes a card: 5 of Clubs (hand value = 6)

Play is complete. Banker wins
```

Of course, now you can run this a few million times and calculate the odds of the Banker winning versus the Player winning versus the tie situation and be a cool, calculated gambler next time you're in the south of France. Helpful, eh?

Dave Taylor is a 26-year veteran of UNIX, creator of The Elm Mail System, and most recently author of both the best-selling Wicked Cool Shell Scripts and Teach Yourself Unix in 24 Hours, among his 16 technical books. His main Web site is at www.intuitive.com, and he also offers up tech support at AskDaveTaylor.com.