Chapter 18
Script Example 4: Blackjack
In This Chapter
Game Time
In our final example, you take a break from the monotony of loans and other boring subjects. It's time to play a few hands of cards and prove that JavaScript is an effective environment for game creation. To this end, you'll cook up a little script that plays a simple game of blackjack.
First, define the ground rules for the game:
- For this demonstration, Aces have the value 11.
- All "face" cards (Jack, Queen, and King) have the value of 10.
- All cards will be dealt "face up." This means you'll know what the dealer (house) has from the start.
- The deck is "infinite," meaning you can draw more than one Ace of Spades in a row. For those of you fond of Las Vegas or Atlantic City, this is called a multiple-deck shoe.
- The user will click a Hit or Stand button, depending on whether they want another card.
- Once the user clicks Stand, the dealer starts drawing cards. The dealer continues to draw until either the house's hand totals more than 17 or the house busts. In other words, the house stands on 17.
- Once both the dealer and user stop taking cards, the winning hand is the one closest to 21 without going over (busting).
- If the dealer and the user have the same total at the end of a hand, they "push" (tie), and no one wins or loses.
Okay, so we cut a few corners with the rules. If you want to extend the game to handle such things as splits, doubles, betting, and Aces that are 1 or 11, please feel free.
Pick a Card
In Chapter 16, you saw how to create a function to generate a random number between 1 and some maximum value using the JavaScript Date object to get the current time (hours, minutes, and seconds). Since time is constantly changing, this provides a very basic, pseudo-random (almost random) generator. For review, here's the random() function:
function random(maxValue)
{
day = new Date();
hour = day.getHours();
min = day.getMinutes();
sec = day.getSeconds();
return (((hour + 1) * (min + 1) * sec) % maxValue) + 1;
}
This works quite nicely for your purposes, because you need to randomly pick two things for each card "drawn" from the deck:
- The suit: Spades, Clubs, Diamonds, or Hearts.
- The face value of the card: Ace, 2-10, Jack, Queen, or King.
Since there are four suits, you can write a function to pick a suit by randomly generating a number between 1 and 4:
function pickSuit()
{
suit = random(4);
if(suit == 1)
return "Spades";
if(suit == 2)
return "Clubs";
if(suit == 3)
return "Diamonds";
return "Hearts";
}
You really need to check suit only to see if it's 1, 2, or 3. If it isn't one of those, it must be 4 and you don't have to use an if statement to make sure. This is an "old programmer's trick" that saves a few keystrokes and a couple of steps when the program is running (if you want to drop a buzzword at your next party, this is called program optimization).
The next step is to pick the card from the suit. There are 13 cards in each suit: Ace, 2 through 10, Jack, Queen, and King. You need your card picker to return two things: the value of the card (a number from 2 to 11_remember, Aces are 11) and the name of the card (either the card number or the word "Jack," for instance). This causes a bit of a dilemma: "Jack", "Queen", "King", and "Ace" are all strings, but "2", "3", "5", and so on are numbers. You need both.
Since you need two distinct things from your card picker, make two distinct functions: one to return the value, and one to return the name. The value function simply takes the number of your card (a number from 1 to 13) and returns a value from 2 to 11:
function cardValue(card)
{
if(card == 1)
return 11;
if(card > 10)
return 10;
return card;
}
If the card is 1 (an Ace), you say it's worth 11. If the card is a face card, its number will be 11, 12, or 13, so you say it's worth 10. Otherwise, it's worth the number that's passed in.
Figuring out the card name is similar:
function cardName(card)
{
if(card == 1)
return "Ace";
if(card == 11)
return "Jack";
if(card == 12)
return "Queen";
if(card == 13)
return "King";
return "" + card;
}
Since each face card has a different name, you can't just say, "If it's greater than 10
," so you need a separate if statement for each face card. Finally, the number (spot) cards are simply returned, but you convert the value to a string (using the "" + trick).
Now, you can construct your PickACard() function:
function PickACard(strWho)
{
card = random(13);
suit = pickSuit();
alert(strWho + " picked the " + cardName(card) + " of " + suit);
return cardValue(card);
}
Return the card's value from PickACard() so you can use this function to add to the totals in the dealer's and user's hands. Also, the parameter strWho gives you the flexibility to call PickACard("You") or PickACard("Dealer") and have the alert() dialog say "Dealer picked
" or "You picked
" without having to write two separate functions (remember Rule #3 of JavaScript programming: Never do more typing than you have to).
You can test your card picker with the following short page:
<HTML>
<TITLE>Pick a Card</TITLE>
<HEAD>
<SCRIPT LANGUAGE="JavaScript">
<!- Hide from non-JavaScript browsers
function random(maxValue)
{
day = new Date();
hour = day.getHours();
min = day.getMinutes();
sec = day.getSeconds();
return (((hour + 1) * (min + 1) * sec) % maxValue) + 1;
}
function pickSuit()
{
suit = random(4);
if(suit == 1)
return "Spades";
if(suit == 2)
return "Clubs";
if(suit == 3)
return "Diamonds";
return "Hearts";
}
function cardName(card)
{
if(card == 1)
return "Ace";
if(card == 11)
return "Jack";
if(card == 12)
return "Queen";
if(card == 13)
return "King";
return "" + card;
}
function cardValue(card)
{
if(card == 1)
return 11;
if(card > 10)
return 10;
return card;
}
function PickACard(strWho)
{
card = random(13);
suit = pickSuit();
alert(strWho + " picked the " + cardName(card) + " of " + suit);
return cardValue(card);
}
//->
</SCRIPT>
</HEAD>
<BODY>
<FORM>
<INPUT TYPE=BUTTON VALUE="Pick A Card" onClick=PickACard("You")>
</FORM>
</BODY>
</HTML>
Clicking the Pick A Card button will generate a JavaScript alert box something like this.
Clicking repeatedly will pop up different card selections-so your card picker works! Start putting together the game logic, beginning with the dealer (which is a little more involved than the user).
Dealer Takes a Card
The user takes a card only when he clicks the Hit me button, but the dealer must repeatedly take cards (after the user clicks Stand) until the house's hand goes over 16. This means you have to set up a function that repeats the pickacard() process until 17 is reached or exceeded. If you think this sounds like a job for a while loop, you're right.
Recall the basic form of the while loop: "While {something} is 'true', keep doing something else." In this case, you want to keep picking cards while the total in the dealer's hand is less than 17:
function Dealer()
{
while(dealerHand < 17)
{
dealerHand = dealerHand + PickACard("Dealer");
}
}
Simple, isn't it? The function for when the user picks a card is even easier:
function User()
{
userHand = userHand + PickACard("You");
}
And, once everybody has taken all the cards they want, figuring out who won is a snap:
function LookAtHands()
{
if(dealerHand > 21)
{
alert("House busts! You win!");
}
else
if(userHand > dealerHand)
{
alert("You win!");
}
else
if(userHand == dealerHand)
{
alert("Push!");
}
else
{
alert("House wins!");
}
}
But what are userHand and dealerHand? They could be variables, but they really are placeholders for the form fields that you need to display this information to the user on the "game board." It's time to "spread the felt" and set up the gaming table.
Deal Me In
The game page needs two fields (for the house's and user's totals), and three buttons: Hit, Stand, and New Hand. Each button will have its own onClick event handler to process taking a card (for a hit) or having the dealer take cards (if the user chooses to stand). From the functions you've compiled so far, you can see that
- The Hit button should run the User() function and check to see whether the user has gone over 21.
- The Stand button should run the Dealer() function and then the LookAtHands() function to see who won.
- The New Hand button should reset the dealer's and user's hands to 0 and pick a new starting card for each.
Since you'll be dealing with an HTML <FORM>, you'll make the dealer's total field dealer, and the user's you. This means you have to replace userHand with form.you.value and dealerHand with form.dealer.value. The correct value for form can be passed into
the various functions from inside the HTML form by using the this.form qualifier.
For example:
<INPUT TYPE=BUTTON VALUE="Hit me!" onClick=User(this.form)>
This would pass the form into the User() function, so that you can update the user's total hand:
function User(form)
{
form.you.value = eval(form.you.value) + PickACard("You");
if(form.you.value > 21)
{
alert("You busted!");
}
}
JavaScript Is Very Fond of Strings
|
In fact, JavaScript will convert any form fields that are nothing but numbers into their string equivalents. This means that, if you want to change the value of a number in a field, you should first use the eval() function to make sure that the field value is treated as a number, not a string.
For example, if you had a form field called number and it was holding the value 23, adding 5 to it by:
form.number.value = form.number.value + 5;
would result in number having the value "235", as though you were tacking strings together. Use eval() to keep this from happening:
form.number.value = eval(form.number.value) + 5;
and the result will be "28".
|
By replacing userHand with form.you.value, you are writing the total of the user's hand back to the form for display. Accessing the dealer's hand information is done the same way.
Using the eval() function guarantees that the information in form.you.value is treated as a number, not a string (JavaScript has a tendency to look at things as strings, whether they are strings or not).
With that said, here's the complete script:
<HTML>
<TITLE>BlackJack</TITLE>
<HEAD>
<SCRIPT LANGUAGE="JavaScript">
<!- Hide from non-JavaScript browsers
function random(maxValue)
{
day = new Date();
hour = day.getHours();
min = day.getMinutes();
sec = day.getSeconds();
return (((hour + 1) * (min + 1) * sec) % maxValue) + 1;
}
function pickSuit()
{
suit = random(4);
if(suit == 1)
return "Spades";
if(suit == 2)
return "Clubs";
if(suit == 3)
return "Diamonds";
return "Hearts";
}
function cardName(card)
{
if(card == 1)
return "Ace";
if(card == 11)
return "Jack";
if(card == 12)
return "Queen";
if(card == 13)
return "King";
return "" + card;
}
function cardValue(card)
{
if(card == 1)
return 11;
if(card > 10)
return 10;
return card;
}
function PickACard(strWho)
{
card = random(13);
suit = pickSuit();
alert(strWho + " picked the " + cardName(card) + " of " + suit);
return cardValue(card);
}
function NewHand(form)
{
form.dealer.value = 0;
form.you.value = 0;
form.dealer.value = eval(form.dealer.value) + PickACard("Dealer");
form.you.value = eval(form.you.value) + PickACard("You");
}
function Dealer(form)
{
while(form.dealer.value < 17)
{
form.dealer.value = eval(form.dealer.value) + PickACard("Dealer");
}
}
function User(form)
{
form.you.value = eval(form.you.value) + PickACard("You");
if(form.you.value > 21)
{
alert("You busted!");
}
}
function LookAtHands(form)
{
if(form.dealer.value > 21)
{
alert("House busts! You win!");
}
else if(form.you.value > form.dealer.value)
{
alert("You win!");
}
else
if(form.dealer.value == form.you.value)
{
alert("Push!");
}
else
{
alert("House wins!");
}
}
//->
</SCRIPT>
</HEAD>
<BODY>
<CENTER><H2>BlackJack</H2></CENTER>
<CENTER>To start a hand, click 'New Hand'.</CENTER>
<CENTER>(Dealer stands on 17)</CENTER>
<HR>
<CENTER>
<FORM>
<TABLE BORDER=3>
<TR>
<TD>Dealer has</TD>
<TD><INPUT TYPE=TEXT NAME=dealer></TD>
</TR>
<TR>
<TD>You have</TD>
<TD><INPUT TYPE=TEXT NAME=you></TD>
</TR>
</TABLE>
<P>
<CENTER>
<INPUT TYPE=BUTTON VALUE="Hit me!" onClick=User(this.form)>
<INPUT TYPE=BUTTON VALUE="Stand" _onClick="Dealer(this.form);LookAtHands(this.form);">
<INPUT TYPE=BUTTON VALUE="New Hand" onClick=NewHand(this.form)>
</CENTER>
</FORM>
</CENTER>
</BODY>
</HTML>
From inside the browser, your blackjack game looks like this.
Gambling with JavaScript (it's cheaper than Vegas).
|
|
The Least You Need To Know
In this example, you looked at creating a game with JavaScript. Using the tools you've collected from previous chapters, you built a simple blackjack player. You also saw how using the while statement makes it possible to continue working inside a function until some condition is met. To make sure that the totals you were building in the form were correct, eval() makes sure that field values are treated as numbers rather than strings.



For comments or technical support for our books and software, select Talk to Us.
To order books, call us at 800-716-0044 or 317-228-4366.
© 1996, QUE Corporation, an imprint of Macmillan Publishing USA, a Simon & Schuster Company.