1. Trang chủ
  2. » Công Nghệ Thông Tin

Minimax algorithm tic tac toe AI in java

22 856 4

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 22
Dung lượng 131,65 KB

Nội dung

Minimax Algorithm Tic Tac Toe AI In Java [Minimax][Full tree Search][Artificial Intelligence] [Java] The minimax tree has leaf values like -1 or Min selects the minimum i.e -1 Max selects the maximum among the available after Min would have taken its move i.e or So it has available moves like -1, -1, 0, 0, +1, +1 at the top most node (root, which is the present game state) and selects the first +1 value as it has a chance of victory no matter what other opponent does (it has already been calculated like if the opponent does this, I can this (it always assumes the opponent takes the smartest move to destroy you) and I can win) There is no summation of values taking place like +3, +4, +1 so that max selects +3 and like that This kind of approach is used in other implementation where you don't have the time to evaluate the whole tree and just want to evaluate the tree at the (say 4th) level and then rank the states accordingly like I have rows in which I can get Xs so that gives a score +1000, rows = +100 and row = +10 -ve values for the opponents position So you get values like +1200 or -2300 at the leaves from where you select the move which is favorable (this player is not perfect, it can lose It has not evaluated all the possibilites It has just gone to some extent of computation to get some available move in some limited time) This AI is a perfect player i.e it can never lose It wins or it draws the match Source: The code isn't really hard Function names are self explanatory Comments are added wherever necessary I've supposed that is the human player playing the game and is the computer If you want to see the actual calculations, just uncomment the commented lines [Make sure you have JDK 8.0 Installed] If not, here's a link: http://www.oracle.com/technetwork/java/javase/downloads/jre8-downloads2133155.html import java.util.*; class Point { int x, y; public Point(int x, int y) { this.x = x; this.y = y; } } @Override public String toString() { return "[" + x + ", " + y + "]"; } class PointsAndScores { int score; Point point; PointsAndScores(int score, Point point) { this.score = score; } this.point = point; } class Board { List availablePoints; Scanner scan = new Scanner(System.in); int[][] board = new int[3][3]; public Board() { } public boolean isGameOver() { //Game is over is someone has won, or board is full (draw) return (hasXWon() || hasOWon() || getAvailableStates().isEmpty()); } public boolean hasXWon() { if ((board[0][0] == board[1][1] && board[0][0] == board[2][2] && board[0][0] == 1) || (board[0][2] == board[1][1] && board[0][2] == board[2][0] && board[0][2] == 1)) { //System.out.println("X Diagonal Win"); return true; } for (int i = 0; i < 3; ++i) { if (((board[i][0] == board[i][1] && board[i][0] == board[i][2] && board[i][0] == 1) || (board[0][i] == board[1][i] && board[0][i] == board[2] [i] && board[0][i] == 1))) { // System.out.println("X Row or Column win"); return true; } } return false; } public boolean hasOWon() { if ((board[0][0] == board[1][1] && board[0][0] == board[2][2] && board[0][0] == 2) || (board[0][2] == board[1][1] && board[0][2] == board[2][0] && board[0][2] == 2)) { // System.out.println("O Diagonal Win"); return true; } for (int i = 0; i < 3; ++i) { if ((board[i][0] == board[i][1] && board[i][0] == board[i][2] && board[i][0] == 2) || (board[0][i] == board[1][i] && board[0][i] == board[2] [i] && board[0][i] == 2)) { // System.out.println("O Row or Column win"); return true; } } } return false; public List getAvailableStates() { availablePoints = new ArrayList(); for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { if (board[i][j] == 0) { availablePoints.add(new Point(i, j)); } } } return availablePoints; } public void placeAMove(Point point, int player) { board[point.x][point.y] = player; //player = for X, for O } public Point returnBestMove() { int MAX = -100000; int best = -1; for (int i = 0; i < rootsChildrenScores.size(); ++i) { if (MAX < rootsChildrenScores.get(i).score) { MAX = rootsChildrenScores.get(i).score; best = i; } } } return rootsChildrenScores.get(best).point; void takeHumanInput() { System.out.println("Your move: "); int x = scan.nextInt(); int y = scan.nextInt(); Point point = new Point(x, y); placeAMove(point, 2); } public void displayBoard() { System.out.println(); for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { System.out.print(board[i][j] + " "); } System.out.println(); } } public int returnMin(List list) { int = Integer.MAX_VALUE; int index = -1; for (int i = 0; i < list.size(); ++i) { if (list.get(i) < min) { = list.get(i); } index = i; } return list.get(index); } public int returnMax(List list) { int max = Integer.MIN_VALUE; int index = -1; for (int i = 0; i < list.size(); ++i) { if (list.get(i) > max) { max = list.get(i); index = i; } } return list.get(index); } List rootsChildrenScores; public void callMinimax(int depth, int turn){ rootsChildrenScores = new ArrayList(); minimax(depth, turn); } public int minimax(int depth, int turn) { if (hasXWon()) return +1; if (hasOWon()) return -1; List pointsAvailable = getAvailableStates(); if (pointsAvailable.isEmpty()) return 0; List scores = new ArrayList(); for (int i = 0; i < pointsAvailable.size(); ++i) { Point point = pointsAvailable.get(i); if (turn == 1) { //X's turn select the highest from below minimax() call placeAMove(point, 1); int currentScore = minimax(depth + 1, 2); scores.add(currentScore); if (depth == 0) rootsChildrenScores.add(new PointsAndScores(currentScore, point)); } else if (turn == 2) {//O's turn select the lowest from below minimax() call placeAMove(point, 2); scores.add(minimax(depth + 1, 1)); } board[point.x][point.y] = 0; //Reset this point } return turn == ? returnMax(scores) : returnMin(scores); } } public class TicTacToe { public static void main(String[] args) { Board b = new Board(); Random rand = new Random(); b.displayBoard(); System.out.println("Who's gonna move first? (1)Computer (2)User: "); int choice = b.scan.nextInt(); if(choice == 1){ Point p = new Point(rand.nextInt(3), rand.nextInt(3)); b.placeAMove(p, 1); b.displayBoard(); } while (!b.isGameOver()) { System.out.println("Your move: "); Point userMove = new Point(b.scan.nextInt(), b.scan.nextInt()); pas.score); b.placeAMove(userMove, 2); //2 for O and O is the user b.displayBoard(); if (b.isGameOver()) { break; } b.callMinimax(0, 1); for (PointsAndScores pas : b.rootsChildrenScores) { System.out.println("Point: " + pas.point + " Score: " + } b.placeAMove(b.returnBestMove(), 1); b.displayBoard(); } } if (b.hasXWon()) { System.out.println("Unfortunately, you lost!"); } else if (b.hasOWon()) { System.out.println("You win! This is not going to get printed."); } else { System.out.println("It's a draw!"); } } Sample run: 000 000 000 Who's gonna move first? (1)Computer (2)User: Your move: 22 000 000 002 Point: Point: Point: Point: Point: Point: Point: Point: [0, [0, [0, [1, [1, [1, [2, [2, 0] 1] 2] 0] 1] 2] 0] 1] Score: Score: Score: Score: Score: Score: Score: Score: -1 -1 -1 -1 -1 -1 -1 Score: Score: Score: Score: Score: Score: -1 0 -1 Score: Score: Score: Score: -1 -1 -1 000 010 002 Your move: 00 200 010 002 Point: Point: Point: Point: Point: Point: [0, [0, [1, [1, [2, [2, 1] 2] 0] 2] 0] 1] 210 010 002 Your move: 21 210 010 022 Point: Point: Point: Point: [0, [1, [1, [2, 2] 0] 2] 0] 210 010 122 Your move: 02 212 010 122 Point: [1, 0] Score: -1 Point: [1, 2] Score: 212 011 122 Your move: 10 212 211 122 It's a draw! Update: Here is an improved version We don't need to evaluate more when we already have found a winning move, so we just skip rest of the evaluations as soon as we get +1 (for max) or -1 (for min) for some state for the next move Source: import import import import java.util.ArrayList; java.util.List; java.util.Random; java.util.Scanner; class Point { int x, y; public Point(int x, int y) { this.x = x; this.y = y; } } @Override public String toString() { return "[" + x + ", " + y + "]"; } class PointAndScore { int score; Point point; PointAndScore(int score, Point point) { this.score = score; this.point = point; } } class Board { List availablePoints; Scanner scan = new Scanner(System.in); int[][] board = new int[3][3]; public Board() { } public boolean isGameOver() { //Game is over is someone has won, or board is full (draw) return (hasXWon() || hasOWon() || getAvailableStates().isEmpty()); } public boolean hasXWon() { if ((board[0][0] == board[1][1] && board[0][0] == board[2][2] && board[0][0] == 1) || (board[0][2] == board[1][1] && board[0][2] == board[2][0] && board[0][2] == 1)) { //System.out.println("X Diagonal Win"); return true; } for (int i = 0; i < 3; ++i) { if (((board[i][0] == board[i][1] && board[i][0] == board[i][2] && board[i][0] == 1) || (board[0][i] == board[1][i] && board[0][i] == board[2] [i] && board[0][i] == 1))) { // System.out.println("X Row or Column win"); return true; } } return false; } public boolean hasOWon() { if ((board[0][0] == board[1][1] && board[0][0] == board[2][2] && board[0][0] == 2) || (board[0][2] == board[1][1] && board[0][2] == board[2][0] && board[0][2] == 2)) { // System.out.println("O Diagonal Win"); return true; } for (int i = 0; i < 3; ++i) { if ((board[i][0] == board[i][1] && board[i][0] == board[i][2] && board[i][0] == 2) || (board[0][i] == board[1][i] && board[0][i] == board[2] [i] && board[0][i] == 2)) { // System.out.println("O Row or Column win"); return true; } } return false; } public List getAvailableStates() { availablePoints = new ArrayList(); for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { if (board[i][j] == 0) { availablePoints.add(new Point(i, j)); } } } return availablePoints; } public void placeAMove(Point point, int player) { board[point.x][point.y] = player; //player = for X, for O } void takeHumanInput() { System.out.println("Your move: "); int x = scan.nextInt(); int y = scan.nextInt(); Point point = new Point(x, y); placeAMove(point, 2); } public void displayBoard() { System.out.println(); for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { System.out.print(board[i][j] + " "); } System.out.println(); } } Point computersMove; public int minimax(int depth, int turn) { if (hasXWon()) return +1; if (hasOWon()) return -1; List pointsAvailable = getAvailableStates(); if (pointsAvailable.isEmpty()) return 0; int = Integer.MAX_VALUE, max = Integer.MIN_VALUE; for (int i = 0; i < pointsAvailable.size(); ++i) { Point point = pointsAvailable.get(i); if (turn == 1) { placeAMove(point, 1); int currentScore = minimax(depth + 1, 2); max = Math.max(currentScore, max); if(depth == 0)System.out.println("Score for position "+(i+1)+" = "+currentScore); if(currentScore >= 0){ if(depth == 0) computersMove = point;} if(currentScore == 1){board[point.x][point.y] = 0; break;} if(i == pointsAvailable.size()-1 && max < 0){if(depth == 0)computersMove = point;} } else if (turn == 2) { placeAMove(point, 2); int currentScore = minimax(depth + 1, 1); = Math.min(currentScore, min); if(min == -1){board[point.x][point.y] = 0; break;} } } board[point.x][point.y] = 0; //Reset this point } return turn == 1?max:min; } public class TicTacToe { public static void main(String[] args) { Board b = new Board(); Random rand = new Random(); b.displayBoard(); System.out.println("Select turn:\n\n1 Computer User: "); int choice = b.scan.nextInt(); if(choice == 1){ Point p = new Point(rand.nextInt(3), rand.nextInt(3)); b.placeAMove(p, 1); b.displayBoard(); } while (!b.isGameOver()) { System.out.println("Your move: "); Point userMove = new Point(b.scan.nextInt(), b.scan.nextInt()); b.placeAMove(userMove, 2); //2 for O and O is the user b.displayBoard(); if (b.isGameOver()) break; b.minimax(0, 1); b.placeAMove(b.computersMove, 1); b.displayBoard(); } } Output: } if (b.hasXWon()) System.out.println("Unfortunately, you lost!"); else if (b.hasOWon()) System.out.println("You win!"); //Can't happen else System.out.println("It's a draw!"); 000 000 000 Select turn: Computer User: Your move: 22 000 000 002 Score Score Score Score Score Score Score Score for for for for for for for for position position position position position position position position = = = = = = = = -1 -1 -1 -1 -1 -1 -1 = = = = = = -1 0 -1 = = = = -1 -1 -1 000 010 002 Your move: 00 200 010 002 Score Score Score Score Score Score for for for for for for position position position position position position 200 010 012 Your move: 01 220 010 012 Score Score Score Score for for for for position position position position 221 010 012 Your move: 20 221 010 212 Score for position = Score for position = -1 221 110 212 Your move: 12 221 112 212 It's a draw! The unbeatable Tic Tac Toe game, is one of my favorite project I built on Java (download TicTacToe for windows or TicTacToe for android device).To create an unbeatable game, you should calculate all possible moves and then choose the best (the best move is the move that gives you win) To so, I used the MiniMax algorithm What is MiniMax algorithm? MiniMax is a decision rule used in decision theory, game theory, statistics and philosophy for minimizing the possible loss for a worst case (maximum loss) scenario Alternatively, it can be thought of as maximizing the minimum gain (MaxiMin) Originally formulated for two-player zero sum game theory, covering both the cases where players take alternate moves and those where they make simultaneous moves, it has also been extended to more complex games and to general decision making in the presence of uncertainty (Reference: Wikipedia - MiniMax) Implementing MiniMax on Tic Tac Toe game: 1) How MiniMax Works To create an unbeatable Tic Tac Toe game, the computer needs to win the game or draw the game So let's give each situation a score: - If computer wins, the score is +1, - If computer loses , the score is -1, - If computer draws, the score is (Note: The computer is O and the player is X) The two players (the computer and the player) are defined as Max (computer) and Min (player) The computer should always search for the best score (the best score is the highest score), and let's suppose that the player is a powerful player, so the player will search for the worst score (the lowest score, the lowest score for the player is the best score for him) Scenario : It's computer's turn and it has two choices ( A and B) If it choose B the score will be 0, but if it choose A it gets +1 And because the computer is Max, it will choose A and get the highest score Scenario : It's computer's turn and it has three options (A, B and C) - If it choose A, the player has two choices A1 and A2, if the player choose A1 the game is draw and the score is 0.But if the player choose A2 the score is -1, and because it's player's turn (Min) the player gives the computer the worst score which is -1, so back to top, Choice (A) gives the computer the score -1 - If the computer choose B, the player has two choices B1 and B2, if the player choose B1, the game is draw so the score is But if the player choose B2, the player wins and the score is -1, and because the player is Min, he gives the computer the worst score so between B1(score=0) and B2(score=-1) the player will choose B2 So back to top, Choice (B) gives the computer the score -1 - If the computer choose C, the player has two choice C1 and C2 If he choose C1 the game is draw so the score is 0, and if the player choose C2 the game is draw too and the score is C1 gives and C2 gives also this means that if the computer choose C the score is So for conclusion : -A gives score -1, -B gives score -1, -C gives score 0, and because it's computer's turn (Max) the computer will choose the highest score (0 is the highest score), so the computer will choose the (C) choice Now let's resume all the above: - We have two players: Max and Min, - The Max always choose the best score, - The Min player choose the worst score In the Tic Tac Toe game the computer is the Max player because we want to build an unbeatable game, which makes the player the Min player 2) How implementing MiniMax on Java:Now we will take a look on how to implement MiniMax in Java (Note: I will note talk about graphics and interface, only about algorithm) We will use the ResultMM class for the algorithm This class has attributes (score, depth and matrix) public class ResultMM { String[] matrix; int score; int depth; public ResultMM(String[] matrix, int score, int depth) { this.matrix = matrix; this.score = score; this.depth = depth; } public void updateMatrix(String[] matrix) { this.matrix = matrix; } public int getScore() { return score; } public int getIntrus() { for(int i=0; i

Ngày đăng: 01/07/2017, 21:24

TỪ KHÓA LIÊN QUAN

w