Related Links

  • Science Fair Project Guide

Project Summary

Difficulty  6  –  8 
Time required Average (about one week)
Prerequisites To do this project, you should already be comfortable with creating basic HTML files using a text editor. You should also be familiar with creating HTML form elements, and having them interact with JavaScript functions.
Material Availability Readily available
Cost Very Low (under $20)
Safety No issues

Donate to Science Buddies

Sponsor

Sponsored by generous support from the AMD Foundation

AMD Changing the Game
Want to Develop Games?
AMD Foundation's partners offer cool programs for K-12 students
www.amd.com/changingthegame

Abstract

This is a more challenging JavaScript project: can you write a program that can play Tic-Tac-Toe? You'll have to figure out a way to translate the game strategy into a computer algorithm. The project will show you how to create a working Tic-Tac-Toe board on a webpage. Your challenge will be to show the computer how to play. Just think: you'll be creating artificial intelligence!

Objective

The goal of this project is to write a JavaScript program that plays Tic-Tac-Toe. This project will take you through the steps of creating the interface for the game. You will need to take it from there and write the algorithms to create a computer opponent.

Introduction

This is an example of an intermediate programming project. You will be writing a program that allows you to play a game of Tic-Tac-Toe against the computer.

To do this project, you should already be comfortable with creating basic HTML files using a text editor. You should also be familiar with creating HTML form elements, and having them interact with JavaScript functions. If you have not done any JavaScript programming before, we suggest you start with a simpler project, like Forms and Functions: Writing a Simple Calculator Program with JavaScript or ABC's of Programming: Writing a Simple 'Alphabetizer' with JavaScript.

The Introduction will help you get started, in a step-by-step manner. If you follow the steps in the Introduction, you can gradually build up a webpage that you can use to play Tic-Tac-Toe with a friend. The experience you gain from building the two-player game will help you when you take on the challenge of programming the computer to play against you.

Here are the steps covered in the Introduction. First you will learn how to write an HTML file (webpage) that represents a Tic-Tac-Toe board. Next you will learn how to make your webpage respond to mouse clicks on the Tic-Tac-Toe board using JavaScript. Then you will learn how to update the text values of HTML elements on the fly. You will also learn how to program Tic-Tac-Toe knowledge into your program to detect when the game has been won or ended in a draw. At this point, you'll have a webpage that you can use to play Tic-Tac-Toe with a friend.

The challenge we leave you with for your project is to write the algorithms so that the computer can be your opponent instead. Can you create a computer opponent that always gives you opportunities to win? Can you improve that opponent so that it plays strongly but sometimes gives you an opportunity to win? Finally, we all know that it is possible to play a perfect game of Tic-Tac-Toe that results in a draw. Can you write an AI player that never loses?

The important HTML elements used in this project are:
SCRIPT The <SCRIPT> element is used to begin and end a section of JavaScript code.
INPUT The <INPUT> element can be used to create buttons. Buttons will represent the squares of our Tic-Tac-Toe board in this lesson.
P The <P> element is used to create paragraphs. We will use this element to create a space that tells the user what is going on in the game.
&nbsp; This element stands for "non-breaking space." It is used in HTML to place a space on the webpage where no line-break can occur. We will use non-breaking spaces to represent empty squares on the Tic-Tac-Toe board.

The important JavaScript objects, functions, and keywords used in this project are:
Var The var keyword is used to declare a variable in JavaScript. A variable is a piece of data in JavaScript that can be changed and compared to other variables.
function The function keyword is used to declare the beginning of a function. A function is a reusable piece of code that performs a specific purpose. In this project you will use functions to do things such as: place an X or an O on the game board, or check to see if someone has won the game, or to start a new game after one has finished.
== , != The operators "is equal to" (==) and "is not equal to" (!=) are used to compare values in JavaScript. There are also comparison operators for "less than" (<), "less than or equal to" (<=), "greater than" (>), and "greater than or equal to" (>=). The result of using a comparison operator is either true or false. Comparison operators are used in if statements and for loops to control program execution (see next two entries).
if...else An if statement is a conditional statement. It is used to control the flow of the program using simple true/false expressions. For example, you might have a variable to indicate whose turn it is (X or O). When there is a mouse click on a blank square, you can use an if statement to check the value of the turn variable so you know whether to mark the square with an X or an O.
for The for keyword is used to loop through a section of code a number of times. In this project we will use loops to check each value on the game board.


