# 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 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')) {
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')) {
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() {
}

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...