简化一些Haskell代码
所以我正在为一个类似跳棋的游戏开发一个minimax实现,以帮助自己更好地学习Haskell。我遇到问题的函数获取游戏状态列表,并生成直接后续游戏状态列表。就像跳棋一样,如果可以跳,玩家必须跳。如果有多个,玩家可以选择 在大多数情况下,这与列表monad配合得很好:循环所有输入游戏状态,循环所有可以跳转的弹珠,循环该弹珠的所有跳转。这个列表单子很好地将所有列表平铺成一个简单的状态列表 诀窍是,如果给定的游戏状态没有跳转,我需要返回当前的游戏状态,而不是空列表。下面的代码是我想出的最好的方法,但对我来说它看起来真的很难看。对如何清理它有什么建议吗简化一些Haskell代码,haskell,monads,Haskell,Monads,所以我正在为一个类似跳棋的游戏开发一个minimax实现,以帮助自己更好地学习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
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 []
eHex::Coord->Coord——将坐标立即返回到棋盘的东方
nwHex::Coord->Coord--将坐标立即返回到板上的西北方向
generateJumpsIter::[ZertzState]->[ZertzState]
generateJumpsIter states=do
返回
n@_->n
哪里
儿童ws@(ZertzState s1 s2 b p)=do
(c,颜色)返回$ZertzState s1(颜色)
(开始c)c(结束c)b)p
其他[]
编辑:为*Hex函数提供示例类型签名。不要滥用列表的monads符号,它太重了。此外,您还可以以相同的方式使用列表理解:
do x <- [1..3]
y <- [2..5] <=> [ x + y | x <- [1..3], y <- [2..5] ]
return x + y
dox
诀窍是,如果给定的游戏状态没有跳转,我需要返回当前的游戏状态,而不是空列表
为什么??我已经写过几次极小极大,我无法想象这样一个函数的用途。使用类型函数不是更好吗
nextStates :: [ZertzState] -> [Maybe [ZertzState]]
[ZertzState] -> [(ZertzState, [ZertzState])]
或
但是,如果您确实希望返回“下一个状态列表,或者如果该列表为空,则返回原始状态”,那么您想要的类型是
nextStates :: [ZertzState] -> [Either ZertzState [ZertzState]]
然后你就可以很容易地把它弄平
至于如何实现,我建议定义类型为的helper函数
nextStates :: [ZertzState] -> [Maybe [ZertzState]]
[ZertzState] -> [(ZertzState, [ZertzState])]
而你却无法绘制地图
(\(start, succs) -> if null succs then Left start else Right succs)
结果,再加上其他各种事情
正如Fred Brooks所说(意译),一旦你得到了正确的类型,代码实际上是自己写的。第一个列表理解不能是[if null(children ws),那么ws else children ws | ws listohex将具有类型listohex::[Coord->Coord]板上的每个十六进制都由一个坐标标识(这只是一对Int的同义词)。例如,函数nwHex返回输入十六进制西北方向的十六进制坐标。listOfHex然后包含这些函数对,用于确定是否可以跳转。listOfHex::[(Coord->Coord,Coord->Coord)],这是一个成对的列表,每个都是一个函数。这只是生成一组可能移动的代码的一部分,这是minimax输入的一部分。特别是,这是与生成可用跳转相关的部分。规则是类似于:如果有可用跳转,则必须执行跳转。如果有多个可用跳转,玩家可以选择跳哪一个。链式跳(即跳棋中的双跳)是允许的,如果可用的规则适用,同样需要。我一直认为这是一个递归生成的状态树。我从包含初始状态的列表开始。从中,我生成最多一跳的可到达状态列表。从这些列表中,我生成最多两跳的状态列表,以此类推。我重复这个过程,直到列表停止更改。这只有在“死胡同”状态保留在列表中,而不是进入空列表时才起作用。@Restor:是Haskell!你为什么不懒洋洋地生成无限移动树呢?你需要的所有信息都在John Hughes的论文中