Making a JavaScript Tic-Tac-Toe Board
  1. Laying out the game board. In this project, the game board is made up of buttons. There are 3 rows that each have 3 button across. Each button represents a square on the Tic-Tac-Toe board. The HTML code necessary to lay this out is easy. To do this, we use the HTML <INPUT> tag. The input tag must have a type. In our case the type is "BUTTON".

    <INPUT TYPE="BUTTON" ID="0_0" VALUE="   ">
    <INPUT TYPE="BUTTON" ID="1_0" VALUE="   ">
    <INPUT TYPE="BUTTON" ID="2_0" VALUE="   ">
    <BR>
    <INPUT TYPE="BUTTON" ID="0_1" VALUE="   ">
    <INPUT TYPE="BUTTON" ID="1_1" VALUE="   ">
    <INPUT TYPE="BUTTON" ID="2_1" VALUE="   ">
    <BR>
    <INPUT TYPE="BUTTON" ID="0_2" VALUE="   ">
    <INPUT TYPE="BUTTON" ID="1_2" VALUE="   ">
    <INPUT TYPE="BUTTON" ID="2_2" VALUE="   ">
    <BR>
    Notice that each input has an "ID" and a "VALUE." The VALUE is displayed on the face of the button. At the start of the game, the buttons are blank. The ID can be used to tell which button was pressed. We will also use the ID to change individual buttons to show an X or an O.

  2. "Catching" mouse clicks. In order to make the Tic-Tac-Toe game interactive you will need to know when the user clicks on a button. JavaScript provides an easy way to do this. <INPUT> tags can have an ONCLICK attribute that you can use to call JavaScript code whenever the button is clicked. This must be added to each button on our board like so:

    <INPUT TYPE="BUTTON" ID="0_0" VALUE=" " ONCLICK="alert('Hi, you clicked me!');">

    Now you will know whenever a player clicks on a button. The next step is putting the right value into the box. After that, we'll tackle alternative turns!

  3. Setting the value of a square. The first step in making the Tic-Tac-Toe game work is setting the value of a square when it is clicked. Each of the squares will work in the same way. Because the click response is common to all of the squares, you should write one piece of code that can be used by any square when it is clicked. To do this you need to create a JavaScript function. At the top of your HTML file (in the <HEAD> section) add a <SCRIPT> tag so you can write JavaScript code, like this:

    <SCRIPT TYPE="TEXT/JAVASCRIPT">
    </SCRIPT>

    Now you can write JavaScript code inside the script section. Let's start by creating the function we will call whenever a button is clicked:

    function squareclicked(square)
    // squareclicked is a function that is called whenever a button is clicked.
    {
    }

    These four lines create a function that will do nothing. The first line is a comment. It summarizes what the function does. The function is named "squareclicked," and it has one argument, "square." The argument will be used to tell the function which button has been clicked. This means you need to update your buttons to call the squareclicked() function:

    <INPUT TYPE="BUTTON" ID="0_0" VALUE=" " ONCLICK="squareclicked(this);">

    Notice how "this" is being sent whenever we call the squareclicked() function. When you put "this" inside an onclick attribute it represents the <INPUT> that the onclick attribute is created in. This means that whenever a button is clicked it will call the squareclicked() function and pass itself to the function. This will enable you to set the value of the square. Now update the squareclicked() function to set the value of the button:

    function squareclicked(square)
    // squareclicked is a function that is called whenever a button is clicked.
    {
       square.value = 'X';
    }

    Jackpot! Now whenever a button is clicked it gets the value 'X'. The next step is to put the right value in the square based on whose turn it is.

  4. Alternating turns. In order to alternate turns and place the right value in the square that is clicked we will need to keep track of whose turn it is. You can do this by creating a "global" variable (a global variable can be accessed from any function) in the JavaScript section outside of the squareclicked() function, like this:

    <SCRIPT TYPE="TEXT/JAVASCRIPT">
    var xTurn = true;

    function squareclicked(square)
    // squareclicked is a function that is called whenever a button is clicked.
    {
     ... code here ...
    }
    <script>

  5. Using the xTurn variable. The next step is to use the xTurn variable in the squareclicked() function to put the right marker (X or O) onto the board, depending on whose turn it is. After marking the square, the function should switch whose turn it is.

    function squareclicked(square)
    // squareclicked is a function that is called whenever a button is clicked.
    {
     var value = square.value;
     if(value != 'X' && value != 'O')
     {
       if(xTurn)
       {
          square.value = 'X';
          xTurn = false;
       }
       else
          {
             square.value = 'O';
             xTurn = true;
          }
     }
       else
          alert('That square has already been played.');
    }

    This function will mark squares and switch turns appropriately. Notice how the outer if ... else statements prevent a square from being chosen more than once. The inner if ... else statements check the xTurn variable, mark the square with the correct market, and switch the xTurn variable to the next player.

    It would be really nice if we could tell the players whose turn it is, though. Let's add a status bar.

  6. Adding a status bar. To add a status bar we will need to add a section near the bottom of our HTML page (above the </body> tag):

    <P ID="status">X's turn</P>

    The "ID" attribute is very important because it will allow us to change the value of the status bar later! Update the squareclicked function to use the status bar:

    function squareclicked(square)
    // squareclicked is a function that is called whenever a button is clicked.
    {
     var status = document.getElementById('status');
     var value = square.value;
     if(value != 'X' && value != 'O')
     {
       if(xTurn)
       {
          square.value = 'X';
          xTurn = false;
          status.innerHTML = 'O\'s turn';
       }
       else
          {
             square.value = 'O';
             xTurn = true;
             status.innerHTML = 'X\'s turn';
          }
     }
       else
          alert('That square has already been played.');
    }

  7. Starting a new game. The last thing we need to do in order to have a functioning Tic-Tac-Toe board is give the players a way to start a new game. You can add a button to do this:

    <INPUT TYPE="BUTTON" ID="NEWGAME" VALUE="New Game" ONCLICK="newgame();">

    This button calls the function "newgame()," which we haven't written yet. The newgame() function must reset everything that is necessary to start the game anew:

    function newgame()
    {
       var status = document.getElementById('status');

       xTurn = true;
       status.innerHTML = 'X\'s turn';

       for(var x = 0; x < 3; x++)
       {
          for(var y = 0; y < 3; y++)
          {
             document.getElementById(x + '_' + y).value = ' ';
          }
       }
    }

