Welcome to a tutorial on how to create a simple Tic Tac Toe game in pure Javascript, HTML, and CSS. Tic Tac Toe is another classic that is perfect for beginners to get their hands on creating games – There is not a lot of sound and graphics to worry about, but beware, this one does require a tad bit of artificial intelligence.
As there are already quite a number of other tutorials out there, I shall keep this one as simple as possible, to the bare necessities with no third-party frameworks required. Read on!
TABLE OF CONTENTS
TIC-TAC-TOE MECHANICS
All right, let us now get into some details on how the Javascript Tic-Tac-Toe works.
JAVASCRIPT TIC-TAC-TOE DEMO
PART 1) HTML INTERFACE
<div id="ttt-game"></div>
That’s right, there is only a single <div id="ttt-game">
. The rest of the squares will be generated by Javascript.
PART 2) BASIC JAVASCRIPT MECHANICS
var ttt = {
board : [], // array to hold the current game
};
- For a start,
var ttt
holds all the necessary game mechanics. ttt.board
is an array with 9 “slots” to represent the squares on the Tic Tac Toe grid. I.E.ttt.board[0]
is the top left square,ttt.board[1]
is the top center,ttt.board[2]
is the top right,ttt.board[3]
is the center-left, etc…- Initially, all 9 slots of
ttt.board
will have a value ofnull
. - If the player selects a square, the corresponding value in
ttt.board
will be changed to0
. For examplettt.board[4] = 0
if the player chooses the center square. - If the computer selects a square, the corresponding value in
ttt.board
will be changed to1
.
PART 3) GAME INITIALIZE & RESET
// (A) RESET THE GAME
reset : () => {
let container = document.getElementById("ttt-game");
container.innerHTML = "";
ttt.board = [];
for (let id=0; id<9; id++) {
let square = document.createElement("div");
square.innerHTML = " ";
square.id = "ttt-" + id;
square.onclick = () => ttt.play(id);
container.appendChild(square);
ttt.board.push(null);
}
},
window.addEventListener("load", ttt.reset);
Moving forward, ttt.reset()
is used to reset and initialize the game. This is very straightforward and does only 2 things.
- It resets
ttt.board
into an array with 9null
slots. - Redraws the HTML squares, each square is simply a
<div id="ttt-N" onclick="ttt.play(N)">
.
PART 4) PLAY!
// (B) HELPER FUNCTION - SET "O" OR "X" ON A SQUARE
// PLAYER IS "O", COMPUTER IS "X"
// id : target square
// by : 0 for player, 1 for computer
set : (id, by) => {
let square = document.getElementById("ttt-"+id);
square.innerHTML = by==0 ? "O" : "X" ;
square.classList.add((by==0 ? "player" : "computer"));
square.onclick = "";
ttt.board[id] = by;
},
// (C) PLAY - WHEN THE PLAYER SELECTS A SQUARE
// id : id of chosen square
play : id => {
// (C1) PLAYER'S MOVE - MARK SQUARE WITH "O"
ttt.set(id, 0);
// (C2) NO MORE MOVES AVAILABLE - NO WINNER
if (ttt.board.indexOf(null) == -1) {
alert("No winner");
ttt.reset();
}
// (C3) COMPUTER'S MOVE - MARK SQUARE WITH "X"
else { ttt.set(ttt.dumbAI(), 1); }
// else { ttt.set(ttt.notBadAI(), 1); } // USE NOT BAD AI IF YOU WANT
// (C4) WHO WON?
win = null;
// (C4-1) HORIZONTAL ROW CHECKS
for (let i=0; i<9; i+=3) {
if (ttt.board[i]!=null && ttt.board[i+1]!=null && ttt.board[i+2]!=null) {
if ((ttt.board[i] == ttt.board[i+1]) && (ttt.board[i+1] == ttt.board[i+2])) { win = ttt.board[i]; }
}
if (win !== null) { break; }
}
// (C4-2) VERTICAL ROW CHECKS
if (win === null) {
for (let i=0; i<3; i++) {
if (ttt.board[i]!=null && ttt.board[i+3]!=null && ttt.board[i+6]!=null) {
if ((ttt.board[i] == ttt.board[i+3]) && (ttt.board[i+3] == ttt.board[i+6])) { win = ttt.board[i]; }
if (win !== null) { break; }
}
}
}
// (C4-3) DIAGONAL ROW CHECKS
if (win === null) {
if (ttt.board[0]!=null && ttt.board[4]!=null && ttt.board[8]!=null) {
if ((ttt.board[0] == ttt.board[4]) && (ttt.board[4] == ttt.board[8])) { win = ttt.board[4]; }
}
}
if (win === null) {
if (ttt.board[2]!=null && ttt.board[4]!=null && ttt.board[6]!=null) {
if ((ttt.board[2] == ttt.board[4]) && (ttt.board[4] == ttt.board[6])) { win = ttt.board[4]; }
}
}
// (C4-4) WE HAVE A WINNER
if (win !== null) {
alert("WINNER - " + (win==0 ? "Player" : "Computer"));
ttt.reset();
}
},
This is probably the most confusing part of the entire script.
- (B)
ttt.set()
is a helper function to set “O” or “X” on a selected square, also updatettt.board
. - (C)
play()
is fired when the player selects an open square, long story short:- (C1) Set the player’s selected square to “O”.
- (C2) If there are no more empty squares and no winners, it’s a draw.
- (C3) Computer makes a move after the player. See “dumb AI” and “not bad AI” below.
- (C4) Check if there are any winners.
PART 5) DUMB AI
// (D) DUMB COMPUTER AI, RANDOMLY CHOOSES AN OPEN SLOT
dumbAI : () => {
let open = [];
for (let i=0; i<9; i++) { if (ttt.board[i] === null) { open.push(i); }}
return open[(Math.floor(Math.random() * (open.length-1)))];
},
So, just how do we create an AI computer move for Tic Tac Toe? This is one of the simplest… and dumbest ways.
- Extract all the slots that are still empty in
ttt.board
. - Then randomly choose an empty slot.
Yep, it works.
PART 6) A SLIGHTLY BETTER COMPUTER AI
// (E) AI WITH A LITTLE MORE INTELLIGENCE
notBadAI : () => {
// (E1) HELPER FUNCTION, CHECK POSSIBLE WINNING ROW
// first : first square number
// direction : "R"ow, "C"ol, "D"iagonal
// pc : 0 for player, 1 for computer
let check = (first, direction, pc) => {
let second = 0, third = 0;
if (direction=="R") {
second = first + 1;
third = first + 2;
} else if (direction=="C") {
second = first + 3;
third = first + 6;
} else {
second = 4;
third = first==0 ? 8 : 6;
}
if (ttt.board[first]==null && ttt.board[second]==pc && ttt.board[third]==pc) {
return first;
} else if (ttt.board[first]==pc && ttt.board[second]==null && ttt.board[third]==pc) {
return second;
} else if (ttt.board[first]==pc && ttt.board[second]==pc && ttt.board[third]==null) {
return third;
}
return null;
};
// (E2) PRIORITY #1 - GO FOR THE WIN
let move = null;
// (E2-1) CHECK HORIZONTAL ROWS
for (let i=0; i<9; i+=3) {
move = check(i, "R", 1);
if (move!==null) { return move; }
}
// (E2-2) CHECK VERTICAL COLUMNS
for (let i=0; i<3; i++) {
move = check(i, "C", 1);
if (move!==null) { return move; }
}
// (E2-3) CHECK DIAGONAL
move = check(0, "D", 1); if (move!==null) { return move; }
move = check(2, "D", 1); if (move!==null) { return move; }}
// (E3) PRIORITY #2 - BLOCK PLAYER FROM WINNING
// (E3-1) CHECK HORIZONTAL ROWS
for (let i=0; i<9; i+=3) {
move = check(i, "R", 0);
if (move!==null) { return move; }
}
// (E3-2) CHECK VERTICAL COLUMNS
for (let i=0; i<3; i++) {
move = check(i, "C", 0);
if (move!==null) { return move; }
}
// (E3-3) CHECK DIAGONAL
move = check(0, "D", 0); if (move!==null) { return move; }
move = check(2, "D", 0); if (move!==null) { return move; }
// (E4) RANDOM MOVE IF NOTHING
return ttt.dumbAI();
}
At this stage, the game is complete. But the AI is still pretty dumb, and let us give it some more intelligence.
- This version may look difficult, but all it does is essentially check for 2 consecutive squares and attempt to plug in the third one (to win the game).
- If there are no squares to “plug”, it reverts to using
dumbAI()
to randomly select an open square.
DOWNLOAD & NOTES
Here is the download link to the example code, so you don’t have to copy-paste everything.
SORRY FOR THE ADS...
But someone has to pay the bills, and sponsors are paying for it. I insist on not turning Code Boxx into a "paid scripts" business, and I don't "block people with Adblock". Every little bit of support helps.
Buy Me A Coffee Code Boxx eBooks
EXAMPLE CODE DOWNLOAD
Click here for the source code on GitHub gist, just click on “download zip” or do a git clone. I have released it under the MIT license, so feel free to build on top of it or use it in your own project.
EXTRA BITS & LINKS
That’s all for this project, and here is a small section on some extras and links that may be useful to you.
HOW TO PLAY TIC-TAC-TOE
Not going to judge the people who don’t know… Or forgot how this works.
- Tic Tac Toe is a simple 2 player game that is played on a grid of 9 squares.
- Each player will take turns choosing a square. One player will mark the selected square with “X” and the other with “O”.
- The first player to have 3 selected squares in a row will win the game – Either horizontally, vertically, or diagonally.
STILL PRETTY DUMB
Congratulations, you have now created a pretty good fully functioning simple game with AI. But of course, it is not the most clever. So for some homework, see if you can further improve on notBadAI()
– Make it check for 2 empty squares and try more predictions.
2 PLAYERS?
Want to change this to a 2 players’ game instead? It should be quite easy.
- Add another flag to
var ttt
to indicate which player’s turn. - Update the
play()
function – Remove the computer move part, and check for the player turn instead.
Yep, that should pretty much turn it into a 2 player game.
COMPATIBILITY CHECKS
- Arrow Functions – CanIUse
This example will work on all modern “Grade A” browsers.
LINKS & REFERENCES
- Javascript BlackJack – Code Boxx
- Javascript MineSweeper – Code Boxx
- Javascript Hangman – Code Boxx
- Javascript Quiz – Code Boxx
- Javascript Memory Game – Code Boxx
- Javascript Number Guessing Game – Code Boxx
- Javascript Tic-Tac-Toe – Code Boxx
- Javascript Rock Paper Scissors Game – Code Boxx
- Tic Tac Toe – Wikipedia
- Minimax Algorithm in Javascript – Ali Alaa
- Example on CodePen – Javascript Tic-Tac-Toe
THE END
Thank you for reading, and we have come to the end of this guide. I hope that it has helped you in your project, and if you want to share anything with this guide, please feel free to comment below. Good luck and happy coding!
Hey! Question, what if I wanted to add the option to chose to be player x or o in the game? How could i do that? Great tutorial by the way super easy to follow 🙂
Quick and dirty way:
1) Create a new
ttt.symbol
flag.2) At the start of the game, let the player choose “X” or “O”. Save into
ttt.symbol
.3) Modify
play()
to usettt.symbol
instead of fixed “O”.Okay thank you so much! I’m new to learning the language and how to write things out so I’m confused on how I would write ttt.symbol flag, any further help would be really appreciated.
You might want to revisit the basics of Javascript object. https://code-boxx.com/faq/#help
Great article for learning functional Javascript and simple game logic. Question: how do I start the game? When I fire ttt.reset(), the game board appears on the DOM. I click on a square but it goes right to ‘There’s no winner’.
Just click on any square to start… The demo in the zip file is working fine on Chrome, Firefox, and Edge.
The board doesn’t load by default. Do I need to add `document.addEventListener(‘DOMContentLoaded’) ?
Yes… Appended that small section to the end of the tutorial.