将河内运动序列转换为配置序列

时间:2016-04-02 18:29:40

标签: haskell towers-of-hanoi

作为一些"自我强加的家庭作业的一部分"在Haskell研究中,我做了河内塔的经典解决方案:

doHanoi :: Int -> Int -> Int -> [(Int, Int)]
doHanoi 0 _ _ = []
doHanoi n from to = first ++ [(from, to)] ++ last 
    where
        using = 3 - from - to;
        first = doHanoi (n - 1) from using; 
        last = doHanoi (n - 1) using to

(假设磁盘doHanoi n from to using处于挂钩0.. n - 1from的含义得到了运动的后果,我们需要将它们移到挂钩to。)

这给出了一系列动作,例如,

>>> doHanoi 3 0 2
[(0,2),(0,1),(2,1),(0,2),(1,0),(1,2),(0,2)]

然后我想看看我是否可以将输出转换为配置集(即,最初,所有环都在左侧挂钩上,然后是中间配置,最后所有环都在右侧挂钩上)。我可以通过编写changeConfig函数

来完成此操作
changeConfig :: [[Int]] -> (Int, Int) -> [[Int]]
changeConfig [e0:e0s, e1s, e2s] (0, 1) = [e0s, e0:e1s, e2s]
changeConfig [e0:e0s, e1s, e2s] (0, 2) = [e0s, e1s, e0:e2s]
changeConfig [e0s, e1:e1s, e2s] (1, 0) = [e1:e0s, e1s, e2s]
changeConfig [e0s, e1:e1s, e2s] (1, 2) = [e0s, e1s, e1:e2s]
changeConfig [e0s, e1s, e2:e2s] (2, 0) = [e2:e0s, e1s, e2s]
changeConfig [e0s, e1s, e2:e2s] (2, 1) = [e0s, e2:e1s, e2s]

然后使用scanl

>>> scanl changeConfig [[0.. 2], [], []] (doHanoi 3 0 2 1)
[[[0,1,2],[],[]],[[1,2],[],[0]],[[2],[1],[0]],[[2],[0,1],[]],[[],[0,1],[2]],[[0],[1],[2]],[[0],[],[1,2]],[[],[],[0,1,2]]]

虽然这有效,但我认为我在changeConfig中遗漏了一些内容:这只是对所有配置的详尽列举,在具有某种形式的循环对称的设置中,恰好有效,因为那里是三个钉子,并且不会很好地扩展(就LOC而言)。什么是" Haskellic"写它的方式?

1 个答案:

答案 0 :(得分:1)

感谢chepner和jberryman的亲切帮助,这就是我想出来的。

找到动作的功能没有改变:

doHanoi :: Int -> Int -> Int -> [(Int, Int)]
doHanoi 0 _ _ = []
doHanoi n from to = first ++ [(from, to)] ++ last 
    where
        using = 3 - from - to;
        first = doHanoi (n - 1) from using; 
        last = doHanoi (n - 1) using to

现在是辅助函数,changePeg es i from to new_e将输出返回到peg i,假设它包含元素es,其索引为i,移动来自from } tonew_e元素。

changePeg :: [Int] -> Int -> Int -> Int -> Int -> [Int]
changePeg es i from to new_e
    | i == from = tail es
    | i == to = new_e: es
    | otherwise = es

使用此功能,changeConfig变为

changeConfig :: [[Int]] -> (Int, Int) -> [[Int]]
changeConfig es (from, to) = new_es where
    new_e = head $ es !! from;
    new_es = [changePeg (es !! i) i from to new_e | i <- [0.. 2]]

和以前一样,解决方案可以找到

>>> scanl changeConfig [[0.. 2], [], []] (doHanoi 3 0 2)
[[[0,1,2],[],[]],[[1,2],[],[0]],[[2],[1],[0]],[[2],[0,1],[]],[[],[0,1],[2]],[[0],[1],[2]],[[0],[],[1,2]],[[],[],[0,1,2]]]