Skip to content

Commit c319d4e

Browse files
Added TowerofHanoi and its test file to recursion
1 parent 79cdb98 commit c319d4e

File tree

2 files changed

+150
-0
lines changed

2 files changed

+150
-0
lines changed
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package com.thealgorithms.recursion;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
import java.util.Scanner;
6+
7+
/**
8+
* TowerOfHanoi - Solves the classic Tower of Hanoi puzzle
9+
*
10+
* This algorithm uses recursion to move a stack of disks from a source rod to a
11+
* destination rod, following the rules:
12+
* 1. Only one disk can be moved at a time.
13+
* 2. Each move consists of taking the upper disk from one of the stacks and
14+
* placing it on top of another stack.
15+
* 3. No disk may be placed on top of a smaller disk.
16+
*
17+
* Example: If n = 3, Source = 'A', Destination = 'C', Auxiliary = 'B'
18+
* Resulting moves will guide disks from A to C using B.
19+
*
20+
* @author justanothercoder
21+
* @see <a href="https://en.wikipedia.org/wiki/Tower_of_Hanoi">Tower of Hanoi</a>
22+
*/
23+
public final class TowerofHanoi {
24+
25+
private TowerofHanoi() {
26+
27+
// Utility class
28+
}
29+
30+
/**
31+
* Solves the Tower of Hanoi puzzle and returns the list of moves
32+
*
33+
* @param n number of disks
34+
* @param source the source rod
35+
* @param destination the destination rod
36+
* @param auxiliary the auxiliary rod
37+
* @return list of moves as strings
38+
*/
39+
public static List<String> solveTowerOfHanoi(int n, char source, char destination, char auxiliary) {
40+
List<String> moves = new ArrayList<>();
41+
if(n<0){
42+
throw new IllegalArgumentException("Number of disks cannot be negative");
43+
}
44+
moveDisks(n, source, destination, auxiliary, moves);
45+
return moves;
46+
}
47+
48+
/**
49+
* Recursive helper method to move disks
50+
*
51+
* @param n number of disks
52+
* @param source the source rod
53+
* @param destination the destination rod
54+
* @param auxiliary the auxiliary rod
55+
* @param moves list to record the moves
56+
*/
57+
private static void moveDisks(int n, char source, char destination, char auxiliary, List<String> moves) {
58+
if (n == 1) {
59+
moves.add("Move disk 1 from rod " + source + " to rod " + destination);
60+
return;
61+
}
62+
moveDisks(n - 1, source, auxiliary, destination, moves);
63+
moves.add("Move disk " + n + " from rod " + source + " to rod " + destination);
64+
moveDisks(n - 1, auxiliary, destination, source, moves);
65+
}
66+
67+
public static void main(String[] args){
68+
Scanner scanner = new Scanner(System.in);
69+
System.out.print("Enter the number of disks: ");
70+
int n = scanner.nextInt();
71+
List<String> result = solveTowerOfHanoi(n, 'A', 'C', 'B');
72+
73+
for(String move: result){
74+
System.out.println(move);
75+
}
76+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package com.thealgorithms.recursion;
2+
3+
import org.junit.jupiter.api.Test;
4+
import static org.junit.jupiter.api.Assertions.assertEquals;
5+
import static org.junit.jupiter.api.Assertions.assertThrows;
6+
import java.util.Arrays;
7+
import java.util.List;
8+
9+
public class TowerOfHanoiTest {
10+
11+
/**
12+
* Test Case 1: Base Case (n = 1)
13+
* Requirement: Explicitly requested.
14+
* Logic: With only 1 disk, it should move directly from Source (A) to Destination (C).
15+
*/
16+
@Test
17+
public void testBaseCase() {
18+
List<String> result = TowerOfHanoi.solveTowerOfHanoi(1, 'A', 'C', 'B');
19+
20+
// Assertion 1: Check size (2^1 - 1 = 1 move)
21+
assertEquals(1, result.size(), "Should have exactly 1 move for 1 disk");
22+
23+
// Assertion 2: Verify the exact string
24+
assertEquals("Move disk 1 from rod A to rod C", result.get(0));
25+
}
26+
27+
/**
28+
* Test Case 2: Small Recursion (n = 2)
29+
* Logic: Tests the basic recursive step (Move 1 to Aux, Move 2 to Dest, Move 1 to Dest).
30+
*/
31+
@Test
32+
public void testSmallRecursion() {
33+
List<String> result = TowerOfHanoi.solveTowerOfHanoi(2, 'A', 'C', 'B');
34+
35+
// Assertion 1: Check size (2^2 - 1 = 3 moves)
36+
assertEquals(3, result.size());
37+
38+
// Assertion 2: Verify the exact sequence of moves
39+
List<String> expected = Arrays.asList(
40+
"Move disk 1 from rod A to rod B", // Small disk to Aux
41+
"Move disk 2 from rod A to rod C", // Big disk to Dest
42+
"Move disk 1 from rod B to rod C" // Small disk to Dest
43+
);
44+
45+
assertEquals(expected, result, "Sequence of moves for 2 disks is incorrect");
46+
}
47+
48+
/**
49+
* Test Case 3: Standard Case (n = 3)
50+
* Logic: Verifies a slightly larger recursion to ensure the stack depth works correctly.
51+
*/
52+
@Test
53+
public void testStandardCase() {
54+
List<String> result = TowerOfHanoi.solveTowerOfHanoi(3, 'A', 'C', 'B');
55+
56+
// Assertion 1: Check size (2^3 - 1 = 7 moves)
57+
assertEquals(7, result.size());
58+
59+
// Assertion 2: Verify start and end moves specifically
60+
assertEquals("Move disk 1 from rod A to rod C", result.get(0)); // First move
61+
assertEquals("Move disk 1 from rod A to rod C", result.get(6)); // Last move
62+
}
63+
64+
/**
65+
* Extra Test Case: Negative Input
66+
* Logic: Ensures your "Defensive Programming" check works.
67+
*/
68+
@Test
69+
public void testNegativeInput() {
70+
assertThrows(IllegalArgumentException.class, () -> {
71+
TowerOfHanoi.solveTowerOfHanoi(-5, 'A', 'C', 'B');
72+
}, "Should throw exception for negative disks");
73+
}
74+
}

0 commit comments

Comments
 (0)