cover-img

Tic Tac Toe 🎮 with HTML, CSS and JS - part 1

1 May, 2022

19

19

2

In this tutorial, we will be creating a basic Tic Tac Toe game with HTML, CSS and JavaScript.
Python version: https://www.showwcase.com/show/14536/tic-tac-toe-with-python-tkinter-part-1

The webpage 👀

Let's go ahead and create a GUI for the game.
Step 1: Create webpage and add some CSS.

  • index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Tic Tac Toe</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <h1>Tic Tac Toe</h1>
    <div id="play-area">
        <button class="square" id="square1"></button>
        <button class="square" id="square2"></button>
        <button class="square" id="square3"></button>
        <br>
        <button class="square" id="square4"></button>
        <button class="square" id="square5"></button>
        <button class="square" id="square6"></button>
        <br>
        <button class="square" id="square7"></button>
        <button class="square" id="square8"></button>
        <button class="square" id="square9"></button>
    </div>
</body>
</html>
  • style.css
body {
    position: absolute;
    text-align: center;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    padding: 10px;
    box-shadow: black 0 0 10px;
}
h1 {
    color: red;
}
#play-area {
    border: black solid 2px;
    overflow: hidden;
}
.square {
    width: 5em;
    height: 5em;
    float: left;
    border: black solid 1px;
    background-color: white;
    cursor: pointer;
}
.square:hover {
    background-color: orange;
    color: white;
}

Tic Tac Toe with HTML, JS and CSS


Step 2: Make the webpage functional with JavaScript.

  • script.js
let currentChr = "X";
let XPoint = [];
let OPoint = [];

class XOSquare {
    constructor(x, y, buttonId) {
        this.x = x;
        this.y = y;
        this.button = document.getElementById(buttonId);
        this.button.onclick = () => {
            this.set(buttonId)
        }
    }
    set(buttonId) {
        this.button = document.getElementById(buttonId);
        if (this.button.innerText === "") {
            this.button.innerText = currentChr;
            switchChr();
        }
    }
    reset() {
        this.button.innerText = "";
    }
}
function switchChr() {
    if (currentChr === "X") {
        currentChr = "O";
    } else {
        currentChr = "X";
    }
}
function setup() {
    let squares = [];
    let squareElements = document.getElementsByClassName("square");
    for (let i = 0; i < squareElements.length; i++) {
        let square = new XOSquare(i % 3, Math.floor(i / 3), squareElements[i].id);
        squares.push(square);
    }
}
window.onload = setup;

Add this to index.html under head tag.

<script src="script.js"></script>

Tic Tac Toe functional webpage interface with HTML, CSS and JavaScript

Detect win and draw 🤔


Let's now implement a logic to detect win/draw.
Step 3: Implement logic to detect win.
We need to check after each move if X or O won the game. There are 8 possible ways in which one can win Tic Tac Toe:
8 possible ways of winning Tic Tac Toe

Let's add some the JavaScript in script.js to detect game win.

let currentChr = "X";
let XPoint = [];
let OPoint = [];

