diff --git a/src/main/java/com/thealgorithms/puzzlesandgames/TowerOfHanoi.java b/src/main/java/com/thealgorithms/puzzlesandgames/TowerOfHanoi.java
index 72e9a14ac070..d94bef69cd3a 100644
--- a/src/main/java/com/thealgorithms/puzzlesandgames/TowerOfHanoi.java
+++ b/src/main/java/com/thealgorithms/puzzlesandgames/TowerOfHanoi.java
@@ -3,27 +3,32 @@
import java.util.List;
/**
- * The {@code TowerOfHanoi} class provides a recursive solution to the Tower of Hanoi puzzle.
- * This puzzle involves moving a set of discs from one pole to another, following specific rules:
+ * Recursive solution to the Tower of Hanoi puzzle.
+ *
+ *
+ * The puzzle rules are:
* 1. Only one disc can be moved at a time.
* 2. A disc can only be placed on top of a larger disc.
* 3. All discs must start on one pole and end on another.
+ *
*
- * This implementation recursively calculates the steps required to solve the puzzle and stores them
- * in a provided list.
+ *
+ * The recursion follows three steps:
+ * 1. Move {@code n-1} discs from start to intermediate.
+ * 2. Move the largest disc from start to end.
+ * 3. Move {@code n-1} discs from intermediate to end.
+ *
*
*
- * For more information about the Tower of Hanoi, see
- * Tower of Hanoi on Wikipedia.
+ * Time Complexity: O(2^n) - exponential due to recursive expansion.
+ * Space Complexity: O(n) - recursion stack depth.
*
*
- * The {@code shift} method takes the number of discs and the names of the poles,
- * and appends the steps required to solve the puzzle to the provided list.
- * Time Complexity: O(2^n) - Exponential time complexity due to the recursive nature of the problem.
- * Space Complexity: O(n) - Linear space complexity due to the recursion stack.
- * Wikipedia: https://en.wikipedia.org/wiki/Tower_of_Hanoi
+ *
+ * See Tower of Hanoi on Wikipedia.
+ *
*/
-final class TowerOfHanoi {
+public final class TowerOfHanoi {
private TowerOfHanoi() {
}
@@ -36,6 +41,7 @@ private TowerOfHanoi() {
* @param intermediatePole The name of the intermediate pole used as a temporary holding area.
* @param endPole The name of the end pole to which discs are moved.
* @param result A list to store the steps required to solve the puzzle.
+ * @throws IllegalArgumentException if {@code n} is negative.
*
*
* This method is called recursively to move n-1 discs
@@ -51,15 +57,20 @@ private TowerOfHanoi() {
*
*/
public static void shift(int n, String startPole, String intermediatePole, String endPole, List result) {
- if (n != 0) {
- // Move n-1 discs from startPole to intermediatePole
- shift(n - 1, startPole, endPole, intermediatePole, result);
+ if (n < 0) {
+ throw new IllegalArgumentException("Number of discs must be non-negative");
+ }
+ if (n == 0) {
+ return;
+ }
- // Add the move of the nth disc from startPole to endPole
- result.add(String.format("Move %d from %s to %s", n, startPole, endPole));
+ // Move n-1 discs from startPole to intermediatePole
+ shift(n - 1, startPole, endPole, intermediatePole, result);
- // Move the n-1 discs from intermediatePole to endPole
- shift(n - 1, intermediatePole, startPole, endPole, result);
- }
+ // Add the move of the nth disc from startPole to endPole
+ result.add(String.format("Move %d from %s to %s", n, startPole, endPole));
+
+ // Move the n-1 discs from intermediatePole to endPole
+ shift(n - 1, intermediatePole, startPole, endPole, result);
}
}
diff --git a/src/test/java/com/thealgorithms/puzzlesandgames/TowerOfHanoiTest.java b/src/test/java/com/thealgorithms/puzzlesandgames/TowerOfHanoiTest.java
index 42669eb03bb4..f0a2686d3e4b 100644
--- a/src/test/java/com/thealgorithms/puzzlesandgames/TowerOfHanoiTest.java
+++ b/src/test/java/com/thealgorithms/puzzlesandgames/TowerOfHanoiTest.java
@@ -1,14 +1,31 @@
package com.thealgorithms.puzzlesandgames;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.ArrayList;
import java.util.List;
+import java.util.stream.Stream;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
public class TowerOfHanoiTest {
+ @ParameterizedTest
+ @MethodSource("diskCountAndMoveCount")
+ void testMoveCountMatchesFormula(int disks, int expectedMoves) {
+ List result = new ArrayList<>();
+ TowerOfHanoi.shift(disks, "A", "B", "C", result);
+ assertEquals(expectedMoves, result.size());
+ }
+
+ private static Stream diskCountAndMoveCount() {
+ return Stream.of(Arguments.of(1, 1), Arguments.of(2, 3), Arguments.of(3, 7), Arguments.of(4, 15), Arguments.of(5, 31), Arguments.of(10, 1023));
+ }
+
@Test
public void testHanoiWithOneDisc() {
List result = new ArrayList<>();
@@ -39,6 +56,15 @@ public void testHanoiWithThreeDiscs() {
assertEquals(expected, result);
}
+ @Test
+ public void testHanoiWithDifferentPoles() {
+ List result = new ArrayList<>();
+ TowerOfHanoi.shift(2, "X", "Y", "Z", result);
+
+ List expected = List.of("Move 1 from X to Y", "Move 2 from X to Z", "Move 1 from Y to Z");
+ assertEquals(expected, result);
+ }
+
@Test
public void testHanoiWithZeroDiscs() {
List result = new ArrayList<>();
@@ -47,4 +73,10 @@ public void testHanoiWithZeroDiscs() {
// There should be no moves if there are 0 discs
assertTrue(result.isEmpty());
}
+
+ @Test
+ public void testHanoiWithNegativeDiscsThrows() {
+ List result = new ArrayList<>();
+ assertThrows(IllegalArgumentException.class, () -> TowerOfHanoi.shift(-1, "Pole1", "Pole2", "Pole3", result));
+ }
}