Knight Moves
March 8, 2013
First Lipovača provides us with a function moveKnight
that determines a knights next possible moves from a position on the board. He treats a Knight’s position as a pair of integers for a column and a row. The function returns a list of next possible moves (were the knight remains on the chessboard).
type KnightPos = (Int,Int)
moveKnight :: KnightPos -> [KnightPos]
moveKnight (c, r) = filter onBoard [(c + 2, r + 1), (c + 2, r - 1),
(c - 2, r + 1), (c - 2, r - 1),
(c + 1, r + 2), (c + 1, r - 2),
(c - 1, r + 2), (c - 1, r - 2)]
where onBoard = \(c',r') -> c' `elem` [1..8] && r' `elem` [1..8]
Using moveKnight
, the function nKnightMoves
returns a list of all possible moves that can be made from some starting position in n moves. We denote a path as a list of knight positions. So from (5,5), in 2 moves we could move to [ [(7,4),(5,2)], [(7,6),(5,7)] …] and so on. After that we define the function pathsTo
which accepts n moves to make, the starting position, the end position, and then filters the list from nKnightMoves
for only paths that reach the end position.
type Path = [KnightPos]
nKnightMoves :: Int -> KnightPos -> [Path]
nKnightMoves n pos
| n == 0 = return []
| otherwise = do
ps <- map return (moveKnight pos)
ps' <- nKnightMoves (n - 1) (last ps)
return (ps ++ ps')
pathsTo :: Int -> KnightPos -> KnightPos -> [Path]
pathsTo n start end = filter ((==end) . last) $ nKnightMoves n start
You can run the program at http://programmingpraxis.codepad.org/wjpQvvAo, where you can also see the 109 ways to move a knight from one corner of the board to the other in six moves.
[…] today’s Programming Praxis exercise, our goal is to list all the potential ways a knight on a chess board […]
My Haskell solution (see http://bonsaicode.wordpress.com/2013/03/08/programming-praxis-knight-moves/ for a version with comments):
My attempt in Python:
Also, just thought I’d point out that you said there are 109 ways to move from (1,1) to (8,8) but there are actually only 108. (Your output has 109 lines but the top line is just the description!)
Python, too
Here’s my version in Racket:
Full writeup (including the source for
knight-neighbors
andin-bounds?
, although they’re pretty much exactly what you’d expect) on my blog: Knight movesMy solution in Common Lisp closely follows the Racket solution, so I will not repeat it. But in the Racket and other codes I don’t see tests to see whether the path has either reached the target position in fewer than the required number of moves, or whether the path has revisited a previously visited position.
This does not make a difference for n=6. But for n=8 if we allow for revisiting, I get 5124 paths, and if we prohibit them, we get 1896 paths.
A related problem that I did not have the CPU, machine resources or patience to analyze is to obtain the distribution of the number of paths as function of number of moves. If we prohibit the path from revisiting positions after increasing (6: 108, 8: 1896, 10: 40252, 12: 731642, …) the number of paths for n-max large should eventually decrease and go to zero after 64 moves (The wikipedia page http://en.wikipedia.org/wiki/Knight%27s_tour shows a tour that covers the 8×8 board).