Skip to content

Commit

Permalink
Uploaded all the code
Browse files Browse the repository at this point in the history
The complete code.
  • Loading branch information
LazoCoder committed Nov 13, 2016
1 parent 511de66 commit 0d48754
Show file tree
Hide file tree
Showing 14 changed files with 1,271 additions and 0 deletions.
76 changes: 76 additions & 0 deletions TicTacToe/ArtificialIntelligence/Algorithms.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package ArtificialIntelligence;

import TicTacToe.Board;

/**
* Uses various algorithms to play Tic Tac Toe.
*/
public class Algorithms {

/**
* Algorithms cannot be instantiated.
*/
private Algorithms() {}

/**
* Play a random move.
* @param board the Tic Tac Toe board to play on
*/
public static void random (Board board) {
Random.run(board);
}

/**
* Play using the MiniMax Algorithm.
* @param board the Tic Tac Toe board to play on
*/
public static void miniMax (Board board) {
MiniMax.run(board.getTurn(), board, Double.POSITIVE_INFINITY);
}

/**
* Play using the MiniMax algorithm. Include a depth limit.
* @param board the Tic Tac Toe board to play on
* @param ply the maximum depth
*/
public static void miniMax (Board board, int ply) {
MiniMax.run(board.getTurn(), board, ply);
}

/**
* Play using the Alpha-Beta Pruning algorithm.
* @param board the Tic Tac Toe board to play on
*/
public static void alphaBetaPruning (Board board) {
AlphaBetaPruning.run(board.getTurn(), board, Double.POSITIVE_INFINITY);
}

/**
* Play using the Alpha-Beta Pruning algorithm. Include a depth limit.
* @param board the Tic Tac Toe board to play on
* @param ply the maximum depth
*/
public static void alphaBetaPruning (Board board, int ply) {
AlphaBetaPruning.run(board.getTurn(), board, ply);
}

/**
* Play using the Alpha-Beta Pruning algorithm. Include depth in the
* evaluation function.
* @param board the Tic Tac Toe board to play on
*/
public static void alphaBetaAdvanced (Board board) {
AlphaBetaAdvanced.run(board.getTurn(), board, Double.POSITIVE_INFINITY);
}

/**
* Play using the Alpha-Beta Pruning algorithm. Include depth in the
* evaluation function and a depth limit.
* @param board the Tic Tac Toe board to play on
* @param ply the maximum depth
*/
public static void alphaBetaAdvanced (Board board, int ply) {
AlphaBetaAdvanced.run(board.getTurn(), board, ply);
}

}
157 changes: 157 additions & 0 deletions TicTacToe/ArtificialIntelligence/AlphaBetaAdvanced.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
package ArtificialIntelligence;

import TicTacToe.Board;

/**
* Uses the Alpha-Beta Pruning algorithm to play a move in a game of Tic Tac Toe
* but includes depth in the evaluation function.
*
* The vanilla MiniMax algorithm plays perfectly but it may occasionally
* decide to make a move that will results in a slower victory or a faster loss.
* For example, playing the move 0, 1, and then 7 gives the AI the opportunity
* to play a move at index 6. This would result in a victory on the diagonal.
* But the AI does not choose this move, instead it chooses another one. It
* still wins inevitably, but it chooses a longer route. By adding the depth
* into the evaluation function, it allows the AI to pick the move that would
* make it win as soon as possible.
*/
class AlphaBetaAdvanced {

private static double maxPly;

/**
* AlphaBetaAdvanced cannot be instantiated.
*/
private AlphaBetaAdvanced() {}

/**
* Execute the algorithm.
* @param player the player that the AI will identify as
* @param board the Tic Tac Toe board to play on
* @param maxPly the maximum depth
*/
static void run (Board.State player, Board board, double maxPly) {

if (maxPly < 1) {
throw new IllegalArgumentException("Maximum depth must be greater than 1.");
}

AlphaBetaAdvanced.maxPly = maxPly;
alphaBetaPruning(player, board, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, 0);
}

/**
* The meat of the algorithm.
* @param player the player that the AI will identify as
* @param board the Tic Tac Toe board to play on
* @param alpha the alpha value
* @param beta the beta value
* @param currentPly the current depth
* @return the score of the board
*/
private static int alphaBetaPruning (Board.State player, Board board, double alpha, double beta, int currentPly) {
if (currentPly++ == maxPly || board.isGameOver()) {
return score(player, board, currentPly);
}

if (board.getTurn() == player) {
return getMax(player, board, alpha, beta, currentPly);
} else {
return getMin(player, board, alpha, beta, currentPly);
}
}

/**
* Play the move with the highest score.
* @param player the player that the AI will identify as
* @param board the Tic Tac Toe board to play on
* @param alpha the alpha value
* @param beta the beta value
* @param currentPly the current depth
* @return the score of the board
*/
private static int getMax (Board.State player, Board board, double alpha, double beta, int currentPly) {
int indexOfBestMove = -1;

for (Integer theMove : board.getAvailableMoves()) {

Board modifiedBoard = board.getDeepCopy();
modifiedBoard.move(theMove);
int score = alphaBetaPruning(player, modifiedBoard, alpha, beta, currentPly);

if (score > alpha) {
alpha = score;
indexOfBestMove = theMove;
}

if (alpha >= beta) {
break;
}
}

if (indexOfBestMove != -1) {
board.move(indexOfBestMove);
}
return (int)alpha;
}

/**
* Play the move with the lowest score.
* @param player the player that the AI will identify as
* @param board the Tic Tac Toe board to play on
* @param alpha the alpha value
* @param beta the beta value
* @param currentPly the current depth
* @return the score of the board
*/
private static int getMin (Board.State player, Board board, double alpha, double beta, int currentPly) {
int indexOfBestMove = -1;

for (Integer theMove : board.getAvailableMoves()) {

Board modifiedBoard = board.getDeepCopy();
modifiedBoard.move(theMove);

int score = alphaBetaPruning(player, modifiedBoard, alpha, beta, currentPly);

if (score < beta) {
beta = score;
indexOfBestMove = theMove;
}

if (alpha >= beta) {
break;
}
}

if (indexOfBestMove != -1) {
board.move(indexOfBestMove);
}
return (int)beta;
}

/**
* Get the score of the board. Takes depth into account.
* @param player the play that the AI will identify as
* @param board the Tic Tac Toe board to play on
* @param currentPly the current depth
* @return the score of the board
*/
private static int score (Board.State player, Board board, int currentPly) {

if (player == Board.State.Blank) {
throw new IllegalArgumentException("Player must be X or O.");
}

Board.State opponent = (player == Board.State.X) ? Board.State.O : Board.State.X;

if (board.isGameOver() && board.getWinner() == player) {
return 10 - currentPly;
} else if (board.isGameOver() && board.getWinner() == opponent) {
return -10 + currentPly;
} else {
return 0;
}
}

}
146 changes: 146 additions & 0 deletions TicTacToe/ArtificialIntelligence/AlphaBetaPruning.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
package ArtificialIntelligence;

