-->
Bookmark and Share

Blackjack

Play the game or view the source code.

The Blackjack Hand Object

The Hand object is designed to represent an individual blackjack hand and the cards in it. It provides methods for actions like adding a card to the hand, removing a card and totaling the its score.

When the game is first initialized, one of these objects is created for each possible hand. This includes the dealer's hand and an array of hands for the player (in case of splits). The constructor function is shown below.

Hand.prototype.leftIncr  =  2.5;  // For positioning cards.
Hand.prototype.topIncr   =  0.2;
Hand.prototype.rollEvery =  5;

function Hand(id) {

  this.cards = new Array();

  // Get page elements based on id.

  this.fieldNode     = document.getElementById(id);
  this.cardsNode     = document.getElementById(id + "Cards");
  this.scoreTextNode = document.getElementById(id + "Score").firstChild;
  if (id != "dealer") {
    this.betTextNode =
      document.getElementById(id + "Bet").firstChild;
    this.resultTextNode =
      document.getElementById(id + "Result").firstChild;
  }

  this.reset      = handReset;
  this.addCard    = handAddCard;
  this.removeCard = handRemoveCard;
  this.getScore   = handGetScore;
  this.clearCards = handClearCards;

  // Initialize as an empty hand.

  this.reset();
}

To create a hand, an ID string is passed to the function so it can find the elements reserved for that particular hand's playing area on the page. These references are saved for later use.

This only needs to be done once. Other properties of the Hand object are only relevant to an individual round. These are defined and set in the reset() method which is used to initialize a hand for play.

function handReset() {

  // Remove any cards and initialize properties.

  this.clearCards();

  this.cards     = new Array();
  this.blackjack = false;
  this.split     = false;
  this.doubled   = false;
  this.surrender = false;
  this.left      = 0;
  this.top       = 0;

  this.scoreTextNode.nodeValue  = "\u00a0";
  if (this.betTextNode) {
    this.betTextNode.parentNode.className = "textBox dollars";
    this.betTextNode.nodeValue = "\u00a0";
  }
  if (this.resultTextNode)
    this.resultTextNode.nodeValue = "\u00a0";
}

First it removes any cards used in the previous round. Then it initializes several flags and values that will be used during the course of play. Finally, it resets any text displays in the hand's playing area. The flags used during game play will be discussed shortly but first let's look at how the cards are displayed.

Displaying Cards

To add a card to a hand, the addCard() method is used. It adds the given Card object to the hand's cards array and creates a DOM node for displaying it. This node is dynamically added to cardArea class DIV assigned to the hand (stored as the property cardsNode) so it will appear on the page. Note that it allows an option to display the card face down.

function handAddCard(card, down) {

  var n;
  var node;

  // Add the given card to the hand.

  n = this.cards.length;
  this.cards[n] = card;

  // Create a card node for display, set as face down if requested.

  node = this.cards[n].createNode();
  if (down)
    node.firstChild.style.visibility = "hidden";

  // Add the card display to the associated card area on the page.

  node.style.left = this.left + "em";
  node.style.top  = this.top  + "em";
  this.cardsNode.appendChild(node);
  this.left += this.leftIncr;
  if (this.cards.length % this.rollEvery == 0)
    this.top = 0;
  else
    this.top += this.topIncr;
}

Likewise, the removeCard() method will remove the last Card object in the cards array and remove the last card node from the cardsNode DIV so that it no longer appears on the page.

function handRemoveCard() {

  var card;

  // Remove the last card in the array and save it.

  card = null;
  if (this.cards.length > 0) {
    card = this.cards.pop();

    // Remove the card node from the display and reset position.

    this.cardsNode.removeChild(this.cardsNode.lastChild);
    this.left -= this.leftIncr;
    this.top  -= this.topIncr;
  }

  // Return the card.

  return card;
}

The card that was removed is returned by the function. This makes it useful for handling splits, as we'll see later.

Finally, there is the clearCards() method which provides a quick way to remove all the card nodes from a playing area.

function handClearCards() {

  // Remove the card nodes in the associated card area.

  while (this.cardsNode.lastChild)
    this.cardsNode.removeChild(this.cardsNode.lastChild);
}

This method is actually used only indirectly via the reset() method to initialize the hand for play.

Scoring

Since the object of the game is to score points by totaling the value of each card in a hand, a method is defined to calculate this total. While it seems simple enough to just add up each card's value, the fact that aces can be counted as one or eleven complicates the task a bit. The getScore() method is defined to handle this.

function handGetScore() {

  var i, total;

  total = 0;

  // Total card values counting Aces as one.

  for (i = 0; i < this.cards.length; i++)
    if (this.cards[i].rank == "A")
      total++;
    else {
      if (this.cards[i].rank == "J" || this.cards[i].rank == "Q" ||
          this.cards[i].rank == "K")
        total += 10;
      else
        total += parseInt(this.cards[i].rank, 10);
    }

  // Change as many ace values to 11 as possible.

  for (i = 0; i < this.cards.length; i++)
    if (this.cards[i].rank == "A" && total <= 11)
      total += 10;

  return total;
}

Basically, it first totals each card value, counting any ace as one point. Then it goes through the cards again looking only at aces. If it finds one and it can be counted as eleven without pushing the total over 21, it does so. This way, the method returns the highest score possible, without going over 21, for the hand.