I made a tic tac toe game using JavaScript. I tried to focus on a logical and well structured program. Could someone give me some feedback on the structuring of the JavaScript code?
//create and manage gameboard
const GameBoard = (function () {
//represents board on website
let board = ["0", "1", "2", "3", "4", "5", "6", "7", "8"];
/* col col col
row 0 0,0 0,1 0,2 -> row, col
row 1 1,0 1,1 1,2 -> row, col
row 2 2,0 2,1 2,2 -> row, col
*/
function getboard() {
return board;
}
function setboard(tile, value) {
board[tile] = value;
}
function resetboard() {
board = ["0", "1", "2", "3", "4", "5", "6", "7", "8"];
}
return { getboard, setboard, resetboard };
})();
//create and manage players
const players = (function () {
let player1 = {
symbol: "X",
}
let player2 = {
symbol: "O",
}
return { player1, player2 };
})();
//manage gameflow
const displayControl = (function () {
const winDrawOutput = document.querySelector(".win");//select field for output.
let counter = 0;
//get all 9 tiles:
const tile0 = document.querySelector(".tile.zero");
const tile1 = document.querySelector(".tile.one");
const tile2 = document.querySelector(".tile.two");
const tile3 = document.querySelector(".tile.three");
const tile4 = document.querySelector(".tile.four");
const tile5 = document.querySelector(".tile.five");
const tile6 = document.querySelector(".tile.six");
const tile7 = document.querySelector(".tile.seven");
const tile8 = document.querySelector(".tile.eight");
//add event listeners:
tile0.addEventListener("click", () => {
if(tile0.textContent === "") {//if empty, add symbol, otherwise dont
tile0.textContent = currentPlayerSymbol();//placeholder for now
GameBoard.setboard(0, currentPlayerSymbol());
checkForWin();
counter++;
}
});
tile1.addEventListener("click", () => {
if(tile1.textContent === "") {//if empty, add symbol, otherwise dont
tile1.textContent = currentPlayerSymbol();
GameBoard.setboard(1, currentPlayerSymbol());//set symbol to board array.
checkForWin();
counter++;
}
});
tile2.addEventListener("click", () => {
if(tile2.textContent === "") {//if empty, add symbol, otherwise dont
tile2.textContent = currentPlayerSymbol();
GameBoard.setboard(2, currentPlayerSymbol());//set symbol to board array.
checkForWin();
counter++;
}
});
tile3.addEventListener("click", () => {
if(tile3.textContent === "") {//if empty, add symbol, otherwise dont
tile3.textContent = currentPlayerSymbol();
GameBoard.setboard(3, currentPlayerSymbol());//set symbol to board array.
checkForWin();
counter++;
}
});
tile4.addEventListener("click", () => {
if(tile4.textContent === "") {//if empty, add symbol, otherwise dont
tile4.textContent = currentPlayerSymbol();
GameBoard.setboard(4, currentPlayerSymbol());//set symbol to board array.
checkForWin();
counter++;
}
});
tile5.addEventListener("click", () => {
if(tile5.textContent === "") {//if empty, add symbol, otherwise dont
tile5.textContent = currentPlayerSymbol();
GameBoard.setboard(5, currentPlayerSymbol());//set symbol to board array.
checkForWin();
counter++;
}
});
tile6.addEventListener("click", () => {
if(tile6.textContent === "") {//if empty, add symbol, otherwise dont
tile6.textContent = currentPlayerSymbol();
GameBoard.setboard(6, currentPlayerSymbol());//set symbol to board array.
checkForWin();
counter++;
}
});
tile7.addEventListener("click", () => {
if(tile7.textContent === "") {//if empty, add symbol, otherwise dont
tile7.textContent = currentPlayerSymbol();
GameBoard.setboard(7, currentPlayerSymbol());//set symbol to board array.
checkForWin();
counter++;
}
});
tile8.addEventListener("click", () => {
if(tile8.textContent === "") {//if empty, add symbol, otherwise dont
tile8.textContent = currentPlayerSymbol();
GameBoard.setboard(8, currentPlayerSymbol());//set symbol to board array.
checkForWin();
counter++;
}
});
function checkForWin() {
/*
what is possible?
-> horizontal win -> xxx/ooo: dont just check for occupied, check that symbols match
-> 0,0 and 0,1 and 0,2 -> first row horiz. win
-> 1,0 and 1,1 and 1,2 -> sec. row horiz. win
-> 2,0 and 2,1 and 2,2 -> third row horiz. win
-> vertical win ->
-> 0,0 and 1,0 and 2,0 -> first col
-> 0,1 and 1,1 and 2,1 -> second col
-> 0,2 and 1,2 and 2,2 -> third col
-> diagonal win ->
-> 0,0 and 1,1 and 2,2 -> top left to bottom right or vice versa
-> 2,0 and 1,1 and 0,2 -> bottom left to top right or vice versa
-> draw -> everyting occupied but no win registered.
*/
const board = GameBoard.getboard();//get board.
//x win horizontal:
if((board[0] === "X" && board[1] === "X" && board[2] === "X") ||
(board[3] === "X" && board[4] === "X" && board[5] === "X") ||
(board[6] === "X" && board[7] === "X" && board[8] === "X") ||
(board[0] === "X" && board[3] === "X" && board[6] === "X") || //x win vertical
(board[1] === "X" && board[4] === "X" && board[7] === "X") ||
(board[2] === "X" && board[5] === "X" && board[8] === "X") ||
(board[0] === "X" && board[4] === "X" && board[8] === "X") || //x win diagonal
(board[6] === "X" && board[4] === "X" && board[2] === "X")) {
winDrawOutput.textContent = `X wins!`; //X wins
} //same for O:
else if ((board[0] === "X" && board[1] === "X" && board[2] === "X") ||
(board[3] === "X" && board[4] === "X" && board[5] === "X") ||
(board[6] === "X" && board[7] === "X" && board[8] === "X") ||
(board[0] === "X" && board[3] === "X" && board[6] === "X") ||
(board[1] === "X" && board[4] === "X" && board[7] === "X") ||
(board[2] === "X" && board[5] === "X" && board[8] === "X") ||
(board[0] === "X" && board[4] === "X" && board[8] === "X") ||
(board[6] === "X" && board[4] === "X" && board[2] === "X")) {
winDrawOutput.textContent = `O wins!`; //O wins
}//else if everything is occupied but no win has been registered -> draw
else if(board[0] !== "0" && board[1] !== "1" && board[2] !== "2" &&
board[3] !== "3" && board[4] !== "4" && board[5] !== "5" &&
board[6] !== "6" && board[7] !== "7" && board[8] !== "8") {
winDrawOutput.textContent = "It's a draw!";
}
}
function currentPlayerSymbol() {
let symbol = "";
if(counter === 0 || counter % 2 === 0) {
symbol = players.player1.symbol;
}
else if(counter % 2 !== 0) {
symbol = players.player2.symbol;
}
return symbol;
}
//reset functionality:
function resetView() {
tile0.textContent = "";
tile1.textContent = "";
tile2.textContent = "";
tile3.textContent = "";
tile4.textContent = "";
tile5.textContent = "";
tile6.textContent = "";
tile7.textContent = "";
tile8.textContent = "";
}
function reset() {
//add reset button, on click, reset board and array for board.
GameBoard.resetboard();
resetView();//reset content of all tiles.
winDrawOutput.textContent = "";//reset output field
counter = 0;
}
//on click, reset everything.
const resetButton = document.querySelector(".reset");
resetButton.addEventListener("click", () => {
reset();
resetView();
});
})();
* {
margin: none;
padding: none;
border-style: border-box;
font-family:'Courier New', Courier, monospace;
}
.wrapper {
display: flex;
height: 100vh;
width: 100vw;
flex-direction: column;
align-items: center;
gap: 30px;
}
.title {
font-size: large;
color: darkblue;
}
.title:hover {
color: lightseagreen;
transform: scale(1.1);
}
.board {
display: grid;
height: 24.5rem;
width: 24.5rem;
grid-template-columns: repeat(3,8rem);
grid-template-rows: repeat(3, 8rem);
}
.tile {
width: 8rem;
height: 8rem;
border: 5px solid grey;
display:flex;
justify-content: center;
align-items: center;
font-size: 50px;
}
.tile.zero {
border-top: none;
border-left: none;
}
.tile.one {
border-top: none;
}
.tile.two {
border-top: none;
border-right: none;
border-left: none;
}
.tile.three {
border-left: none;
border-bottom: none;
}
.tile.four {
border-bottom: none;
}
.tile.five {
border-right: none;
border-left: none;
border-bottom: none;
}
.tile.six {
border-left: none;
border-bottom: none;
}
.tile.seven {
border-bottom: none;
}
.tile.eight {
border-left: none;
border-right: none;
border-bottom: none;
}
.win {
height: 100px;
width: 250px;
text-align: center;
}
button {
width: 8rem;
height: 4rem;
font-size: 1.5rem;
border-radius: 1rem;
background: white;
}
button:hover {
transform: scale(1.1);
}
<!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="stylesheet" href="./css/style.css">
<script defer src="./javaScript/doStuff.js"></script>
</head>
<body>
<div class="wrapper">
<div class="title">
<h1>Tic-Tac-Toe</h1>
</div>
<div class="gridContainer">
<div class="board">
<div class="tile zero"></div>
<div class="tile one"></div>
<div class="tile two"></div>
<div class="tile three"></div>
<div class="tile four"></div>
<div class="tile five"></div>
<div class="tile six"></div>
<div class="tile seven"></div>
<div class="tile eight"></div>
</div>
</div>
<div class="win"></div>
<button type="button "class="reset">Reset?</button>
</div>
</body>
</html>
Edit: just realized that I forgot to change the Symbols that the program checks for in the win function to "O" instead of "X" for the if condition that checks whether "O" won. Ignore that please.