Before we move on to new things, this exercise puts the random number function to use in a more complex application. I am also showing you how to use a Java Script file that stores the script you write instead of entering the code as part of the HTML document. On this page, we are creating a test on the states and capitals like the one you see below.
<html>
<head>
<title>States and Capitals Test</title>
<Script Language = "JavaScript" src = "StatesCapitals.js">
<!--
// -->
</script>
</head>
<body onLoad = "initialize();">
<h1 align = "center">States and Capitals Test</h1>
<form name = "frmStatesCapitals">
<center>
<table border = "0" cellpadding = "5" cellspacing = "0" width = "300" height = "120">
<tr>
<td width = "100" height = "25">
<p align = "right">State:</td>
<td width = "200" height = "25"><input type = "text" name = "txtState" size =
"25" onFocus = "this.blur();"></td>
</tr>
<tr>
<td width = "100" height = "25">
<p align = "right">Capital:</td>
<td width = "200" height = "25">
<input type = "text" name = "txtCapital" size = "25"></td>
</tr>
<tr>
<td width = "300" colspan = "2" height = "27" align = "center">
<p align = "center"><input type = "button" value = "Enter" name = "enter" onClick = "check();"></td>
</tr>
</table>
</center>
</div>
<p align = "center">Correct: <input type = "text" name = "txtCorrect" size = "5" onFocus = "this.blur();">
Incorrect: <input type = "text" name = "txtIncorrect" size = "5" onFocus = "this.blur();">
</p>
</form>
</body>
</html>
Load your page and see how it looks. Hopefully, it looks the same or similar to the form above. Notice that the text boxes txtState, txtCorrect, and txtIncorrect cannot be focused upon due to the command this.blur() entered into the objects' onFocus event. Notice that the code for the enter calls a function called check() when it is clicked. We write this function momentarily to test the user's answer. The one major difference between this document and the others we have written previously is the opening script tag. Unlike the other pages we have done, this tag reads <Script Language = "JavaScript" src = "StatesCapitals.js">. This tag has an extra assignment. It assigns a value to the src property, which stands for source. The source in this case is StatesCapitals.js. This is the name of the file we are writing momentarily. The .js extension means Java Script, thus creating a Java Script source file. This tag works no differently than an image tag. It just needs to have the proper extension and the code in the .js file needs to be bug-free as usual. Let's get started on this file.
<!--
var Correct = 0;
var Incorrect = 0;
var WrongGuess = 0;
var Minutes = 0;
var Seconds = 0;
var State;
var Time = "";
var States = new Array(50);
var Capitals = new Array(50);
var Answers = new Array(50);
Notice the first line we still use the HTML comment to hide the script from browser's not supporting Java Script. This still works even though this is a Java Script document. So we just started our script with the necessary variables for this program. The variable Correct stores the amount of capitals the user answers correctly, and the variable Incorrect works conversely. WrongGuess is used to see if the user has answered a capital incorrectly. When a capital is guessed incorrectly, this value prevents the user from incrementing his incorrect answers and also tells the user what the correct capital is. Because this application is timed, we use variables Minutes and Seconds to track the time. The variable State is used later to store the random number we generate, which is then used as an array index to test a state and capital answer. The next 3 lines create our arrays. The first two, States and Capitals, store all fifty states and capitals as strings. This is where the form gets the information to display and what to test the user's answer to. Next, the array Answers is used to store the user's entry. These arrays are made up of 50 parts, indexed 0-49.
// store the states in the array States[0] = "Alabama"; States[1] = "Alaska"; States[2] = "Arizona"; States[3] = "Arkansas"; States[4] = "California"; States[5] = "Colorado"; States[6] = "Connecticut"; States[7] = "Delaware"; States[8] = "Florida"; States[9] = "Georgia"; States[10] = "Hawaii"; States[11] = "Idaho"; States[12] = "Illinois"; States[13] = "Indiana"; States[14] = "Iowa"; States[15] = "Kansas"; States[16] = "Kentucky"; States[17] = "Louisiana"; States[18] = "Maine"; States[19] = "Maryland"; States[20] = "Massachusetts"; States[21] = "Michigan"; States[22] = "Minnesota"; States[23] = "Mississippi"; States[24] = "Missouri"; States[25] = "Montana"; States[26] = "Nebraska"; States[27] = "Nevada"; States[28] = "New Hampshire"; States[29] = "New Jersey"; States[30] = "New Mexico"; States[31] = "New York"; States[32] = "North Carolina"; States[33] = "North Dakota"; States[34] = "Ohio"; States[35] = "Oklahoma"; States[36] = "Oregon"; States[37] = "Pennsylvania"; States[38] = "Rhode Island"; States[39] = "South Carolina"; States[40] = "South Dakota"; States[41] = "Tennessee"; States[42] = "Texas"; States[43] = "Utah"; States[44] = "Vermont"; States[45] = "Virginia"; States[46] = "Washington"; States[47] = "West Virginia"; States[48] = "Wisconsin"; States[49] = "Wyoming"; |
// store the capitals in the array
Capitals[0] = "Montgomery"; Capitals[1] = "Juneau"; Capitals[2] = "Phoenix"; Capitals[3] = "Little Rock"; Capitals[4] = "Sacramento"; Capitals[5] = "Denver"; Capitals[6] = "Hartford"; Capitals[7] = "Dover"; Capitals[8] = "Tallahassee"; Capitals[9] = "Atlanta"; Capitals[10] = "Honolulu"; Capitals[11] = "Boise"; Capitals[12] = "Springfield"; Capitals[13] = "Indianapolis"; Capitals[14] = "Des Moines"; Capitals[15] = "Topeka"; Capitals[16] = "Frankfort"; Capitals[17] = "Baton Rough"; Capitals[18] = "Augusta"; Capitals[19] = "Annapolis"; Capitals[20] = "Boston"; Capitals[21] = "Lansing"; Capitals[22] = "St. Paul"; Capitals[23] = "Jackson"; Capitals[24] = "Jefferson City"; Capitals[25] = "Helena"; Capitals[26] = "Lincoln"; Capitals[27] = "Carson City"; Capitals[28] = "Concord"; Capitals[29] = "Trenton"; Capitals[30] = "Santa Fe"; Capitals[31] = "Albany"; Capitals[32] = "Raleigh"; Capitals[33] = "Bismarck"; Capitals[34] = "Columbus"; Capitals[35] = "Oklahoma City"; Capitals[36] = "Salem"; Capitals[37] = "Harrisburg"; Capitals[38] = "Providence"; Capitals[39] = "Columbia"; Capitals[40] = "Pierre"; Capitals[41] = "Nashville"; Capitals[42] = "Austin"; Capitals[43] = "Salt Lake City"; Capitals[44] = "Montpelier"; Capitals[45] = "Richmond"; Capitals[46] = "Olympia"; Capitals[47] = "Charleston"; Capitals[48] = "Madison"; Capitals[49] = "Cheyenne"; |
These lines simply store each state in the States array and each capital in the Capitals array. The other array (Answers) need to remain empty because it stores the user's answer. However, when you use Internet Explorer to run this script, it generates an error when it tests the array for an entry because it does not like null values The next lines avoid this problem.
var index = 0
for (index = 0; index < 50; index ++)
{
Answers[index] = "";
}
This code very simply uses the variable index to loop through the array using a for loop. It starts at 0 and ends at 49 because we say index is less than 50. The next command sets the array elements 0 to 49 as a blank string (""). This, however, is not treated as a null (empty) value by the Java Script debugger.
Now let's get this script working.
function initialize()
{
State = Math.floor(Math.random() * 50);
document.frmStatesCapitals.txtCapital.focus();
document.frmStatesCapitals.txtState.value = States[State];
document.frmStatesCapitals.txtCorrect.value = Correct;
document.frmStatesCapitals.txtIncorrect.value = Incorrect;
Timer(); // call function to keep time
}
Line 1: Declare function initialize().
This function is used for the onLoad event of the body to start the test.
Line 3: Set variable State to a random number between 0 and 49. This number is rounded to a whole number using
the Math.floor function.
Line 4: Set the focus to the text box txtCapital.
Line 5: Set the text of the text box txtState to the string (text) in array States at the element value state
(0 to 49).
Line 6: Set the text in text box txtCorrect to the value of variable Correct.
Line 7: Set the text in text box txtIncorrect to the value of variable Incorrect.
Line 8: Call the function Timer(). We write this function later, which counts the minutes and seconds the user takes to finish.
Now we are going to code the function Timer.
function Timer() { Seconds++; if (Seconds == 60) { Minutes++; Seconds = 0; } if (Seconds < 10) { Time = "Time: " + Minutes + ":0" + Seconds; } else { Time = "Time: " + Minutes + ":" + Seconds; } window.status = Time; Timer(); |
Line 1: Begin function timer. Line 3: Increment Seconds by 1. Line 5: Test if Seconds equals 60. Line 7: Increment Minutes by 1. Line 8: Reset Seconds to zero. Line 11: Test if seconds is less than 10.
Line 17: Set string variable Time. If the value of Seconds is 6, Time stores
displays Time: then the value of Minutes, then the value of Seconds. No zero is added before seconds this time. |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
function check() { Answers[State] = document.frmStatesCapitals.txtCapital.value; if (Capitals[State].toUpperCase() == Answers[State].toUpperCase()) { Correct++; WrongGuess = 0; document.frmStatesCapitals.txtCorrect.value = Correct; document.frmStatesCapitals.txtIncorrect.value = Incorrect; if (Correct < 50) { NextState(); } else { var TotalCorrect = eval(Correct) - eval(Incorrect); if (Minutes == 1) { alert("You answered " + TotalCorrect + " capitals correctly in " + Minutes + " minute and " + Seconds + " seconds."); location.reload(); } else { alert("You answered " + TotalCorrect + " capitals correctly in " + Minutes + " minutes and " + Seconds + " seconds."); location.reload(); } } } else { // incorrect answer if (WrongGuess == 0) { Incorrect++; WrongGuess++; document.frmStatesCapitals.txtIncorrect.value = Incorrect; } else { alert("The capital of " + States[State] + " is " + Capitals[State] + "."); } } document.frmStatesCapitals.txtCapital.select(document.frmStatesCapitals.txtCapital.value.length); } // end function check |
Line 1: Begin function check() Line 3: Set the element value State (the random number that was generated) of array Answers to the text entered in the text box txtCapital (the user's answer). Line 5: Test if array index State of array Capitals is equal to the index State in array Answers. These are string values. We then use the string function toUpperCase(), which converts the strings to upper case letters. Because the states and capitals are entered with the first letter capital and the other's lower-case, this prevents the user from having to enter the first letter upper-case and all the other letters lower-case. Line 7: Increment variable Correct because the user answers correctly according to line 5 Line 8: Reset variable WrongGuess to 0. When it is 1, the program tells the user the answer. Line 9: Update the text box txtCorrect to display the amount of correct answers. Line 10: Update the text box txtIncorrect to display the amount of incorrect answers. Line 12: Test if Correct (the amount of correct answers) is less than 50. We want to generate another random number to display another state from the array when the user has not answered 50 states. Line 14: Call the function NextState(), which generates another random number and displays another state from the array. Line 16: When the correct answers are 50 (all states have been answered). Line 18: Declare variable TotalCorrect and set in to the amount of correct answers (Correct) minus the amount of incorrect answers (Incorrect). Line 20: Check to see if Minutes are 1. Line 22: When line 20 is true (Minutes are 1), display the alert seen. This tells them the amount of capitals they answered and how long it took them. Line 24: Reload the page, thus resetting the form and the results Line 26: Else... (when Minutes does not equal 1) Lines 28 and 30: Do the same this as lines 20 and 22, but displays the message to say Minutes instead of Minute. Just a minor grammatical correction to avoid displaying 1 minutes. Line 34: Else (when the user answers incorrectly) Line 36: Check if variable WrongGuess equals 0. When it does, execute lines 38 through 40. Line 38: Increment variable Incorrect by 1. Line 39: Increment variable WrongGuess by 1. Line 40: Display value of variable Incorrect in the text box txtIncorrect. Line 42: When line 36 is false (WrongGuess does not equal 0), execute line 44. Line 44: Display the answer in an alert. "The capital of", then the value of the current States array index displayed, " is ", then the value of the current Capitals array index displayed. This displays the capital to the user. Notice that the else block (lines 42 to 45) does not increment the variable Incorrect. This prevents the
user from continuously incrementing his incorrect answers. The result is that the user can only have one incorrect answer
per state tested. |
On line 14 of the function check (the function we just wrote), a call is made to a function NextState(). Now we are going to write this function.
function NextState()
{
do
{
State = Math.floor(Math.random() * 50);
document.frmStatesCapitals.txtState.value = States[State];
document.frmStatesCapitals.txtCapital.focus();
document.frmStatesCapitals.txtCapital.select(document.frmStatesCapitals.txtCapital.value.length);
}
while (Capitals[State].length == Answers[State].length);
} // end function NextState
Line 1: Begin function NextState().
Line 3: Begin Do While loop.
We use the word do here because we want the loop to execute once, even when the test on line 7 is false. A number is generated first without a condition begin true.
Line 5: Set variable State to a random number between 0 and 49, then round it down to a whole number using
the Math.floor function. The values generated by Math.random() are between 0 and 1, so the number 50 cannot
be generated because the function Math.floor rounds the number down to the nearest whole number.
Line 6: Set the text in text box txtState to the string in array States at the element with value State.
Line 7: Set the focus to the text box txtCapital.
Line 8: Select all the text in the text box txtCapital.
Line 10: Check if the array Answers at index State is equal to the array Capitals at index State. If
these are equal, it means that the capital entered into the array index at value State has already been answered. When this happens,
line 5 keeps on executing, thus it keeps on creating a random number until it corresponds with an empty array index in the Answers
array. The array starts as empty, so this determines if an entry has been made already and prevents a state from being displayed twice. We
convert to upper-case because the user may have entered previous answers in lower-case letters, in which case the array index may be displayed
again because they are NOT equal.
Hopefully, your form works the same as the one at the top of this page. Now we can continue on to new topics on Page 17.