cHappiness
cHappiness

Reputation: 41

TicTacToe Game in JavaScript

I have been trying to find out why my TicTacToe game is not checking the way I wanted to. As I have been watching tutorials but still not able to figure out the logic to properly make the function winning runs when the player wins the game.

Here I try to push the O or X to the array, and console.log to see what it looks like and why the winning condition check is not working.

  spaces.push[id];
  console.log(spaces);

I have also tried other ways to make the program right, like using a pre-made winning condition and map the current array through, but also not working...

  const winningCondition = [
    [0, 1, 2],
    [3, 4, 5],
    [6, 7, 8],
    [0, 3, 6],
    [1, 4, 7],
    [2, 5, 8],
    [0, 4, 8],
    [2, 4, 6],
  ];

For the cells, I am creating 9 divs in HTML and using the grids system in CSS.

I would truly appreciate your help! Below is the JavaScript code for the TicTacToe game:

const winning = (player) => {
  if (spaces[0] === player) {
    if (spaces[1] === player && spaces[2] === player) return true;
    if (spaces[3] === player && spaces[6] === player) return true;
    if (spaces[4] === player && spaces[8] === player) return true;
  }
  if (spaces[8] === player) {
    if (spaces[2] === player && spaces[5] === player) return true;
    if (spaces[6] === player && spaces[7] === player) return true;
  }
  if (spaces[4] === player) {
    if (spaces[1] === player && spaces[7] === player) return true;
    if (spaces[3] === player && spaces[5] === player) return true;
  }
};

Upvotes: 0

Views: 1162

Answers (2)

Vitalii
Vitalii

Reputation: 2131

There is no reason to have spaces.push(id) which adds extra element to the end of array, just remove it. You already have spaces[id] = currentPlayer which writes current player value into needed position in spaces.

The only issue I've found was that cells should have numbers from 0 to 8 which correspond to indexes in spaces array:

0 1 2
3 4 5
6 7 8
<div class="game">
    <div class="cell" id="0"></div>
    <div class="cell" id="1"></div>
    <div class="cell" id="2"></div>
    <div class="cell" id="3"></div>
    <div class="cell" id="4"></div>
    <div class="cell" id="5"></div>
    <div class="cell" id="6"></div>
    <div class="cell" id="7"></div>
    <div class="cell" id="8"></div>
</div>

There are 8 winning conditions (3 rows, 3 cols and 2 diagonals). One diagonal condition was missing:

if (spaces[4] === player) {
    // ...
    if (spaces[2] === player && spaces[6] === player) return true;
}

Here's full code:

const cells = document.querySelectorAll(".cell");
const playText = document.getElementById("game-text");
const restartBtn = document.getElementById("restart");

const spaces = [];
const OPlayer = "O";
const XPlayer = "X";
let currentPlayer;

function handleClick(e) {
    const id = e.target.id;
    if (!spaces[id]) {
        spaces[id] = currentPlayer;

        console.log('[' + spaces.slice(0, 3) + ']\n[' + spaces.slice(3, 6) + ']\n[' + spaces.slice(6) + ']');
        e.target.innerText = currentPlayer;

        if (playerWon(currentPlayer)) {
            const winningAlert = document.createElement("p");
            winningAlert.setAttribute("id", "winning-text");
            winningAlert.innerText = `${currentPlayer} HAS WON!`;
            playText.appendChild(winningAlert);

            setTimeout(() => {
                restart();
            }, 4000);
            return;
        }
        currentPlayer = currentPlayer === OPlayer ? XPlayer : OPlayer;
    }
}

cells.forEach((cell) => {
    cell.addEventListener("click", handleClick);
});

const playerWon = (player) => {
    if (spaces[0] === player) {
        if (spaces[1] === player && spaces[2] === player) return true;
        if (spaces[3] === player && spaces[6] === player) return true;
        if (spaces[4] === player && spaces[8] === player) return true;
    }
    if (spaces[8] === player) {
        if (spaces[2] === player && spaces[5] === player) return true;
        if (spaces[6] === player && spaces[7] === player) return true;
    }
    if (spaces[4] === player) {
        if (spaces[1] === player && spaces[7] === player) return true;
        if (spaces[3] === player && spaces[5] === player) return true;
        if (spaces[2] === player && spaces[6] === player) return true;
    }
};

const restart = () => {
    spaces.forEach((space, index) => {
        console.log(space);
        spaces[index] = null;
    });
    cells.forEach((cell) => {
        cell.innerText = "";
    });
    playText.innerHTML = `LET'S PLAY!`;
    currentPlayer = OPlayer;
};

restartBtn.addEventListener("click", restart);

restart();
* {
    box-sizing: border-box;
    font-family: Verdana, Geneva, Tahoma, sans-serif;
}

.game-board {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    margin: 6% 15%;
}

.game {
    display: grid;
    grid-gap: 1px;
    grid-template-columns: repeat(3, 1fr);
}

.btn {
    padding: 15px 18px;
    margin: 30px auto auto auto;
    width: 120px;
    font-size: 18px;
    border-radius: 8px;
    border: none;
    color: white;
    background: green;
    cursor: pointer;
}

.btn:hover {
    transition-duration: 0.3s;
    background-color: red;
    transform: translateY(-5px);
}


.cell {
    width: 150px;
    height: 150px;
    margin: 8px 8px;
    border-radius: 15px;
    background-color: brown;
    text-align: center;
    font-size: 120px;
}

#game-text {
    font-size: 25px;
    font-weight: bold;
    text-transform: uppercase;
    margin: -10px auto 25px auto;
}

#winning-text {
    text-align: center;
    margin-bottom: -20px;
    font-size: 20px;
    color: purple;
}
<section class="game-board">
    <div id="game-text"></div>
    <div class="game">
        <div class="cell" id="0"></div>
        <div class="cell" id="1"></div>
        <div class="cell" id="2"></div>
        <div class="cell" id="3"></div>
        <div class="cell" id="4"></div>
        <div class="cell" id="5"></div>
        <div class="cell" id="6"></div>
        <div class="cell" id="7"></div>
        <div class="cell" id="8"></div>
    </div>
    <button class="btn" id="restart">Restart</button>
</section>

Upvotes: 0

danh
danh

Reputation: 62686

It looks like the board is an array called spaces of length nine. It looks like the array has values of either ' ', 'x' or 'o', representing unoccupied or occupied by one of the two players.

You've enumerated which spaces must be occupied by a player in a win. A simple function to check for a win would iterate that array.

// assuming spaces is defined here as game state, an array 'x', 'o' or ' '
const winningLines = [
    [0, 1, 2],
    [3, 4, 5],
    [6, 7, 8],
    [0, 3, 6],
    [1, 4, 7],
    [2, 5, 8],
    [0, 4, 8],
    [2, 4, 6],
  ];


// call with 'x' or 'o' representing player
function playerWon(player) {
  const playerOccupiesLine = line => line.every(el => spaces[el] === player);
  return winningLines.some(line => playerOccupiesLine(line);
}

Upvotes: 1

Related Questions