2013-05-16 34 views
15

這是我第一次嘗試使用(我所理解的)動態編程。我試圖解決這個有趣的問題:A* Admissible Heuristic for die rolling on gridHaskell的動態編程備忘錄

q函數試圖向後遞歸,保持壓模的定向的軌道(visited在技術上是下一個單元格,但在遞歸的條款,以防止「訪問」無限的來回循環)。儘管我不確定它提供的答案是否是最好的解決方案,但它似乎確實提供了答案。

我希望有關如何實現某種記憶化的加快它的想法 - 我沒能成功實現與lookup代替!!memoized_fib(看到here),映射到q組合列表(i,j),但得到Nothing,沒有雙關意圖。

Haskell代碼:

import Data.List (minimumBy) 
import Data.Ord (comparing) 

fst3 (a,b,c) = a 

rollDie [email protected][left,right,top,bottom,front,back] move 
    | move == "U" = [left,right,front,back,bottom,top] 
    | move == "D" = [left,right,back,front,top,bottom] 
    | move == "L" = [top,bottom,right,left,front,back] 
    | move == "R" = [bottom,top,left,right,front,back] 

dieTop die = die!!2 

leftBorder = max 0 (min startColumn endColumn - 1) 
rightBorder = min columns (max startColumn endColumn + 1) 
topBorder = endRow 
bottomBorder = startRow 

infinity = 6*rows*columns 

rows = 10 
columns = 10 

startRow = 1 
startColumn = 1 

endRow = 6 
endColumn = 6 

dieStartingOrientation = [4,3,1,6,2,5] --left,right,top,bottom,front,back 

q i j visited 
    | i < bottomBorder || i > topBorder 
    || j < leftBorder || j > rightBorder = (infinity,[1..6],[]) 
    | i == startRow && j == startColumn = (dieTop dieStartingOrientation,dieStartingOrientation,[]) 
    | otherwise       = (pathCost + dieTop newDieState,newDieState,move:moves) 
     where previous 
       | visited == (i, j-1) = zip [q i (j+1) (i,j),q (i-1) j (i,j)] ["L","U"] 
       | visited == (i, j+1) = zip [q i (j-1) (i,j),q (i-1) j (i,j)] ["R","U"] 
       | otherwise   = zip [q i (j-1) (i,j),q i (j+1) (i,j),q (i-1) j (i,j)] ["R","L","U"] 
      ((pathCost,dieState,moves),move) = minimumBy (comparing (fst3 . fst)) previous 
      newDieState = rollDie dieState move 

main = putStrLn (show $ q endRow endColumn (endRow,endColumn)) 
+1

我認爲,如果你發佈你的嘗試,沒有工作,這將有助於。 – svick

+0

前段時間,我花費了很多時間來對付Haskell的記憶問題。我不記得細節,但最終我成功了(我認爲它可能有其他問題,例如空間泄漏),方法是定義一個數組實例,以便任何給定索引的值都根據其他數組元素進行計算。懶惰評估似乎迫使所有的數組元素按照正確的順序「填充」,這看起來有點神奇(儘管我比欣慰更放心)。 IOW數據結構「領先」,功能「跟隨」。 –

+0

@j_random_hacker請檢查應用的骰子算法 - 300x300在2.13秒內沒有表和總和比保羅的A *小,酷或什麼? http://stackoverflow.com/questions/16547724/a-admissible-heuristic-for-die-rolling-on-grid/16629766#16629766 –

回答

15

我去到工具,這種問題是data-memocombinators庫。

要使用它,只需導入Data.MemoCombinators,重命名q到別的這樣的東西作爲q'(但保留遞歸調用,因爲它們是),並定義一個新q這樣的:

q = M.memo3 M.integral M.integral (M.pair M.integral M.integral) q' 
  • memo3爲每個參數提供memoizer,爲三個參數函數創建一個memoizer。
  • integral是一個整型類型的簡單記憶。
  • pair結合了兩個記憶器爲這些類型的記憶對象做記憶。
  • 最後,我們將此備忘錄應用於q'以獲取備忘錄版本。

就是這樣。你的功能現在被記憶。時間來測試它:

> :set +s 
> q endRow endColumn (endRow,endColumn) 
(35,[5,2,4,3,6,1],["R","R","R","R","R","U","U","U","U","U"]) 
(0.01 secs, 516984 bytes) 

全部下面的代碼:


import Data.List (minimumBy) 
import Data.Ord (comparing) 
import qualified Data.MemoCombinators as M 

fst3 (a,b,c) = a 

rollDie [email protected][left,right,top,bottom,front,back] move 
    | move == "U" = [left,right,front,back,bottom,top] 
    | move == "D" = [left,right,back,front,top,bottom] 
    | move == "L" = [top,bottom,right,left,front,back] 
    | move == "R" = [bottom,top,left,right,front,back] 

dieTop die = die!!2 

leftBorder = max 0 (min startColumn endColumn - 1) 
rightBorder = min columns (max startColumn endColumn + 1) 
topBorder = endRow 
bottomBorder = startRow 

infinity = 6*rows*columns 

rows = 10 
columns = 10 

startRow = 1 
startColumn = 1 

endRow = 6 
endColumn = 6 

dieStartingOrientation = [4,3,1,6,2,5] --left,right,top,bottom,front,back 

q = M.memo3 M.integral M.integral (M.pair M.integral M.integral) q' 
    where 
    q' i j visited 
     | i < bottomBorder || i > topBorder || j < leftBorder || j > rightBorder = (infinity,[1..6],[]) 
     | i == startRow && j == startColumn = (dieTop dieStartingOrientation,dieStartingOrientation,[]) 
     | otherwise       = (pathCost + dieTop newDieState,newDieState,move:moves) 
     where previous 
       | visited == (i, j-1) = zip [q i (j+1) (i,j),q (i-1) j (i,j)] ["L","U"] 
       | visited == (i, j+1) = zip [q i (j-1) (i,j),q (i-1) j (i,j)] ["R","U"] 
       | otherwise   = zip [q i (j-1) (i,j),q i (j+1) (i,j),q (i-1) j (i,j)] ["R","L","U"] 
      ((pathCost,dieState,moves),move) = minimumBy (comparing (fst3 . fst)) previous 
      newDieState = rollDie dieState move 

main = putStrLn (show $ q endRow endColumn (endRow,endColumn)) 
+0

謝謝!我做了這個包的實驗,但不知道如何解釋我的q函數類型爲此目的。 –