Bookmark and Share


Play the game or view the source code.

2. The Player's Turn

At this point, the player may choose one of several options: surrender, double down, hit, stand or (if dealt a pair) split. Each option and the actions taken by the associated code are described below.


This one is easy. When a player surrenders, he or she is forfeiting the round in exchange for losing only half of his or her bet.

function playerSurrender() {

  // Unhighlight the player's hand.

  removeClassName(player[0].fieldNode, "activeField");

  // Note the surrender and end the round.

  player[0].surrender = true;

The playerSurrender() function simply flags the hand as having been surrendered and calls endRound() to end the round. Note that this option is only available after the initial deal.


This one is a little more complicated. If the player chooses to split a pair, a new hand has to be put into play for the player. The playerSplit() function handles this.

function playerSplit() {

  var m, n;
  var card, node;

  // Enable/disable buttons.


  // Update the number of player hands.

  m = curPlayerHand;
  n = numPlayerHands;

  // Note the split.

  player[m].split = true;
  player[n].split = true;

  // Remove the second card from the current hand and add it to a
  // new hand.

  card = player[m].removeCard();
  player[m].scoreTextNode.nodeValue = player[m].getScore();
  player[n].addCard(card, false);
  player[n].scoreTextNode.nodeValue = player[n].getScore();
  player[n].fieldNode.style.display = "";

  // Update bet and credits.

  player[n].bet = player[m].bet;
  credits -= player[n].bet;
  updateBetDisplay(n + 1);

  // Give the current hand a second card.

  setTimeout(playerHit, dealTimeDelay);

First it increments the global numPlayerHands and marks both the original and new hands as split. Then it removes the second card from the original hand and places it in the new one. The player must place a bet on this new hand equal to the bet on the original so credits are deducted and the new bet is placed.

The last step is to add a second card to the current hand to replace the one that was split off, so the playerHit() function is called. Again, a timer is used to cause a slight delay. Note that the buttons for play have been disabled. So the user can't press any while the timer is running.

The playerHit() function is also called when the "Hit" button is pressed (see below). Once it runs and exits, the game in left in step 2 so that player can play the original hand with the new second card. The new hand created by the split will be handled later.


A player can choose to "double down" meaning that he or she doubles the current bet on a hand and risks taking one and only one additional card. The playerDouble() function updates the bet and credits appropriately, flags the hand as a double down and calls playerHit() to add the additional card.

function playerDouble() {

  // Double the player's bet and deal a single card.

  player[curPlayerHand].bet *= 2;
  credits -= defaultBet;
  player[curPlayerHand].doubled = true;
  player[curPlayerHand].top = 0;

You might notice that it also alters the position for this new card before it is dealt, to give the user a visual cue.


The playerHit() function handles adding a card to a hand. It will first disable some of the other options and then deal a new card to the current hand.

function playerHit() {

  var n, p;

  // Enable/disable buttons.

  document.forms["controls"].elements["hit"].disabled   = false;
  document.forms["controls"].elements["stand"].disabled = false;

  // Give the player another card and find total.

  n = curPlayerHand;
  player[n].addCard(getNextCard(), false);
  p = player[n].getScore();


At this point we need to evaluate the hand and check flags to determine what to do next. Remember that playerHit() may have been called in response to the user pressing the "Hit" button, by the playerSplit() or playerDouble() functions. Where it was called from may affect the next course of action.

First we check the player's total to see if he or she has busted. If so, the hand is done so it will call startNextHand() and exit (moving to step 3).

  // If the player has busted, go to the next hand.

  if (p > 21) {
    player[n].scoreTextNode.nodeValue =  "Busted (" + p + ")";
    player[n].scoreTextNode.nodeValue = p;

Likewise, if the player has reached a score of 21, or if the player doubled down on the hand, we can also move on to the next step.

  // If the player has reached 21, or is doubling down, go on to the
  // next hand.

  if (p == 21 || player[n].doubled) {

The last check is to determine if the function was initiated from the playerSplit() function in order to add a new second card to a split hand.

  // Handle second card on split hands.

  if (player[n].split && player[n].cards.length == 2) {

    // If Aces were split, go on to next hand.

    if (player[n].split && player[n].cards[0].rank == "A") {

    // Enable/disable buttons.

    document.forms["controls"].elements["double"].disabled = false;
    if (canSplit())
      document.forms["controls"].elements["split"].disabled = false;

If this hand was just split, we check to see if it was a pair of aces. Since aces cannot be resplit and receive only one additional card, play should move onto the next hand (step 3). Of course, the next hand will be the one with the other ace that was split off, so this process will end up being repeated for that hand.

Otherwise, we treat this hand as though it were an initial deal, re-enabling the "Double" option and, if another pair was dealt, the "Split" option as well. In this case, we're basically starting over at step 2 with the current hand.


This one is easy to implement. The playerStand() function simply calls startNextHand() to move on to step 3.

function playerStand() {

  // Go on to the next hand.


We'll look at this function next.