Skip to content

Commit 15695c6

Browse files
yashsaha555sousaha97DenizAltunkapan
authored
Fix MiniMaxAlgorithm setScores bug and add comprehensive tests (#6566)
* 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() * Fix Checkstyle violations and improve setScores validation - Replace star imports with explicit imports in test file - Remove trailing whitespaces from all lines - Add proper file ending newline - Improve setScores method to handle edge cases properly - Use direct bit manipulation for power-of-2 check as suggested - Ensure error message is printed and scores remain unchanged for invalid input All Checkstyle violations resolved and tests pass successfully. * Add missing newline at end of MiniMaxAlgorithmTest.java - Fix Checkstyle violation: NewlineAtEndOfFile - Ensure file ends with proper newline character - All tests continue to pass successfully * Fix PMD violation by utilizing isPowerOfTwo method - Replace inline bit manipulation with isPowerOfTwo method call - Resolves PMD UnusedPrivateMethod violation - Maintains same validation logic and error handling - All tests continue to pass successfully * test: improve MiniMaxAlgorithm test coverage for CodeCov - Add comprehensive test cases for isPowerOfTwo function edge cases - Test setScores method with various invalid array lengths (0, 3, 5, 6, 7, 9, 10, 15) - Add tests for large valid powers of 2 (up to 64 elements) - Ensure complete coverage of error handling branches - Increase test count from 14 to 19 tests - Fix partial coverage issues identified in CodeCov report Resolves CodeCov coverage gaps in MiniMaxAlgorithm.java * Fix checkstyle errors * Fix checkstyle errors --------- Co-authored-by: ssaha <[email protected]> Co-authored-by: Deniz Altunkapan <[email protected]>
1 parent f8f315e commit 15695c6

File tree

2 files changed

+286
-4
lines changed

2 files changed

+286
-4
lines changed

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

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -109,13 +109,18 @@ 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) {
114-
this.scores = scores;
115-
height = log2(this.scores.length);
116-
} else {
118+
if (!isPowerOfTwo(scores.length)) {
117119
System.out.println("The number of scores must be a power of 2.");
120+
return;
118121
}
122+
this.scores = scores;
123+
height = log2(this.scores.length);
119124
}
120125

