'Unexpected Result' is a tech blog by a self-taught developer whose passions for continuous growth and to stay busy led to an accidental Master's in Computer Science and a fortuitous position with a fantastic software consultancy firm. Each post or series highlights a point of interest to software developers and users, and features tangents that follow the author's stream of consciousness.

2013-02-07

Value of an Ace

I made a Blackjack game to test myself on the JavaScript I have learned so far. (Link to it at the bottom of this post.) The greatest challenge I faced in getting the game to work was the variable value of an Ace. As you will know if you're familiar with the game of Blackjack, the objective is to get the player's hand as close as possible to a value of 21, without going over (which is an automatic loss). The player starts with two cards, and can continually ask for more cards until the player fears "busting" (going over 21), then the player may stop and pray that the dealer will do a worse job.

Aces behave in a special way in this game, as they are generally valued at 11, but their value changes if the player accidentally goes over 21. If the player is holding an Ace and goes over 21, the Ace will drop from a value of 11 to just 1. This value changes as the player draws new cards, and every Ace drawn will behave this way independently. So I needed to handle the scoring of a hand in a way that would allow the value of an Ace to be evaluated anew every time a new card was drawn.

When I started building the scoring function I ran into some problems. The first problem was timing. Because Aces change their value based on the non-Ace cards in the player's hand, I couldn't evaluate the player's hand in the order it was dealt.

Take the following example, in which the player is dealt (and the player hand is populated with) 5, 4, Ace, and 8, in that order. If I evaluate the cards in order, I would come to the Ace at a time when the cumulative value of the hand is still only 9 (first 5, then add the next card, 4). Since the 8 hasn't been added yet, the Ace seems like a great addition to the hand at this point, because even if I'm checking for bust (going over 21), 9 + Ace (11) would be 20, which is very close to 21. But then, when the 8 is added, the player would bust - I would want to evaluate the Ace as a 1, but it would be too late, the Ace was already evaluated!

One solution that came to mind early on was to reiterate through the hand any time a bust was detected, and check for Aces. I could subtract 10 from the total value of the hand for each Ace (if any) until the value of the hand came back to under 22 (leaving any remaining Ace valued at 11). But this struck me as a rather inelegant and scrappy solution. I wanted to evaluate the Aces on the fly so I wouldn't have to feel like I was "going back" and removing value that had already been added to the hand.

I got around this by adding the value of each non-Ace to the value of the hand and leaving out the values of any Aces, but counting the number of Aces. Only after the non-Ace value of the hand was evaluated, I began to evaluate and add in the value of each Ace. This is where things became complicated algorithmically. I needed to put together an algorithm to check not just whether an Ace would bust the hand, but whether an Ace would bust the hand in light of the fact that there is a variable quantity of Aces left to evaluate!

Here's what I came up with, I'll explain it below.

The good part is the for loop at line 24, where Ace values are evaluated. The for loop iterates through all the Aces. For each Ace, I check whether the hand would bust if the Ace was valued at 11, and all remaining Aces were valued at 1. If the hand would bust, the Ace is evaluated to 1; otherwise, it gets an 11 and the loop continues.

In retrospect, and as more experienced developers / mathematicians / Blackjack players will likely have noticed, this excessively elaborate Ace evaluation algorithm is entirely unnecessary! You only ever have to check whether the first Ace would bust the hand. If one Ace is valued at 11, you know all the rest must be valued at 1, because if two Aces evaluated to 11, you would already have busted with 22. Oops! If I continue to iterate this game with future editions, I will fix this inefficiency (because now it's bugging me).

If you want to try out the game, you're of course welcome! Be warned, it's fairly rudimentary as Blackjack games go, I was more concerned with getting JavaScript up and running on a website than with putting together a faithful representation of the game of Blackjack. (No betting, can't double down or split, no automatic win for Blackjack, but the basics are all there, single player versus a dealer.) Also, as a bare-bones first attempt at writing my own JS in the wild, the entire game exists in alert() and confirm() pop-ups, so apologies for all the clicking you'll have to do to play it! At any rate, here it is.