Search code examples
javascripthtmlcsstic-tac-toe

Javascript code works, but not immediately


I tried to write a simple tic tac toe game. When I was coding I encounter a weird "bug" I would say? A function called "isWinner" checks if someone won. It compares one array called "winningCombinations" with a combination which it gets. The thing is that code should show "winner chicken dinner" immediately after it finds the winning combination. Well, It doesn't. It shows it up after 3 additional moves. I don't have any idea what's wrong, so I will appreciate any help. Thanks in advance. Oh, and here is the code:

Codepen: https://codepen.io/vivmaha/pen/abJNBzX

const turndiv = document.getElementById('turn');
const board = document.getElementById('board');
const boxes = document.querySelectorAll('.boxes');

const winningCombinations = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9],
    [1, 4, 7],
    [2, 5, 8],
    [3, 6, 9],
    [1, 5, 9],
    [3, 5, 7]
];

let claimedcells = new Array();
let xturn = true;

/* Those variables will have X and O combinations separetly */

let xcombination = new Array();
let ocombination = new Array();
let turn = xcombination;

/* Add event listeners to every cell */

boxes.forEach(cell => {
    cell.addEventListener('click', handleCellClick);
});

/* Handles cell, at this stage is confirmed, that this cell has ben clicked for first time */

function handleCellPlayed(cell, value) {
    if(xturn) {
        cell.textContent = 'x';
        xturn = false;
        xcombination.push(value);
    }
    else {
        cell.textContent = 'o';
        xturn = true;
        ocombination.push(value);
    }
}

/* Handles click on any cell */

function handleCellClick() {

    if(xturn) {
        if(isWinner(xcombination)) {
            alert('winner chicken dinner');
        }
    }
    else if(isWinner(ocombination)) {
            alert('winner chicken dinner');
    }

    let clickedcell = this.getAttribute('value');

    let freeCell = isCellFree(clickedcell);

    if(freeCell) {

        handleCellPlayed(this, this.getAttribute('value'));
        
        claimedcells.push(clickedcell);
    }
    
}

/* Checks is Cell free */

function isCellFree(cell) {

    let freeCell = true;

    for(i=0; i<claimedcells.length; i++) {

        let claimedcell = claimedcells[i];

        if(cell == claimedcell) {
            freeCell = false;
        }

    }

    return freeCell;
}

/* Check if game has winner */

function isWinner(usercombination) {

    let winner = false;

    winningCombinations.forEach(combination => {

        let a = combination[0] + "";
        let b = combination[1] + "";
        let c = combination[2] + "";

        if(usercombination.includes(a) && usercombination.includes(b) && usercombination.includes(c)) {
            winner = true;
        }

    });

    return winner;
}
body {
    background-color:azure;
}

.container {
    min-width: 100%;
    min-height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
}

#gameholder {
    width: 30vw;
    background-color: beige;
    padding: 10px;
    text-align: center;
}

#board {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-wrap: wrap;
    flex-basis: 33.333333%;
    text-transform: uppercase;
    font-weight: bold;
    font-size: 100px;
}

.boxes {
    width: 31%;
    height: 8vw;
    border: 0.5px black solid;
}

.boxes:first-child, .boxes:nth-child(2), .boxes:nth-child(3) {
    border-top: none;
}

.boxes:first-child, .boxes:nth-child(4), .boxes:nth-child(7) {
    border-left: none;
}

.boxes:nth-child(7), .boxes:nth-child(8), .boxes:nth-child(9) {
    border-bottom: none;
}

.boxes:nth-child(3),
.boxes:nth-child(6),
.boxes:nth-child(9) {
    border-right: none;
}
<body>
    <div class="container">
        <div id="gameholder">
            <!-------Current turn-------------->
            <div id="turn">
                <h1>X turn!</h1>
            </div>

            <!--- Game board --->
            <div id="board">
                <div class="boxes" value='1'></div>
                <div class="boxes" value='2'></div>
                <div class="boxes" value='3'></div>
                <div class="boxes" value='4'></div>
                <div class="boxes" value='5'></div>
                <div class="boxes" value='6'></div>
                <div class="boxes" value='7'></div>
                <div class="boxes" value='8'></div>
                <div class="boxes" value='9'></div>
            </div>

            <div id="time"></div>
        </div>
    </div>

    <script src="game.js" async></script>
</body>


