Skip to content

Commit 5e12b57

Browse files
author
Harsh Dubey
committed
fix(MiniMaxAlgorithm): correct power-of-2 validation and log2 handling, add tests
1 parent 5e9d9f7 commit 5e12b57

File tree

2 files changed

+102
-13
lines changed

2 files changed

+102
-13
lines changed

src/main/java/com/thealgorithms/others/MiniMaxAlgorithm.java

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import java.util.Random;
55

66
/**
7-
* MiniMax is an algorithm used int artificial intelligence and game theory for
7+
* MiniMax is an algorithm used in artificial intelligence and game theory for
88
* minimizing the possible loss for the worst case scenario.
99
*
1010
* See more (https://en.wikipedia.org/wiki/Minimax,
@@ -74,22 +74,18 @@ public int miniMax(int depth, boolean isMaximizer, int index, boolean verbose) {
7474
bestScore = Math.min(score1, score2);
7575
}
7676

77-
// Leaf nodes can be sequentially inspected by
78-
// recurssively multiplying (0 * 2) and ((0 * 2) + 1):
79-
// (0 x 2) = 0; ((0 x 2) + 1) = 1
80-
// (1 x 2) = 2; ((1 x 2) + 1) = 3
81-
// (2 x 2) = 4; ((2 x 2) + 1) = 5 ...
8277
if (verbose) {
83-
System.out.printf("From %02d and %02d, %s chooses %02d%n", score1, score2, (isMaximizer ? "Maximizer" : "Minimizer"), bestScore);
78+
System.out.printf("From %02d and %02d, %s chooses %02d%n",
79+
score1, score2, (isMaximizer ? "Maximizer" : "Minimizer"), bestScore);
8480
}
8581

8682
return bestScore;
8783
}
8884

8985
/**
90-
* Returns an array of random numbers which lenght is a power of 2.
86+
* Returns an array of random numbers whose length is a power of 2.
9187
*
92-
* @param size The power of 2 that will determine the lenght of the array.
88+
* @param size The power of 2 that will determine the length of the array.
9389
* @param maxScore The maximum possible score.
9490
* @return An array of random numbers.
9591
*/
@@ -104,17 +100,29 @@ public static int[] getRandomScores(int size, int maxScore) {
104100
return randomScores;
105101
}
106102

107-
// A utility function to find Log n in base 2
103+
// A utility function to find log2(n)
108104
private int log2(int n) {
109-
return (n == 1) ? 0 : log2(n / 2) + 1;
105+
if (n <= 0) {
106+
throw new IllegalArgumentException("Input must be a positive integer.");
107+
}
108+
return (n == 1) ? 0 : 1 + log2(n / 2);
110109
}
111110

111+
/**
112+
* Sets the scores array if its length is a power of 2, otherwise throws exception.
113+
*
114+
* @param scores input array of scores
115+
*/
112116
public void setScores(int[] scores) {
113-
if (scores.length % 1 == 0) {
117+
if (scores == null || scores.length == 0) {
118+
throw new IllegalArgumentException("Scores array cannot be null or empty.");
119+
}
120+
// Check if length is power of 2 using bitwise trick
121+
if ((scores.length & (scores.length - 1)) == 0) {
114122
this.scores = scores;
115123
height = log2(this.scores.length);
116124
} else {
117-
System.out.println("The number of scores must be a power of 2.");
125+
throw new IllegalArgumentException("The number of scores must be a power of 2.");
118126
}
119127
}
120128

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package com.thealgorithms.others;
2+
3+
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
4+
import static org.junit.jupiter.api.Assertions.assertEquals;
5+
import static org.junit.jupiter.api.Assertions.assertThrows;
6+
import org.junit.jupiter.api.BeforeEach;
7+
import org.junit.jupiter.api.Test;
8+
9+
class MiniMaxAlgorithmTest {
10+
11+
private MiniMaxAlgorithm miniMax;
12+
13+
@BeforeEach
14+
void setUp() {
15+
miniMax = new MiniMaxAlgorithm();
16+
}
17+
18+
@Test
19+
void testRandomScoresLengthIsPowerOfTwo() {
20+
int[] scores = MiniMaxAlgorithm.getRandomScores(3, 100); // 2^3 = 8
21+
assertEquals(8, scores.length);
22+
}
23+
24+
@Test
25+
void testSetScoresValidPowerOfTwo() {
26+
int[] validScores = {1, 2, 3, 4};
27+
miniMax.setScores(validScores);
28+
assertArrayEquals(validScores, miniMax.getScores());
29+
assertEquals(2, miniMax.getHeight()); // log2(4) = 2
30+
}
31+
32+
@Test
33+
void testSetScoresInvalidLengthThrowsException() {
34+
int[] invalidScores = {1, 2, 3}; // length 3, not a power of 2
35+
assertThrows(IllegalArgumentException.class, () -> miniMax.setScores(invalidScores));
36+
}
37+
38+
@Test
39+
void testSetScoresNullThrowsException() {
40+
assertThrows(IllegalArgumentException.class, () -> miniMax.setScores(null));
41+
}
42+
43+
@Test
44+
void testSetScoresEmptyThrowsException() {
45+
assertThrows(IllegalArgumentException.class, () -> miniMax.setScores(new int[]{}));
46+
}
47+
48+
@Test
49+
void testLog2ValidInputs() {
50+
// indirectly tested through setScores, but also test directly
51+
assertEquals(0, invokeLog2(1));
52+
assertEquals(1, invokeLog2(2));
53+
assertEquals(2, invokeLog2(4));
54+
assertEquals(3, invokeLog2(8));
55+
}
56+
57+
@Test
58+
void testLog2InvalidInputs() {
59+
assertThrows(IllegalArgumentException.class, () -> invokeLog2(0));
60+
assertThrows(IllegalArgumentException.class, () -> invokeLog2(-4));
61+
}
62+
63+
@Test
64+
void testMiniMaxComputation() {
65+
int[] customScores = {3, 5, 2, 9}; // Tree height = 2
66+
miniMax.setScores(customScores);
67+
int bestScore = miniMax.miniMax(0, true, 0, false);
68+
assertEquals(5, bestScore); // Correct result from minimax
69+
}
70+
71+
// Utility to call private log2 method using reflection
72+
private int invokeLog2(int n) {
73+
try {
74+
var method = MiniMaxAlgorithm.class.getDeclaredMethod("log2", int.class);
75+
method.setAccessible(true);
76+
return (int) method.invoke(miniMax, n);
77+
} catch (Exception e) {
78+
throw new RuntimeException(e);
79+
}
80+
}
81+
}

0 commit comments

Comments
 (0)