Computer Science 180
Web Design

Fall 2011, Siena College

Lab 7: JavaScript Programming
Due: 1:30 PM, Monday, November 7, 2011

For this week's lab, you will gain much more experience with JavaScript programming.

You may work alone or with a partner on all parts of this lab.

Tic-Tac-Toe

"...nearly all the people I take down there have precisely the same response to the prospect of playing ticktacktoe with a chicken. After looking the situation over, they say, `The chicken gets to go first!' `But she's a chicken,' I say. `You're a human being. Surely there should be some advantage in that.' Some of my guests, I always report with some embarrassment, don't stop there. Some of them say, 'The chicken plays every day. I haven't played in years.' " - Calvin Trillin, The New Yorker, Feb. 8, 1999.

For this task, you will create a web page using JavaScript to play a game of Tic-Tac-Toe. Start with this partially-completed document that lays out the playing board and contains one JavaScript function you'll need later.

Place the document into your folder for today's lab and open it up. You should see a header and a blank Tic-Tac-Toe board. Note that each table cell contains a non-breaking space - the   character which indicates that no "X" or "O" has been placed in each cell yet.

Your first modification should be to add your name(s) to the comment at the top of the document. Remember, you should be including your name in a comment in every document you create!

"X"s and "O"s are to be placed by clicking in cells on the board. Your first real task is to get that to happen. You will need to write a JavaScript event handler function and add onclick attributes to each table cell that call this function to make this happen. Your function needs to take a parameter that indicates the id of the cell, so we can look it up using document.getElementById.

Initially, place only an "X" in any cell that is clicked. Only after you have verified that you can place an "X" into any cell should you worry about placing any "O"'s.

