PHP Tutorial: 2 Player Tic-Tac-Toe Game (no database required)

In the first part of my games tutorial series we created a PHP Hangman game and then in the second installment we converted Hangman to use AJAX. Now it’s time to follow the same approach, only with Tic Tac Toe.

The Beauty of Classes

One of the things I like about classes is how easy it is to use and reuse them without writing a lot of code to go with it. So to start our Tic Tac Toe game we’re going to copy all the files from our original PHP Hangman game. We won’t need to change anything in the game class but we will need to make some modifications to the other class. First we’ll remove all references to letters, then we’ll remove any functions we don’t need anymore. Finally we change the main functions to display a Tic Tac Toe board instead of our hangman pictures, and finish it off by changing the logic behind how you win a game and how you make a move in the game.

Our new Tic Tac Toe game will need a player (or turn) variable so we know whose turn it is to place an X or an O. Then we’re going to add another variable to keep track of how many guesses have been made — that makes it easier to figure out if there’s a tie game instead of looping through the whole array each time someone guesses. We’ll also need a new array called Board to store all of the X and O’s placed on our game board.

The Index File

We’re going to keep things as short and easy as possible. The only changes we have to make to our index file is to load a tic tac toe game instead of a hangman game. Then we change the page title and we’re nearly done!

        Tic Tac Toe

Let's Play Tic Tac Toe!

        playGame($_POST);         ?>         

The Updated Class File

Here’s the class file with our updated game logic. Can you see how similar it is to our hangman class file? What’s changed and what looks the same?


        //reset the player
        $this->player = "X";
        $this->totalMoves = 0;

        //clear out the board
        $this->board = array();

    * Purpose: run the game until it's tied or someone has won
    * Preconditions: all $_POST content
    * Postconditions: game is in play
    function playGame($_POST)
        if (!$this->isOver() && $_POST['move'])

        //player pressed the button to start a new game
        if ($_POST['newgame'])

        //display the game

    * Purpose: display the game interface
    * Preconditions: none
    * Postconditions: start a game or keep playing the current game
    function displayGame()

        //while the game isn't over
        if (!$this->isOver())
            echo "
";             for ($x = 0; $x < 3; $x++)             {                 for ($y = 0; $y < 3; $y++)                 {                     echo "
";                     //check to see if that position is already filled                     if ($this->board[$x][$y])                         echo "{$this->board[$x][$y]}";                     else                     {                         //let them choose to put an x or o there                         echo "";                     }                     echo "
";                 }                 echo "
";             }             echo "                 

                    It's player {$this->player}'s turn.

";         }         else         {             //someone won the game or there was a tie             if ($this->isOver() != "Tie")                 echo successMsg("Congratulations player " . $this->isOver() . ", you've won the game!");             else if ($this->isOver() == "Tie")                 echo errorMsg("Whoops! Looks like you've had a tie game. Want to try again?");             session_destroy();             echo "

";         }     }     /**     * Purpose: trying to place an X or O on the board     * Preconditions: the position they want to make their move     * Postconditions: the game data is updated     **/     function move($_POST)     {                     if ($this->isOver())             return;         //remove duplicate entries on the board             $_POST = array_unique($_POST);         foreach ($_POST as $key => $value)         {             if ($value == $this->player)             {                     //update the board in that position with the player's X or O                 $coords = explode("_", $key);                 $this->board[$coords[0]][$coords[1]] = $this->player;                 //change the turn to the next player                 if ($this->player == "X")                     $this->player = "O";                 else                     $this->player = "X";                 $this->totalMoves++;             }         }         if ($this->isOver())             return;     }     /**     * Purpose: check for a winner     * Preconditions: none     * Postconditions: return the winner if found     **/     function isOver()     {         //top row         if ($this->board[0][0] && $this->board[0][0] == $this->board[0][1] && $this->board[0][1] == $this->board[0][2])             return $this->board[0][0];         //middle row         if ($this->board[1][0] && $this->board[1][0] == $this->board[1][1] && $this->board[1][1] == $this->board[1][2])             return $this->board[1][0];         //bottom row         if ($this->board[2][0] && $this->board[2][0] == $this->board[2][1] && $this->board[2][1] == $this->board[2][2])             return $this->board[2][0];         //first column         if ($this->board[0][0] && $this->board[0][0] == $this->board[1][0] && $this->board[1][0] == $this->board[2][0])             return $this->board[0][0];         //second column         if ($this->board[0][1] && $this->board[0][1] == $this->board[1][1] && $this->board[1][1] == $this->board[2][1])             return $this->board[0][1];         //third column         if ($this->board[0][2] && $this->board[0][2] == $this->board[1][2] && $this->board[1][2] == $this->board[2][2])             return $this->board[0][2];         //diagonal 1         if ($this->board[0][0] && $this->board[0][0] == $this->board[1][1] && $this->board[1][1] == $this->board[2][2])             return $this->board[0][0];         //diagonal 2         if ($this->board[0][2] && $this->board[0][2] == $this->board[1][1] && $this->board[1][1] == $this->board[2][0])             return $this->board[0][2];         if ($this->totalMoves >= 9)             return "Tie";     } }

Try the working example or Download the source code.

Learn how to create an AJAX version of this game.

You may also like...

5 Responses

  1. Desire says:

    I tried your code and it returns an error message saying undefined offset error on most of the lines from /** Check for winner **/ i have a feeling that $board is not set to anything.

  2. dhanrajsinh says:

    @desire:hey,you just try isset on each of the checking of $board and error will be gone..

  3. Hammad says:

    i just download code and it gives me 500 Internal Server Error. its in class tictactoe

Leave a Reply