class XOSquare {
    constructor(x, y, buttonId) {
        this.x = x;
        this.y = y;
        this.button = document.getElementById(buttonId);
        this.button.onclick = () => {
            this.set(buttonId)
        }
    }
    set(buttonId) {
        this.button = document.getElementById(buttonId);
        if (this.button.innerText === "") {
            this.button.innerText = currentChr;
            if (currentChr === "X") {
                XPoint.push(this);
            } else {
                OPoint.push(this);
            }
            switchChr();
            checkWin();
        }
    }
    reset() {
        this.button.innerText = "";
    }
}
class winningPossibility {
    constructor(x1, y1, x2, y2, x3, y3) {
        this.x1 = x1;
        this.y1 = y1;
        this.x2 = x2;
        this.y2 = y2;
        this.x3 = x3;
        this.y3 = y3;
    }
}
function checkWinningPossibility(winningPossibility, forChr) {
    let p1Satisfied = false;
    let p2Satisfied = false;
    let p3Satisfied = false;
    if (forChr === 'X') {
        for (let i = 0; i < XPoint.length; i++) {
            if (XPoint[i].x === winningPossibility.x1 && XPoint[i].y === winningPossibility.y1) {
                p1Satisfied = true;
            }
            else if (XPoint[i].x === winningPossibility.x2 && XPoint[i].y === winningPossibility.y2) {
                p2Satisfied = true;
            }
            else if (XPoint[i].x === winningPossibility.x3 && XPoint[i].y === winningPossibility.y3) {
                p3Satisfied = true;
            }
        }
    } else {
        for (let i = 0; i < OPoint.length; i++) {
            if (OPoint[i].x === winningPossibility.x1 && OPoint[i].y === winningPossibility.y1) {
                p1Satisfied = true;
            }
            else if (OPoint[i].x === winningPossibility.x2 && OPoint[i].y === winningPossibility.y2) {
                p2Satisfied = true;
            }
            else if (OPoint[i].x === winningPossibility.x3 && OPoint[i].y === winningPossibility.y3) {
                p3Satisfied = true;
            }
        }
    }
    return p1Satisfied && p2Satisfied && p3Satisfied;
}
const winningPossibilities = [
    new winningPossibility(1, 1, 1, 2, 1, 3),
    new winningPossibility(2, 1, 2, 2, 2, 3),
    new winningPossibility(3, 1, 3, 2, 3, 3),
    new winningPossibility(1, 1, 2, 1, 3, 1),
    new winningPossibility(1, 2, 2, 2, 3, 2),
    new winningPossibility(1, 3, 2, 3, 3, 3),
    new winningPossibility(1, 1, 2, 2, 3, 3),
    new winningPossibility(3, 1, 2, 2, 1, 3)
]
function checkWin() {
    for (let i = 0; i < winningPossibilities.length; i++) {
        if (checkWinningPossibility(winningPossibilities[i], 'X')) {
            console.log("X wins");
            return;
        }
        if (checkWinningPossibility(winningPossibilities[i], 'O')) {
            console.log("O wins");
            return;
        }
    }
}
function setup() {
    let squares = [];
    let squareElements = document.getElementsByClassName("square");
    for (let i = 0; i < squareElements.length; i++) {
        let square = new XOSquare(i % 3 + 1, Math.floor(i / 3) + 1, squareElements[i].id);
        squares.push(square);
    }
}

Tic Tac Toe interface with HTML, CSS and JS

When X or O wins the game, console.log is triggered.


Step 4: Detect draw.
Append the following code to function "checkWin" in script.js

if (XPoint.length + OPoint.length === 9) {
    console.log("Draw");
}

Enhancements

Step 5: Add a status label and use it instead of console.log
Let's make a few changes to script.js:

  • function "switchChr":
function switchChr() {
    const statusLabel = document.getElementById("status");
    if (currentChr === "X") {
        currentChr = "O";
        statusLabel.innerText = "O's turn";
    } else {
        currentChr = "X";
        statusLabel.innerText = "X's turn";
    }
}
  • function "checkWin":
function checkWin() {
    const statusLabel = document.getElementById("status");
    for (let i = 0; i < winningPossibilities.length; i++) {
        if (checkWinningPossibility(winningPossibilities[i], 'X')) {
            statusLabel.innerText = "X wins";
            disableGame();
            return;
        }
        if (checkWinningPossibility(winningPossibilities[i], 'O')) {
            statusLabel.innerText = "O wins";
            disableGame();
            return;
        }
    }
    if (XPoint.length + OPoint.length === 9) {
        statusLabel.innerText = "Draw";
        disableGame();
    }
}

Add this new element in index.html under body tag

<p id="status">X's turn</p>

Add the following to style.css

#status {
    color: green;
}

Tic Tac Toe with HTML, CSS and JS with status label

Step 6: Play again


Let's add a play again button so that we don't need to refresh the webpage if we want to replay. We need to create new functions in script.js

  • function "playAgain"
function playAgain() {
    const buttons = document.getElementsByClassName("square");
    for (let i = 0; i < buttons.length; i++) {
        buttons[i].disabled = false;
        buttons[i].innerText = "";
    }
    XPoint = [];
    OPoint = [];
    currentChr = "X";
    const statusLabel = document.getElementById("status");
    statusLabel.innerText = "X's turn";
    const playAgainButton = document.getElementById("play-again");
    playAgainButton.style.display = "none";
}
  • function "disableGame":
