After reverse printing a string recursively in our previous article, it is time to dive into more fascinating procedural recursion problems. And when talking about procedural recursion, how can one not talk about the famous “Tower of Brahma”, also referred as “Tower of Hanoi”. The puzzle comes from a story.
In the Kashi Vishwanath temple in India, there is a large room. It has three diamond poles, surrounded by 64 golden disks of decreasing radius from bottom to top. As the legend goes, when the Universe was created by Brahma, he created these disks and placed them all on one of the three poles in decreasing size from bottom to top. He then assigned the temple priests with the task of moving these disks from one pole to another, in accordance with the immutable rules of Brahma, since that time. The last move of the task which would move all the 64 disks to one of the other three poles would herald the end of the Universe. The rules to be followed are:
- Only one disk should be moved at a time.
- No bigger disk can be placed on a smaller disk.
In computation and logic, this puzzle is generalised to have n disks, and is referred to as “Tower of Hanoi”. For more technical information on the same, visit its Wiki Page.
Here is how to derive the recursive logic for the same. As discussed in the previous article, the first step is to have a very clear and precise statement of the procedure to be recursed. Puzzle Statement: Implement a procedure to move n disks from pole A to pole B, using an intermediate pole C, following the above two rules.
Now, the trick to derive the recursive relation logic is to assume the procedure to be already existing for a lower order, and then use it to achieve implementing the original higher order procedure. So here, assume the existence of the following: A procedure to move (n – 1) disks from pole X to pole Y, using an intermediate pole Z, following the above two rules. Again, note the similarity between this statement and the actual puzzle statement. And now use this to implement the original procedure. In original procedure, there are n disks, but a procedure is available only for (n – 1) disks. So, it can be visualised to be solved by breaking into the following steps:
- (First) Move the (top) (n – 1) disks from pole A to (the intermediate) pole C, using pole B as an intermediate pole, following the above two rules. (using the assumed available procedure)
- (Second) Move the largest single disk left on pole A to pole B.
- (Last) Move the (n – 1) disks from (the intermediate) pole C to pole B, using pole A as an intermediate pole, following the above two rules. (using the assumed available procedure)
Good. Now the terminating condition. That is again simple. If there is only one disk. Or, even simpler, when there is no disk, do nothing.
Here’s the summary of the above discussion:
tob(n, A, B, C) { if (n == 0) { do_nothing; } else { tob(n - 1, A, C, B); move(A, B); // move 1 disk from A to B tob(n - 1, C, B, A); } }
That’s all? Such an involved puzzle. Such a simple solution. Unbelievable, right? But that’s the beauty of recursion. Seemingly complex problems, and why seemingly? Real complex problems can be solved with elegant simplicity using recursion. That’s why it is the king of all kinds of logic – closest to the way our brain operates.
For implementing & checking the above logic, one may implement the move(X, Y) procedure with the corresponding programming language constructs / functions, and try it out. A simplest implementation of the same could be just printing the step, as follows:
move(A, B) { print("Move 1 disk from ", A, " to ", B, ".\n"); }
One may implement it in more hi-fi ways using graphics and what not, but the gist is the same – that the overall recursion logic remains the same.
Getting hooked into the world of elegant recursion? Keep reading as more secrets are unfolded.