2023-12-14 18:37:25 -05:00
|
|
|
const tictactoeBoard = (function() {
|
|
|
|
|
|
|
|
let gameBoard = new Array(["", "", ""], ["", "", ""], ["", "", ""]);
|
|
|
|
|
|
|
|
const getGameBoard = () => gameBoard;
|
|
|
|
// const printGameBoard = () => console.log(gameBoard[0] + "\n" + gameBoard[1] + "\n" + gameBoard[2]);
|
|
|
|
|
|
|
|
const resetGameBoard = () => {
|
|
|
|
gameBoard.forEach(item => {
|
|
|
|
item[0] = '';
|
|
|
|
item[1] = '';
|
|
|
|
item[2] = '';
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
const posititionAvailable = (position) => {
|
|
|
|
switch (position) {
|
|
|
|
case 1:
|
|
|
|
return isEmpty(gameBoard[0][0]);
|
|
|
|
case 2:
|
|
|
|
return isEmpty(gameBoard[0][1]);
|
|
|
|
case 3:
|
|
|
|
return isEmpty(gameBoard[0][2]);
|
|
|
|
case 4:
|
|
|
|
return isEmpty(gameBoard[1][0]);
|
|
|
|
case 5:
|
|
|
|
return isEmpty(gameBoard[1][1]);
|
|
|
|
case 6:
|
|
|
|
return isEmpty(gameBoard[1][2]);
|
|
|
|
case 7:
|
|
|
|
return isEmpty(gameBoard[2][0]);
|
|
|
|
case 8:
|
|
|
|
return isEmpty(gameBoard[2][1]);
|
|
|
|
case 9:
|
|
|
|
return isEmpty(gameBoard[2][2]);
|
|
|
|
default:
|
|
|
|
Alert('Must enter a number 1 - 9');
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const isEmpty = position => position === "";
|
|
|
|
|
|
|
|
const placeOnBoard = (position, marker) => {
|
|
|
|
// places marker on the gameboard
|
|
|
|
marker = marker.getValue(); // get value from object
|
|
|
|
|
|
|
|
switch (position) {
|
|
|
|
case 1:
|
|
|
|
gameBoard[0][0] = marker;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
gameBoard[0][1] = marker;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
gameBoard[0][2] = marker;
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
gameBoard[1][0] = marker;
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
gameBoard[1][1] = marker;
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
gameBoard[1][2] = marker;
|
|
|
|
break;
|
|
|
|
case 7:
|
|
|
|
gameBoard[2][0] = marker;
|
|
|
|
break;
|
|
|
|
case 8:
|
|
|
|
gameBoard[2][1] = marker;
|
|
|
|
break;
|
|
|
|
case 9:
|
|
|
|
gameBoard[2][2] = marker;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
resetGameBoard,
|
|
|
|
// printGameBoard,
|
|
|
|
getGameBoard,
|
|
|
|
placeOnBoard,
|
|
|
|
posititionAvailable
|
|
|
|
};
|
|
|
|
})();
|
|
|
|
|
|
|
|
|
|
|
|
const playerInfo = (function() {
|
|
|
|
class Player {
|
|
|
|
constructor(name, piece) {
|
|
|
|
this.piece = piece;
|
|
|
|
this.name = name;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const player = (name, piece) => {
|
|
|
|
return new Player(name, piece);
|
|
|
|
};
|
|
|
|
|
|
|
|
return { player }
|
|
|
|
})();
|
|
|
|
|
|
|
|
|
|
|
|
function block() {
|
|
|
|
value = "-";
|
|
|
|
const addToken = player => {
|
|
|
|
// player is a player info object
|
|
|
|
value = player.piece;
|
|
|
|
};
|
|
|
|
|
|
|
|
const getValue = () => value;
|
|
|
|
|
|
|
|
return {
|
|
|
|
addToken,
|
|
|
|
getValue
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
const gameController = (() => {
|
|
|
|
// Controls the overall flow of the game
|
|
|
|
let players = [
|
|
|
|
playerInfo.player('Player 1', 'X'),
|
|
|
|
playerInfo.player('Player 2', 'O')
|
|
|
|
]
|
|
|
|
|
|
|
|
let gameOver;
|
|
|
|
let xTurn = true; // True = X's turn, False = O's turn
|
|
|
|
let round = 0; // 9 Total Rounds for Tic Tac Toe
|
|
|
|
|
|
|
|
const resetGame = () => {
|
|
|
|
round = 0;
|
|
|
|
xTurn = true;
|
|
|
|
gameOver = false;
|
|
|
|
tictactoeBoard.resetGameBoard();
|
|
|
|
}
|
|
|
|
|
|
|
|
const gameStatus = () => gameOver;
|
|
|
|
const gameRound = () => round;
|
|
|
|
|
|
|
|
const switchPlayerTurn = () => {
|
|
|
|
xTurn = !xTurn;
|
|
|
|
}
|
|
|
|
|
|
|
|
const playRound = position => {
|
|
|
|
let marker = new block()
|
|
|
|
let positionOpen = tictactoeBoard.posititionAvailable(position);
|
|
|
|
|
|
|
|
if (round < 10 && positionOpen) {
|
|
|
|
|
|
|
|
let player = xTurn ? players[0] : players[1];
|
|
|
|
marker.addToken(player);
|
|
|
|
tictactoeBoard.placeOnBoard(position, marker); // position on board
|
|
|
|
|
|
|
|
// Check for Winner
|
|
|
|
gameOver = evalGameOutcome(tictactoeBoard.getGameBoard());
|
|
|
|
|
|
|
|
if (gameOver) {
|
|
|
|
console.log(`${player.name}: ${player.piece} won!`)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
switchPlayerTurn();
|
|
|
|
|
|
|
|
} else {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
round += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
const evalGameOutcome = gameBoard => {
|
|
|
|
// create a new array of the vertical indexes in the game board
|
|
|
|
let vertArray = [];
|
|
|
|
gameBoard.forEach((_, index) => vertArray.push(gameBoard.map(e => e[index])));
|
|
|
|
|
|
|
|
// create an array of diagnal pieces
|
|
|
|
let diagArray = [
|
|
|
|
[gameBoard[0][0], gameBoard[1][1], gameBoard[2][2]],
|
2023-12-15 16:21:27 -05:00
|
|
|
[gameBoard[0][2], gameBoard[1][1], gameBoard[2][0]]
|
2023-12-14 18:37:25 -05:00
|
|
|
];
|
|
|
|
|
2023-12-15 16:33:59 -05:00
|
|
|
let checkGameBoard = [gameBoard, vertArray, diagArray];
|
|
|
|
for (i = 0; i < 3; i++) {
|
2023-12-14 18:37:25 -05:00
|
|
|
let outcome = _evalGameOutcome(checkGameBoard[i]);
|
|
|
|
if (outcome) {
|
|
|
|
return true;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
|
|
|
|
const _evalGameOutcome = arr => {
|
|
|
|
// Checks if array values are equal to determine winner
|
|
|
|
let isWinner = checkArr => checkArr.reduce(function(a, b) { return a === b ? a : false; });
|
|
|
|
|
|
|
|
const outcome = arr.find(element => {
|
|
|
|
let result = isWinner(element);
|
|
|
|
if (result != false) {
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
return outcome;
|
|
|
|
};
|
|
|
|
|
|
|
|
return { playRound, resetGame, gameStatus, gameRound }
|
|
|
|
})();
|
|
|
|
|
|
|
|
|
|
|
|
const screenController = (() => {
|
|
|
|
const contentDiv = document.querySelector('.content')
|
|
|
|
const gameDiv = document.querySelector('.game-area');
|
|
|
|
const gameStatus = document.querySelector('.game-status')
|
|
|
|
const game = tictactoeBoard.getGameBoard();
|
|
|
|
const resetButton = document.createElement('button');
|
|
|
|
|
|
|
|
resetButton.classList.add(['btn']);
|
|
|
|
resetButton.textContent = 'New Game';
|
|
|
|
contentDiv.appendChild(resetButton);
|
|
|
|
|
|
|
|
const updateScreen = () => {
|
|
|
|
status()
|
|
|
|
displayBoard();
|
|
|
|
}
|
|
|
|
|
|
|
|
const status = () => {
|
|
|
|
let pTags = gameStatus.querySelectorAll('p');
|
|
|
|
if (pTags) pTags.forEach(e => e.remove());
|
|
|
|
|
|
|
|
let message = document.createElement('p');
|
|
|
|
let gameOn = gameController.gameStatus() ? "Play again?" : "";
|
|
|
|
let round = gameController.gameRound();
|
|
|
|
|
|
|
|
if (round <= 9 && gameOn) {
|
|
|
|
message.textContent = gameOn;
|
|
|
|
} else if (round >= 9 && !gameOn) {
|
|
|
|
message.textContent = "Draw, play again?";
|
|
|
|
}
|
|
|
|
|
|
|
|
gameStatus.appendChild(message);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const displayBoard = () => {
|
|
|
|
// Check if someone won the game
|
|
|
|
|
|
|
|
let count = 0; // This is for the data blocks
|
|
|
|
gameDiv.querySelectorAll('.block').forEach(e => e.remove());
|
|
|
|
game.forEach((e) => {
|
|
|
|
e.forEach((element) => {
|
|
|
|
count += 1;
|
|
|
|
const block = document.createElement('div');
|
|
|
|
block.classList.add('block');
|
|
|
|
block.setAttribute('data-block', count);
|
|
|
|
block.textContent = element;
|
|
|
|
block.addEventListener('click', clickHandlerBoard);
|
|
|
|
gameDiv.appendChild(block);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function clickHandlerBoard(e) {
|
|
|
|
const selectedBlock = e.target.dataset.block;
|
|
|
|
const empty = e.target.textContent;
|
|
|
|
const gameStatus = gameController.gameStatus();
|
|
|
|
|
|
|
|
if (!selectedBlock || empty !== "" || gameStatus) return;
|
|
|
|
|
|
|
|
gameController.playRound(Number(selectedBlock));
|
|
|
|
updateScreen();
|
|
|
|
};
|
|
|
|
|
|
|
|
function clickResetButton() {
|
|
|
|
gameController.resetGame();
|
|
|
|
status();
|
|
|
|
updateScreen();
|
|
|
|
}
|
|
|
|
|
|
|
|
resetButton.addEventListener('click', clickResetButton);
|
|
|
|
|
|
|
|
|
|
|
|
// Initial Load
|
|
|
|
updateScreen();
|
|
|
|
})();
|
|
|
|
|
|
|
|
|