为什么骑士不能覆盖所有桌子?

时间:2016-11-06 02:40:29

标签: algorithm haskell

我希望骑士从(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步后停止?

1 个答案:

答案 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