From b12e3b98fa5c8cffa17e4c027bb87b72a6691d8a Mon Sep 17 00:00:00 2001 From: spencerstith Date: Wed, 25 Aug 2021 21:13:55 -0500 Subject: [PATCH] Ported minimax Tic Tac Toe to Processing --- .../CC_154_Tic_Tac_Toe_Minimax.pde | 136 ++++++++++++++++++ .../CC_154_Tic_Tac_Toe_Minimax/Minimax.pde | 69 +++++++++ 2 files changed, 205 insertions(+) create mode 100644 CodingChallenges/CC_154_Tic_Tac_Toe_Minimax/Processing/CC_154_Tic_Tac_Toe_Minimax/CC_154_Tic_Tac_Toe_Minimax.pde create mode 100644 CodingChallenges/CC_154_Tic_Tac_Toe_Minimax/Processing/CC_154_Tic_Tac_Toe_Minimax/Minimax.pde diff --git a/CodingChallenges/CC_154_Tic_Tac_Toe_Minimax/Processing/CC_154_Tic_Tac_Toe_Minimax/CC_154_Tic_Tac_Toe_Minimax.pde b/CodingChallenges/CC_154_Tic_Tac_Toe_Minimax/Processing/CC_154_Tic_Tac_Toe_Minimax/CC_154_Tic_Tac_Toe_Minimax.pde new file mode 100644 index 0000000000..f2c8c33b8a --- /dev/null +++ b/CodingChallenges/CC_154_Tic_Tac_Toe_Minimax/Processing/CC_154_Tic_Tac_Toe_Minimax/CC_154_Tic_Tac_Toe_Minimax.pde @@ -0,0 +1,136 @@ +// Tic Tac Toe AI with Minimax Algorithm +// The Coding Train / Daniel Shiffman +// https://thecodingtrain.com/CodingChallenges/154-tic-tac-toe-minimax.html +// https://youtu.be/I64-UTORVfU +// https://editor.p5js.org/codingtrain/sketches/0zyUhZdJD +// Ported to Processing4 by Spencer Stith + +char[][] board = { + {(char)0, (char)0, (char)0}, + {(char)0, (char)0, (char)0}, + {(char)0, (char)0, (char)0} +}; + +int w; // = width / 3; +int h; // = height / 3; + +char ai = 'X'; +char human = 'O'; +boolean currentPlayerIsHuman = true; + +HashMap scores; + +void setup() { + size(400, 400); + w = width / 3; + h = height / 3; + + scores = new HashMap(); + scores.put('X', 10); + scores.put('O', -10); + scores.put('t', 0); + + bestMove(); //<>// +} + +boolean equals3(char a, char b, char c) { + return a == b && b == c && a != (char)0; +} + +char checkWinner() { + // Must use 'n' for "null" since Java doesn't allow primitive data types to be null + char winner = 'n'; + + // horizontal + for (int i = 0; i < 3; i++) { + if (equals3(board[i][0], board[i][1], board[i][2])) { + winner = board[i][0]; + } + } + + // Vertical + for (int i = 0; i < 3; i++) { + if (equals3(board[0][i], board[1][i], board[2][i])) { + winner = board[0][i]; + } + } + + // Diagonal + if (equals3(board[0][0], board[1][1], board[2][2])) { + winner = board[0][0]; + } + if (equals3(board[2][0], board[1][1], board[0][2])) { + winner = board[2][0]; + } + + int openSpots = 0; + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + if (board[i][j] == (char)0) { + openSpots++; + } + } + } + + if (winner == 'n' && openSpots == 0) { + return 't'; + } else { + return winner; + } +} + +void mousePressed() { + if (currentPlayerIsHuman) { + // Human make turn + int i = floor(mouseX / w); + int j = floor(mouseY / h); + // If valid turn + if (board[i][j] == (char)0) { + board[i][j] = human; + currentPlayerIsHuman = false; + bestMove(); + } + } +} + +void draw() { + background(255); + strokeWeight(4); + + line(w, 0, w, height); + line(w * 2, 0, w * 2, height); + line(0, h, width, h); + line(0, h * 2, width, h * 2); + + for (int j = 0; j < 3; j++) { + for (int i = 0; i < 3; i++) { + int x = w * i + w / 2; + int y = h * j + h / 2; + char spot = board[i][j]; + textSize(32); + int r = w / 4; + if (spot == human) { + noFill(); + circle(x, y, r * 2); + } else if (spot == ai) { + line(x - r, y - r, x + r, y + r); + line(x + r, y - r, x - r, y + r); + } + } + } + + char result = checkWinner(); + if (result != 'n') { + noLoop(); + textAlign(CENTER, CENTER); + rectMode(CENTER); + fill(255); + rect(width / 2, height / 3, 200, 100); + fill(0); + if (result == 't') { + text("Tie!", width / 2, height / 3); + } else { + text(result + " wins!", width / 2, height / 3); + } + } +} diff --git a/CodingChallenges/CC_154_Tic_Tac_Toe_Minimax/Processing/CC_154_Tic_Tac_Toe_Minimax/Minimax.pde b/CodingChallenges/CC_154_Tic_Tac_Toe_Minimax/Processing/CC_154_Tic_Tac_Toe_Minimax/Minimax.pde new file mode 100644 index 0000000000..875b69ac95 --- /dev/null +++ b/CodingChallenges/CC_154_Tic_Tac_Toe_Minimax/Processing/CC_154_Tic_Tac_Toe_Minimax/Minimax.pde @@ -0,0 +1,69 @@ +// Tic Tac Toe AI with Minimax Algorithm +// The Coding Train / Daniel Shiffman +// https://thecodingtrain.com/CodingChallenges/154-tic-tac-toe-minimax.html +// https://youtu.be/I64-UTORVfU +// https://editor.p5js.org/codingtrain/sketches/0zyUhZdJD +// Ported to Processing4 by Spencer Stith + + +import java.util.HashMap; + +void bestMove() { + // AI to make its turn + int bestScore = Integer.MIN_VALUE; + int[] move = {0, 0}; + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + // Is the spot available? + if (board[i][j] == (char)0) { + board[i][j] = ai; + int score = minimax(board, 0, false); + board[i][j] = (char)0; + if (score > bestScore) { + bestScore = score; + move[0] = i; + move[1] = j; + } + } + } + } + board[move[0]][move[1]] = ai; + currentPlayerIsHuman = true; +} + +int minimax(char[][] board, int depth, boolean isMaximizing) { + char result = checkWinner(); + if (result != 'n') { + return scores.get(result); + } + + if (isMaximizing) { + int bestScore = Integer.MIN_VALUE; + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + // Is the spot available? + if (board[i][j] == (char)0) { + board[i][j] = ai; + int score = minimax(board, depth + 1, false); + board[i][j] = (char)0; + bestScore = max(score, bestScore); + } + } + } + return bestScore; + } else { + int bestScore = Integer.MAX_VALUE; + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + // Is the spot available? + if (board[i][j] == (char)0) { + board[i][j] = human; + int score = minimax(board, depth + 1, true); + board[i][j] = (char)0; + bestScore = min(score, bestScore); + } + } + } + return bestScore; + } +}