I am trying to solve the Hanoi Puzzle, with forbidden moves. I have 3 poles, a left pole, a middle pole and a right pole. On the left pole I have 2 plates (the smallest is on the top and the biggest on the bottom) and want to get them to the right pole. You can just move one plate at a time. But here's the catch: you can't stack a larger on a smaller plate and move a plate from the left pole to the middle pole and from the middle pole to the right pole.
I have the following algorithm:
type HanoiMovement = (Integer , Char , Char)
hanoi :: Integer -> [HanoiMovement]
hanoi n = hanoi_gen 'l' 'r' 'm' n
where
hanoi_gen s z aux 0 = []
hanoi_gen s z aux n = hanoi_gen s aux z (n-1) ++ [(n,s,z)] ++ hanoi_gen aux z s (n-1)
it does generate the solution on how to move the plates, but it ignores the forbidden moves [('l','m'), ('m','r')]. How do I implement them into the algorithm?
Thank you in advance
Well, your current solution to the "standard" Hanoi puzzle takes advantage of the fact that, say, moving 3 discs from left to right using middle (
hanoi 'l' 'r' 'm' 3) can be recursively expressed as moving 2 discs from left to middle using right (hanoi 'l' 'm' 'r' 2), then moving the'3'disc from left to right, and then moving 2 discs from middle to right using left (hanoi 'm' 'r' 'l' 2).In order to implement your modified Hanoi puzzle, you need to modify the recursion to take into account the forbidden moves. Because the forbidden moves break the symmetry of the poles, you won't be able to define a single recursive step that works for all values of
s,z, andaux.Instead, you'll need to work through each of the cases:
To move
ndiscs fromLtoRwithout using the forbidden moves, you should moven-1discs fromLtoM, then move discnfromLtoR, and then moven-1discs fromMtoR, as usual. In other words:However, to move
ndiscs fromLtoMwithout using forbidden moves, you can't use the same pattern, as it would use the forbidden move(n,L,M), instead you need to first moven-1discs fromLtoM, then move discnfromLtoR, which is allowed, then moven-1discs fromMtoL, move discnfromRback toM(also allowed), and finally moven-1discs fromLtoM. As code:If you define similar patterns for all permutations of the poles and use the usual base case. That should give you your solution.
SPOILERS FOLLOW....
.
.
.
.
The remaining patterns are:
If desired, these can be simplified somewhat with a helper, as follows, though it would be hard to see this pattern without writing them all out in detail first:
Full runnable example:
which gives solutions for 2 and 3 discs:
These appear to be correct.