I searched the web for different solutions to the n-queens problem in Haskell but couldn\'t find any that could check for unsafe positions in O(1) time, like that one that you k
The basic potential problem with this approach is that the arrays for the diagonals need to be modified every time a queen is placed. The small improvement of constant lookup time for the diagonals might not necessarily be worth the additional work of constantly creating new modified arrays.
But the best way to know the real answer is to try it, so I played around a bit and came up with the following:
import Data.Array.IArray (array, (//), (!))
import Data.Array.Unboxed (UArray)
import Data.Set (Set, fromList, toList, delete)
-- contains sets of unoccupied columns and lookup arrays for both diagonals
data BoardState = BoardState (Set Int) (UArray Int Bool) (UArray Int Bool)
-- an empty board
board :: Int -> BoardState
board n
= BoardState (fromList [0..n-1]) (truearr 0 (2*(n-1))) (truearr (1-n) (n-1))
where truearr a b = array (a,b) [(i,True) | i <- [a..b]]
-- modify board state if queen gets placed
occupy :: BoardState -> (Int, Int) -> BoardState
occupy (BoardState c s d) (a,b)
= BoardState (delete b c) (tofalse s (a+b)) (tofalse d (a-b))
where tofalse arr i = arr // [(i, False)]
-- get free fields in a row
freefields :: BoardState -> Int -> [(Int, Int)]
freefields (BoardState c s d) a = filter freediag candidates
where candidates = [(a,b) | b <- toList c]
freediag (a,b) = (s ! (a+b)) && (d ! (a-b))
-- try all positions for a queen in row n-1
place :: BoardState -> Int -> [[(Int, Int)]]
place _ 0 = [[]]
place b n = concatMap place_ (freefields b (n-1))
where place_ p = map (p:) (place (occupy b p) (n-1))
-- all possibilities to place n queens on a n*n board
queens :: Int -> [[(Int, Int)]]
queens n = place (board n) n
This works and is for n=14 roughly 25% faster than the version you mentioned. The main speedup comes from using the unboxed arrays bdonian recommended. With the normal Data.Array
it has about the same runtime as the version in the question.
It might also be worth it to try the other array types from the standard library to see if using them can further improve performance.