2009-08-05 69 views
3

所以我工作的一個極小實現了跳棋類遊戲,以幫助自己學習哈斯克爾更好。我遇到的功能需要列出遊戲狀態列表,並生成直接後繼遊戲狀態列表。就像跳棋一樣,如果有跳轉,球員必須拿下。如果有多個玩家可以選擇。簡化一些Haskell代碼

在大多數情況下,這個工程很好地與列表單子:遍歷所有輸入的遊戲狀態,遍歷可能再漲所有彈珠,環比那個大理石的所有跳躍。這個monad列表很好地將所有列表展平成最後的狀態列表。

訣竅是,如果沒有找到給定遊戲狀態的跳轉,我需要返回當前的遊戲狀態,而不是空的列表。下面的代碼是我想到的最好的方式,但對我來說似乎非常難看。有關如何清理它的任何建議?

eHex :: Coord -> Coord -- Returns the coordinates immediately to the east on the board 
nwHex :: Coord -> Coord -- Returns the coordinates immediately to the northwest on the board 

generateJumpsIter :: [ZertzState] -> [ZertzState] 
generateJumpsIter states = do 
    ws <- states 
    case children ws of 
     [] -> return ws 
     [email protected]_ -> n 
    where 
    children [email protected](ZertzState s1 s2 b p) = do 
     (c, color) <- occupiedCoords ws 
     (start, end) <- [(eHex, wHex), (wHex, eHex), (swHex, neHex), 
         (neHex, swHex), (nwHex, seHex), (seHex, nwHex)] 
     if (hexOccupied b $ start c) && (hexOpen b $ end c) 
     then case p of 
      1 -> return $ ZertzState (scoreMarble s1 color) s2 
            (jumpMarble (start c) c (end c) b) p 
      (-1) -> return $ ZertzState s1 (scoreMarble s2 color) 
             (jumpMarble (start c) c (end c) b) p 
     else [] 

編輯:提供* Hex函數的示例類型簽名。

回答

3

訣竅是,如果沒有發現給定遊戲狀態的跳轉,我需要返回當前的遊戲狀態,而不是空的列表。

爲什麼?我已經寫了好幾次了,我無法想象這種功能的用途。你會不會與類型的函數

nextStates :: [ZertzState] -> [Maybe [ZertzState]] 

nextStates :: [ZertzState] -> [[ZertzState]] 

然而更好,如果你真的想返回「無論未來國家的名單,或者如果該列表是空的,原始狀態「,那麼你想要的類型是

nextStates :: [ZertzState] -> [Either ZertzState [ZertzState]] 

然後你可以很容易地扁平化。

至於如何實施,我建議定義類型

[ZertzState] -> [(ZertzState, [ZertzState])] 

的一個輔助功能,比你可以映射

(\(start, succs) -> if null succs then Left start else Right succs) 

過的結果,再加上其他各種東西。

弗雷德布魯克斯說(解釋),一旦你得到的類型正確,代碼實際上寫自己。

1

不要濫用單子記法列表中,它是沒有這麼重。此外,你可以以同樣的方式使用列表理解:

do x <- [1..3] 
    y <- [2..5]  <=> [ x + y | x <- [1..3], y <- [2..5] ] 
    return x + y 

現在的「簡化」

listOfHex :: [(Coord -> Coord,Coord -> Coord)] 
listOfHex = [ (eHex, wHex), (wHex, eHex), (swHex, neHex) 
      , (neHex, swHex), (nwHex, seHex), (seHex, nwHex)] 

generateJumpsIter :: [ZertzState] -> [ZertzState] 
generateJumpsIter states = 
    [if null ws then ws else children ws | ws <- states] 
    where -- I named it foo because I don t know what it do.... 
    foo True 1 = ZertzState (scoreMarble s1 color) s2 
           (jumpMarble (start c) c (end c) b) p 
    foo True (-1) = ZertzState s1 (scoreMarble s2 color) 
           (jumpMarble (start c) c (end c) b) p 
    foo False _ = [] 
    foo _ _ = error "Bleh" 

    children [email protected](ZertzState s1 s2 b p) = 
     [ foo (valid c hex) p | (c, _) <- occupiedCoords ws, hex <- listOfHex ] 
     where valid c (start, end) = 
       (hexOccupied b $ start c) && (hexOpen b $ end c) 

在列表commprehension的讓我們在頂部的讓利打擾我了一點,但我沒有所有的代碼,我真的不知道如何以其他方式做到這一點。如果你可以更深入地修改,我建議你使用更多的組合器(map,foldr,foldl'等),因爲它們真的減少了我的經驗中的代碼大小。

注意,代碼沒有測試,並且可以不進行編譯。

+0

不能第一個列表理解只是[如果null(兒童ws)然後其他孩子ws | ws < - states]?我希望編譯器可以消除重複的函數調用。 – 2009-08-05 12:52:20

+0

是的,編輯的代碼遵循您的評論 – 2009-08-05 14:47:08