var cellWidth = 0; var gameOver = false; var humanFirst; var usePruning; var gameBoard = [ ['', '', ''], ['', '', ''], ['', '', ''] ]; var currentPlayer = 0; var players = ['X', 'O']; var scores = { X: 1, Tie: 0, O: -1 }; var eh = true; function setup() { var canvas = createCanvas(500, 500); cellWidth = floor(width / 3); canvas.parent('sketch-holder'); humanFirst = document.getElementById("humanFirst").checked; usePruning = document.getElementById("usePruning").checked; } function draw() { background(220); strokeWeight(4); line(0, height / 3, width, height / 3); line(0, height - height / 3, width, height - height / 3); line(width / 3, 0, width / 3, height); line(width - width / 3, 0, width - width / 3, height); if(!humanFirst) nextTurn(); noLoop(); } function nextTurn() { //minimax let bestScore = players[currentPlayer] == 'X' ? -Infinity : Infinity; let move; for(let i = 0; i < 3; i++) for(let j = 0; j < 3; j++) { if(gameBoard[i][j] == ''){ gameBoard[i][j] = players[currentPlayer]; let score; if(!usePruning) score = minimax(gameBoard, !(players[currentPlayer] == 'X')); else score = minimaxPrune(gameBoard, -Infinity, Infinity, !(players[currentPlayer] == 'X')); gameBoard[i][j] = ''; if(players[currentPlayer] == 'X') { if(score > bestScore){ bestScore = score; move = {i, j}; } } else { if(score < bestScore){ bestScore = score; move = {i, j}; } } } } gameBoard[move.i][move.j] = players[currentPlayer]; drawPlayer(move.j, move.i, cellWidth, players[currentPlayer]); currentPlayer = (currentPlayer + 1) % players.length; } function minimaxPrune(board, alpha, beta, isMaximizing){ let result = checkWinner(board); if(result != null) { return scores[result]; } if(isMaximizing){ let bestScore = -Infinity; for(let i = 0; i < 3; i++) for(let j = 0; j < 3; j++) { if(board[i][j] == ''){ board[i][j] = 'X'; let score = minimaxPrune(board, alpha, beta, false); board[i][j] = ''; bestScore = max(score, bestScore); alpha = max(alpha, bestScore); if(beta <= alpha) return bestScore; } } return bestScore; } else { let bestScore = Infinity; for(let i = 0; i < 3; i++) for(let j = 0; j < 3; j++) { if(board[i][j] == ''){ board[i][j] = 'O'; let score = minimaxPrune(board, alpha, beta, true); board[i][j] = ''; if (score > 1 || score < -1) print(score); bestScore = min(score, bestScore); beta = min(beta, bestScore); if(beta <= alpha) return bestScore; } } return bestScore; } } function minimax(board, isMaximizing){ let result = checkWinner(board); if(result != null) { return scores[result]; } if(isMaximizing){ let bestScore = -Infinity; for(let i = 0; i < 3; i++) for(let j = 0; j < 3; j++) { if(board[i][j] == ''){ board[i][j] = 'X'; let score = minimax(board, false); board[i][j] = ''; bestScore = max(score, bestScore); } } return bestScore; } else { let bestScore = Infinity; for(let i = 0; i < 3; i++) for(let j = 0; j < 3; j++) { if(board[i][j] == ''){ board[i][j] = 'O'; let score = minimax(board, true); board[i][j] = ''; bestScore = min(score, bestScore); } } return bestScore; } } function checkWinner(board, showEnd = false){ let winner = null; // Horizontal for(let i = 0; i < 3; i++){ if(board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ''){ winner = board[i][0]; let y = 0; if(i == 0) y = cellWidth / 2; else y = cellWidth * i + cellWidth / 2; if(showEnd) line(0, y, width, y); } } // Vertical for(let i = 0; i < 3; i++){ if(board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ''){ winner = board[0][i]; let x = 0; if(i == 0) x = cellWidth / 2; else x = cellWidth * i + cellWidth / 2; if(showEnd) line(x, 0, x, width); } } // Diagonal if(board[0][0] != '' && board[0][0] == board[1][1] && board[2][2] == board[0][0]){ winner = board[0][0]; if(showEnd) line(0, 0, width, width); } else if(board[2][0] != '' && board[2][0] == board[1][1] && board[0][2] == board[2][0]){ winner = board[2][0]; if(showEnd) line(width, 0, 0, width); } let openMoves = 0; for(let i = 0; i < 3; i++) for(let j = 0; j < 3; j++) if(board[i][j] == '') openMoves++; if(!winner && openMoves == 0) return "Tie"; return winner; } function mouseClicked(){ if(gameOver) { return; } let x = floor(mouseX / cellWidth); let y = floor(mouseY / cellWidth); if(gameBoard[y][x] == ''){ drawPlayer(x, y, cellWidth, players[currentPlayer]); gameBoard[y][x] = players[currentPlayer]; let result = checkWinner(gameBoard, true); if(result != null) { showWinner(result); return; } currentPlayer = (currentPlayer + 1) % players.length; nextTurn(); result = checkWinner(gameBoard, true); if(result != null) showWinner(result); } } function showWinner(player) { gameOver = true; if(player == "Tie") document.getElementById("statusLabel").innerHTML = `

Its a tie. (Pruning? ${usePruning})

`; else document.getElementById("statusLabel").innerHTML = `

Game over ${player} wins! (Pruning? ${usePruning})

`; } function drawPlayer(x, y, w, player) { strokeWeight(2); if(player == 'O'){ fill(220); ellipse(w / 2 + w * x, w / 2 + w * y, floor(width / 4)); } else if (player == 'X'){ let newX = w * x; let newY = w * y; let trim = w * 0.90; line(newX + trim * 0.15, newY + trim * 0.15, newX + trim, newY + trim); line(newX + trim * 0.15, newY + trim, newX + trim, newY + trim * 0.15); } strokeWeight(10); }