hanoi :: Log -> Log
hanoi ((('o',0),i,d),s) = ((('o',0),('i',0),('d',0)), [])
hanoi ((('o',1),i,d),s) = moveLOD((('o',1),i,d),s)
hanoi ((('o',n),i,d),s)= hanoi(swapLOI(hanoi(swapLOI(swapLID(moveLOD(swapLID((('o',n),i,d),s)))))))
只为参数定义函数,其中Char
在第一个Pin
of the Plate
is 'o'
,您还需要提供当角色是其他角色时的方程。
当接收到的参数与任何有定义方程的模式不匹配时,就会出现“非穷举模式”错误。解决这个问题的唯一方法是提供其余模式的方程。
在您修改后的代码中,首先,您对原始引脚为空的情况的处理不正确,
hanoi (((o,0),i,d),s) = ((('o',0),('i',0),('d',0)),[])
意味着无论何时应用这种情况,结果都是相同的d
and i
是。什么时候hanoi
被调用自chamahanoi
当参数大于 2 时,有时原点会变空,并且由于在调用链之上只有hanoi
and swapLOI
,那个恒定的结果就会冒出来。您会得到正确的结果n == 2
(n == 1
直接由第二个方程求解),因为递归调用hanoi
那么两者的原极上都只有一个圆盘。
这种情况应该是
hanoi (((o,0),i,d),s) = (((o,0),i,d),s)
这仍然不会产生正确的结果(错误的移动顺序),因为一般情况下的递归是错误的。
You
- 将顶部圆盘移至中间销(
swapLID . moveLOD . swapLID
);
- 然后将剩余的磁盘移动到目的地(
hanoi
),但这是不允许的,因为最小的圆盘位于中间销上,因此不能将其他圆盘放置在那里;
- 最后,使用(现在为空)原点销作为中间,将磁盘从中间销移动到目的地。
你应该
- move
n-1
从原点到中间销的圆盘,
- 然后将底部(最大)的磁盘移动到目的地,
- 最后,移动
n-1
从中间到目的地的磁盘。
如果没有额外的参数来跟踪要移动的磁盘数量,我看不出有什么简单的方法可以做到这一点。考虑一个四盘游戏。首先,将顶部的三个圆盘移动到中间销,然后将底部的圆盘移动到目标销。现在的任务是使用原始销作为辅助,将三个圆盘从中间销移动到目标销。
正确的做法是顺序
-
i -> d
(([],[1,2,3],[4]) -> ([],[2,3],[1,4])
)
-
i -> o
(([],[2,3],[1,4]) -> ([2],[3],[1,4])
)
-
d -> o
(([2],[3],[1,4]) -> ([1,2],[3],[4])
)
-
i -> d
(([1,2],[3],[4]) -> ([1,2],[],[3,4])
)
-
o -> i
(([1,2],[],[3,4]) -> ([2],[1],[3,4])
)
-
o -> d
(([2],[1],[3,4]) -> ([],[1],[2,3,4])
)
-
i -> d
(([],[1],[2,3,4]) -> ([],[],[1,2,3,4])
)
在第 2 步之后,原始目标引脚将成为磁盘(好吧,一个)要移动到的引脚o
,但在这种情况下,最低的不得移动。如果唯一的信息是每个引脚上有多少个磁盘以及磁盘应从何处移动到何处,那么如何实现这一点呢?
如果你改变类型hanoi
to
hanoi :: Int -> Log -> Log
并称之为
chamahanoi n = hanoi n ((('o',n),('i',0),('d',0)),[])
它很容易实现。
如果您不想这样做,或者不允许这样做,您可以跟踪每个引脚上的大小,并且仅将磁盘移动到较大的引脚上,或者您可以偷偷地在适当的引脚处删除并添加磁盘以进行模拟这种限制,但如果没有适当的解释,就很难将其与作弊区分开来。