-- The classic 8-queens problem made famous by Wirth.
-- This version Colin Runciman, March 2000.

main =
    if null solutions then putStrLn "no solution!"
    else putStr (board (head solutions))
    where
    solutions = queens 8

queens :: Int -> [[Int]]
queens n = valid n n

valid :: Int -> Int -> [[Int]]
valid 0 n = [[]]
valid m n = filter safe (extend n (valid (m-1) n))

extend n b = cp (fromTo 1 n) b

cp :: [a] -> [[a]] -> [[a]]
cp [] y = []
cp (a:x) y = map (a:) y ++ cp x y

safe (a:b) = no_threat a b 1

no_threat a [] m = True
no_threat a (b:y) m =
    a /= b && a+m /= b && a-m /= b && no_threat a y (m+1)

board :: [Int] -> String
board b =
    unlines (concat (zipWith rank (from 1) b))
  where
    rank r qcol =
        map line ["o o o", " \\|/ ", " === "]
      where
        line crown_slice =
            concat (zipWith square (from 1) b)
          where
            square scol _ =
                if scol == qcol then crown_slice
                else if (scol `rem` (2::Int)) == (r `rem` (2::Int)) then "....."
                else "     "

-- in place of ..

from :: Int -> [Int]
from n = n : from (n+1)

fromTo :: Int -> Int -> [Int]
fromTo m n = if m > n then [] else m : fromTo (m+1) n
