How To Make A Tic-Tac-Toe Game using HTML, CSS and JavaScript
Ubcodes

Ubcodes

Apr 22, 2023

How To Make A Tic-Tac-Toe Game using HTML, CSS and JavaScript

Let's start with creating our HTML file.

HTML

<div class="header">
    <h1>Tic Tac Toe</h1>
  </div>

  <div class="box">
    <!-- First Row -->
    <div class="row">
      <input type="text" class="btn" readonly>
      <input type="text" class="btn" readonly>
      <input type="text" class="btn" readonly>
    </div>

    <!-- Second Row -->
    <div class="row">
      <input type="text" class="btn" readonly>
      <input type="text" class="btn" readonly>
      <input type="text" class="btn" readonly>
    </div>

    <!-- Third Row -->
    <div class="row">
      <input type="text" class="btn" readonly>
      <input type="text" class="btn" readonly>
      <input type="text" class="btn" readonly>
    </div>
  </div>

  <p class="result">Player X Turn</p>

  <div class="reset">
    <button id="reset">Reset</button>
  </div>

The code block above displays the structure of the game. We start by creating a div for our header. The div contains the title of our game Tic-Tac-Toe.

Next, we create a div element with the class box. This div element is where we would write the entire HTML code for our game. Within this div class="box" , three rows are created, these three rows would represent the rows of our tic-tac-toe game. A div element with the class row is created in order to achieve this. Within our div class="row" three input tags are created. These input tags represent the columns of our game. We would later style these columns using CSS. The readonly attribute is set in our input tags. The readonly attribute prevents our players from being able to edit the input box. Input elements are commonly used in building forms, and you wouldn't see any readonly attribute being used. This is because the readonly attribute is to restrict any writing.

Moving on, we create a p element that displays the players' turn. The class result is assigned to this paragraph element. We would later manipulate the DOM to display the results and the players' turn. Then,we create our last div which contains the reset button for our game.

CSS

Here, I will explain the key things I feel you should note. All other things can be understood by observation as you write the code.

Now, Create your CSS file. Do not forget to link your CSS and JS files with your HTML file.

You may import the font style used or any other font style of your choice. These font styles are from Google Fonts - Google fonts

@import url('https://fonts.googleapis.com/css2?family=Chelsea+Market&family=Radio+Canada:wght@400;500&display=swap');

*{
    padding: 0;
    margin: 0;
    font-family: 'Chelsea Market', cursive;
}

body{
    background: url(./bg.avif) no-repeat;
    background-size: cover;
    background-position: center;
    height: 100vh;
    width: 100%;
    overflow-y: hidden;
    margin-top: 90px;
}

.header{
    display: flex;
    align-items: center;
    justify-content: center;
    margin: 15px;
}

.header h1 {
    text-align: center;
    font-size: 3em;
    color: whitesmoke;
    font-family: 'Radio Canada', sans-serif;
}

.box{
    display: flex;
    align-items: center;
    justify-content: center;
    flex-direction: column;
    margin: 35px;
}

.row{
    display: flex;
    align-items: center;
    justify-content: center;
}

.btn{
    border: 1px solid black;
    border-radius: 5px;
    height: 75px;
    margin: 2px;
    width: 75px;
    text-align: center;
    font-size: 50px;
    font-weight: 500;
}

.btn:hover{
    cursor: pointer;
    background-color: rgb(240, 240 ,240);
}

.btn:disabled{
    color: black;
    cursor: no-drop;
}

.result{
    text-align: center;
    color: whitesmoke;
    font-size: 2em;
}

.reset{
    text-align: center;
}

#reset{
    border: 1px solid black;
    cursor: pointer;
    color: black;
    background-color: white;
    border-radius: 5px;
    padding: 5px 20px;
    font-size: 24px;
    margin: 35px;
    transition: all 0.1s ease-in-out;
}

#reset:hover{
    color: white;
    background-color: black;
}

