Is minimax possible

It uses infinity and -infinity so is it possible

What do you mean by minimax? But yeah, it's possible to use it.

function makeAIMove() {
 var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
 var board = sheet.getRange('A1:G6').getValues();
  // Check if AI plays first and places 'O'
 var aiPlaysFirst = sheet.getRange('H1').getValue() === true;


 if (checkWin(board, aiPlaysFirst ? 'X' : 'O')) {
   var response = SpreadsheetApp.getUi().alert('Player wins! Click OK to reset the board.');
   if (response === SpreadsheetApp.getUi().Button.OK) {
     resetBoard(sheet);
     return; // Exit the function if player wins
   }
 }


 var bestMove = minimax(board, 6, true, -Infinity, Infinity).col;
 placeToken(sheet, bestMove, aiPlaysFirst ? 'O' : 'X');


 board = sheet.getRange('A1:G6').getValues(); // Update the board after AI move


 if (checkWin(board, aiPlaysFirst ? 'O' : 'X')) {
   var response = SpreadsheetApp.getUi().alert('AI wins! Click OK to reset the board.');
   if (response === SpreadsheetApp.getUi().Button.OK) {
     resetBoard(sheet);
   }
 }
}


function resetBoard(sheet) {
 sheet.getRange('A1:G6').clearContent();
}


function checkWin(board, player) {
 // Check horizontally
 for (var row = 0; row < 6; row++) {
   for (var col = 0; col <= 3; col++) {
     if (board[row][col] === player &&
         board[row][col + 1] === player &&
         board[row][col + 2] === player &&
         board[row][col + 3] === player) {
       return true;
     }
   }
 }


 // Check vertically
 for (var col = 0; col < 7; col++) {
   for (var row = 0; row <= 2; row++) {
     if (board[row][col] === player &&
         board[row + 1][col] === player &&
         board[row + 2][col] === player &&
         board[row + 3][col] === player) {
       return true;
     }
   }
 }


 // Check diagonally (top-left to bottom-right)
 for (var row = 0; row <= 2; row++) {
   for (var col = 0; col <= 3; col++) {
     if (board[row][col] === player &&
         board[row + 1][col + 1] === player &&
         board[row + 2][col + 2] === player &&
         board[row + 3][col + 3] === player) {
       return true;
     }
   }
 }


 // Check diagonally (bottom-left to top-right)
 for (var row = 3; row < 6; row++) {
   for (var col = 0; col <= 3; col++) {
     if (board[row][col] === player &&
         board[row - 1][col + 1] === player &&
         board[row - 2][col + 2] === player &&
         board[row - 3][col + 3] === player) {
       return true;
     }
   }
 }


 return false;
}


function minimax(board, depth, maximizingPlayer, alpha, beta) {
 var validMoves = findValidMoves(board);


 if (depth === 0 || checkWin(board, 'X') || checkWin(board, 'O') || validMoves.length === 0) {
   var score = evaluateBoard(board);
   return { score: score };
 }


 if (maximizingPlayer) {
   var maxScore = -Infinity;
   var bestMove = null;


   for (var col of validMoves) {
     var newBoard = simulateMove(board, col, 'X');
     if (checkWin(newBoard, 'X')) {
       return { score: 1000, col: col }; // If the AI can win with this move, return immediately
     }
     var score = minimax(newBoard, depth - 1, false, alpha, beta).score;
     if (score > maxScore) {
       maxScore = score;
       bestMove = col;
     }
     alpha = Math.max(alpha, score);
     if (beta <= alpha) {
       break;
     }
   }


   return { score: maxScore, col: bestMove };
 } else {
   var minScore = Infinity;
   var bestMove = null;


   for (var col of validMoves) {
     var newBoard = simulateMove(board, col, 'O');
     if (checkWin(newBoard, 'O')) {
       return { score: -1000, col: col }; // If the player can win with this move, return immediately
     }
     var score = minimax(newBoard, depth - 1, true, alpha, beta).score;
     if (score < minScore) {
       minScore = score;
       bestMove = col;
     }
     beta = Math.min(beta, score);
     if (beta <= alpha) {
       break;
     }
   }


   return { score: minScore, col: bestMove };
 }
}








function evaluateBoard(board) {
 var aiScore = evaluatePlayerScore(board, 'X');
 var playerScore = evaluatePlayerScore(board, 'O');
 return aiScore - playerScore;
}


