我希望骑士从(1,1)
开始并试图在整个桌子上移动。这是我的代码:
canMove :: (Int -> Int) -> (Int -> Int) -> [(Int,Int)] -> Bool
canMove (x) (y) list
| (x (fst lastMove),y (snd lastMove)) `elem` list = False
| newX> 8 || newY> 8 || newX<=0 || newY<=0 = False
| otherwise = True
where lastMove = last list
newX = x (fst lastMove)
newY = y (snd lastMove)
move :: [(Int, Int)] -> [( Int, Int)]
move list
| length list == 64 = list
| canMove (+1) (+2) list = move (list ++ [(x+1,y+2)])
| canMove (+2) (+1) list = move (list ++ [(x+2,y+1)])
| canMove (subtract 1) (+2) list = move (list ++ [(x-1,y+2)])
| canMove (subtract 2) (+1) list = move (list ++ [(x-2,y+1)])
| canMove (subtract 1) (subtract 2) list = move (list ++ [(x-1,y-2)])
| canMove (subtract 2) (subtract 1) list = move (list ++ [(x-2,y-1)])
| canMove (+1) (subtract 2) list = move (list ++ [(x+1,y-2)])
| canMove (+2) (subtract 1) list = move (list ++ [(x+2,y-1)])
| otherwise = list
where lastMove = last list
x = fst lastMove
y = snd lastMove
y=length (move [(1,1)])
main = print $ y
为什么骑士在34
步后停止?
答案 0 :(得分:5)
我假设您正在尝试解决Haskell中的knight's tour问题。在这种情况下,你的问题是你正在使用贪婪算法,这对于骑士的旅行问题是失败的。如果您从length
功能中删除y
,则可以看到算法选择的路径。
[(1,1),(2,3),(3,5),(4,7),(6,8),(5,6),(7,7),(5,8),(4,6),(6,7),
(8,8),(7,6),(5,7),(7,8),(6,6),(8,7),(7,5),(6,3),(8,4),(6,5),
(8,6),(7,4),(5,5),(3,6),(4,8),(2,7),(1,5),(3,4),(2,6),(3,8),
(1,7),(2,5),(3,7),(1,8)]
-- From (1,8), we can go to either (4,6) or (3,5).
-- But we've already been to both of those positions.
简单地说,你的骑士在某个时刻做出了“错误的”转弯,并且在没有重复位置的情况下陷入无法脱身的位置。为了避免这种情况,你需要使用某种回溯算法,这样当骑士犯这样的错误时,它可以撤消其移动并尝试别的东西。幸运的是,Haskell使用List monad使这相对容易。如果你不熟悉monad,那么它们就是Haskell的组成部分,你可以了解它们here。