Professional Documents
Culture Documents
Mastering Javascript and Jscript: Bonus Chapter Two: Programming Games
Mastering Javascript and Jscript: Bonus Chapter Two: Programming Games
TRADEMARKS: SYBEX has attempted throughout this book to distinguish proprietary trademarks from descriptive terms by
following the capitalization style used by the manufacturer.
Netscape Communications, the Netscape Communications logo, Netscape, and Netscape Navigator are trademarks of
Netscape Communications Corporation.
Microsoft® Internet Explorer ©1996 Microsoft Corporation. All rights reserved. Microsoft, the Microsoft Internet Explorer logo,
Windows, Windows NT, and the Windows logo are either registered trademarks or trademarks of Microsoft Corporation in
the United States and/or other countries.
The author and publisher have made their best efforts to prepare this book, and the content is based upon final release soft-
ware whenever possible. Portions of the manuscript may be based upon pre-release versions supplied by software manufac-
turer(s). The author and the publisher make no representation or warranties of any kind with regard to the completeness or
accuracy of the contents herein and accept no liability of any kind including but not limited to performance, merchantability,
fitness for any particular purpose, or any losses or damages of any kind caused or alleged to be caused directly or indirectly
from this book.
Photographs and illustrations used in this book have been downloaded from publicly accessible file archives and are used in
this book for news reportage purposes only to demonstrate the variety of graphics resources available via electronic access.
Text and images available over the Internet may be subject to copyright and other rights owned by third parties. Online avail-
ability of text and images does not imply that they may be reused without the permission of rights holders, although the
Copyright Act does permit certain unauthorized reuse as fair use under 17 U.S.C. Section 107.
Copyright ©1999 SYBEX Inc., 1151 Marina Village Parkway, Alameda, CA 94501. World rights reserved. No part of this pub-
lication may be stored in a retrieval system, transmitted, or reproduced in any way, including but not limited to photocopy,
photograph, magnetic or other record, without the prior agreement and written permission of the publisher.
2492web2.qxd 3/4/99 10:25 AM Page 1
B O N U S C H A PT E R
T W O 2
Programming Games
■ Poker Machine
■ Board Game
I
n this chapter, you’ll have some fun as you learn more JavaScript game pro-
gramming. First, you’ll develop a poker machine that will let you play poker
against your browser. Then, you’ll develop a board game that I call Web Walk,
which will test your knowledge of the Web. Of course, the chapter isn’t only fun
and games—by programming these entertaining projects, you’ll learn some very
useful skills, including how to use JavaScript to build appealing user interfaces,
to work with images, and to respond to a variety of user interface events. When
you finish this chapter, you’ll be able to develop your own games in JavaScript.
Poker Machine
The first game that you’ll develop is a JavaScript version of a Vegas-style poker
machine. In this game, you place an initial bet of $1.00 and are dealt five cards
that you use to try to form a poker hand. Refer to Table 1 for a description and
ranking of possible poker hands.
4 Full house Three cards of one rank and two cards of another
8 Two pair Two cards of the same rank and two cards of another rank
10 Everything else
Poker Machine 3
After receiving your five cards, you are allowed to discard any unwanted cards
and receive an equal number of replacement cards in return. (You discard a card
by clicking on it.) Once you have been dealt your replacement cards, you will
receive a payoff based on the value of your hand. Table 2 summarizes the payoff
algorithm.
Hand Payoff
Flush $ 50.00
Straight $ 25.00
To play this game, open poker.htm. The program will display the screen shown
in Figure 1 until it loads all of the card images. It will then deal you a five-card
hand, as shown in Figure 2. You are also given $100.00 dollars to start with—the
You Have $ text box displays your current budget for the game. The amount is
updated after each hand. (Each hand costs $1.00 to play.)
If you’re happy with the hand you were dealt, click on the Continue button to
play the next hand. Otherwise, click on any cards that you want to discard—they
will be turned over, as shown in Figure 3—and then click on the Continue button.
You can discard only once per each hand. The cards you indicated as discards
will be replaced, and you will be told of your winnings, as shown in Figure 4.
Click on the Continue button to play another hand.
FIGURE 1:
Poker machine being
loaded (Listing 1)
FIGURE 2:
Poker machine initial deal
(Listing 1)
Poker Machine 5
FIGURE 3:
Selecting cards to discard
(Listing 1)
FIGURE 4:
A winning hand
(Listing 1)
Poker Machine 7
}
}
function play() {
state=”deal”
shuffleDeck()
dealCards()
}
function shuffleDeck() {
for(var i=0;i<52;++i) deck[i]=i
for(var i=0;i<52;++i) {
var temp=deck[i]
var rand=Math.round(Math.random()*51)
deck[i]=deck[rand]
deck[rand]=temp
}
}
function dealCards() {
for(var i=0;i<5;++i){
cards[i]=deck[i]
replacements[i]=deck[5+i]
}
displayCards()
window.document.forms[0].status.value=”$”+budget
var msg=”Click on the cards you want to discard. “
msg+=”When finished, click on Continue.”
window.defaultStatus=msg
state=”draw”
}
function displayCards() {
for(var i=0;i<5;++i)
window.document.images[i].src=cardImages[cards[i]].src
}
function processCard(n) {
if(state==”draw”) {
var img=window.document.images[n]
if(img.src!=cardImages[cards[n]].src)
img.src=cardImages[cards[n]].src
else img.src=”blank.gif”
}
}
function statusChange() {
alert(“Are you cheating?”)
window.document.forms[0].status.value=”$”+budget
}
function continueClicked() {
if(state==”draw”) {
state=”payoff”
for(var i=0;i<5;++i) {
var img=window.document.images[i]
if(img.src!=cardImages[cards[i]].src) {
cards[i]=replacements[i]
img.src=cardImages[cards[i]].src
}
}
showPayoff()
}else if(state==”payoff”) play()
}
function showPayoff() {
var payoff=-1
evaluateHand()
if(isRoyalFlush()) payoff=1000
else if(isStraightFlush()) payoff=500
else if(isFourOfAKind()) payoff=250
else if(isFullHouse()) payoff=100
else if(isFlush()) payoff=50
else if(isStraight()) payoff=25
else if(isThreeOfAKind()) payoff=10
else if(isTwoPair()) payoff=5
else if(isJacksOrBetter()) payoff=1
else msg=”You lose $1.”
window.defaultStatus=msg+” Click on Continue to play again.”
budget+=payoff
window.document.forms[0].status.value=”$”+budget
}
function compare(a,b) {
return a-b
}
function evaluateHand() {
for(var i=0;i<5;++i) {
rank[i]=cards[i]%13+1
suit[i]=Math.floor(cards[i]/13)
}
rank=rank.sort(compare)
}
Poker Machine 9
function isRoyalFlush() {
if(sameSuit() && straight()) {
if(rank[0]==1 && rank[1]==10) {
msg=”A ROYAL FLUSH! You win $1000.”
return true
}
}
return false
}
function sameSuit() {
if(suit[0]==suit[1] && suit[0]==suit[2]
&& suit[0]==suit[3] && suit[0]==suit[4]) return true
return false
}
function straight() {
var aceHi = new Array(5)
for(var i=0;i<5;++i) {
aceHi[i]=rank[i]
if(aceHi[i]==1) aceHi[i]=14
}
if(straightCheck(rank)) return true
if(straightCheck(aceHi.sort(compare))) return true
return false
}
function straightCheck(a) {
for(var i=0;i<4;++i)
if(a[i]+1!=a[i+1]) return false
return true
}
function isStraightFlush() {
if(sameSuit() && straight()) {
msg=”A STRAIGHT FLUSH! You win $500.”
return true
}
return false
}
function isFlush() {
if(sameSuit()) {
msg=”A FLUSH! You win $50.”
return true
}
return false
}
function isStraight() {
if(straight()) {
msg=”A STRAIGHT! You win $25.”
return true
}
return false
}
function isFourOfAKind() {
for(var i=0;i<2;++i) {
if(matches(rank[i])==4) {
msg=”FOUR OF A KIND! You win $250.”
return true
}
}
return false
}
function matches(n) {
var count=0
for(var i=0;i<5;++i)
if(rank[i]==n) ++count
return count
}
function isThreeOfAKind() {
for(var i=0;i<3;++i) {
if(matches(rank[i])==3) {
msg=”THREE OF A KIND! You win $10.”
return true
}
}
return false
}
function isFullHouse() {
var matched3 = false
var matched2 = false
for(var i=0;i<4;++i) {
if(matches(rank[i])==3) matched3=true
else if(matches(rank[i])==2) matched2=true
}
if(matched3 && matched2) {
msg=”A FULL HOUSE! You win $100.”
return true
Poker Machine 11
}
return false
}
function isTwoPair() {
var count = 0
for(var i=0;i<5;++i)
if(matches(rank[i])==2) ++count
if(count==4) {
msg=”TWO PAIR! You win $5.”
return true
}
return false
}
function isJacksOrBetter() {
for(var i=0;i<5;++i) {
if(matches(rank[i])==2){
if(rank[i]==1 || rank[i]>10){
msg=”A PAIR OF “
msg+=jacksOrBetterPairName(rank[i])
msg+=”! You win $1.”
return true
}
}
}
return false
}
function jacksOrBetterPairName(n) {
if(n==1) return “ACES”
if(n==11) return “JACKS”
if(n==12) return “QUEENS”
if(n==13) return “KINGS”
return “”
}
// —></SCRIPT>
</HEAD>
<BODY BGCOLOR=”white”>
<TABLE>
<TR>
<TD COLSPAN=”5”>
<H1 ALIGN=”CENTER”>Poker Machine</H1></TD>
</TR>
<TR>
Poker Machine 13
TIP Whenever you require images to be loaded before the main part of a script
begins, use time-outs to check for the completion of image loading.
Poker Machine 15
Poker Machine 17
FIGURE 5:
The opening screen of
Web Walk (Listing 2)
FIGURE 6:
The message in the
right frame tells you how
many squares to move
(Listing 3).
FIGURE 7:
Footprints mark your move
(Listing 3).
When you click on the last square of your move, you will either be told to
move again (Figure 8) or a question will appear in the right side of the window
(Figure 9). This is determined by the type of square you have landed on. If the
square is labeled with an integer, then you will be told to move the indicated
number of squares forward or backward. If you land on a square that is labeled
with a Q, then you will be asked a question. If you answer the question correctly
(Figure 10), you will be told to move forward either one, two, or three squares.
If you answer the question incorrectly, you will be told to move backward one,
two, or three squares.
FIGURE 8:
A new message appears
when you finish your move
on a numbered square
(Listing 3).
The object of the game is to get to the End square, as shown in Figure 11. To get
there, you must correctly answer the questions along the way.
FIGURE 9:
A question appears when
you land on a square
labeled Q (Listing 3).
FIGURE 10:
Answer the question
correctly to move
forward (Listing 3).
FIGURE 11:
Work your way to the
End square to win
(Listing 3).
The number of ways to tailor Web Walk is infinite—feel free to substitute your
own questions and adapt the game to your needs.
The webwalk.htm file sets up a two-frame set: the left frame runs the JavaScript
code in ww.htm, and the right frame is used to display messages and questions.
}
}else msg(“Can’t move there!”)
}
}
function board(n) {
return boardLayout[Math.floor(n/8)][n%8]
}
function steps() {
return Math.round((Math.random()*2)+1)
}
function move() {
var squares=” squares.”
if(stepsToMove==1) squares=” square.”
var dir=” forward “
if(direction==”B”) dir=” backward “
return “Move”+dir+stepsToMove+squares
}
function canMove(n) {
for(var i=0;i<validMoves.length;++i){
if(direction==”F” && validMoves[i].from==position &&
validMoves[i].to==n) return true
if(direction==”B” && validMoves[i].from==n &&
validMoves[i].to==position) return true
}
return false
}
function restoreCurrentPosition() {
var sq=board(position)
var imgPos=imagePosition(position)
var oldImage=questionGIF
if(sq==”s”) return
else if(sq==”1”) oldImage=plus1GIF
else if(sq==”3”) oldImage=plus3GIF
else if(sq==”6”) oldImage=plus6GIF
else if(sq==”-1”) oldImage=minus1GIF
else if(sq==”-2”) oldImage=minus2GIF
else if(sq==”-3”) oldImage=minus3GIF
else if(sq==”-5”) oldImage=minus5GIF
else if(sq==”-6”) oldImage=minus6GIF
else if(sq==”-10”) oldImage=minus10GIF
window.document.images[imgPos].src=oldImage.src
}
function imagePosition(n) {
imageCount=0
for(var i=0;i<n;++i)
if(board(i)!=””) ++imageCount
var len=window.document.images.length
// Fixes bug in Navigator 3.0
if(len>38) imageCount+=Math.floor(len/2)
return imageCount
}
function showMovement(n) {
var imgPos=imagePosition(n)
window.document.images[imgPos].src=feetGIF.src
}
function processMovement(n) {
position=n
—stepsToMove
if(stepsToMove==0){
var sq=board(position)
var num=0
if(sq==”q”) askQuestion()
else{
num=parseInt(sq)
if(num<0) direction=”B”
else direction=”F”
stepsToMove=Math.abs(num)
state=”move”
msg(move())
}
}else{
state=”move”
msg(move())
}
}
function winner() {
var doc=parent.frames[1].document
doc.open()
doc.writeln(‘<BODY BGCOLOR=”white”>’)
doc.writeln(‘<H3>Congratulations — You Won!!!</H3>’)
doc.writeln(‘Click Reload to play again.’)
doc.writeln(‘</BODY>’)
doc.close()
}
function Question() {
this.question=Question.arguments[0]
var n=Question.arguments.length
this.answers = new Array(n-2)
for(var i=1; i<n-1; ++i) this.answers[i-1]=Question.arguments[i]
this.correctAnswer=Question.arguments[n-1]
}
function askQuestion() {
rnd=Math.round(Math.random()*(qa.length-1))
var doc=parent.frames[1].document
doc.open()
doc.writeln(‘<HTML>’)
doc.writeln(‘<BODY BGCOLOR=”white”>’)
doc.writeln(“<H4 ALIGN=’CENTER’>”+qa[rnd].question+”</H4>”)
doc.writeln(‘<FORM NAME=”answerForm”>’)
for(var ii=0;ii<qa[rnd].answers.length;++ii) {
doc.writeln(‘<H4 ALIGN=”CENTER”>’)
doc.write(‘<INPUT TYPE=”RADIO” NAME=”answer”>’)
doc.writeln(qa[rnd].answers[ii])
if(ii+1==qa[rnd].answers.length) {
doc.write(‘<BR><BR><INPUT TYPE=”BUTTON”’)
doc.writeln(‘NAME=”continue” VALUE=”Continue” ‘)
doc.writeln(‘ onClick=”parent.frames[0].focus()”>’)
}
doc.writeln(‘</H4>’)
}
doc.writeln(‘</FORM>’)
doc.writeln(‘</BODY></HTML>’)
doc.close()
}
function checkAnswers() {
if(state!=”wait”) return
var numAnswers=qa[rnd].answers.length
var correctAnswer=qa[rnd].correctAnswer
var doc=parent.frames[1].document
for(var jj=0;jj<numAnswers;++jj) {
if(doc.answerForm.elements[jj].checked) {
if(jj==correctAnswer){
correct()
break
}else{
incorrect()
break
}
}
if(jj==numAnswers){
incorrect()
break
}
}
}
function correct() {
var num=steps()
direction=”F”
stepsToMove=num
state=”move”
msg(“<H4>Correct!</H4>”+move())
}
function incorrect() {
var num=steps()
direction=”B”
stepsToMove=num
state=”move”
msg(“<H4>Incorrect.</H4>”+move())
}
//Questions
qa = new Array()
qa[0] = new Question(“Who created the Web?”,
“Marc Andreessen”,
“James Gosling”,
“Tim Berners-Lee”,
“Bill Gates”,
2)
qa[1] = new Question(“Who invented HTML?”,
“Marc Andreessen”,
“James Gosling”,
“Tim Berners-Lee”,
“Bill Gates”,
2)
qa[2] = new Question(“Who is the creator of Mosaic?”,
“Marc Andreessen”,
“James Gosling”,
“Tim Berners-Lee”,
“Bill Gates”,
0)
qa[3] = new Question(“Who is the creator of JavaScript?”,
“Tim Berners-Lee”,
“Spike Lee”,
“Brendan Eich”,
“Marc Andreessen”,
2)
qa[4] = new Question(“What is Lynx?”,
“A mark-up language”,
“A Web browser”,
“A Web server”,
“A protocol”,
1)
qa[5] = new Question(“What company created Java?”,
“Microsoft”,
“Sun Microsystems”,
“Netscape”,
“IBM”,
1)
qa[6] = new Question(“What company created JavaScript ?”,
“Microsoft”,
“Sun Microsystems”,
“Netscape”,
“IBM”,
2)
qa[7] = new Question(“Where was the Web created?”,
“CERN”,
“NCSA”,
“MIT”,
“USC”,
0)
qa[8] = new Question(“Where was Mosaic created?”,
“CERN”,
“NCSA”,
“MIT”,
“USC”,
1)
qa[9] = new Question(“What is HTTP?”,
“A mark-up language”,
“A protocol”,
“A Web server”,
“A Web browser”,
1)
qa[10] = new Question(“Which of the following speak HTTP?”,
“Web browsers”,
“Web servers”,
“Both Web browsers and servers”,
“None of the above”,
2)
qa[11] = new Question(“Where do CGI programs run?”,
“On browsers”,
“On Web servers”,
“On both Web browsers and servers”,
“None of the above”,
1)
qa[12] = new Question(“What is a MIME type?”,
“A CGI program”,
“A file type identifier”,
“A plug-in”,
“A protocol”,
1)
qa[13] = new Question(“What is a plug-in?”,
“A CGI program”,
“A helper program that executes in the context of a browser”,
“An external helper program”,
“A protocol”,
1)
qa[14] = new Question(“What is LiveScript?”,
“The precursor to JavaScript”,
“An ActiveX scripting language”,
“A Visual Basic scripting language”,
“A C++ scripting language”,
0)
qa[15] = new Question(“What is an event?”,
“An object that represents the occurrence of an action”,
“A function that responds to an action”,
“An HTML tag”,
“A protocol data unit”,
0)
qa[16] = new Question(“What is an event handler?”,
“An object that represents the occurrence of an action”,
“A function that responds to an action”,
“An HTML tag”,
“A protocol data unit”,
1)
qa[17] = new Question(“What is an object type?”,
“A MIME type”,
“An HTML tag”,
“An HTML attribute”,
“A template for defining and creating objects”,
3)
qa[18] = new Question(“What is an object?”,
“A function that does not return a value”,
“An HTML tag”,
“A VRML document”,
“An instance of an object type”,
3)
qa[19] = new Question(“What is a property?”,
“A function that is associated with an object”,
“A data item that is associated with an object”,
“A JavaScript syntax rule”,
“An object type”,
1)
qa[20] = new Question(“What is a method?”,
“A function that is associated with an object”,
“A data item that is associated with an object”,
“A JavaScript syntax rule”,
“An object type”,
0)
qa[21] = new Question(“What is an applet?”,
“A Macintosh program”,
“A small script”,
“An ActiveX script”,
“A Java program that executes in the context of a browser”,
3)
// —></SCRIPT>
</HEAD>
<BODY BGCOLOR=”white” onLoad=”startGame()” onFocus=”checkAnswers()”>
<TABLE BGCOLOR=”black”>
<TR>
<TD><A HREF=”javascript:void(0)” onClick=”square(0)”>
<IMG SRC=”start.gif” BORDER=”0”></A></TD>
<TD><A HREF=”javascript:void(0)” onClick=”square(1)”>
<IMG SRC=”plus6.gif” BORDER=”0”></A></TD>
<TD><A HREF=”javascript:void(0)” onClick=”square(2)”>
<IMG SRC=”plus3.gif” BORDER=”0”></A></TD>
The ww.htm file is very long. It contains the code to implement the game plus all
of the questions and answers displayed in the right frame set. To understand how
ww.htm works, start with the document body. The generateBoard() function is
invoked to display the game board, and the loadImages() function is used to load
cached copies of the images displayed in the game. When these documents have
completed their processing, the startGame() function is invoked to handle the
document’s onLoad event. The checkAnswers() function is invoked to handle the
onFocus event. This occurs when the user has answered a question that is dis-
played in the right frame of the window. The data and functions defined in the
document head are presented in the following paragraphs.
s Starting square
e Ending square
q Question square
an integer Square that specifies a forward (positive integer) or backward (negative integer)
movement
NOTE I’ve included a fix in the imagePosition() function to address a Navigator bug that
sometimes causes the length of the images array to be doubled.
• The user has landed on a number square: the method automatically moves
the user that many squares forward or backward.
• The user has landed on a Q square: askQuestion() is invoked to ask the
user a question.
Summary 39
The qa Array
This array is used to store the Question objects used in the game. (Refer to Chap-
ter 8, “Using Hidden Fields and Cookies.”)
Summary
In this chapter you learned to program JavaScript games. You created a poker
game that lets you play against your browser—good luck collecting your win-
nings! You also developed the Web Walk board game, which can be easily tailored
to a variety of subjects.