Solution

  • You had 2 issues here,

    1. You was doing your isWinner check before you placed the mark
    2. You was changing the xturn before doing the check.

    Below I'v modified to fix both.

    I did a simple xturn = !xturn; to flip the user after working out if they had won.

    const turndiv = document.getElementById('turn');
    const board = document.getElementById('board');
    const boxes = document.querySelectorAll('.boxes');
    
    const winningCombinations = [
        [1, 2, 3],
        [4, 5, 6],
        [7, 8, 9],
        [1, 4, 7],
        [2, 5, 8],
        [3, 6, 9],
        [1, 5, 9],
        [3, 5, 7]
    ];
    
    let claimedcells = new Array();
    let xturn = true;
    
    /* Those variables will have X and O combinations separetly */
    
    let xcombination = new Array();
    let ocombination = new Array();
    let turn = xcombination;
    
    /* Add event listeners to every cell */
    
    boxes.forEach(cell => {
        cell.addEventListener('click', handleCellClick);
    });
    
    /* Handles cell, at this stage is confirmed, that this cell has ben clicked for first time */
    
    function handleCellPlayed(cell, value) {
        if(xturn) {
            cell.textContent = 'x';
            //xturn = false;
            xcombination.push(value);
        }
        else {
            cell.textContent = 'o';
            //xturn = true;
            ocombination.push(value);
        }
    }
    
    /* Handles click on any cell */
    
    function handleCellClick() {
    
     
    
        let clickedcell = this.getAttribute('value');
    
        let freeCell = isCellFree(clickedcell);
    
        if(freeCell) {
    
            handleCellPlayed(this, this.getAttribute('value'));
            if(xturn) {
              if(isWinner(xcombination)) {
                 alert('winner chicken dinner');
              }
            }
            else if(isWinner(ocombination)) {
              alert('winner chicken dinner');
            }
            xturn = !xturn;
            claimedcells.push(clickedcell);
        }
        
    }
    
    /* Checks is Cell free */
    
    function isCellFree(cell) {
    
        let freeCell = true;
    
        for(i=0; i<claimedcells.length; i++) {
    
            let claimedcell = claimedcells[i];
    
            if(cell == claimedcell) {
                freeCell = false;
            }
    
        }
    
        return freeCell;
    }
    
    /* Check if game has winner */
    
    function isWinner(usercombination) {
    
        let winner = false;
    
        winningCombinations.forEach(combination => {
    
            let a = combination[0] + "";
            let b = combination[1] + "";
            let c = combination[2] + "";
    
            if(usercombination.includes(a) && usercombination.includes(b) && usercombination.includes(c)) {
                winner = true;
            }
    
        });
    
        return winner;
    }
    body {
        background-color:azure;
    }
    
    .container {
        min-width: 100%;
        min-height: 100%;
        display: flex;
        align-items: center;
        justify-content: center;
    }
    
    #gameholder {
        width: 30vw;
        background-color: beige;
        padding: 10px;
        text-align: center;
    }
    
    #board {
        display: flex;
        align-items: center;
        justify-content: center;
        flex-wrap: wrap;
        flex-basis: 33.333333%;
        text-transform: uppercase;
        font-weight: bold;
        font-size: 100px;
    }
    
    .boxes {
        width: 31%;
        height: 8vw;
        border: 0.5px black solid;
    }
    
    .boxes:first-child, .boxes:nth-child(2), .boxes:nth-child(3) {
        border-top: none;
    }
    
    .boxes:first-child, .boxes:nth-child(4), .boxes:nth-child(7) {
        border-left: none;
    }
    
    .boxes:nth-child(7), .boxes:nth-child(8), .boxes:nth-child(9) {
        border-bottom: none;
    }
    
    .boxes:nth-child(3),
    .boxes:nth-child(6),
    .boxes:nth-child(9) {
        border-right: none;
    }
    <body>
        <div class="container">
            <div id="gameholder">
                <!-------Current turn-------------->
                <div id="turn">
                    <h1>X turn!</h1>
                </div>
    
                <!--- Game board --->
                <div id="board">
                    <div class="boxes" value='1'></div>
                    <div class="boxes" value='2'></div>
                    <div class="boxes" value='3'></div>
                    <div class="boxes" value='4'></div>
                    <div class="boxes" value='5'></div>
                    <div class="boxes" value='6'></div>
                    <div class="boxes" value='7'></div>
                    <div class="boxes" value='8'></div>
                    <div class="boxes" value='9'></div>
                </div>
    
                <div id="time"></div>
            </div>
        </div>
    
        <script src="game.js" async></script>
    </body>