function disableGame() {
    const buttons = document.getElementsByClassName("square");
    for (let i = 0; i < buttons.length; i++) {
        buttons[i].disabled = true;
    }
    const playAgainButton = document.getElementById("play-again");
    playAgainButton.style.display = "block";
}

Add this element to index.html under body tag:

<button id="play-again" onclick="playAgain()">Play Again</button>

Add this property to #play-area in style.css:

 margin-bottom: 10px;

Add some css for #play-again (play again button) in style.css:

#play-again {
    box-shadow: black 0 0 5px;
    margin: auto;
    display: none;
}

Step 7: Theme switch.
A webpage won't be complete without a cool theme switch. So, let's add one!
Add the following JS code to script.js:

let currentTheme = 'light';
function switchTheme() {
    if (currentTheme === 'dark') {
        document.querySelectorAll('.dark-mode').forEach(function (element) {
            element.classList.remove('dark-mode');
            element.classList.add('light-mode');
        });
        currentTheme = 'light';
    }
    else {
        document.querySelectorAll('.light-mode').forEach(function (element) {
            element.classList.remove('light-mode');
            element.classList.add('dark-mode');
        });
        currentTheme = 'dark';
    }
}

Let's rewrite the CSS:

body.light-mode {
    position: absolute;
    text-align: center;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    padding: 10px;
    box-shadow: black 0 0 10px;
}
h1.light-mode {
    color: red;
}
#status.light-mode {
    color: green;
}
#play-area.light-mode {
    border: black solid 2px;
    overflow: hidden;
    margin-top: 10px;
    margin-bottom: 10px;
}
.square.light-mode {
    width: 5em;
    height: 5em;
    float: left;
    border: black solid 1px;
    background-color: white;
    cursor: pointer;
}
.square.light-mode:hover {
    background-color: orange;
    color: white;
}
.square.clicked.light-mode {
    background-color: red;
    color: white;
}
#play-again.light-mode {
    box-shadow: black 0 0 5px;
    margin: auto;
    display: none;
}

body.dark-mode {
    position: absolute;
    text-align: center;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    padding: 10px;
    box-shadow: white 0 0 10px;
    background: black;
}
h1.dark-mode {
    color: white;
}
#status.dark-mode {
    color: blue;
}
#play-area.dark-mode {
    border: white solid 2px;
    overflow: hidden;
    margin-top: 10px;
    margin-bottom: 10px;
}
.square.dark-mode {
    width: 5em;
    height: 5em;
    float: left;
    border: white solid 1px;
    background-color: black;
    color: white;
    cursor: pointer;
}
.square.dark-mode:hover {
    background-color: gray;
    color: white;
}
#play-again.dark-mode {
    box-shadow: black 0 0 5px;
    margin: auto;
    display: none;
}

Let's change the body tag in index.html:

<body class="light-mode">
    <h1 class="light-mode">Tic Tac Toe</h1>
    <p id="status" class="light-mode">X's turn</p>
    <button id="theme-switch" onclick="switchTheme()" class="light-mode">Switch Theme</button>
    <div id="play-area" class="light-mode">
        <button class="square light-mode" id="square1"></button>
        <button class="square light-mode" id="square2"></button>
        <button class="square light-mode" id="square3"></button>
        <br>
        <button class="square light-mode" id="square4"></button>
        <button class="square light-mode" id="square5"></button>
        <button class="square light-mode" id="square6"></button>
        <br>
        <button class="square light-mode" id="square7"></button>
        <button class="square light-mode" id="square8"></button>
        <button class="square light-mode" id="square9"></button>
    </div>
    <button id="play-again" onclick="playAgain()" class="light-mode">Play Again</button>
</body>

Tic Tac Toe with HTML, CSS and JS theme switch

Full code available at GitHub repository: https://github.com/Jothin-kumar/tic-tac-toe

If you find this article useful, drop a like ⭐ and follow me to get all my latest content.

css

html

javascript

js

webpage

19

19

2

css

html

javascript

js

webpage

Jothin Kumar
Pythonista || Open source enthusiast.

More Articles

Showwcase is a professional tech network with over 0 users from over 150 countries. We assist tech professionals in showcasing their unique skills through dedicated profiles and connect them with top global companies for career opportunities.

© Copyright 2024. Showcase Creators Inc. All rights reserved.