I’m making a tic tac toe game in JS. Code is below.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Tic Tac Toe</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap"
rel="stylesheet"
/>
<link rel="stylesheet" href="tis.css" />
</head>
<body>
<div id="gameContainer">
<h1>Tic Tac Toe</h1>
<h2 id="statusText">Testing...</h2>
<div id="cellContainer">
<div cellIndex="0" class="cell"></div>
<div cellIndex="1" class="cell"></div>
<div cellIndex="2" class="cell"></div>
<div cellIndex="3" class="cell"></div>
<div cellIndex="4" class="cell"></div>
<div cellIndex="5" class="cell"></div>
<div cellIndex="6" class="cell"></div>
<div cellIndex="7" class="cell"></div>
<div cellIndex="8" class="cell"></div>
</div>
<button id="restartBtn">RESTART</button>
</div>
<script src="tic.js"></script>
</body>
</html>
body {
padding: 0;
margin: 0;
font-family: "Press Start 2P", sans-serif;
background-color: black;
height: 100vh; /*height is the height of the browser vwindow*/
text-align: center;
}
h1 {
color: white;
text-align: center;
font-size: 50px;
margin-top: 10%;
}
#statusText {
color: white;
text-align: center;
font-size: 15px;
margin-top: 2em; /*1m is margin size of the font size}*/
margin-bottom: 2em;
}
#cellContainer {
width: 300px;
height: 300px;
margin: 0 auto; /*centre the element to its parent container*/
color: #fff;
border: 2px solid white;
display: grid;
grid-template: repeat(3, 1fr) / repeat(3, 1fr); /*each column and each row a third of the grid*/
}
.cell {
border: 2px solid white;
border-radius: 2px;
font-weight: bold;
font-size: 50px;
display: flex;
justify-content: center;
align-items: center;
}
#restartBtn {
padding: 15px;
margin: 1.5em;
border-radius: 10px;
border: none;
cursor: pointer;
font-size: 30px;
font-family: "Press Start 2P", sans-serif;
background-color: #d62839;
color: white;
}
const cells = document.querySelectorAll(".cell");
const statusText = document.querySelector("#statusText");
const restartBtn = document.querySelector("#restartBtn");
const winConditions = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[0, 3, 6],
[1, 4, 7],
[2, 5, 8],
[0, 4, 8],
[2, 4, 6],
];
let options = ["", "", "", "", "", "", "", "", ""]; //empty board. array of empty trings representing the board options
let currentPlayer = "X"; //starting player, to keep track
let isGameActive = false; //keep track of wheteher game is running. will be stwitched to true when game is initialised
initialiseGame(); //this function will be called whenever we open the browser
function initialiseGame() {
cells.forEach((cell) => cell.addEventListener("click", cellClicked)); //for each cell carry out the cell clicked function
restartBtn.addEventListener("click", restartGame); //when we click restarttn, run the restart game
statusText.textContent = `Waiting for Player ${currentPlayer} to start game`;
isGameActive = true;
}
function cellClicked() {
const cellIndex = this.getAttribute("cellIndex"); //get the attribute. we want the elements with the attribute cellIndex to execute the cunction
//if the cell isnt empty or game isnt running dont do anything if cell is clicked
if (options[cellIndex] != "" || !isGameActive) {
return;
}
updateCell(this, cellIndex); //otherwise reun the updateCellFunction with this as a parameter?
checkWinner();
}
function updateCell(cell, index) {
options[index] = currentPlayer; //update the placeholders in the options array, aka generate options array using index and place current players value within the index of the cell clicked
cell.textContent = currentPlayer; //display the above within the cell
addColour();
}
function addColour() {
if (currentPlayer == "X") {
document.querySelector(".cell").style.color = "red";
}
}
function changePlayer() {
currentPlayer = currentPlayer == "X" ? "O" : "X";
statusText.textContent = `Waiting for Player ${currentPlayer} to play turn`;
}
function checkWinner() {
let roundWon = false;
for (let i = 0; i < winConditions.length; i++) {
const condition = winConditions[i]; //we take the index of all the win conditions
const cellA = options[condition[0]]; //first index in winconditions
const cellB = options[condition[1]]; //second index in winconditions
const cellC = options[condition[2]]; //third index in winconditions
//if we check wincondition's index 0 aka 0,1,2. cell a will be 0, cellb will be 1 cell c will be 2 for index 2 a=3 b=4 c=5, for index 7 a =2 =4 c=6
//3 cells as 3 indices ber wincondition and 3x3 grid
if (cellA == "" || cellB == "" || cellC == "") {
continue; //aka keep loop running if the indices arent complete therefore condition hasnt been met
}
//checking if all the indices are Xs or Os for the winning condition
if (cellA == cellB && cellB == cellC) {
roundWon = true;
break; //break out of the for loop if win condition me
}
}
if (roundWon) {
statusText.textContent = `${currentPlayer} has Won!`;
isGameActive = false; //end game aka make nothing be able to be clicked anymore since game has been won
//if options does not include any spaces then update status aka all the board has been played with no winners so far
} else if (!options.includes("")) {
statusText.textContent = "Match draw";
//if noone has won yet and noone has drawn (aka there are still empty cells, run the function to change player)
} else {
changePlayer();
}
}
function restartGame() {
currentPlayer = "X";
options = ["", "", "", "", "", "", "", "", ""];
statusText.textContent = `${currentPlayer}'s turn`;
cells.forEach((cell) => (cell.textContent = ""));
isGameActive = true;
}
I am a beginner (as in very beginner), this is my first project. I have managed to make a working game by following a tutorial. I want to make player X one colour, and player O another. So that when X clicks it will the color style of the text content within the cell a specific colour and same for O.
function updateCell(cell, index) {
options[index] = currentPlayer; //update the placeholders in the options array, aka generate options array using index and place current players value within the index of the cell clicked
cell.textContent = currentPlayer; //display the above within the cell
addColour();
}
function addColour() {
if (currentPlayer == "X") {
document.querySelector(".cell").style.color = "red";
}
}
I tried adding a function in the updateCell function that I thought would do so but it only turns the first X red (for reasons I cannot comprehend.
2
Answers
The
addColour()
function is querying the cell class, not targeting the selected cell. Change it to accept a cell as its parameter. Set only that cell’s color depending on the current player. Like this…With only that change, the app runs as follows…
In the function
addColor
, you have this line:The querySelector searches the DOM for elements matching the
cell
class, and returns the first result it finds. Then your code changes the color of that cell to red. It gives no regard to the cell that was actually clicked, it just changes the first cell in the DOM that it finds.To fix this, you can make the
changeColour
function take the cell element as a parameter, like this:Then, in
updateCell
, instead ofaddColour()
, useaddColour(cell)
. See here for a working example.