Lean CSS
Welcome to CSS
Introduction to CSS
CSS Syntax
Insert style sheet
CSS Background
CSS Text
CSS Font
CSS Border
CSS Margin
CSS Padding
CSS List
CSS Dimensions
CSS Classification
CSS Positioning
CSS classes
CSS elements
CSS2 Media Types
CSS Units
CSS Colors
 

Free Tutorials
HTML
Learn HTML
Learn CSS
Learn XML
Learn WML
Database
Learn Access
Learn Data-VB
Learn Oracle
Learn SQL
Programming
Learn C++
Learn JavaScript
Learn Vbscript
Learn VisualBasic

Chapter 15

Real-Life Examples III


CONTENTS

This chapter includes a single example program: a poker solitaire game written in JavaScript. This is the largest program presented in this guide and illustrates the following concepts from previous chapters:

In addition, it's a good demonstration of a large-scale JavaScript application. The next sections describe and present the program.

Planning the Program

The task for this example is to create a JavaScript poker solitaire game. The game board, at the start of a game, is shown in Figure 15.1. Here is a summary of how the game is played:

Figure 15.1 : The Poker Solitaire game board at the start of a game.

  • The board consists of 25 squares in a 5-by-5 grid. A "draw" card is on the lower right corner.
  • The computer deals cards one at a time. Each card appears in the draw pile. You can click on one of the 25 squares in the grid to move the card to the board.
  • Scoring is based on poker hands. Each row, column, and diagonal is a separate hand, and is scored when it is completed. The total score is a combination of all of these.
  • The game ends when 25 cards have been dealt. You can also click on the New Game link to start over.

Before you move on to the program itself, let's look at a few of the challenges of planning a project of this size:

  • The board consists of 25 squares. By including a title graphic, I conveniently made these the 1st through 25th images on the page-this will make them easy to access via the document.images array.
  • I used a custom object, Card, to store information about the cards in the game. This object includes a number (1-13) and a suit (c, h, s, or d.)
  • The deck of cards is stored in an array called deck; each element is a Card object.
  • The cards currently on the board are placed in an array called board. Once again, these are Card objects.
  • I created 52 images-one for each card-and a blank image to represent blank spaces on the board. These are all exactly the same size, so they can be easily swapped inline.
  • The whole game board is laid out using a table. The first column includes a link to start a new game and the total score, columns 2 through 6 are the game board, and the last column and row are used for text fields. These will hold the score for each column, row, and diagonal.

Tip
You'll find the graphics you need for this example (cards, blank card, title) on the CD-ROM accompanying this guide.

The Complete Application

Without further ado, Listing 15.1 shows the complete Poker Solitaire application, including all HTML and JavaScript functions.