function evaluatePlayerScore(board, player) {
 var score = 0;


 // Horizontal
 for (var row = 0; row < 6; row++) {
   for (var col = 0; col <= 3; col++) {
     var window = [board[row][col], board[row][col + 1], board[row][col + 2], board[row][col + 3]];
     score += evaluateWindow(window, player);
   }
 }


 // Vertical
 for (var col = 0; col < 7; col++) {
   for (var row = 0; row <= 2; row++) {
     var window = [board[row][col], board[row + 1][col], board[row + 2][col], board[row + 3][col]];
     score += evaluateWindow(window, player);
   }
 }


 // Diagonal /
 for (var row = 0; row <= 2; row++) {
   for (var col = 0; col <= 3; col++) {
     var window = [board[row][col], board[row + 1][col + 1], board[row + 2][col + 2], board[row + 3][col + 3]];
     score += evaluateWindow(window, player);
   }
 }


 // Diagonal \
 for (var row = 3; row < 6; row++) {
   for (var col = 0; col <= 3; col++) {
     var window = [board[row][col], board[row - 1][col + 1], board[row - 2][col + 2], board[row - 3][col + 3]];
     score += evaluateWindow(window, player);
   }
 }


 return score;
}




function evaluateWindow(window, player) {
 var opponent = player === 'X' ? 'O' : 'X';
 var score = 0;


 if (window.filter(cell => cell === player).length === 4) {
   score += 100;
 } else if (window.filter(cell => cell === player).length === 3 && window.filter(cell => cell === '').length === 1) {
   score += 5;
 } else if (window.filter(cell => cell === player).length === 2 && window.filter(cell => cell === '').length === 2) {
   score += 2;
 }


 if (window.filter(cell => cell === opponent).length === 3 && window.filter(cell => cell === '').length === 1) {
   score -= 4;
 }


 return score;
}


// Function to simulate placing a token on the board
function simulateMove(board, col, player) {
 var newBoard = board.map(function(row) {
   return row.slice();
 });
 var row = findEmptyRow(newBoard, col);
 newBoard[row][col] = player;
 return newBoard;
}


// Function to find empty row in a column
function findEmptyRow(board, col) {
 for (var row = 5; row >= 0; row--) {
   if (board[row][col] === '') {
     return row;
   }
 }
 return -1;
}


// Function to place a token on the board
function placeToken(sheet, col, player) {
 var emptyRow = findEmptyRow(sheet.getRange('A1:G6').getValues(), col);
 sheet.getRange(emptyRow + 1, col + 1).setValue(player);
}


// Function to find valid moves
function findValidMoves(board) {
 var validMoves = [];
 for (var col = 0; col < 7; col++) {
   if (board[0][col] === '') {
     validMoves.push(col);
   }
 }
 return validMoves;
}
	
function onOpen() {
 var ui = SpreadsheetApp.getUi();
 // Create a custom menu
 ui.createMenu('Connect 4')
   .addItem('Update AI Move', 'makeAIMove')
   .addToUi();
}




function onEdit(e) {
 var range = e.range;
 var sheet = range.getSheet();
  // Check if the edited range is in the correct sheet and range A1:G6
 if (sheet.getName() === "Sheet1" &&
     range.getColumn() >= 1 && range.getColumn() <= 8 && // Check column range
     range.getRow() >= 1 && range.getRow() <= 6) { // Check row range
    
   var statusCell = sheet.getRange('H1');
   if (range.getA1Notation() === statusCell.getA1Notation()) {
     makeAIMove(); // If H1 is clicked, make AI move immediately
   } else {
     var status = statusCell.getValue();
    
     // Count the number of empty cells in range A1:G6
     var emptyCellsCount = countEmptyCellsInRange(sheet);
    
     // Check if H1 is true and the number of empty cells is even or H1 is false and the number of empty cells is odd
     if ((status === true && emptyCellsCount % 2 === 0) ||
         (status === false && emptyCellsCount % 2 === 1)) {
       makeAIMove();
     }
   }
 }
}


// Function to count the number of empty cells in range A1:G6
function countEmptyCellsInRange(sheet) {
 var range = sheet.getRange('A1:G6');
 var values = range.getValues();
 var emptyCellsCount = 0;
 values.forEach(function(row) {
   row.forEach(function(cell) {
     if (cell === "") {
       emptyCellsCount++;
     }
   });
 });
 return emptyCellsCount;
}

like in this code

Isn't it something like



except that's just one level deep; I have to make it recursive with a depth input. And it's only at the bottommost level that it uses an external score function. Tomorrow...

what about infinity

can you help with my project

What about it?

nevermind

can you help debug mine