.btn.x-symbol {
    color: red;
}

.btn.o-symbol{
    color: blue;
}

I started by the universal selector * this is for a general styling.

*{
    padding: 0;
    margin: 0;
    font-family: 'Chelsea Market', cursive;
}

This is used in order to remove excess spaces around the webpage or the content we are building.

.btn.x-symbol {
    color: red;
}

.btn.o-symbol{
    color: blue;
}

In our HTML file, no element was assigned the class x-symbol or o-sybol this is because we will manipulate our DOM using JavaScript to change the color of 'X' and the color 'O'.

:disabled - this selector here is a boolean selector used to disable a button, making it unusable and un-clickable. We styled it in order to make it visible to our players that our button is disabled.

JAVASCRIPT

Shall we...

let cells = ['', '', '', '', '', '', '', '', ''];
let currentPlayer = 'X';
let result = document.querySelector('.result');
let btns = document.querySelectorAll('.btn');
let conditions = [
    [0, 1, 2],
    [3, 4, 5],
    [6, 7, 8],
    [0, 3, 6],
    [1, 4, 7],
    [2, 5, 8],
    [0, 4, 8],
    [2, 4, 6]
];

// element represents the button is clicked
// index represents the position that has been clikced

const ticTicToe = (element, index) => {
    element.value = currentPlayer;
    element.disabled = true;
    element.classList.add(currentPlayer === 'X' ? 'x-symbol' : 'o-symbol');
    //Add the class name based on the current player's symbol

    cells[index] = currentPlayer;
    currentPlayer = currentPlayer == 'X' ? 'O' : 'X';
    result.innerHTML = `Player ${currentPlayer} Turn`;

    let isTie = true; //assume it's a tie until we find an empty cell
    for(let i =0; i < cells.length; i++) {
        if (cells[i] == '') {
            isTie = false; //found an empty cell, so it;s not a tie
            break;
        }
    }
    if (isTie) {
        result.innerHTML = "It's a tie! 😐";
        btns.forEach((btn) => btn.disabled = true);
    } else{
        for (let i = 0; i < conditions.length; i++) {
            let condition = conditions[i];
            let a = cells[condition[0]];
            let b = cells[condition[1]];
            let c = cells[condition[2]];

            if (a == '' || b == '' || c == '') {
                continue
            }

            if((a == b) && (b == c)) {
                result.innerHTML = `Player ${a} Won 🎉`;
                btns.forEach((btn) => disabled = true);
            }
        }
    }
};

function reset() {
    cells = ['', '', '', '', '', '', '', '', ''];
    btns.forEach((btn) => {
        btn.value = '';
    });
    currentPlayer = 'X';
    result.innerHTML = `Player X Turn`;
    btns.forEach((btn) => btn.disabled =false);
};

document.querySelector('#reset').addEventListener('click', reset);

btns.forEach((btn, i) => {
    btn.addEventListener('click', () => ticTicToe(btn, i));
});

We start by creating an array of cells.

let cells = ['', '', '', '', '', '', '', '', ''];

This is because our tic-tac-toe game contains 9 cells - In simpler terms 9 spaces to play. Next, we create a variable called currentPlayer. We then set our default player to player X.

We also declare a variable called result . We use our querySeclector to target the element with the class .result. We also use querySelectorAll to target all the elements of the class .btn. Next, we create a variable for the rules that determine whether a player wins.

let conditions = [
    [0, 1, 2],
    [3, 4, 5],
    [6, 7, 8],
    [0, 3, 6],
    [1, 4, 7],
    [2, 5, 8],
    [0, 4, 8],
    [2, 4, 6]
];

Each index represents each cell in each row. This array contains the possible conditions that get us our winner.

I hope this image is able to portray my explanation.

A player wins when the same symbol is found in cell positions [0,1,2] as well as [3,4,5], [6,7,8], [0,2,6], [1,4,7],[2,5,8],[0,4,8], [2,4,6] respectively.

