Files
2021-02-08 00:12:41 -06:00

268 lines
5.7 KiB
JavaScript

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 = `<h1>Its a tie. (Pruning? ${usePruning})</h1>`;
else
document.getElementById("statusLabel").innerHTML = `<h1>Game over ${player} wins! (Pruning? ${usePruning})</h1>`;
}
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);
}