Tic Tac Toe
As valuable as it is to understand the theory behind the code we write, nothing is more important than just writing code! So, as part of the blog, I am aiming to do at least one "project" every month. This will range from small, refactoring projects to bigger, more ambitious builds.
Project overview #
For my first project, I decided to build a game of tic tac toe using JavaScript & jQuery. I have seen a few of these around, but most of them are two human-player games. What I wanted to build was a single player game, with the program as the opposition. This meant that the program had to be smart enough, not only to know when there was a win/lose/draw, but also to play tactically.
My solution #
You can view the full code on my github repository, as well as play the game yourself. I thought I would share with you here the pseudocode to show the basic logic of the program.
The solution I came up with used classes on each of the tiles to determine when there was a win/lose/draw state. First, I created the actual playing board, which was just a bunch of <div>
s.
<div class="tic-tac-toe">
<div id="square1" class="tile free"></div>
<div id="square2" class="tile free"></div>
<div id="square3" class="tile free"></div>
<div id="square4" class="tile free"></div>
<div id="square5" class="tile free"></div>
<div id="square6" class="tile free"></div>
<div id="square7" class="tile free"></div>
<div id="square8" class="tile free"></div>
<div id="square9" class="tile free"></div>
</div>
Next, I mapped out what every winning state could be.
In total there were 8 winning states, e.g. 1-2-3 or 1-5-9. When the user clicked on a tile, it added the class 'X-play', and when the program played, it added the class 'O-play'. With this, I could write a statement like:
if ( sq1.hasClass('X-play') && sq2.hasClass('X-play') && sq3.hasClass('X-play') ) {
// X wins
}
This method involved a lot of hard-coding to enable the program to determine the winning states and also how to play tactically. I had 9 functions in total -
function validatePlay {
// check if the square attempted has already been played
// if square is available
// return true
// else
// return false
}
function clearBoard {
// resets the board to blank state
}
function winAlert {
// alerts who won the game
// calls clearBoard
}
function checkWin {
// checks if any of the winning states were played by the same player
// if true
// call winAlert
}
function checkDraw {
// checks if all the tiles were played, but there is no win
// if true
// alert that there has been a draw
// call clearBoard
}
function Oplay {
function Oplaying {
// call validatePlay on square passed
// if play is valid
// play square
// else
// call Orandomplay
}
function Orandomplay {
// loop through numbers 1 to 9 to find a square to play
// call validatePlay
// if play is valid
// play square and break loop
// else
// continue loop
}
// Check for tactical play option
// Check which squares have been played and which O should play in response
// e.g. if square 1 and square 2 have been played by X, O should play square 3
// If tactical option available
// call Oplaying(tacticalsquare)
// If no tactical option,
// call Orandomplay
// call checkDraw
// call checkWin
}
function Xplay {
// check which square was played by user
// call validatePlay on square played
// if play is valid
// play square
// call checkDraw
// call checkWin
// call Oplay
}
That's the basic idea! Although this might not be the most elegant solution, it works well enough for the moment. There are still some bugs and other things that I will like to improve on in the future. One thing I would definitely like to do is to re-write the program without jQuery in order to get more comfortable writing pure JavaScript.
If you have any suggestions, please do leave a comment below.
Update: I rebuilt this game again, 8 months later. Read the new article.