Next, we create the function for our game and pass in the parameter element and index . The parameter element represents the button clicked. while index represents the position that has been clicked.

element.value = currentPlayer;
    element.disabled = true;
    element.classList.add(currentPlayer === 'X' ? 'x-symbol' : 'o-symbol');
cells[index] = currentPlayer;
    currentPlayer = currentPlayer == 'X' ? 'O' : 'X';
    result.innerHTML = `Player ${currentPlayer} Turn`;

When a cell is clicked, this code above tells the computer that it is the current player you clicked the cell. As soon as the current Player is done playing, the cell is disabled. That is the reason for the element.disabled = true;. Next, as soon as the current player is done playing, the next player should play. We did this using ternary operators.

Next, we set the conditions that determine if the game is a tie or not. We initially assume that it is a tie until we find a tie.

let isTie = true;

We create a for loop which is to iterate through all the cells, if an empty cell is found it is not a tie else it is a tie.

for(let i =0; i < cells.length; i++) {
        if (cells[i] == '') {
            isTie = false; //found an empty cell, so it;s not a tie
            break;
        }
    }

since we declared this earlier let isTie = true; . we then create an if-else statement. This if-else statement would check through the cells using the conditions declared earlier.

if (isTie) {
        result.innerHTML = "It's a tie! 😐";
        btns.forEach((btn) => btn.disabled = true);
    } else{
        for (let i = 0; i < conditions.length; i++) {
            let condition = conditions[i];
            let a = cells[condition[0]];
            let b = cells[condition[1]];
            let c = cells[condition[2]];

            if (a == '' || b == '' || c == '') {
                continue
            }

            if((a == b) && (b == c)) {
                result.innerHTML = `Player ${a} Won 🎉`;
                btns.forEach((btn) => disabled = true);
            }
        }
    }

a , b , c represent each position in the condition set earlier. If the code finds the same symbol in any of the positions given by the condition, we declare the winner else it is a tie.

Then, we create the function for our reset button.

function reset() {
    cells = ['', '', '', '', '', '', '', '', ''];
    btns.forEach((btn) => {
        btn.value = '';
    });
    currentPlayer = 'X';
    result.innerHTML = `Player X Turn`;
    btns.forEach((btn) => btn.disabled =false);
};

document.querySelector('#reset').addEventListener('click', reset);

btns.forEach((btn, i) => {
    btn.addEventListener('click', () => ticTicToe(btn, i));
});

What we simply want to achieve is to clear all cells as soon as we click the button. So we see here cells = ['', '', '', '', '', '', '', '', ''] that each index is set to be empty. Each value is also set to be empty - btn.value = ''; . We set our disabled to be false - btns.forEach((btn) => btn.disabled =false); thereby enabling our players to play. Then an event listener is added to listen for a click on the reset button.

document.querySelector('#reset').addEventListener('click', reset);

In addition to this, an event listener is also added to listen for when each cell is clicked to continue the game.

btns.forEach((btn, i) => {
    btn.addEventListener('click', () => ticTicToe(btn, i));

This is the link to the tutorial video on making this game - How to make a tic-tac-toe game using HTML, CSS, and JavaScript

Ubcodes

Ubcodes

Hi there, I am Etop-Essien Emmanuella Ubokabasi. Welcome to my blog, where I share my insights and tips on web development, mental health, and books. Whether you are a beginner or an expert, a reader or a writer, a coder or a therapist, you will find something useful and interesting here. I am passionate about web development and drumming with a keen interest in topics related to mental health, books, and knowledge. As a developer, I share insightful topics, development tips, and tutorials to inspire personal growth and empower others to grow in their careers. With a desire to be and make a positive impact, I enjoy exploring ways to promote positive mental health, discussing books, and sharing knowledge with others. I hope to inspire you to pursue your passions, learn new things, and care for your mental health.

Leave a Reply

0 Comments

Related Posts

Categories