Work the Shell - <emphasis>Baccarat Punto Banco</emphasis>, Part II

 in
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, 
if you're already an expert...

** 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 has been hacking shell scripts for over thirty years. Really. He's the author of the popular "Wicked Cool Shell Scripts" and can be found on Twitter as @DaveTaylor and more generally at www.DaveTaylorOnline.com.

Webinar
One Click, Universal Protection: Implementing Centralized Security Policies on Linux Systems

As Linux continues to play an ever increasing role in corporate data centers and institutions, ensuring the integrity and protection of these systems must be a priority. With 60% of the world's websites and an increasing share of organization's mission-critical workloads running on Linux, failing to stop malware and other advanced threats on Linux can increasingly impact an organization's reputation and bottom line.

Learn More

Sponsored by Bit9

Webinar
Linux Backup and Recovery Webinar

Most companies incorporate backup procedures for critical data, which can be restored quickly if a loss occurs. However, fewer companies are prepared for catastrophic system failures, in which they lose all data, the entire operating system, applications, settings, patches and more, reducing their system(s) to “bare metal.” After all, before data can be restored to a system, there must be a system to restore it to.

In this one hour webinar, learn how to enhance your existing backup strategies for better disaster recovery preparedness using Storix System Backup Administrator (SBAdmin), a highly flexible bare-metal recovery solution for UNIX and Linux systems.

Learn More

Sponsored by Storix