Skip to content

Commit 676981a

Browse files
committed
Fix MiniMaxAlgorithm setScores bug and add comprehensive tests
- Fix bug in setScores method where scores.length % 1 == 0 always returned true - Add isPowerOfTwo helper method to properly validate array length - Add comprehensive unit tests covering edge cases and algorithm correctness - Tests include validation for power of 2 check, minimax logic, and error handling Fixes issue with incorrect validation logic in MiniMaxAlgorithm.setScores()
1 parent f9a9ccb commit 676981a

File tree

2 files changed

+191
-1
lines changed

2 files changed

+191
-1
lines changed

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,13 @@ private int log2(int n) {
109109
return (n == 1) ? 0 : log2(n / 2) + 1;
110110
}
111111

112+
// A utility function to check if a number is a power of 2
113+
private boolean isPowerOfTwo(int n) {
114+
return n > 0 && (n & (n - 1)) == 0;
115+
}
116+
112117
public void setScores(int[] scores) {
113-
if (scores.length % 1 == 0) {
118+
if (isPowerOfTwo(scores.length)) {
114119
this.scores = scores;
115120
height = log2(this.scores.length);
116121
} else {
Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
package com.thealgorithms.others;
2+
3+
import org.junit.jupiter.api.BeforeEach;
4+
import org.junit.jupiter.api.Test;
5+
import static org.junit.jupiter.api.Assertions.*;
6+
7+
import java.io.ByteArrayOutputStream;
8+
import java.io.PrintStream;
9+
10+
/**
11+
* Test class for MiniMaxAlgorithm
12+
* Tests the minimax algorithm implementation for game tree evaluation
13+
*/
14+
class MiniMaxAlgorithmTest {
15+
16+
private MiniMaxAlgorithm miniMax;
17+
private final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
18+
private final PrintStream originalOut = System.out;
19+
20+
@BeforeEach
21+
void setUp() {
22+
miniMax = new MiniMaxAlgorithm();
23+
System.setOut(new PrintStream(outputStream));
24+
}
25+
26+
@Test
27+
void testConstructorCreatesValidScores() {
28+
// The default constructor should create scores array of length 8 (2^3)
29+
assertEquals(8, miniMax.getScores().length);
30+
assertEquals(3, miniMax.getHeight());
31+
32+
// All scores should be positive (between 1 and 99)
33+
for (int score : miniMax.getScores()) {
34+
assertTrue(score >= 1 && score <= 99);
35+
}
36+
}
37+
38+
@Test
39+
void testSetScoresWithValidPowerOfTwo() {
40+
int[] validScores = {10, 20, 30, 40};
41+
miniMax.setScores(validScores);
42+
43+
assertArrayEquals(validScores, miniMax.getScores());
44+
assertEquals(2, miniMax.getHeight()); // log2(4) = 2
45+
}
46+
47+
@Test
48+
void testSetScoresWithInvalidLength() {
49+
int[] invalidScores = {10, 20, 30}; // Length 3 is not a power of 2
50+
miniMax.setScores(invalidScores);
51+
52+
// Should print error message and not change the scores
53+
String output = outputStream.toString();
54+
assertTrue(output.contains("The number of scores must be a power of 2."));
55+
56+
// Scores should remain unchanged (original length 8)
57+
assertEquals(8, miniMax.getScores().length);
58+
}
59+
60+
@Test
61+
void testSetScoresWithSingleElement() {
62+
int[] singleScore = {42};
63+
miniMax.setScores(singleScore);
64+
65+
assertArrayEquals(singleScore, miniMax.getScores());
66+
assertEquals(0, miniMax.getHeight()); // log2(1) = 0
67+
}
68+
69+
@Test
70+
void testMiniMaxWithKnownScores() {
71+
// Test with a known game tree: [3, 12, 8, 2]
72+
int[] testScores = {3, 12, 8, 2};
73+
miniMax.setScores(testScores);
74+
75+
// Maximizer starts: should choose max(min(3,12), min(8,2)) = max(3, 2) = 3
76+
int result = miniMax.miniMax(0, true, 0, false);
77+
assertEquals(3, result);
78+
}
79+
80+
@Test
81+
void testMiniMaxWithMinimizerFirst() {
82+
// Test with minimizer starting first
83+
int[] testScores = {3, 12, 8, 2};
84+
miniMax.setScores(testScores);
85+
86+
// Minimizer starts: should choose min(max(3,12), max(8,2)) = min(12, 8) = 8
87+
int result = miniMax.miniMax(0, false, 0, false);
88+
assertEquals(8, result);
89+
}
90+
91+
@Test
92+
void testMiniMaxWithLargerTree() {
93+
// Test with 8 elements: [5, 6, 7, 4, 5, 3, 6, 2]
94+
int[] testScores = {5, 6, 7, 4, 5, 3, 6, 2};
95+
miniMax.setScores(testScores);
96+
97+
// Maximizer starts
98+
int result = miniMax.miniMax(0, true, 0, false);
99+
// Expected: max(min(max(5,6), max(7,4)), min(max(5,3), max(6,2)))
100+
// = max(min(6, 7), min(5, 6)) = max(6, 5) = 6
101+
assertEquals(6, result);
102+
}
103+
104+
@Test
105+
void testMiniMaxVerboseOutput() {
106+
int[] testScores = {3, 12, 8, 2};
107+
miniMax.setScores(testScores);
108+
109+
miniMax.miniMax(0, true, 0, true);
110+
111+
String output = outputStream.toString();
112+
assertTrue(output.contains("Maximizer"));
113+
assertTrue(output.contains("Minimizer"));
114+
assertTrue(output.contains("chooses"));
115+
}
116+
117+
@Test
118+
void testGetRandomScoresLength() {
119+
int[] randomScores = MiniMaxAlgorithm.getRandomScores(4, 50);
120+
assertEquals(16, randomScores.length); // 2^4 = 16
121+
122+
// All scores should be between 1 and 50
123+
for (int score : randomScores) {
124+
assertTrue(score >= 1 && score <= 50);
125+
}
126+
}
127+
128+
@Test
129+
void testGetRandomScoresWithDifferentParameters() {
130+
int[] randomScores = MiniMaxAlgorithm.getRandomScores(2, 10);
131+
assertEquals(4, randomScores.length); // 2^2 = 4
132+
133+
// All scores should be between 1 and 10
134+
for (int score : randomScores) {
135+
assertTrue(score >= 1 && score <= 10);
136+
}
137+
}
138+
139+
@Test
140+
void testMainMethod() {
141+
// Test that main method runs without errors
142+
assertDoesNotThrow(() -> MiniMaxAlgorithm.main(new String[]{}));
143+
144+
String output = outputStream.toString();
145+
assertTrue(output.contains("The best score for"));
146+
assertTrue(output.contains("Maximizer"));
147+
}
148+
149+
@Test
150+
void testHeightCalculation() {
151+
// Test height calculation for different array sizes
152+
int[] scores2 = {1, 2};
153+
miniMax.setScores(scores2);
154+
assertEquals(1, miniMax.getHeight()); // log2(2) = 1
155+
156+
int[] scores16 = new int[16];
157+
miniMax.setScores(scores16);
158+
assertEquals(4, miniMax.getHeight()); // log2(16) = 4
159+
}
160+
161+
@Test
162+
void testEdgeCaseWithZeroScores() {
163+
int[] zeroScores = {0, 0, 0, 0};
164+
miniMax.setScores(zeroScores);
165+
166+
int result = miniMax.miniMax(0, true, 0, false);
167+
assertEquals(0, result);
168+
}
169+
170+
@Test
171+
void testEdgeCaseWithNegativeScores() {
172+
int[] negativeScores = {-5, -2, -8, -1};
173+
miniMax.setScores(negativeScores);
174+
175+
// Tree evaluation with maximizer first:
176+
// Level 1 (minimizer): min(-5,-2) = -5, min(-8,-1) = -8
177+
// Level 0 (maximizer): max(-5, -8) = -5
178+
int result = miniMax.miniMax(0, true, 0, false);
179+
assertEquals(-5, result);
180+
}
181+
182+
void tearDown() {
183+
System.setOut(originalOut);
184+
}
185+
}

0 commit comments

Comments
 (0)