Alternating between "X" and "O" placement requires a bit more effort. First, we will need to remember whose turn it is, so the next selected cell gets the proper letter. Our mechanism to remember information is to declare and use a global variable. Recall that a global variable is one declared outside of any function, so it can retain its value throughout the lifetime of the document. You will need to initialize yours (let's call it turn) so that "X" goes first. It will be most convenient if you use the strings "X" and "O" as the values for turn. Now, when a cell is clicked, instead of always setting its innerHTML to "X", you should set it to the value of your variable.

After placing an "X" or "O" based on the current value of turn, its value must be swapped to the other possibility. We can accomplish this as follows:

  if (turn == "X") {
    turn = "O";
  }
  else {
    turn = "X";
  }

The condition here on our if statement is an equality comparison (the ==). If the value stored in turn is "X", it evaluates to true, and we execute the statement in the first { } block, which changes the value of turn to "O". If turn was not "X", the else part is executed, and turn becomes "X". This accomplishes the desired switch. Be sure you do this after you use turn's original value to place an "X" or "O" as appropriate. Note: make sure you use == for the comparison for equality in the if condition and = for the assignment of new values to variables.

After adding all of this, verify that your page alternates between placing "X"s and "O"s.

Once that works, we'll take the next step toward a playable game by making sure a player cannot choose an already-occupied cell. To do this, we need to check the innerHTML of the cell to see if it contains an "X" or "O". If so, we will put up a message that the cell is already occupied instead of setting the innerHTML to the current value of turn and switching the turn. Suppose we have given the name cell to the table cell we've clicked on with a statement like:

  var cell = document.getElementById(id);

(here, id is the name of your parameter specifying the id of the cell that was clicked). We can then use the following conditional to do something only in the case that the cell's innerHTML contains either an "X" or "O":

  if (cell.innerHTML == "X" || cell.innerHTML == "O") {
    // handle case of an already-occupied cell
    return;
  }

Here, we have two equality comparisons grouped together with the || operator, which is the "or" operation. It means we should execute the code inside the if when either the first equality is true or the second is true. You will need to replace the comment with some way to give feedback to the player that the move did not occur and that some other cell should be chosen. (Suggestion: use an alert for now). Having a return statement inside the if means that the function will stop executing at that point. This is exactly what we want, as the rest of the function is dealing with placing a letter and updating the turn, all of which should not occur in the case when an occupied cell was selected.

Next, we will add a message to the page that can be used to remind the players whose turn is next and indicate the error when someone attempts to use a cell that is already occupied (have this replace the alert you used before). Soon, we'll use it to indicate a win or draw.

To do this, add an element below the <table> that you can use for this purpose. At the start, it should contain a message like "X goes first." Be sure to give it an id attribute so you can look it up from your JavaScript function. In that function, set this element's innerHTML to display appropriate messages such as whose turn it is and to indicate when an already-occupied cell is selected.

Now, your game is playable, but there is no indication of a win or tie, nor does anything stop you from continuing play when someone has won. This will be the most complex addition, but the good news is that a function is provided that does much of the hard work.

Take a look at the checkGameStatus function. It retrieves the value from each cell and places it into a local variable for easy access throughout the function. Next, it checks for a win by the "X" player by seeing if there is an "X" in each cell in some row, column, or diagonal. If it finds a winning case, it immediately returns "X" to indicate a win by player "X". It then does the same to see if "O" has won. If there has not yet been a win, perhaps the game has ended in a tie. We check this by seeing if all cells contain something other than the "&nbsp;" placed there at the start. If this is the case, the function returns "draw". Finally, if none of those things happened, the function returns "none" to indicate that the game should continue. Note that this function makes extensive use of conditions that contain && operators - which mean "and". For example, the first condition checks for a win by "X" in the first row by seeing if topLeft == "X" and topCenter == "X" and topRight == "X". If all three were true, the entire expression evaluates to true and the function immediately returns "X".

So this function will look at the current state of the board and return one of four values: "X", "O", "draw", or "none". We can use this in the event-handler function to determine if any move should be allowed (i.e., that the game has not already ended) or if a win or draw message should be displayed.

Take this approach: add a global variable called winner which gets initialized to "none". At the start of your event handler, you can use the statement

  if (winner != "none") return;

to prevent it from doing anything in cases where some player has already won or the game has ended in a tie.

The only time that the value of winner can change is right after an "X" or "O" has been placed on the board. So right after doing that, we can update the value of winner to be the return value of the checkGameStatus function:

  winner = checkGameStatus();

After this, your function can check to see if winner has become "X", "O" or "draw", in which case the message below the board should be updated and the function should return immediately (to prevent the turn from changing and the message about whose turn is next from being displayed).

This gives us a fully-functional game! Verify that your game plays properly before making our final addition for now: the ability to restart a game.

This last step involves adding a "Start Over" button that calls a JavaScript function to reset the game to its initial state. This involves setting the innerHTML of all cells to &nbsp;, resetting the winner variable to "none", the turn variable to "X", and the message to indicate that "X" plays first.

Extending the "Style Setting" Example

For this lab task, you will be looking more at the details of the restylesomethings.html example, then extending it a bit.

Make sure you understand how the addition of the checkboxes works and why styles for unchecked items are not applied when you click on elements of the page.

The first part of the task is to add at least two more style properties to the table of styles that can be applied.

The second part of the task is to "disable" the <select> elements corresponding to those styles that would not be applied because their checkbox is unchecked. A few things you will need to use to make this happen:

Blastoff!

Your final task involves developing a simple "countdown" page. It should begin by displaying a large, black number 10 and a button labeled "Continue Countdown". Each time the button is clicked, the number displayed goes down by 1. When the number reaches 0, the number should be replaced with the word "Blastoff!" in large, red letters, and the label on the button should be replaced with "Start Over". When the button is pressed in this case, the display should again be a large, black number 10 and the button should again be labeled "Continue Countdown".

Submitting Your Work

Before 1:30 PM, Monday, November 7, 2011, submit your files for grading. There are three things you need to do to complete the submission: (i) make sure your pages are uploaded properly to the class web space and are available at your URI, (ii) update your main index on the class web space to have links to all documents you have created for this lab, and (iii) email a copy of your files to me at jteresco AT siena.edu. If you worked with a partner on any of the items, you need only upload to the account of one of the team members, but each team member should link to the pages on his or her own main index. Make sure all of your pages validate properly as XHTML Strict.

Grading Sheet

This lab is worth 30 points, which are distributed as follows:

> FeatureValueScore
Required Documents
Tic-Tac-Toe 8
Style setting: two new style entries 4
Style setting: disable menus for unselected styles 3
Blastoff! 9
Style
XHTML documents pass validation 3
Formatting of HTML text 1
Submission
Main index updated 1
Email submission 1
Total 30