Reputation: 329
I am new to JavaScript. I am trying to make a Tic-Tac-Toe with AI capabilities. Here is the full code.
const statusDisplay = document.querySelector('.game--status');
let gameActive = true;
let currentPlayer = "X";
let gameState = ["", "", "", "", "", "", "", "", ""];
let winingScores = {
X: 10,
O: -10,
tie: 0
};
const winningMessage = () => `Player ${currentPlayer} has won!`;
const drawMessage = () => `Game ended in a draw!`;
const currentPlayerTurn = () => `It's ${currentPlayer}'s turn`;
statusDisplay.innerHTML = currentPlayerTurn();
const winningConditions = [
// Horizontal wins
[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
// Vertical wins
[0, 3, 6],
[1, 4, 7],
[2, 5, 8],
// Diagonal wins
[0, 4, 8],
[2, 4, 6]
];
function handleCellPlayed(clickedCell, clickedCellIndex) {
gameState[clickedCellIndex] = currentPlayer;
clickedCell.innerHTML = currentPlayer;
}
function handlePlayerChange() {
currentPlayer = currentPlayer === "X" ? "O" : "X";
statusDisplay.innerHTML = currentPlayerTurn();
}
function handleResultValidation() {
let roundWon = false;
for (let i = 0; i <= 7; i++) {
const winCondition = winningConditions[i];
let a = gameState[winCondition[0]];
let b = gameState[winCondition[1]];
let c = gameState[winCondition[2]];
if (a === '' || b === '' || c === '') {
continue;
}
if (a === b && b === c) {
roundWon = true;
break
}
}
if (roundWon) {
statusDisplay.innerHTML = winningMessage();
gameActive = false;
return;
}
let roundDraw = !gameState.includes("");
if (roundDraw) {
statusDisplay.innerHTML = drawMessage();
gameActive = false;
return;
}
handlePlayerChange();
}
function handleCellClick(clickedCellEvent) {
if(currentPlayer === "X"){
const clickedCell = clickedCellEvent.target;
const clickedCellIndex = parseInt(clickedCell.getAttribute('data-cell-index'));
if (gameState[clickedCellIndex] !== "" || !gameActive) {
return;
}
handleCellPlayed(clickedCell, clickedCellIndex);
handleResultValidation();
}
else{
const clickedCellIndex = bestMoveForAI();
const clickedCell =
handleCellPlayed(clickedCell, clickedCellIndex);
handleResultValidation();
}
}
function handleRestartGame() {
gameActive = true;
currentPlayer = "X";
gameState = ["", "", "", "", "", "", "", "", ""];
statusDisplay.innerHTML = currentPlayerTurn();
document.querySelectorAll('.cell').forEach(cell => cell.innerHTML = "");
}
function bestMoveForAI(){
let bestScore = -Infinity;
let bestMove = -1;
for(let i = 0; i < 9; i++){
if(shadowGameState[i] === ""){
shadowGameState[i] = "O";
let score = minimax(gameState,0, false);
gameState[i] = "";
if(score > bestScore){
bestScore = score;
bestMove = i;
}
}
}
return bestMove;
}
function minimax(gameState, depth, isMaximizing){
// check for AI win as "O" only
let result = checkWinner();
if (result !== null) {
return winingScores[result];
}
if(isMaximizing===false){
for(let i = 0; i < 9; i++){
if(gameState[i] === ""){
gameState = "O";
let score = minimax(gameState, depth + 1, false);
gameState = "";
bestScore = max(score, bestScore);
}
}
return bestScore;
}
}
function checkWinner(){
let winner;
for(let i = 0; i <= 7; i++){
const winCondition = winningConditions[i];
let a = gameState[winCondition[0]];
let b = gameState[winCondition[1]];
let c = gameState[winCondition[2]];
if(a === '' || b === '' || c === ''){
continue;
}
if(a === b && b === c){
winner = a;
break;
}
}
return winner;
}
document.querySelectorAll('.cell').forEach(cell => cell.addEventListener('click', handleCellClick));
document.querySelector('.game--restart').addEventListener('click', handleRestartGame);
Human player (in this case first player with "X") can click a cell and javascript update the value of the game state and the cell in question.
For AI player's (in this case second player with "O") move, I am finding the best move and then updating the game state accordingly. But I don't know how to update the cell according to the best move.
Can anyone please help me ?
This is the function I am stuck at:
function handleCellClick(clickedCellEvent) {
if(currentPlayer === "X"){
const clickedCell = clickedCellEvent.target;
const clickedCellIndex = parseInt(clickedCell.getAttribute('data-cell-index'));
if (gameState[clickedCellIndex] !== "" || !gameActive) {
return;
}
handleCellPlayed(clickedCell, clickedCellIndex);
handleResultValidation();
}
else{
const clickedCellIndex = bestMoveForAI();
const clickedCell = // how to find the clickedCell based on clickedCellIndex ?
handleCellPlayed(clickedCell, clickedCellIndex);
handleResultValidation();
}}
I know the index of clickedCell. I want to find the clickedCell , so that I can show "O" in the clickedCell.
Upvotes: 0
Views: 131
Reputation: 6187
You can query elements by the attribute. For example, for index 0, you could:
const clickedCell = document.querySelector('[data-cell-index="0"]');
Or in your case:
const clickedCell = document.querySelector(`[data-cell-index="${clickedCellIndex}"]`);
Upvotes: 1