Blackjack
Play the game or view the source code.1. Starting a Round
The startRound()
function first does a little housekeeping.
This involves resetting the hands from the previous round, enabling and
disabling form buttons and checking if a new deck is needed.
function startRound() { var i; // Reset all hands. dealer.reset(); for (i = 0; i < player.length; i++) { player[i].reset(); if (i > 0) player[i].fieldNode.style.display = "none"; } // Start with a single player hand. curPlayerHand = 0; numPlayerHands = 1; // Enable/disable buttons. document.forms["controls"].elements["deal"].disabled = true; document.forms["controls"].elements["increase"].disabled = true; document.forms["controls"].elements["decrease"].disabled = true; DisablePlayButtons(); // If the burn card was reached, start a new deck. if (deck.cardCount() < burnCard) { alert("New deck."); newDeck(); } ...
The DisablePlayButtons()
function simply disables the "Split,"
"Double," "Surrender," "Hit" and "Stand" buttons. This must be done at several
other points in the code so it makes sense to define a function for it.
Next it takes the player's bet, deducting the amount from the player's credits.
// Take the player's bet. player[0].bet = defaultBet; credits -= player[0].bet; updateBetDisplay(0);
The final step is to start dealing the initial cards for the player and the
dealer. We could just call the .addCard()
method twice on each
hand. But then all the cards would appear on the page at once. It's more
desirable to have a short pause before each card is dealt.
JavaScript has no function for pausing execution. Performing a busy wait,
say with an empty for
loop between each deal of a card, wouldn't
help either. The browser will not update the display while script code is
executing. A busy wait would just lock up the browser for a time, then all the
cards would appear at once.
Instead, we create a function to deal one card at a time. To cause a delay
between each deal of a card, the built-in setTimeout()
function
will be used. To start things off, the global variable
dealRoundCounter
is set to one and dealRound()
is
called.
// Start dealing the cards. dealRoundCounter = 1; dealRound();
Dealing the Cards
Within dealRound()
a card is dealt according to the value of
dealRoundCounter.
The first to the player, the second to the
dealer, etc.
function dealRound() { // Deal a card to the player or the dealer based on the counter. switch(dealRoundCounter) { case 1: player[0].addCard(getNextCard(), false); break; case 2: dealer.addCard(getNextCard(), true); break; case 3: player[0].addCard(getNextCard(), false); break; case 4: dealer.addCard(getNextCard(), false); break; default: // No more cards to deal, play the round. playRound(); return; break; } // Update the player's score. if (player[0].getScore() == 21) { player[0].blackjack = true; player[0].scoreTextNode.nodeValue = "Blackjack"; } else player[0].scoreTextNode.nodeValue = player[0].getScore(); // Set a timer for the next call. dealRoundCounter++; setTimeout(dealRound, dealTimeDelay); }
Once a card is dealt, the player's score is updated, the counter is
incremented, setTimeout()
is called to fire another call to
dealRound
(after a delay determined by dealTimeDelay
)
and the function exits.
By ending code execution, the browser is free to update the page, showing
the new card. When the timer expires, dealRound
will execute again
to deal the next card. After all the card have been dealt, the
playRound()
function is called and we exit without setting a
timer.
Evaluating the Initial Hands
The playRound()
function examines the initial cards dealt to
the player and the dealer to determine what action to take.
First, if the dealer's face up card is an Ace, we need to offer the player
insurance. As insurance is a side bet, the outcome doesn't affect the rest of
the game play so a call is made to doInsurance()
to handle this
(see below) before moving on.
function playRound() { // If dealer's up card is an ace, offer insurance. if (dealer.cards[1].rank == "A") offerInsurance();
If either the player or the dealer has a blackjack, the round is over.
The function checks and will call endRound()
to finish the round
and exit (step 5).
// Check for dealer blackjack. if (dealer.getScore() == 21) { dealer.blackjack = true; dealer.scoreTextNode.nodeValue = "Blackjack"; } // If player or dealer has blackjack, end the round. if (player[0].blackjack || dealer.blackjack) { endRound(); return; }
If neither has blackjack, we move on and enable the play buttons: "Split" (if the player was dealt a pair), "Double," "Surrender," "Hit" and "Stand." The player's hand is highlighted and the function exits, leaving the game at step 2, where the next action will depend on which button the player presses.
// Enable/disable buttons. if (canSplit()) document.forms["controls"].elements["split"].disabled = false; document.forms["controls"].elements["double"].disabled = false; document.forms["controls"].elements["surrender"].disabled = false; document.forms["controls"].elements["hit"].disabled = false; document.forms["controls"].elements["stand"].disabled = false; // Highlight the player's hand. addClassName(player[0].fieldNode, "activeField"); }
Insurance
The doInsurance()
function will prompt the player using the
built-in confirm()
function, so execution will halt until the
player responds to the dialog box.
function offerInsurance() { var amount; // Offer insurance bet to player. This is a side bet so it's resolved // here. if (confirm("Do you want to buy insurance?")) { // Take half of player's current bet from credits. amount = player[0].bet / 2; credits -= amount; // If the dealer has blackjack, show the down card and pay player at // 2 to 1. if (dealer.getScore() == 21) { dealer.cardsNode.firstChild.firstChild.style.visibility = ""; credits += player[0].bet; alert("Dealer has Blackjack, you win " + formatDollar(player[0].bet)); } else alert("Dealer does not have Blackjack, you lose " + formatDollar(amount)); // Update credits. updateBetDisplay(0); } }
If the player selects "OK" to buy insurance, it adjusts the player's credits
and checks the dealer's hand for a blackjack. If the dealer has blackjack, it
updates the player's credits again to pay off the bet. In any case, it returns
execution to the calling function, playRound().