Checking for the End of the Game

You have now successfully made a program that lets two players play a game of Tic-Tac-Toe. You can make this game better by detecting when the game has ended (win, lose or draw). To do this we need to do several things.

  1. First we need to create a global variable to keep track of whether or not the game is over:

    var gameOver = false;

  2. Next we need to keep track of how many moves have been made. If 9 moves have been made and nobody has won then we know all of the spaces on the board have been filled, and we have a tie. We'll create a global variable to keep track of the number of moves that have been made:

    var numMoves = 0;

  3. Now you can write a function that checks to see if a player has won. Call it checkWin(). The checkWin function will determine if a player has won by checking every row, every column, and both diagonals to see if any of them are made up entirely of X's or O's. The function will return a value of either "true" or "false" indicating whether or not someone has won:

    function checkWin()
    {
     var status = document.getElementById('status');
     var val0;
     var val1;
     var val2;

     // check columns
     for(var y = 0; y < 3; y++)
     {
       val0 = document.getElementById('0_'+y).value;
       val1 = document.getElementById('1_'+y).value;
       val2 = document.getElementById('2_'+y).value;
       if(val0 == 'X' && val1 == 'X' && val2 == 'X')
       {
          status.innerHTML = "X WINS!";
          return true;
       }
       else if(val0 == 'O' && val1 == 'O' && val2 == 'O')
       {
          status.innerHTML = "O WINS!";
          return true;
       }
     }

     // check rows
     for(var x = 0; x < 3; x++)
     {
       val0 = document.getElementById(x + '_0').value;
       val1 = document.getElementById(x + '_1').value;
       val2 = document.getElementById(x + '_2').value;
       if(val0 == 'X' && val1 == 'X' && val2 == 'X')
       {
          status.innerHTML = "X WINS!";
          return true;
       }
       else if(val0 == 'O' && val1 == 'O' && val2 == 'O')
       {
          status.innerHTML = "O WINS!";
          return true;
       }
     }

     // check top left to lower right diagonal
     val0 = document.getElementById('0_0').value;
     val1 = document.getElementById('1_1').value;
     val2 = document.getElementById('2_2').value;
     if(val0 == 'X' && val1 == 'X' && val2 == 'X')
     {
       status.innerHTML = "X WINS!";
       return true;
     }
     else if(val0 == 'O' && val1 == 'O' && val2 == 'O')
     {
       status.innerHTML = "O WINS!";
       return true;
     }

     // check lower left to top right diagonal
     val0 = document.getElementById('2_0').value;
     val1 = document.getElementById('1_1').value;
     val2 = document.getElementById('0_2').value;
     if(val0 == 'X' && val1 == 'X' && val2 == 'X')
     {
       status.innerHTML = "X WINS!";
     return true;
     }
     else if(val0 == 'O' && val1 == 'O' && val2 == 'O')
     {
       status.innerHTML = "O WINS!";
       return true;
     }

     // no winner yet  return false;
    }

  4. We also need to incorporate the gameOver variable, the numMoves variable, and the checkWin() function into the newGame() function and the squareclicked()function. The newGame() function needs to set gameOver = false, and numMoves = 0:

    numMoves = 0;
    gameOver = false;

  5. The squareclicked() function will need three updates.
    1. You will need to check at the beginning of the squareClicked function to see if the game is over (so the players can't make moves after the game is over):

       if(gameOver)
       {
         alert("The game is already over.");
         return;
       }

    2. You will need to increment numMoves each time a player takes a turn:

         if(xTurn)
         {
            numMoves++;
            square.value = 'X';
            xTurn = false;
            status.innerHTML = 'O\'s turn';
         }
         else
         {
            numMoves++;
            square.value = 'O';
            xTurn = true;
            status.innerHTML = 'X\'s turn';
         }

    3. You will need to check at the bottom of the squareClicked function (after a move has been made) to see if there is a winner or a tie:

       var winner = checkWin();
       if(!winner)
       {
         //check to see if there is a tie
         if(numMoves == 9)
            status.innerHTML = 'Tie Game!';
       }
       else
         gameOver = true;

Creating a Computer Opponent

Now that you have created a working game of Tic-Tac-Toe for two players wouldn't it be nice to have someone to play against? How about playing against the computer? This requires artificial intelligence to the game. What is involved in adding artificial intelligence? Check out the Experimental Procedure section!

Terms, Concepts and Questions to Start Background Research

To do this project, you should do research that enables you to understand the following terms and concepts:

Questions:

Bibliography

Materials and Equipment

To do this experiment you will need the following materials and equipment:

Experimental Procedure

The Introduction took you through the steps to create a working Tic-Tac-Toe game that you could play with a friend. The next step is to program the computer to play the game in place of one player. You'll be adding a simple form of artificial intelligence (AI) to your program! What is involved in adding AI to the program? Several things:

  1. The computer must know when it is has the turn to move.
    1. Your program can keep track of this with another global variable:

      var computerTurn = false; // true/false variable to keep track of the turn

    2. Whenever a move is made, you can switch the value of the computerTurn variable, like this:

      computerTurn = !computerTurn

  2. There must be code in place to make a move! You can use a code snippet like the one below, but where should you put it? You should be able to figure this out on your own!

     if(computerTurn)
     {
       makeComputerMove();
     }

  3. How will the computer determine where to place its X or O? In other words, what will go into the "makeComputerMove()" function? You'll have to think about Tic-Tac-Toe strategy, and try to reduce it to a series of steps that you can write in a program. For example, the computer could mark the first empty spot it finds, or it could choose a random empty spot, or it could look for places where the opponent has 2 in a row in order to block, or it could look for places where it has 2 in a row so it could win. It could also be a mix of all of the above! This is entirely up to you but it's easy to see that some methods will produce a better computer opponent than others.
  4. Whatever strategy you choose you will most likely have to loop through all the squares. The code in the checkWin() function should help you figure out what to do.
  5. It's a good idea to follow the method used in the Introduction. Start out with something simple, get it working, and then refine it. As you improve your program, remember save your previous version, and re-name the file before making radical changes. That way, you can always go back to a working version.
  6. Can you create a computer opponent that always gives you opportunities to win? Can you improve that opponent so that it plays strongly but sometimes gives you an opportunity to win?
  7. When you have a working computer opponent, make a prediction about how well the computer's strategy will work. Test your prediction by playing a few dozen games against the computer, and record the results of each game. How did your prediction hold up? How can you improve the computer's performance? Refine the program and try again!

Variations

Credits

Credits image

By Adam Schepis, Software Engineer

Edited by Andrew Olson, Ph.D., Science Buddies


Last edit date: 2007-01-02 12:31:48


Career Focus

If you like this project, you might enjoy exploring careers in Video & Computer Games.

Multimedia Artist or Animator
If you've ever watched a cartoon, played a video game, or seen an animated movie, you've seen the work of multimedia artists and animators. People in these careers use computers to create the series of pictures that form the animated images or special effects seen in movies, television programs, and computer games.
 



Join Science Buddies

Become a Science Buddies member! It's free! As a member you will be the first to receive our new and innovative project ideas, news about upcoming science competitions, science fair tips, and information on other science related initiatives.


Support Science Buddies

If this website has helped you, won't you consider a small gift so we may continue developing resources to help teachers and students?

 



 

Science Buddies gratefully acknowledges its Presenting Sponsor
 
It's free! As a member you will be the first to receive our new and innovative project ideas, news about upcoming science competitions, science fair tips, and information on other science related initiatives.


Science Fair Project Home      Our Sponsors      Partners      About Us      Volunteer      Donate      Contact Us      Research Grants & Outreach      Site Map

Science Fair Project Ideas      Science Fair Project Guide      Ask an Expert      Blog      Teacher Resources      Parent Resources      Student Resources      Science Careers      Join Science Buddies     


Privacy Policy Science Buddies

Copyright © 2002-2010 Kenneth Lafferty Hess Family Charitable Foundation. All rights reserved.
Reproduction of material from this website without written permission is strictly prohibited.
Use of this site constitutes acceptance of our Terms and Conditions of Fair Use.