Listing 15.1. (CARDS.asp) The Poker Solitaire application (HTML and JavaScript).
<HTML> <HEAD> <TITLE>Poker Solitaire</TITLE> <SCRIPT LANGUAGE="JavaScript"> // global variables var tally = new Array(14) var nextcard = 1; var nexti = new Image(53,68); // numeric comparison for sort () function numsort (a,b){ return a-b; } function InitGame() { nextcard = 1; // clear scores for (i=0; i<5; i++) { document.form1.col[i].value = " "; document.form1.row[i].value = " "; document.form1.diag1.value = " "; document.form1.diag2.value = " "; document.form1.total.value = " "; } // array for board contents board = new Array(26); for (i=1; i<26; i++) { board[i] = new Card(0,"x"); document.images[i].src = "blank.gif"; } // fill the deck (in order, for now) deck = new Array(53); for (i=1; i<14; i++) { deck[i] = new Card(i,"c"); deck[i+13] = new Card(i,"h"); deck[i+26] = new Card(i,"s"); deck[i+39] = new Card(i,"d"); } // shuffle the deck n = Math.floor(52 * Math.random() + 200); for (i=1; i<n; i++) { card1 = Math.floor(52*Math.random() + 1); card2 = Math.floor(52*Math.random() + 1); if (card1 != card2) { temp = deck[card2]; deck[card2] = deck[card1]; deck[card1] = temp; } } // draw the first card on screen document.images[26].src = deck[nextcard].fname(); nexti.src = deck[nextcard+1].fname(); // end InitGame } // place the draw card on the board where clicked function PlaceCard(pos) { if (board[pos].suit != "x") { return; } document.images[pos].src = document.images[26].src; document.images[26].src = "blank.gif"; board[pos] = deck[nextcard]; nextcard++; Score(); if (nextcard > 25) { EndGame(); } else { document.images[26].src = deck[nextcard].fname(); // cache next image for draw pile nexti = new Image(53,68); nexti.src = deck[nextcard+1].fname(); } } // check for completed rows and display row scores function Score() { totscore = 0; // rows for (x=0; x<5; x++) { r = x * 5 + 1; a = AddScore(board[r],board[r+1],board[r+2],board[r+3],board[r+4]) if (a != -1) { document.form1.row[x].value = a; totscore += a; } } // columns for (x=0; x<5; x++) { r = x + 1; a = AddScore(board[r],board[r+5],board[r+10],board[r+15],board[r+20]) if (a != -1) { document.form1.col[x].value = a; totscore += a; } } // diagonals a = AddScore(board[5],board[9],board[13],board[17],board[21]) if (a != -1) { document.form1.diag1.value = a; totscore += a; } a = AddScore(board[1],board[7],board[13],board[19],board[25]) if (a != -1) { document.form1.diag2.value = a; totscore += a; } document.form1.total.value = totscore; } // check for poker hands function AddScore(c1,c2,c3,c4,c5) { straight = false; flush = false; pairs = 0; three = false; // sorted array for convenience nums = new Array(5); nums[0] = c1.num; nums[1] = c2.num; nums[2] = c3.num; nums[3] = c4.num; nums[4] = c5.num; nums.sort(numsort); // no score if row is not filled if (c1.num == 0 || c2.num == 0 || c3.num == 0 || c4.num == 0 || c5.num == 0) { return -1; } // flush if (c1.suit == c2.suit && c2.suit == c3.suit && c3.suit == c4.suit && c4.suit == c5.suit) { flush = true; } // straight if (nums[0] + 4 == nums[1] + 3 == nums[2] +2 == nums[3] + 1 == nums[4]) { straight = true; } // royal flush, straight flush, straight, flush if (straight && flush && nums[4]==13) return 250; if (straight && flush) return 50; if (straight) return 4; if (flush) return 5; // tally array is a count for each card value for (i=1; i<14; i++) { tally[i] = 0; } for (i=0; i<5; i++) { tally[nums[i]] += 1; } for (i=1; i<14; i++) { // four of a kind if (tally[i] == 4) return 25; if (tally[i] == 3) three = true; if (tally[i] == 2) pairs += 1; } // full house if (three && pairs == 1) return 8; // two pair if (pairs == 2) return 2; // three of a kind if (three) return 3; // just a pair if (pairs == 1) return 1; // nothing return 0; // end AddScore() } // game over - final score function EndGame() { document.images[26].src = "blank.gif"; window.alert("Game Over"); } // make a filename for an image, given Card object function fname() { return this.num + this.suit + ".gif"; } // constructor for Card objects function Card(num,suit) { this.num = num; this.suit = suit; this.fname = fname; } </SCRIPT> </HEAD> <BODY> <FORM NAME="form1"> <TABLE> <tr> <td> <img src="title.gif" height=59 width=150> </td> <td> <a href="#" onClick="PlaceCard(1);"> <img border=0 src="blank.gif" height=68 width=53></a> <td> <a href="#" onClick="PlaceCard(2);"> <img border=0 src="blank.gif" height=68 width=53></a> <td> <a href="#" onClick="PlaceCard(3);"> <img border=0 src="blank.gif" height=68 width=53></a> <td> <a href="#" onClick="PlaceCard(4);"> <img border=0 src="blank.gif" height=68 width=53></a> <td> <a href="#" onClick="PlaceCard(5);"> <img border=0 src="blank.gif" height=68 width=53></a> <td> <INPUT TYPE="TEXT" SIZE=4 NAME="row"> </td> <td> </td> </tr> <tr> <td> </td> <td> <a href="#" onClick="PlaceCard(6);"> <img border=0 src="blank.gif" height=68 width=53></a> <td> <a href="#" onClick="PlaceCard(7);"> <img border=0 src="blank.gif" height=68 width=53></a> <td> <a href="#" onClick="PlaceCard(8);"> <img border=0 src="blank.gif" height=68 width=53></a> <td> <a href="#" onClick="PlaceCard(9);"> <img border=0 src="blank.gif" height=68 width=53></a> <td> <a href="#" onClick="PlaceCard(10);"> <img border=0 src="blank.gif" height=68 width=53></a> <td> <INPUT TYPE="TEXT" SIZE=4 NAME="row"> </td> <td> </td> </tr> <tr> <td> <B>Total<BR>Score:</B> <INPUT TYPE="TEXT" SIZE=5 NAME="total"></td> <td> <a href="#" onClick="PlaceCard(11);"> <img border=0 src="blank.gif" height=68 width=53></a> <td> <a href="#" onClick="PlaceCard(12);"> <img border=0 src="blank.gif" height=68 width=53></a> <td> <a href="#" onClick="PlaceCard(13);"> <img border=0 src="blank.gif" height=68 width=53></a> <td> <a href="#" onClick="PlaceCard(14);"> <img border=0 src="blank.gif" height=68 width=53></a> <td> <a href="#" onClick="PlaceCard(15);"> <img border=0 src="blank.gif" height=68 width=53></a> <td> <INPUT TYPE="TEXT" SIZE=4 NAME="row"> </td> <td> </td> </tr> <tr> <td> <a href="#" onClick="InitGame();"> <b>New Game</b></a> <br><b><a href="psoldoc.asp">Instructions</b></a></td> <td> <a href="#" onClick="PlaceCard(16);"> <img border=0 src="blank.gif" height=68 width=53></a> <td> <a href="#" onClick="PlaceCard(17);"> <img border=0 src="blank.gif" height=68 width=53></a> <td> <a href="#" onClick="PlaceCard(18);"> <img border=0 src="blank.gif" height=68 width=53></a> <td> <a href="#" onClick="PlaceCard(19);"> <img border=0 src="blank.gif" height=68 width=53></a> <td> <a href="#" onClick="PlaceCard(20);"> <img border=0 src="blank.gif" height=68 width=53></a> <td> <INPUT TYPE="TEXT" SIZE=4 NAME="row"> </td> <td> <b><BR>Next<BR>Card:</b></td> </tr> <tr> <td> </td> <td> <a href="#" onClick="PlaceCard(21);"> <img border=0 src="blank.gif" height=68 width=53></a> <td> <a href="#" onClick="PlaceCard(22);"> <img border=0 src="blank.gif" height=68 width=53></a> <td> <a href="#" onClick="PlaceCard(23);"> <img border=0 src="blank.gif" height=68 width=53></a> <td> <a href="#" onClick="PlaceCard(24);"> <img border=0 src="blank.gif" height=68 width=53></a> <td> <a href="#" onClick="PlaceCard(25);"> <img border=0 src="blank.gif" height=68 width=53></a> <td> <INPUT TYPE="TEXT" SIZE=4 NAME="row"> </td> <td> <img src="blank.gif" height=68 width=53></td> </tr> <tr> <td align=right> <INPUT TYPE="TEXT" SIZE=4 NAME="diag1"> </td> <td> <INPUT TYPE="TEXT" SIZE=4 NAME="col"> </td> <td> <INPUT TYPE="TEXT" SIZE=4 NAME="col"> </td> <td> <INPUT TYPE="TEXT" SIZE=4 NAME="col"> </td> <td> <INPUT TYPE="TEXT" SIZE=4 NAME="col"> </td> <td> <INPUT TYPE="TEXT" SIZE=4 NAME="col"> </td> <td> <INPUT TYPE="TEXT" SIZE=4 NAME="diag2"> </td> </TABLE> </FORM> </BODY> </HTML>

