2016-04-02 25 views
1

上哈斯克爾研究一些「自我施加的功課」的一部分,我做了漢諾塔的經典解決方案:轉化漢諾塔運動順序爲配置順序

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意義GET運動假設磁盤0.. n - 1的asequence是在PEG from,我們需要將它們移動到掛to。)

這給運動的序列,例如

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

然後我想看看是否可以將輸出轉換爲一組配置(即最初,所有環都位於左側掛鉤上,然後存在中間配置,最後所有環都位於右側掛鉤上)。然後我可以使用scanl通過編寫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 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」的寫法?

+0

發現能否請您記錄您的功能? 'n'究竟是什麼?究竟是「使用」?你在哪裏找到這個算法? – dfeuer

+0

@dfeuer對不起,我添加了一個解釋。如果有其他問題,請LMK不清楚。謝謝! –

+0

請注意,'using'不必被指定爲參數;它完全由'3 - (from + to)'指定。 – chepner

回答

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返回輸出釘住i假設它包含的元素es,其指數爲i,該運動是從fromto,和元素new_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]]]