Add MiniMax algorithm (#2563)
Co-authored-by: aitorfi <afidalgo@birt.eus>
This commit is contained in:
parent
5dd3366edc
commit
febc601d88
128
Others/MiniMaxAlgorithm.java
Normal file
128
Others/MiniMaxAlgorithm.java
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user