javascriptreactjsothello

Othello Game Switching Turns Doesn't Work in React.js


I'm working on an Othello game in React and I've already implemented the code to switch player turns. It does switch from one to another(between white and black). But if there's no move available for the upcoming player, the turn stays the same. I though I had it all done but now I came across to such a case when trying out the game, and although it does switch player turns regularly, my code does not consider keeping it the same when necessary. Do you know why? How can I solve it?

Here's my code:

Where I change it:

    setWinnerAndTurn() {
        const history = this.state.history.slice(0, this.state.stepNumber + 1);
        const current = history[this.state.stepNumber];
        const squares = current.squares.slice()

        const blackSquares = []
        const whiteSquares = []
        // Check for a winner
        for (var row=0;row<squares.length;row++) {
            for (var col=0;col<squares[row].length;col++) {
                if (squares[row][col] === 'black') {
                    blackSquares.push([row,col])
                } else if (squares[row][col] === 'white') {
                    whiteSquares.push([row,col])
                }
            }
        }

        // Debug
        //console.log(blackSquares)
        //console.log(whiteSquares)
        

        const total = [blackSquares,whiteSquares]
        const movesAvailable = [[],[]]
        for (var t=0;t<total.length;t++) {
            const currentArray = total[t]
            const returned = this.checkElementsAround(currentArray)
            for (var r=0;r<returned.length;r++) {
                movesAvailable[t].push(returned[r])
            }
        }

        // Debug
        console.log(movesAvailable)


        if (blackSquares.length + whiteSquares.length === squares.length * squares[0].length || (movesAvailable[0] === [] && movesAvailable[1] === [])) {
            // Declare a winner
            if (blackSquares.length !== whiteSquares.length) {
                this.setState({
                    winner: (blackSquares.length > whiteSquares.length) ? 'black' : 'white'
                })
            } else {
                this.setState({
                    winner: 'tie'
                })
            }
        } else {
            // Change turn
            if (movesAvailable[0] === []) {
                this.setState({
                    blackIsNext: false
                })
            } else if (movesAvailable[1] === []){
                this.setState({
                    blackIsNext: true
                })
            } else {
                this.setState({
                    blackIsNext: !this.state.blackIsNext
                })
            }
        }
    }

And where I call the function:

render() {
<GameBoard squares={current.squares} onClick={(row,col) => {
                    const elems = this.checkElementsAround(this.checkMoveValidity())
                    //console.log(elems)
                    for (let el=0;el<elems.length;el++) {
                        const turning = this.checkTurningStones(elems[el].directions)
                        if (turning.length !== 0) {
                            if (row === elems[el].coordinates[0] && col === elems[el].coordinates[1]) {
                                this.handleMove(row,col);
                                //console.log(turning)
                                for (var t=0;t<turning.length;t++) {
                                    this.handleMove(turning[t][0],turning[t][1])
                                }
                                this.setWinnerAndTurn()
                                break
                            }
                        }
                    }
                }}/>
}

Solution

  • Solved the problem, but don't know how. That's strange...

    Here's the Code:

    setWinnerAndTurn() {
            const history = this.state.history.slice(0, this.state.stepNumber + 1);
            const current = history[this.state.stepNumber];
            const squares = current.squares.slice()
    
            const blackSquares = []
            const whiteSquares = []
            // Check for a winner
            for (var row=0;row<squares.length;row++) {
                for (var col=0;col<squares[row].length;col++) {
                    if (squares[row][col] === 'black') {
                        blackSquares.push([row,col])
                    } else if (squares[row][col] === 'white') {
                        whiteSquares.push([row,col])
                    }
                }
            }
            
            const valids = this.checkElementsAround(this.checkEmptySpaces())
    
            // checkEmptySpaces returns all the empty spaces in the game
            // checkElementsAround returns all the objects in all directions if there's initially an element in that direction
    
            const movesAvailable = [0,0]
    
            for (var t=0;t<2;t++) {
                const isBlack = (t === 0) ? true : false
                for (var v=0;v<valids.length;v++) {
                    const valid = valids[v]
                    const turned = this.checkTurningStones(valid.directions,isBlack)
                    if (turned.length !== 0) {
                        movesAvailable[t]++;
                    }
                }
            }
    
            if (blackSquares.length + whiteSquares.length === squares.length * squares[0].length || (movesAvailable === [0,0])) {
                // Declare a winner
                if (blackSquares.length !== whiteSquares.length) {
                    this.setState({
                        winner: (blackSquares.length > whiteSquares.length) ? 'black' : 'white'
                    })
                } else {
                    this.setState({
                        winner: 'tie'
                    })
                }
            } else {
                // Change turn
                if (movesAvailable[0] === 0) {
                    this.setState({
                        blackIsNext: false
                    })
                } else if (movesAvailable[1] === 0){
                    this.setState({
                        blackIsNext: true
                    })
                } else {
                    this.setState({
                        blackIsNext: !this.state.blackIsNext
                    })
                }
            }
        }
    
    

    Where I used it:

    <div className="master-container">
                    <GameBoard squares={current.squares} onClick={(row,col) => {
                        const elems = this.checkElementsAround(this.checkEmptySpaces())
                        for (let el=0;el<elems.length;el++) {
                            const turning = this.checkTurningStones(elems[el].directions, this.state.blackIsNext)
                            if (turning.length !== 0) {
                                turning.unshift([row,col])
                                if (row === elems[el].coordinates[0] && col === elems[el].coordinates[1]) {
                                    this.handleMove(turning)
                                    this.setWinnerAndTurn()
                                    // Debug
                                    console.log(history.length)
                                    break
                                }
                            }                        
                        }
                    }}/>
    
    // handleMove -> You give an array of coordinates and it does turn them
    // setWinnerAndTurn -> Our function
    // checkTurningStones -> I give it the output of checkElementsAround as a parameter, it does return the elements that are to be turned upside down
    

    Actually I know how I fixed it; the thing is that since most of my conditional statements depend on the values returned from some of my functions, when used inappropriately, some conditional statements would never return true. That's what I solved.