#!/usr/bin/env nix-script #!>haskell {- Learn you a Haskell exercise -} import Control.Monad import Data.List import Data.Function type Pos = (Int, Int) chessboard = liftM2 (,) [1..8] [1..8] -- | Compose a monadic function with itself n times compose :: Monad m => (a -> m a) -> Int -> a -> m a compose n = foldr (<=<) return . flip replicate n -- | Calculate every possible next move moves :: Pos -> [Pos] moves (x, y) = filter (`elem` chessboard) [ (x+2, y-1), (x+2, y+1) , (x-2, y-1), (x-2, y+1) , (x+1, y-2), (x+1, y+2) , (x-1, y-2), (x-1, y+2) ] -- | Positions the knight can reach in `n` moves reachIn :: Int -> Pos -> [Pos] reachIn = compose moves -- | Test for a path between `start` and `end` in `n` moves canReachIn :: Int -> Pos -> Pos -> Bool canReachIn n start end = end `elem` reachIn n start -- | Pretty print for the chessboard pprint = putStrLn . show' . groupBy (on (==) fst) where show' = concatMap $ (++"\n") . intercalate " " . map show main = do let reached = nub $ reachIn 1 (1,2) unreached = chessboard \\ reached print (length reached) pprint (sort reached) print (length unreached) pprint (sort unreached)