import TicTacToe.Board;

/**
* Uses the Alpha-Beta Pruning algorithm to play a move in a game of Tic Tac Toe.
*/
class AlphaBetaPruning {

private static double maxPly;

/**
* AlphaBetaPruning cannot be instantiated.
*/
private AlphaBetaPruning () {}

/**
* Execute the algorithm.
* @param player the player that the AI will identify as
* @param board the Tic Tac Toe board to play on
* @param maxPly the maximum depth
*/
static void run (Board.State player, Board board, double maxPly) {
if (maxPly < 1) {
throw new IllegalArgumentException("Maximum depth must be greater than 1.");
}

AlphaBetaPruning.maxPly = maxPly;
alphaBetaPruning(player, board, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, 0);
}

/**
* The meat of the algorithm.
* @param player the player that the AI will identify as
* @param board the Tic Tac Toe board to play on
* @param alpha the alpha value
* @param beta the beta value
* @param currentPly the current depth
* @return the score of the board
*/
private static int alphaBetaPruning (Board.State player, Board board, double alpha, double beta, int currentPly) {
if (currentPly++ == maxPly || board.isGameOver()) {
return score(player, board);
}

if (board.getTurn() == player) {
return getMax(player, board, alpha, beta, currentPly);
} else {
return getMin(player, board, alpha, beta, currentPly);
}
}

/**
* Play the move with the highest score.
* @param player the player that the AI will identify as
* @param board the Tic Tac Toe board to play on
* @param alpha the alpha value
* @param beta the beta value
* @param currentPly the current depth
* @return the score of the board
*/
private static int getMax (Board.State player, Board board, double alpha, double beta, int currentPly) {
int indexOfBestMove = -1;

for (Integer theMove : board.getAvailableMoves()) {

Board modifiedBoard = board.getDeepCopy();
modifiedBoard.move(theMove);
int score = alphaBetaPruning(player, modifiedBoard, alpha, beta, currentPly);

if (score > alpha) {
alpha = score;
indexOfBestMove = theMove;
}

// Pruning.
if (alpha >= beta) {
break;
}
}

if (indexOfBestMove != -1) {
board.move(indexOfBestMove);
}
return (int)alpha;
}

/**
* Play the move with the lowest score.
* @param player the player that the AI will identify as
* @param board the Tic Tac Toe board to play on
* @param alpha the alpha value
* @param beta the beta value
* @param currentPly the current depth
* @return the score of the board
*/
private static int getMin (Board.State player, Board board, double alpha, double beta, int currentPly) {
int indexOfBestMove = -1;

for (Integer theMove : board.getAvailableMoves()) {

Board modifiedBoard = board.getDeepCopy();
modifiedBoard.move(theMove);

int score = alphaBetaPruning(player, modifiedBoard, alpha, beta, currentPly);

if (score < beta) {
beta = score;
indexOfBestMove = theMove;
}

// Pruning.
if (alpha >= beta) {
break;
}
}

if (indexOfBestMove != -1) {
board.move(indexOfBestMove);
}
return (int)beta;
}

/**
* Get the score of the board.
* @param player the play that the AI will identify as
* @param board the Tic Tac Toe board to play on
* @return the score of the board
*/
private static int score (Board.State player, Board board) {
if (player == Board.State.Blank) {
throw new IllegalArgumentException("Player must be X or O.");
}

Board.State opponent = (player == Board.State.X) ? Board.State.O : Board.State.X;

if (board.isGameOver() && board.getWinner() == player) {
return 10;
} else if (board.isGameOver() && board.getWinner() == opponent) {
return -10;
} else {
return 0;
}
}

}
Loading

0 comments on commit 0d48754

Please sign in to comment.