diff --git a/src/main/java/com/thealgorithms/recursion/TowerOfHanoi.java b/src/main/java/com/thealgorithms/recursion/TowerOfHanoi.java new file mode 100644 index 000000000000..45471843e998 --- /dev/null +++ b/src/main/java/com/thealgorithms/recursion/TowerOfHanoi.java @@ -0,0 +1,64 @@ +package com.thealgorithms.recursion; + +import java.util.ArrayList; +import java.util.List; + +/** + * TowerOfHanoi - Solves the classic Tower of Hanoi puzzle + * + * This algorithm uses recursion to move a stack of disks from a source rod to a + * destination rod, following the rules: + * 1. Only one disk can be moved at a time. + * 2. Each move consists of taking the upper disk from one of the stacks and + * placing it on top of another stack. + * 3. No disk may be placed on top of a smaller disk. + * + * Example: If n = 3, Source = 'A', Destination = 'C', Auxiliary = 'B' + * Resulting moves will guide disks from A to C using B. + * + * @author justanothercoder-hub + * @see Tower of Hanoi + */ +public final class TowerOfHanoi { + + private TowerOfHanoi() { + // Utility class + } + + /** + * Solves the Tower of Hanoi puzzle and returns the list of moves + * + * @param n number of disks + * @param source the source rod + * @param destination the destination rod + * @param auxiliary the auxiliary rod + * @return list of moves as strings + */ + public static List solveTowerOfHanoi(int n, char source, char destination, char auxiliary) { + List moves = new ArrayList<>(); + if (n < 0) { + throw new IllegalArgumentException("Number of disks cannot be negative"); + } + moveDisks(n, source, destination, auxiliary, moves); + return moves; + } + + /** + * Recursive helper method to move disks + * + * @param n number of disks + * @param source the source rod + * @param destination the destination rod + * @param auxiliary the auxiliary rod + * @param moves list to record the moves + */ + private static void moveDisks(int n, char source, char destination, char auxiliary, List moves) { + if (n == 1) { + moves.add("Move disk 1 from rod " + source + " to rod " + destination); + return; + } + moveDisks(n - 1, source, auxiliary, destination, moves); + moves.add("Move disk " + n + " from rod " + source + " to rod " + destination); + moveDisks(n - 1, auxiliary, destination, source, moves); + } +} diff --git a/src/test/java/com/thealgorithms/recursion/TowerOfHanoiTest.java b/src/test/java/com/thealgorithms/recursion/TowerOfHanoiTest.java new file mode 100644 index 000000000000..a82e844ed917 --- /dev/null +++ b/src/test/java/com/thealgorithms/recursion/TowerOfHanoiTest.java @@ -0,0 +1,39 @@ +package com.thealgorithms.recursion; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.util.Arrays; +import java.util.List; +import org.junit.jupiter.api.Test; + +public class TowerOfHanoiTest { + + @Test + public void testBaseCase() { + List result = TowerOfHanoi.solveTowerOfHanoi(1, 'A', 'C', 'B'); + assertEquals(1, result.size(), "Should have exactly 1 move for 1 disk"); + assertEquals("Move disk 1 from rod A to rod C", result.get(0)); + } + + @Test + public void testSmallRecursion() { + List result = TowerOfHanoi.solveTowerOfHanoi(2, 'A', 'C', 'B'); + assertEquals(3, result.size()); + List expected = Arrays.asList("Move disk 1 from rod A to rod B", "Move disk 2 from rod A to rod C", "Move disk 1 from rod B to rod C"); + assertEquals(expected, result, "Sequence of moves for 2 disks is incorrect"); + } + + @Test + public void testStandardCase() { + List result = TowerOfHanoi.solveTowerOfHanoi(3, 'A', 'C', 'B'); + assertEquals(7, result.size()); + assertEquals("Move disk 1 from rod A to rod C", result.get(0)); + assertEquals("Move disk 1 from rod A to rod C", result.get(6)); + } + + @Test + public void testNegativeInput() { + assertThrows(IllegalArgumentException.class, () -> { TowerOfHanoi.solveTowerOfHanoi(-5, 'A', 'C', 'B'); }, "Should throw exception for negative disks"); + } +}