Imperial College of Science, Technology and Medicine, London
Department of Computing, Faculty of Engineering

A mathematical approach to iterative Hanoi

The Hanoi-puzzle contains lots of hidden maths and mathematical formulae that we can figure out. Throughout this article we will only consider 3Peg Hanoi.

Let us consider the moves using two disks first. These are:
[(1,2), (1,3), (2,3)]

The list contains three moves of the form (from,to). If we replace these tuples by the differences of to and from, we get:
[1, 2, 1]

There is an obvious symmetrie which we need to consider further using additional disks. The moves of 3 disks are:
[(1,3), (1,2), (3,2), (1,3), (2,1), (2,3), (1,3)]
Applying the difference-mapping we get
[2, 1, -1, 2, -1, 1, 2]

There is a symmetrie again and there seems to be some system behind it. It is indeed hard to see, but let us imagine the pegs not to be in a linear order, but in a triangle.

    B

A       C

For 2 disks:
Disk 1 moves clockwise 1 step (from A to B).
Disk 2 moves clockwise 2 steps (from A to C).
Disk 1 moves clockwise 1 step (from B to C).

The second line can be rewritten as "Disk 2 moves clockwise -1 step" or "Disk 2 moves anticlockwise 1 step". This leads to the following difference-list for 2 Disks:
[1, -1, 1]

Similar for 4 disks:
[-1, 1, -1, -1, -1, 1, -1]

These are the directions, if we now consider the disks being moved, we get a list like the following. Disk 1 is the top-most disk, resp. 3 the one at the bottom. [ 1, 2, 1, 3, 1, 2, 1]

We can derive

Rule 1:

With an odd number of disks, the top-most disk moves clockwise, the second anticlockwise, the third clockwise and so on. With an even number of disks, they all move in the opposite direction. In other words:
Let n = number of disks and i = disk being moved, then i moves anti-clockwise iff and only if odd(n)=odd(i)




There is something obvious about the list that contains the disk being moved. The lists for 2, 3 and 4 disks are:
[1, 2, 1]
[1, 2, 1, 3, 1, 2, 1]
[1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1]

The first thing you think is probably, "this looks like a flattened binary tree in in-order representation". If you think that, you are right.

      3
  2       2
1   1   1   1

If you don't believe me, feel free to write it on paper, connect the nodes and draw a nice tree. As this tree is perfectly balanced and completely filled, we can calculate the size of the tree.

Rule 2:

The number of moves for n disks equals 2^n -1.



Knowing the size of the tree and therefore the total number of moves, we should consider again when a disk is being moved.
If we take the 4-disk tree similar to that one above and replace the disk-numbers by move-numbers, the rows giving us the information which disk is being moved (top-most row for bottom most disk), then the tree would look like that:

              8
      4                 12
  2       6       10          14
1   3   5   7   9    11    13    15

Now lets convert that into binary:

                        1000
          100                            1100
   10            110             1010            1110
1     11     101    111      1001    1011    1101    1101

There are obvious patterns: The last digit of all numbers in the bottom-most row is a 1, in the rows above it's 10, 100 or 1000 respectively. If you pick any number in the tree, count how often you need to divide it by 2 until it gets odd and add 1, this will tell you which disk is being moved in that step. You can also count the zero bits at the end of each number, to get the same information.

Rule 3:

Let n>0 and i be the ith step in Hanoi, and let 2n be a factor of i such that n is minimal, then n+1 is the disk being moved. Note: The number of disks may be unknown.




An example function that gives out any step of Hanoi with given pegs. Running it in a loop from 1 to 2n-1 gives you a complete iterative Hanoi! Pascal is said to be one of the most easy-to-read programming languages. If you don't know it, don't worry and just have a go. Shl x means shift-left by x digits (in binary) and is just a quicker way to multiply a number by a power of 2.

function PrintStep(Step, TotalDisks: integer): string;
var disk, MoveNo: integer;
    fromPeg, toPeg: char;
begin 
  disk := 0;
  while (step mod (1 shl disk) = 0) do
    inc(disk);
  MoveNo := Step div trunc(power(2, disk));
  if odd(TotalDisks) xor odd(disk) then begin
    fromPeg := chr(MoveNo mod 3 + 65);
    toPeg := chr((MoveNo + 1) mod 3 + 65);
  end 
  else begin
    fromPeg := chr((MoveNo shl 1) mod 3 + 65);
    toPeg := chr(((MoveNo shl 1) + 2) mod 3 + 65);
  end;
  result := Format('Move disk %d from peg %s to peg %s', [disk, fromPeg, toPeg]);
end;

Nicolai Stawinoga
(c) 2006