package tictactoe; import javax.swing.JOptionPane; import java.util.Scanner; import java.util.ArrayList; import java.util.List; import java.util.Random; public class TicTacToe { public static void main(String[] args) { BoardAndAIRules c = new BoardAndAIRules(); c.playAIvsAI(true, 100); //true for minmax BoardAndAIRules b = new BoardAndAIRules(); b.playAIvsAI(false, 100); //false for alpha beta System.out.println("alpha beta average recursive calls: "+ b.averageRecursiveCallCount+ " AI wins "+b.numberOfAIWins+" P1 wins "+b.numberOfP1Wins+" Draws "+b.numberOfDraws); System.out.println("min max average recursive calls: "+ c.averageRecursiveCallCount+" AI wins "+c.numberOfAIWins+" P1 wins "+c.numberOfP1Wins+" Draws "+c.numberOfDraws); //b.playGame(false); //false for alphaminmax // System.out.println("alpha-beta: "+ b.recursiveCallsCount); /**BoardAndAIRules c = new BoardAndAIRules(); c.playGame(true); //false for alphaminmax System.out.println("min-max: "+ c.recursiveCallsCount);**/ } } class BoardAndAIRules { int averageRecursiveCallCount = 0; int totalRecusirveCallCount = 0; int recursiveCallsCount = 0; int numberOfDraws = 0; int numberOfAIWins = 0; int numberOfP1Wins = 0; String[][] board = new String[3][3]; List allPossibleSequences; Position bestMoveForAI; String whoWon; public void initializeBoard() { recursiveCallsCount = 0; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { board[j][i] = "OO"; } } } public void randomizeAIFirstTurn(String AI) { Random rand = new Random(); board[rand.nextInt(3)][rand.nextInt(3)]=AI; } public void playAIvsAI(boolean isMinMax, int howManyPlays) { for(int i = 1; i<=howManyPlays;i++){ initializeBoard(); randomizeAIFirstTurn("AI");printBoard(); boolean turn = false; do { if (didAIWin("AI") || didUserWin("P1") || allPossibleNextMoves().isEmpty()) break; if (turn == true){ if (!isMinMax) minMaxAlphaBeta(0, true, -11, 11,"AI","P1"); else minMax(0, true,"AI","P1"); board[bestMoveForAI.x][bestMoveForAI.y] = "AI";turn =false; } else { if (!isMinMax) minMaxAlphaBeta(0, true, -11, 11,"P1","AI"); else minMax(0, true,"P1","AI"); board[bestMoveForAI.x][bestMoveForAI.y] = "P1";turn =true; } printBoard(); } while(!(didAIWin("AI") || didUserWin("P1") || allPossibleNextMoves().isEmpty())); if(didAIWin("AI")) {whoWon= "AI WON"; numberOfAIWins++; } else if (didUserWin("P1")) {whoWon= "P1 WON"; numberOfP1Wins++;} else {whoWon="DRAW"; numberOfDraws++;} totalRecusirveCallCount +=recursiveCallsCount; averageRecursiveCallCount = totalRecusirveCallCount/i; } } public void playGame(boolean isMinMax) { Scanner userInput; userInput = new Scanner(System.in); initializeBoard(); printBoard(); String[]buttons = {"AI","ME"}; int rc = JOptionPane.showOptionDialog(null, "Who goes first? AI or You", "Confirmation", JOptionPane.WARNING_MESSAGE, 0, null, buttons, buttons[1]); if(rc==0){ randomizeAIFirstTurn("AI"); printBoard(); } do { System.out.println("User Turn. Enter X Y format for coordinate position X, Y on board"); Position userMove = new Position(userInput.nextInt(), userInput.nextInt()); while (userMove.x>=3||userMove.y>=3||userMove.x<0||userMove.y<0||board[userMove.x][userMove.y].equals("AI")|| board[userMove.x][userMove.y].equals("P1")) { System.out.println("Incorrect coordinates, renter again"); userMove = new Position(userInput.nextInt(), userInput.nextInt()); } board[userMove.x][userMove.y] = "P1"; printBoard(); if (didAIWin("AI") || didUserWin("P1") || allPossibleNextMoves().isEmpty()) break; if (!isMinMax)minMaxAlphaBeta(0, true, -11, 11,"AI","P1"); else minMax(0, true,"AI","P1"); board[bestMoveForAI.x][bestMoveForAI.y] = "AI"; printBoard(); } while(!(didAIWin("AI") || didUserWin("P1") || allPossibleNextMoves().isEmpty())); } public boolean didUserWin(String user) { if ((board[0][0].equals(board[1][1]) && board[0][0].equals(board[2][2]) && board[0][0].equals(user)) || (board[0][2].equals(board[1][1]) && board[0][2].equals(board[2][0]) && board[0][2].equals(user)) || ((board[1][0].equals(board[1][1]) && board[1][0].equals(board[1][2]) && board[1][0].equals(user)) || (board[0][1].equals(board[1][1]) && board[0][1].equals(board[2][1]) && board[0][1].equals(user))) || ((board[0][0].equals(board[0][1]) && board[0][0].equals(board[0][2]) && board[0][0].equals(user)) || (board[0][0].equals(board[1][0]) && board[0][0].equals(board[2][0]) && board[0][0].equals(user))) || ((board[2][0].equals(board[2][1]) && board[2][0].equals(board[2][2]) && board[2][0].equals(user)) || (board[0][2].equals(board[1][2]) && board[0][2].equals(board[2][2]) && board[0][2].equals(user))) ) { return true; } else return false; } public void printBoard() { for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { System.out.print(board[j][i] + " "); } System.out.println(); } System.out.println(); } public boolean didAIWin(String AI) { if ((board[0][0].equals(board[1][1]) && board[0][0].equals(board[2][2]) && board[0][0].equals(AI)) || (board[0][2].equals(board[1][1]) && board[0][2].equals(board[2][0]) && board[0][2].equals(AI)) || ((board[1][0].equals(board[1][1]) && board[1][0].equals(board[1][2]) && board[1][0].equals(AI)) || (board[0][1].equals(board[1][1]) && board[0][1].equals(board[2][1]) && board[0][1].equals(AI))) || ((board[0][0].equals(board[0][1]) && board[0][0].equals(board[0][2]) && board[0][0].equals(AI)) || (board[0][0].equals(board[1][0]) && board[0][0].equals(board[2][0]) && board[0][0].equals(AI))) || ((board[2][0].equals(board[2][1]) && board[2][0].equals(board[2][2]) && board[2][0].equals(AI)) || (board[0][2].equals(board[1][2]) && board[0][2].equals(board[2][2]) && board[0][2].equals(AI))) ) { return true; } else return false; } public List allPossibleNextMoves() { allPossibleSequences = new ArrayList<>(); for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { if (board[i][j].equals("OO")) { allPossibleSequences.add(new Position(i, j)); } } } return allPossibleSequences; } class Position { int x; int y; public Position(int x, int y) { this.x = x; this.y = y; } } public int minMaxAlphaBeta(int depth, boolean isItAiMove, int alpha, int beta, String ai, String opposingPlayer) { recursiveCallsCount++; List PositionsAvailable; if (didAIWin(ai)) return +10; else if (didUserWin(opposingPlayer)) return -10; else { PositionsAvailable = allPossibleNextMoves(); if (PositionsAvailable.isEmpty()) return 0; } if (isItAiMove) { for (Position result:PositionsAvailable){ board[result.x][result.y] = ai; int heuristic = minMaxAlphaBeta(depth + 1, false, alpha, beta, ai, opposingPlayer); if (heuristic > alpha) {alpha = heuristic;if(depth ==0)bestMoveForAI = result;} if(alpha >= beta){board[result.x][result.y] = "OO";break;} if (depth == 0){System.out.println("Heuristic Score at Position "+result.x+","+result.y+" is: "+ heuristic);} board[result.x][result.y] = "OO"; } } else if (!isItAiMove) { for (Position result:PositionsAvailable) { board[result.x][result.y] = opposingPlayer; int heuristic = minMaxAlphaBeta(depth + 1, true, alpha, beta,ai, opposingPlayer); if (heuristic < beta) beta = heuristic; if(alpha>=beta){board[result.x][result.y] = "OO";break;} board[result.x][result.y] = "OO"; } } int returnValue = 0; if (isItAiMove) returnValue = alpha; else returnValue = beta; return returnValue; } public int minMax(int depth, boolean isItAiMove,String ai, String opposingPlayer) { int min = 11; int max = -11; recursiveCallsCount++; List PositionsAvailable; if (didAIWin(ai)) return +10; else if (didUserWin(opposingPlayer)) return -10; else { PositionsAvailable = allPossibleNextMoves(); if (PositionsAvailable.isEmpty()) return 0; } if (isItAiMove) { for (Position result:PositionsAvailable){ board[result.x][result.y] = ai; int heuristic = minMax(depth + 1, false, ai, opposingPlayer); if (depth == 0){System.out.println("Heuristic Score at Position "+result.x+","+result.y+" is: "+ heuristic);}; if (heuristic > max) {max = heuristic; if(depth == 0) bestMoveForAI = result;} board[result.x][result.y] = "OO"; } } else if (!isItAiMove) { for (Position result:PositionsAvailable) { board[result.x][result.y] = opposingPlayer; int c = minMax(depth + 1, true,ai, opposingPlayer); if (c < min) min = c; board[result.x][result.y] = "OO"; } } int returnValue = 0; if (isItAiMove) returnValue = max; else returnValue = min; return returnValue; } }