How the Program Works

The HTML for this application is nearly as complicated as the JavaScript code, but it's easy because it's repetitive. Each of the images in the game board includes an onClick event handler that calls the PlaceCard() function, described later.

In the next few sections, you'll take a look at how the program works.

Initializing the Game

The InitGame() function, shown in Listing 15.2, is called when the page loads and also when you use the New Game link. It performs the following tasks:

  • Stores 52 Card objects, in order, in the deck array
  • Initializes the board array with null values
  • Shuffles the deck by swapping a random number of random cards
  • Places the first card on the draw pile (otherwise known as document.images[26])

Listing 15.2. The InitGame() function begins a new game.
function InitGame() { nextcard = 1; // clear scores for (i=0; i<5; i++) { document.form1.col[i].value = " "; document.form1.row[i].value = " "; document.form1.diag1.value = " "; document.form1.diag2.value = " "; document.form1.total.value = " "; } // array for board contents board = new Array(26); for (i=1; i<26; i++) { board[i] = new Card(0,"x"); document.images[i].src = "blank.gif"; } // fill the deck (in order, for now) deck = new Array(53); for (i=1; i<14; i++) { deck[i] = new Card(i,"c"); deck[i+13] = new Card(i,"h"); deck[i+26] = new Card(i,"s"); deck[i+39] = new Card(i,"d"); } // shuffle the deck n = Math.floor(52 * Math.random() + 200); for (i=1; i<n; i++) { card1 = Math.floor(52*Math.random() + 1); card2 = Math.floor(52*Math.random() + 1); if (card1 != card2) { temp = deck[card2]; deck[card2] = deck[card1]; deck[card1] = temp; } } // draw the first card on screen document.images[26].src = deck[nextcard].fname(); nexti.src = deck[nextcard+1].fname(); // end InitGame }

Placing Cards

Once the InitGame() function is finished, the program isn't running at all-that's the beauty of event-based programming. The next step is up to the user, who should click on one of the squares of the game board.

When a square is clicked, the PlaceCard() function, shown in Listing 15.3, is called. This function moves the card from the draw pile to the appropriate square. Because it's already in the cache, this happens instantly. An image object is then created to preload the next card. Figure 15.2 shows a game in progress with several cards placed.

Figure 15.2 : The Poker Solitaire game in progress.


Listing 15.3. The PlaceCard() function places the next card.
function PlaceCard(pos) { if (board[pos].suit != "x") { return; } document.images[pos].src = document.images[26].src; document.images[26].src = "blank.gif"; board[pos] = deck[nextcard]; nextcard++; Score(); if (nextcard > 25) { EndGame(); } else { document.images[26].src = deck[nextcard].fname(); // cache next image for draw pile nexti = new Image(53,68); nexti.src = deck[nextcard+1].fname(); } }

Scoring the Game

The Score() function, shown in Listing 15.4, is called each time a card is placed. This routine scans through the five rows and five columns and the two diagonals. The cards for each row are passed to the AddScore() function, which does the tricky part-finding poker hands and scoring them.


Listing 15.4. The Score() function scores the rows and columns.
function Score() { totscore = 0; // rows for (x=0; x<5; x++) { r = x * 5 + 1; a = AddScore(board[r],board[r+1],board[r+2],board[r+3],board[r+4]) if (a != -1) { document.form1.row[x].value = a; totscore += a; } } // columns for (x=0; x<5; x++) { r = x + 1; a = AddScore(board[r],board[r+5],board[r+10],board[r+15],board[r+20]) if (a != -1) { document.form1.col[x].value = a; totscore += a; } } // diagonals a = AddScore(board[5],board[9],board[13],board[17],board[21]) if (a != -1) { document.form1.diag1.value = a; totscore += a; } a = AddScore(board[1],board[7],board[13],board[19],board[25]) if (a != -1) { document.form1.diag2.value = a; totscore += a; } document.form1.total.value = totscore; }

The following scores are assigned to the various poker hands, based on their relative probability:

Poker hand
Score
Pair
1
2 pair
2
3 of a kind
3
Straight
4
Flush
5
Full house
8
4 of a kind
25
Straight flush
50
Royal Flush
250

Ending a Game

The EndGame() function, shown in Listing 15.5, is called when 25 cards have been played. This function is simple; it "blanks out" the draw card and informs you that the game is over with an alert. Because the total score is updated continuously, there's no need to worry about it here.


Listing 15.5. The EndGame() function ends the game.
// game over - final score function EndGame() { document.images[26].src = "blank.gif"; window.alert("Game Over"); }

Figure 15.3 shows the screen after a reasonably successful game. That's it! I hope this example shows you how much you can do with JavaScript and inspires you to even bigger things.

Figure 15.3 : The Poker Solitaire game display after all cards have been played.







|  About us | Categories | New Releases | Most Popular | Web Tutorial | Free Download | Drivers |



2013 Softlookup Corp. Privacy Statement