121126
public int[] getScores() {
Lines changed: 277 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,277 @@
1+
package com.thealgorithms.others;
2+
3+
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
4+
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
5+
import static org.junit.jupiter.api.Assertions.assertEquals;
6+
import static org.junit.jupiter.api.Assertions.assertTrue;
7+
8+
import java.io.ByteArrayOutputStream;
9+
import java.io.PrintStream;
10+
import org.junit.jupiter.api.BeforeEach;
11+
import org.junit.jupiter.api.Test;
12+
13+
/**
14+
* Test class for MiniMaxAlgorithm
15+
* Tests the minimax algorithm implementation for game tree evaluation
16+
*/
17+
class MiniMaxAlgorithmTest {
18+
19+
private MiniMaxAlgorithm miniMax;
20+
private final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
21+
private final PrintStream originalOut = System.out;
22+
23+
@BeforeEach
24+
void setUp() {
25+
miniMax = new MiniMaxAlgorithm();
26+
System.setOut(new PrintStream(outputStream));
27+
}
28+
29+
@Test
30+
void testConstructorCreatesValidScores() {
31+
// The default constructor should create scores array of length 8 (2^3)
32+
assertEquals(8, miniMax.getScores().length);
33+
assertEquals(3, miniMax.getHeight());
34+
35+
// All scores should be positive (between 1 and 99)
36+
for (int score : miniMax.getScores()) {
37+
assertTrue(score >= 1 && score <= 99);
38+
}
39+
}
40+
41+
@Test
42+
void testSetScoresWithValidPowerOfTwo() {
43+
int[] validScores = {10, 20, 30, 40};
44+
miniMax.setScores(validScores);
45+
46+
assertArrayEquals(validScores, miniMax.getScores());
47+
assertEquals(2, miniMax.getHeight()); // log2(4) = 2
48+
}
49+
50+
@Test
51+
void testSetScoresWithInvalidLength() {
52+
int[] invalidScores = {10, 20, 30}; // Length 3 is not a power of 2
53+
miniMax.setScores(invalidScores);
54+
55+
// Should print error message and not change the scores
56+
String output = outputStream.toString();
57+
assertTrue(output.contains("The number of scores must be a power of 2."));
58+
59+
// Scores should remain unchanged (original length 8)
60+
assertEquals(8, miniMax.getScores().length);
61+
}
62+
63+
@Test
64+
void testSetScoresWithZeroLength() {
65+
int[] emptyScores = {}; // Length 0 is not a power of 2
66+
miniMax.setScores(emptyScores);
67+
68+
// Should print error message and not change the scores
69+
String output = outputStream.toString();
70+
assertTrue(output.contains("The number of scores must be a power of 2."));
71+
72+
// Scores should remain unchanged (original length 8)
73+
assertEquals(8, miniMax.getScores().length);
74+
}
75+
76+
@Test
77+
void testSetScoresWithVariousInvalidLengths() {
78+
// Test multiple invalid lengths to ensure isPowerOfTwo function is fully covered
79+
int[][] invalidScoreArrays = {
80+
{1, 2, 3, 4, 5}, // Length 5
81+
{1, 2, 3, 4, 5, 6}, // Length 6
82+
{1, 2, 3, 4, 5, 6, 7}, // Length 7
83+
new int[9], // Length 9
84+
new int[10], // Length 10
85+
new int[15] // Length 15
86+
};
87+
88+
for (int[] invalidScores : invalidScoreArrays) {
89+
// Clear the output stream for each test
90+
outputStream.reset();
91+
miniMax.setScores(invalidScores);
92+
93+
// Should print error message for each invalid length
94+
String output = outputStream.toString();
95+
assertTrue(output.contains("The number of scores must be a power of 2."), "Failed for array length: " + invalidScores.length);
96+
}
97+
98+
// Scores should remain unchanged (original length 8)
99+
assertEquals(8, miniMax.getScores().length);
100+
}
101+
102+
@Test
103+
void testSetScoresWithSingleElement() {
104+
int[] singleScore = {42};
105+
miniMax.setScores(singleScore);
106+
107+
assertArrayEquals(singleScore, miniMax.getScores());
108+
assertEquals(0, miniMax.getHeight()); // log2(1) = 0
109+
}
110+
111+
@Test
112+
void testMiniMaxWithKnownScores() {
113+
// Test with a known game tree: [3, 12, 8, 2]
114+
int[] testScores = {3, 12, 8, 2};
115+
miniMax.setScores(testScores);
116+
117+
// Maximizer starts: should choose max(min(3,12), min(8,2)) = max(3, 2) = 3
118+
int result = miniMax.miniMax(0, true, 0, false);
119+
assertEquals(3, result);
120+
}
121+
122+
@Test
123+
void testMiniMaxWithMinimizerFirst() {
124+
// Test with minimizer starting first
125+
int[] testScores = {3, 12, 8, 2};
126+
miniMax.setScores(testScores);
127+
128+
// Minimizer starts: should choose min(max(3,12), max(8,2)) = min(12, 8) = 8
129+
int result = miniMax.miniMax(0, false, 0, false);
130+
assertEquals(8, result);
131+
}
132+
133+
@Test
134+
void testMiniMaxWithLargerTree() {
135+
// Test with 8 elements: [5, 6, 7, 4, 5, 3, 6, 2]
136+
int[] testScores = {5, 6, 7, 4, 5, 3, 6, 2};
137+
miniMax.setScores(testScores);
138+
139+
// Maximizer starts
140+
int result = miniMax.miniMax(0, true, 0, false);
141+
// Expected: max(min(max(5,6), max(7,4)), min(max(5,3), max(6,2)))
142+
// = max(min(6, 7), min(5, 6)) = max(6, 5) = 6
143+
assertEquals(6, result);
144+
}
145+
146+
@Test
147+
void testMiniMaxVerboseOutput() {
148+
int[] testScores = {3, 12, 8, 2};
149+
miniMax.setScores(testScores);
150+
151+
miniMax.miniMax(0, true, 0, true);
152+
153+
String output = outputStream.toString();
154+
assertTrue(output.contains("Maximizer"));
155+
assertTrue(output.contains("Minimizer"));
156+
assertTrue(output.contains("chooses"));
157+
}
158+
159+
@Test
160+
void testGetRandomScoresLength() {
161+
int[] randomScores = MiniMaxAlgorithm.getRandomScores(4, 50);
162+
assertEquals(16, randomScores.length); // 2^4 = 16
163+
164+
// All scores should be between 1 and 50
165+
for (int score : randomScores) {
166+
assertTrue(score >= 1 && score <= 50);
167+
}
168+
}
169+
170+
@Test
171+
void testGetRandomScoresWithDifferentParameters() {
172+
int[] randomScores = MiniMaxAlgorithm.getRandomScores(2, 10);
173+
assertEquals(4, randomScores.length); // 2^2 = 4
174+
175+
// All scores should be between 1 and 10
176+
for (int score : randomScores) {
177+
assertTrue(score >= 1 && score <= 10);
178+
}
179+
}
180+
181+
@Test
182+
void testMainMethod() {
183+
// Test that main method runs without errors
184+
assertDoesNotThrow(() -> MiniMaxAlgorithm.main(new String[] {}));
185+
186+
String output = outputStream.toString();
187+
assertTrue(output.contains("The best score for"));
188+
assertTrue(output.contains("Maximizer"));
189+
}
190+
191+
@Test
192+
void testHeightCalculation() {
193+
// Test height calculation for different array sizes
194+
int[] scores2 = {1, 2};
195+
miniMax.setScores(scores2);
196+
assertEquals(1, miniMax.getHeight()); // log2(2) = 1
197+
198+
int[] scores16 = new int[16];
199+
miniMax.setScores(scores16);
200+
assertEquals(4, miniMax.getHeight()); // log2(16) = 4
201+
}
202+
203+
@Test
204+
void testEdgeCaseWithZeroScores() {
205+
int[] zeroScores = {0, 0, 0, 0};
206+
miniMax.setScores(zeroScores);
207+
208+
int result = miniMax.miniMax(0, true, 0, false);
209+
assertEquals(0, result);
210+
}
211+
212+
@Test
213+
void testEdgeCaseWithNegativeScores() {
214+
int[] negativeScores = {-5, -2, -8, -1};
215+
miniMax.setScores(negativeScores);
216+
217+
// Tree evaluation with maximizer first:
218+
// Level 1 (minimizer): min(-5,-2) = -5, min(-8,-1) = -8
219+
// Level 0 (maximizer): max(-5, -8) = -5
220+
int result = miniMax.miniMax(0, true, 0, false);
221+
assertEquals(-5, result);
222+
}
223+
224+
void tearDown() {
225+
System.setOut(originalOut);
226+
}
227+
228+
@Test
229+
void testSetScoresWithNegativeLength() {
230+
// This test ensures the first condition of isPowerOfTwo (n > 0) is tested
231+
// Although we can't directly create an array with negative length,
232+
// we can test edge cases around zero and ensure proper validation
233+
234+
// Test with array length 0 (edge case for n > 0 condition)
235+
int[] emptyArray = new int[0];
236+
outputStream.reset();
237+
miniMax.setScores(emptyArray);
238+
239+
String output = outputStream.toString();
240+
assertTrue(output.contains("The number of scores must be a power of 2."));
241+
assertEquals(8, miniMax.getScores().length); // Should remain unchanged
242+
}
243+
244+
@Test
245+
void testSetScoresWithLargePowerOfTwo() {
246+
// Test with a large power of 2 to ensure the algorithm works correctly
247+
int[] largeValidScores = new int[32]; // 32 = 2^5
248+
for (int i = 0; i < largeValidScores.length; i++) {
249+
largeValidScores[i] = i + 1;
250+
}
251+
252+
miniMax.setScores(largeValidScores);
253+
assertArrayEquals(largeValidScores, miniMax.getScores());
254+
assertEquals(5, miniMax.getHeight()); // log2(32) = 5
255+
}
256+
257+
@Test
258+
void testSetScoresValidEdgeCases() {
259+
// Test valid powers of 2 to ensure isPowerOfTwo returns true correctly
260+
int[][] validPowersOf2 = {
261+
new int[1], // 1 = 2^0
262+
new int[2], // 2 = 2^1
263+
new int[4], // 4 = 2^2
264+
new int[8], // 8 = 2^3
265+
new int[16], // 16 = 2^4
266+
new int[64] // 64 = 2^6
267+
};
268+
269+
int[] expectedHeights = {0, 1, 2, 3, 4, 6};
270+
271+
for (int i = 0; i < validPowersOf2.length; i++) {
272+
miniMax.setScores(validPowersOf2[i]);
273+
assertEquals(validPowersOf2[i].length, miniMax.getScores().length, "Failed for array length: " + validPowersOf2[i].length);
274+
assertEquals(expectedHeights[i], miniMax.getHeight(), "Height calculation failed for array length: " + validPowersOf2[i].length);
275+
}
276+
}
277+
}

0 commit comments

Comments
 (0)