diff --git a/Others/MiniMaxAlgorithm.java b/Others/MiniMaxAlgorithm.java new file mode 100644 index 000000000..06bfa732c --- /dev/null +++ b/Others/MiniMaxAlgorithm.java @@ -0,0 +1,128 @@ +package Others; + +import java.util.Arrays; +import java.util.Random; + +/** + * MiniMax is an algorithm used int artificial intelligence and game theory for + * minimizing the possible loss for the worst case scenario. + * + * See more (https://en.wikipedia.org/wiki/Minimax, + * https://www.geeksforgeeks.org/minimax-algorithm-in-game-theory-set-1-introduction/). + * + * @author aitofi (https://github.com/aitorfi) + */ +public class MiniMaxAlgorithm { + /** + * Game tree represented as an int array containing scores. Each array element + * is a leaf node. + */ + private int[] scores; + private int height; + + /** + * Initializes the scores with 8 random leaf nodes + */ + public MiniMaxAlgorithm() { + scores = getRandomScores(3, 99); + height = log2(scores.length); + } + + public static void main(String[] args) { + MiniMaxAlgorithm miniMaxAlgorith = new MiniMaxAlgorithm(); + boolean isMaximizer = true; // Specifies the player that goes first. + boolean verbose = true; // True to show each players choices. + int bestScore; + + bestScore = miniMaxAlgorith.miniMax(0, isMaximizer, 0, verbose); + + if (verbose) { + System.out.println(); + } + + System.out.println(Arrays.toString(miniMaxAlgorith.getScores())); + System.out.println( + "The best score for " + (isMaximizer ? "Maximizer" : "Minimizer") + " is " + String.valueOf(bestScore)); + } + + /** + * Returns the optimal score assuming that both players play their best. + * + * @param depth Indicates how deep we are into the game tree. + * @param isMaximizer True if it is maximizers turn; otherwise false. + * @param index Index of the leaf node that is being evaluated. + * @param verbose True to show each players choices. + * @return The optimal score for the player that made the first move. + */ + public int miniMax(int depth, boolean isMaximizer, int index, boolean verbose) { + int bestScore, score1, score2; + + if (depth == height) { // Leaf node reached. + return scores[index]; + } + + score1 = miniMax(depth + 1, !isMaximizer, index * 2, verbose); + score2 = miniMax(depth + 1, !isMaximizer, (index * 2) + 1, verbose); + + if (isMaximizer) { + // Maximizer player wants to get the maximum possible score. + bestScore = Math.max(score1, score2); + } else { + // Minimizer player wants to get the minimum possible score. + bestScore = Math.min(score1, score2); + } + + // Leaf nodes can be sequentially inspected by + // recurssively multiplying (0 * 2) and ((0 * 2) + 1): + // (0 x 2) = 0; ((0 x 2) + 1) = 1 + // (1 x 2) = 2; ((1 x 2) + 1) = 3 + // (2 x 2) = 4; ((2 x 2) + 1) = 5 ... + + if (verbose) { + System.out.println(String.format("From %02d and %02d, %s chooses %02d", score1, score2, + (isMaximizer ? "Maximizer" : "Minimizer"), bestScore)); + } + + return bestScore; + } + + /** + * Returns an array of random numbers which lenght is a power of 2. + * + * @param size The power of 2 that will determine the lenght of the array. + * @param maxScore The maximum possible score. + * @return An array of random numbers. + */ + public static int[] getRandomScores(int size, int maxScore) { + int[] randomScores = new int[(int) Math.pow(2, size)]; + Random rand = new Random(); + + for (int a : randomScores) { + a = rand.nextInt(maxScore) + 1; + } + + return randomScores; + } + + // A utility function to find Log n in base 2 + private int log2(int n) { + return (n == 1) ? 0 : log2(n / 2) + 1; + } + + public void setScores(int[] scores) { + if (scores.length % 1 == 0) { + this.scores = scores; + height = log2(this.scores.length); + } else { + System.out.println("The number of scores must be a power of 2."); + } + } + + public int[] getScores() { + return scores; + } + + public int getHeight() { + return height; + } +} \ No newline at end of file