How to fix Tic Tac Toe in JavaScript with minimax not returning score to original call?

94 Views Asked by At

I think the problem may lie in my call for emptyIndexes. The return IndexArray always returns 0. The Moves array does not return score to original 8 open indexes.

How do I get the score to return to the original minimax call function? I've tried debugging but couldn't find where I'm going wrong.

From my understanding, the recursion occurs until a terminal condition (10, -10, 0) then passes those values backwards until the initial call is met, then updates the best scores based on all outcomes and returns the object with the BestMove. The call for BestMove only returns value of 0.

const minimax = (newBoard,currentPlayer)=>{
            
            let availSpots = emptyIndexes(newBoard)
            newBoard = Array.from(newBoard)
            if(CheckForWin(newBoard) && currentPlayer === players[0]){
                return {score:-10}
            }
         else if(CheckForWin(newBoard) && currentPlayer ===players[1]{
                return {score:10}
            }
            else if (availSpots.length === 0){
                return {score:0}
            }
            
            let Moves = []
            for(let k = 0;k<availSpots.length;k++){
                let move = {}
                move.index = availSpots[k]
                newBoard[availSpots[k]] = currentPlayer
                if(currentPlayer === players[1] ){
                    let result = minimax(newBoard,players[0]).score
                    move.score = result
                }
                else{
                    let result = minimax(newBoard,players[1]).score
                    move.score = result
                }
                newBoard[availSpots[k]] = move.index
                Moves.push(move)
                console.log(Moves)
                
            }
            let BestMove;
                if(currentPlayer === players[1]){    
                    let bestscore1 = -Infinity
                        for(let j = 0;j < Moves.length;j++){
                            if(Moves[j].score > bestscore1){
                                bestscore1 = Moves[j].score
                                BestMove = j
                            }    
                        }
                }
                else if(currentPlayer === players[0]){
                    let bestscore = Infinity
                        for(let i = 0;i < Moves.length;i++){
                            if(Moves[i].score < bestscore){
                                bestscore = Moves[i].score
                                BestMove = i 
                            }
                        }
                }
                return Moves[BestMove]
    }                               
function emptyIndexes(array){
        let indexArray = []
        for(i = 0;i<array.length;i++){
            if(array[i] == ''){
                indexArray.push(i)
            }
        }
        return indexArray
    }
      

EDIT: I was able to fix the code by adding depth move.score = Math.sign(move.score) * (Math.abs(move.score)-1)

changing Board[availSpots[k]] = currentPlayer to Board[availSpots[k]] = currentPlayer.mark

and changing my return scores, previously my return score condition returned 10 if Human player was called and -10 if AI was called. But i realized I had to reverse that because by calling minimax(Board,players[0]).score I was changing the current player, my CheckForWin function didnt return if the winner was AI or Human. So returning the opposite score return the proper score to the initial call.

thanks for everyone tht tried to help and also those who decided not to, hopefully this will help others.

1

There are 1 best solutions below

1
ADITYA On

try this one

const minimax = (board, currentPlayer) => {
    let availSpots = emptyIndexes(board);

    if (CheckForWin(board) && currentPlayer === players[0]) {
        return { score: -10 };
    } else if (CheckForWin(board) && currentPlayer === players[1]) {
        return { score: 10 };
    } else if (availSpots.length === 0) {
        return { score: 0 };
    }

    let moves = [];
    for (let i = 0; i < availSpots.length; i++) {
        let move = {};
        move.index = availSpots[i];
        
        // Create a copy of the board
        let newBoard = [...board];
        newBoard[availSpots[i]] = currentPlayer;

        if (currentPlayer === players[1]) {
            let result = minimax(newBoard, players[0]).score;
            move.score = result;
        } else {
            let result = minimax(newBoard, players[1]).score;
            move.score = result;
        }

        moves.push(move);
    }

    let bestMove;
    if (currentPlayer === players[1]) {
        let bestScore = -Infinity;
        for (let j = 0; j < moves.length; j++) {
            if (moves[j].score > bestScore) {
                bestScore = moves[j].score;
                bestMove = j;
            }
        }
    } else if (currentPlayer === players[0]) {
        let bestScore = Infinity;
        for (let i = 0; i < moves.length; i++) {
            if (moves[i].score < bestScore) {
                bestScore = moves[i].score;
                bestMove = i;
            }
        }
    }

    return moves[bestMove];
};