JS Tic Tac Toe minimax AI not picking the correct spot

For some reason my supposedly unbeatable AI is easily bypass-able because it never tries to prevent me from winning. I’ve tried restarting functions, like my checkForWinner, which I separated into two functions now, one to return a winner value (can be null) and one to check if the game is actually over and prevent anyone from continuing. I don’t know what to do anymore and have basically given up on this project.

const GameBoard = (() => {
    const winConditions = [
      [0, 1, 2],
      [3, 4, 5],
      [6, 7, 8],
      [0, 3, 6],
      [1, 4, 7],
      [2, 5, 8],
      [0, 4, 8],
      [2, 4, 6]
    ];
    let slots = ["", "", "", "", "", "", "", "", ""];
    const player1 = "X";
    const player2 = "O";
    let currentPlayer = player2;
    const playerText = document.querySelector(".player");
    const computerText = document.querySelector(".computer");
    const winnerText = document.querySelector(".winner-text");
    let isRunning = false;
    const cells = document.querySelectorAll(".card");
  
  
    function initializeGame() {
      computerText.classList.add("highlighted");
      isRunning = true;
      ComputerPlayer.bestMove(); 
  
      cells.forEach((cell) => {
        cell.addEventListener("click", function () {
          cellClicked(cell);
        });
  
        const restartBtn = document.querySelector("#restart-btn");
        restartBtn.addEventListener("click", function () {
          restartGame(cell);
          initializeGame(); 
          
        });
      });
     
    }
    function cellClicked(item) {
      const cellIndex = item.getAttribute("cell-index"); 
      if (currentPlayer === player1) {
        if (slots[cellIndex] != "" || !isRunning) {
          return;
        }
        updateCell(item, cellIndex);
        checkGameOver();
        switchPlayers();
       
        

        

      }
    }
    function updateCell(cell, index) {
      slots[index] = currentPlayer;
      console.log(slots);
      cell.textContent = currentPlayer;
    }
  
    function switchPlayers() {
      if (isRunning) {
        if (currentPlayer === player1) {
          currentPlayer = player2;
          ComputerPlayer.bestMove(); 
          checkGameOver(); 
          console.log(`current player is: ${currentPlayer}`);
          playerText.classList.remove("highlighted");
          computerText.classList.add("highlighted"); 
    
        } else if (currentPlayer === player2) {
          currentPlayer = player1;
          console.log(`current player is: ${currentPlayer}`);
          computerText.classList.remove("highlighted");
          playerText.classList.add("highlighted");
        }
      }
    }
    function equals3(a,b,c) {
        if (a == b && b == c) {
            return true; 
        }
        return false; 
    }
  
    function checkForWinner() { 
        let winner = null; 
        for(let i = 0; i < winConditions.length; i++) {
            if (equals3(slots[winConditions[i][0]],slots[winConditions[i][1]],slots[winConditions[i][2]]) == true && slots[winConditions[i][0]] != '') {
                winner = slots[winConditions[i][0]]; 
            }
            if ((winner === null) && (slots[0] != '' && slots[1] != '' && slots[2] != '' && slots[3] != '' && slots[4] != '' && slots[5] != '' && slots[6] != '' && slots[7] != '' && slots[8] != '')) {
                winner = 'Tie'; 
                
            }  
                
            

        }
        return winner; 
        console.log(winner)
        
    }
    function checkGameOver() {
        let result = checkForWinner(); 
        if (result != null) {
            if(result === 'Tie') {
                winnerText.classList.add('winner-visible'); 
                winnerText.textContent = 'Tie!'
                isRunning = false; 

            } else {
                winnerText.classList.add('winner-visible'); 
                winnerText.textContent = result + ' Wins!'
                isRunning = false; 
            }
        } 
      
    }
  

    function restartGame(card) {
      isRunning = true;
      slots = ["", "", "", "", "", "", "", "", ""];
      console.log(slots);
      card.textContent = "";
      winnerText.classList.remove("winner-visible");
    }
    
    
    return {
      winConditions,
      slots,
      player1,
      player2,
      currentPlayer,
      playerText,
      computerText,
      winnerText,
      cells,
      isRunning,
      switchPlayers,
      updateCell,
      checkForWinner, 
      initializeGame, 
      checkGameOver
     
    };
  })();
  const ComputerPlayer = (() => {
    
        function bestMove() {
            if (GameBoard.currentPlayer === GameBoard.player2 ) {
            let bestScore = -Infinity; 
            let move; 
            for(let i = 0 ; i < GameBoard.slots.length; i++) {
                if (GameBoard.slots[i] === '') {
                    GameBoard.slots[i] = 'O'; 
                    let score = minimax(GameBoard.slots, 0, false); 
                    console.log('score is ' + score); 
                    GameBoard.slots[i] = ''; 
                    if (score > bestScore) {
                        bestScore = score; 
                        console.log(bestScore + ' is bestScore'); 
                        move = i; 
                    }
                }
          
             }
           
             GameBoard.slots[move] = 'O'; 
             GameBoard.cells[move].textContent = 'O'; 
             GameBoard.switchPlayers(); 
            }
        
        }
       


        function minimax(board, depth, isMaximizing) {
            let result = GameBoard.checkForWinner(); 
            if (result == 'X') {
                return 1;    
            } else if (result == 'O') {
                return -1; 
            } else if(result == 'Tie') {
                return 0; 
            }

            if (isMaximizing) {
                let bestScore = -Infinity; 
                for(let i = 0 ; i < board.length; i++) {
                    if(board[i] === '') {
                        board[i] = 'O'; 
                        let score = minimax(board, depth + 1, false); 
                        board[i] = ''; 
                       bestScore = Math.max(score, bestScore); 

                    }
                }
                return bestScore;  
                
            } else {
                let bestScore = Infinity; 
                for(let i = 0; i < board.length; i++ ) {
                    if(board[i] === '') {
                        board[i] = 'X'; 
                        let score = minimax(board, depth +1, true); 
                        board[i] = ''; 
                        bestScore = Math.min(score, bestScore);
                    }
                }
                return bestScore; 
               
            }

        }

        return {
            bestMove, 
            minimax
        }
    


        
  })();
GameBoard.initializeGame(); 

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.