I am trying to solve the Towers of Hanoi at compile-time, but I have discovered a problem:
template<int src, int dst>
struct move_disc
{
// member access will print src and dst
};
template<int n, int src, int tmp, int dst>
struct hanoi
{
hanoi<n-1, src, dst, tmp> before;
typename move_disc<src, dst>::lol disc;
hanoi<n-1, tmp, src, dst> after;
};
template<int src, int tmp, int dst>
struct hanoi<0, src, tmp, dst>
{
// recursive base case
};
hanoi<3, 1, 2, 3> go;
Unfortunately, the above meta program only prints six moves instead of seven:
prog.cpp:11:39: error: no type named ‘lol’ in ‘struct move_disc<1, 3>’
prog.cpp:11:39: error: no type named ‘lol’ in ‘struct move_disc<1, 2>’
prog.cpp:11:39: error: no type named ‘lol’ in ‘struct move_disc<3, 2>’
prog.cpp:11:39: error: no type named ‘lol’ in ‘struct move_disc<1, 3>’
prog.cpp:11:39: error: no type named ‘lol’ in ‘struct move_disc<2, 1>’
prog.cpp:11:39: error: no type named ‘lol’ in ‘struct move_disc<2, 3>’
The final move from 1 to 3 is missing. Why is that? Can the problem be solved?
So, if the tower had five discs, the formula would be 2⁵-1, which is 31. Therefore, solving the puzzle would take a minimum of 31 steps. If it had four discs, it would require only 15 steps – and for three discs, only 7. Interestingly, this formula can lead us back to the Tower of Hanoi's supposed mythological roots.
Tower of Hanoi puzzle with n disks can be solved in minimum 2n−1 steps. This presentation shows that a puzzle with 3 disks has taken 23 - 1 = 7 steps.
Tower of Hanoi is a mathematical puzzle where we have three rods (A, B, and C) and N disks. Initially, all the disks are stacked in decreasing value of diameter i.e., the smallest disk is placed on the top and they are on rod A.
I think that's because hanoi<1, 1, 2, 3>
has already been instantiated (giving the first error) and is not instantiated again when later "encountered" during template instantiation.
[Edit: To make it maybe clearer, here's a "graph" of recursive template instantiations (with errors):
hanoi<3, 1, 2, 3>
:
hanoi<2, 1, 3, 2>
:
hanoi<1, 1, 2, 3>
:
hanoi<0, 1, 3, 2>
.move_disc<1, 3>
)hanoi<0, 2, 1, 3>
.move_disc<1, 2>
)hanoi<1, 3, 1, 2>
:
hanoi<0, 3, 2, 1>
.move_disc<3, 2>
)hanoi<0, 1, 3, 2>
.move_disc<1, 3>
)hanoi<2, 2, 1, 3>
:
hanoi<1, 2, 3, 1>
:
hanoi<0, 2, 1, 3>
.move_disc<2, 1>
)hanoi<0, 3, 2, 1>
.move_disc<2, 3>
)hanoi<1, 1, 2, 3>
: already instantiated at 1.1 (move_disc<1, 3>
error not repeated).-- end edit.]
A "fix" I can think of is to make every specialization unique, e.g. by adding an "id" template parameter (and generate unique new values during recursive instantiation):
template<int n, int src, int tmp, int dst, int id>
struct hanoi
{
hanoi<n-1, src, dst, tmp, id*2> before;
typename move_disc<src, dst>::lol disc;
hanoi<n-1, tmp, src, dst, id*2+1> after;
};
template<int src, int tmp, int dst, int id>
struct hanoi<0, src, tmp, dst, id>
{
// recursive base case
};
hanoi<3, 1, 2, 3, 1> go;
Live: http://ideone.com/0lQaXs
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With