I am making a simple tic tac toe game in order to practice the module pattern and factory pattern. i have implemented event listeners on the fields to mark x and o. but i need the x's and o's to also go inside the board array in order to compare with the winning combinations array.
i need to ultimately be able to find the winner after.
//player factory function
const createPlayer = (name,marker) => {
return {name,marker}
}
//gameboard object
const gameBoard = (() => {
//create board array
let board = []
for (i=0; i<9; i ) {
board.push("")
}
//add event listeners on each field that will mark field and change player's turn state
const fields = document.querySelectorAll(".field")
const nextTurn = document.querySelector(".message")
let turn = 0
fields.forEach((field) => {
field.addEventListener('click',handleClick,{once:true})
function handleClick() {
if(turn %= 2) {
field.innerHTML = "O"
field.classList.toggle("marker")
nextTurn.innerHTML= "Player X's turn"}
else {
field.innerHTML = "X"
field.classList.toggle("marker")
nextTurn.innerHTML= "Player O's turn"}
turn
}
})
//restart game
const restart = document.getElementById("restart-button")
restart.addEventListener("click",clicke)
function clicke() {
const fields = document.querySelectorAll(".field").innerHTML=""
}
return {
board,
}
})()
// game object
const game = (() => {
//declare players
const playerOne = createPlayer("player x", "x")
const playerTwo = createPlayer("player o", "o")
//starting point
let activePlayer = playerOne
let winnerDeclared = false
let remainingSpots = 9
//selectors
let playerName = document.querySelector('.message') //alert next turn
//winning conditons
const winningConditons = [
[0,1,2]
[3,4,5]
[6,7,8]
[0,3,8]
[1,4,7]
[2,5,8]
[0,4,8]
[2,4,6]
];
//check for winner
function checkWinner() {
}
function declareTie(){
playerName.innerHTML = "Its a tie!"
}
}
)()
.gameboard{
display: grid;
grid-template-columns: repeat(3,1fr);
grid-gap: 5px;
}
.field{
width: 150px;
height: 150px;
background-color: #ededee;
}
<div >
<div >
<div >
Tic-Tac-Toe
</div>
</div>
<div >
<div >Player X's turn</div>
<div >
<div ></div>
<div ></div>
<div ></div>
<div ></div>
<div ></div>
<div ></div>
<div ></div>
<div ></div>
<div ></div>
</div>
<div >
<button id="restart-button">Restart</button>
</div>
</div>
</div>
CodePudding user response:
See the comments in the attached snipped - it should guide you
//player factory function
const createPlayer = (name,marker) => {
return {name,marker}
}
//gameboard object
const gameBoard = (() => {
//create board array
let board = []
for (i=0; i<9; i ) {
board.push("")
}
//add event listeners on each field that will mark field and change player's turn state
const fields = document.querySelectorAll(".field")
const nextTurn = document.querySelector(".message")
let turn = 0
fields.forEach((field) => {
field.addEventListener('click',handleClick,{once:true})
function handleClick() {
if(turn %= 2) {
field.innerHTML = "O"
field.classList.toggle("marker")
nextTurn.innerHTML= "Player X's turn"
}
else {
field.innerHTML = "X"
field.classList.toggle("marker")
nextTurn.innerHTML= "Player O's turn"
}
game.checkWinner(); // <- check winner after every move
turn ;
}
})
//restart game
const restart = document.getElementById("restart-button")
restart.addEventListener("click",clicke)
function clicke() {
console.log('you had a mistake here - you need to iterate the fields', document.querySelectorAll(".field"));
const fields = document.querySelectorAll(".field").forEach(field =>
{
field.innerHTML="";
// you also need to add the event listeners again where needed - field.addEventListener('click', ...)
}
);
}
return {
board,
}
})()
// game object
const game = (() => {
//declare players
const playerOne = createPlayer("player x", "x")
const playerTwo = createPlayer("player o", "o")
//starting point
let activePlayer = playerOne
let winnerDeclared = false
let remainingSpots = 9
//selectors
let playerName = document.querySelector('.message') //alert next turn
//winning conditons
const winningConditons = [
[0,1,2], // <- you forgot the commas here!
[3,4,5],
[6,7,8],
[0,3,8],
[1,4,7],
[2,5,8],
[0,4,8],
[2,4,6]
];
//check for winner
function checkWinner() {
console.log('do stuff here');
}
function declareTie(){
playerName.innerHTML = "Its a tie!"
}
return { // <- you need to "export" a function to be able to use it
checkWinner
}
}
)()
.gameboard{
display: grid;
grid-template-columns: repeat(3,1fr);
grid-gap: 5px;
}
.field{
width: 150px;
height: 150px;
background-color: #ededee;
}
<div >
<div >
<div >
Tic-Tac-Toe
</div>
</div>
<div >
<div >Player X's turn</div>
<div >
<div ></div>
<div ></div>
<div ></div>
<div ></div>
<div ></div>
<div ></div>
<div ></div>
<div ></div>
<div ></div>
</div>
<div >
<button id="restart-button">Restart</button>
</div>
</div>
</div>
CodePudding user response:
I have added a function checkPlayerMeetsConditions()
to check whether player meets the conditions.
const checkPlayerMeetsConditions = (boardNodes, targetPlayer) => {
const currResult = [];
//winning conditons
const winningConditons = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[0, 3, 6],
[1, 4, 7],
[2, 5, 8],
[0, 4, 8],
[2, 4, 6],
];
boardNodes.forEach(({
innerHTML: val
}, i) => {
if (val === targetPlayer) {
currResult.push(i);
}
});
let isWinner = false;
winningConditons.forEach((condition) => {
const isMatched = condition.reduce((isMatched, currVal, i) => currResult[i] !== currVal ? false : isMatched, true);
if (isMatched) {
isWinner = true;
return;
}
});
return isWinner;
}
Additionally I have filled your checkWinner()
function as:
//check for winner
const checkWinner = () => {
const fields = document.querySelectorAll(".field");
const isOWinner = checkPlayerMeetsConditions(fields, "O");
const isXWinner = checkPlayerMeetsConditions(fields, "X");
if (isOWinner && isXWinner) { // when tie
document.querySelector(".message").innerHTML = "Game Tie";
} else if (isOWinner) {
document.querySelector(".message").innerHTML = "O is Winner";
} else if (isXWinner) {
document.querySelector(".message").innerHTML = "X is Winner";
}
}
Here is the full working codes:
//player factory function
const createPlayer = (name, marker) => {
return {
name,
marker
}
}
const checkPlayerMeetsConditions = (boardNodes, targetPlayer) => {
const currResult = [];
//winning conditons
const winningConditons = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[0, 3, 6],
[1, 4, 7],
[2, 5, 8],
[0, 4, 8],
[2, 4, 6],
];
boardNodes.forEach(({
innerHTML: val
}, i) => {
if (val === targetPlayer) {
currResult.push(i);
}
});
let isWinner = false;
winningConditons.forEach((condition) => {
const isMatched = condition.reduce((isMatched, currVal, i) => currResult[i] !== currVal ? false : isMatched, true);
if (isMatched) {
isWinner = true;
return;
}
});
return isWinner;
}
//check for winner
const checkWinner = () => {
const fields = document.querySelectorAll(".field");
const isOWinner = checkPlayerMeetsConditions(fields, "O");
const isXWinner = checkPlayerMeetsConditions(fields, "X");
if (isOWinner && isXWinner) { // when tie
document.querySelector(".message").innerHTML = "Game Tie";
} else if (isOWinner) {
document.querySelector(".message").innerHTML = "O is Winner";
} else if (isXWinner) {
document.querySelector(".message").innerHTML = "X is Winner";
}
}
//gameboard object
const gameBoard = (() => {
//create board array
let board = []
for (i = 0; i < 9; i ) {
board.push("")
}
//add event listeners on each field that will mark field and change player's turn state
const fields = document.querySelectorAll(".field")
const nextTurn = document.querySelector(".message")
let turn = 0
fields.forEach((field) => {
field.addEventListener('click', handleClick, {
once: true
})
function handleClick() {
if (turn %= 2) {
field.innerHTML = "O"
field.classList.toggle("marker")
nextTurn.innerHTML = "Player X's turn"
} else {
field.innerHTML = "X"
field.classList.toggle("marker")
nextTurn.innerHTML = "Player O's turn"
}
turn
checkWinner(); //check the winner
}
})
//restart game
const restart = document.getElementById("restart-button")
restart.addEventListener("click", clicke)
function clicke() {
const fields = document.querySelectorAll(".field").innerHTML = ""; // This is not correct
}
return {
board,
}
})()
// game object
const game = (() => {
//declare players
const playerOne = createPlayer("player x", "x")
const playerTwo = createPlayer("player o", "o")
//starting point
let activePlayer = playerOne
let winnerDeclared = false
let remainingSpots = 9
//selectors
let playerName = document.querySelector('.message') //alert next turn
function declareTie() {
playerName.innerHTML = "Its a tie!"
}
})()
.gameboard{
display: grid;
grid-template-columns: repeat(3,1fr);
grid-gap: 5px;
}
.field{
width: 150px;
height: 150px;
background-color: #ededee;
}
<div >
<div >
<div >
Tic-Tac-Toe
</div>
</div>
<div >
<div >Player X's turn</div>
<div >
<div ></div>
<div ></div>
<div ></div>
<div ></div>
<div ></div>
<div ></div>
<div ></div>
<div ></div>
<div ></div>
</div>
<div >
<button id="restart-button">Restart</button>
</div>
</div>
</div>
Hope it helps, cheers!