所以我正在为类似跳棋的游戏开发一个minimax实现,以帮助自己更好地学习Haskell。我遇到问题的功能会获取游戏状态列表,并生成即时后续游戏状态列表。像跳棋一样,如果跳跃可用,玩家必须接受它。如果不止一个,玩家可以选择。
在大多数情况下,这适用于列表monad:循环遍历所有输入游戏状态,循环遍历所有可跳跃的弹珠,循环遍历所有大理石的跳跃。这个列表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
n@_ -> n
where
children ws@(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函数提供示例类型签名。
答案 0 :(得分:3)
诀窍是,如果没有找到给定游戏状态的跳转,我需要返回当前游戏状态,而不是空列表。
为什么呢?我已经写了几次minimax,我无法想象这种功能的用途。使用
类型的函数不是更好吗?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 :(得分:1)
不要滥用monad表示法列表,它没有任何重要性。此外,您可以以相同的方式使用列表理解:
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 ws@(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)
顶部的让位列表中的让我感到烦恼,但由于我没有所有的代码,我真的不知道如何以其他方式做到这一点。如果你可以更深入地修改,我建议你使用更多的组合器(map,foldr,foldl'等),因为它们确实减少了我的经验中的代码大小。
注意,代码未经过测试,可能无法编译。