module Main where
import Char
import List
import Random
data Content = Bomb | Free Int
data Square = Hidden Content | Revealed Content | Flagged Content
dSquare (Hidden x) = '?'
dSquare (Revealed x) = dContent x
dSquare (Flagged x) = '!'
dContent Bomb = '#'
dContent (Free 0) = ' '
dContent (Free i) = chr (ord '0' + i)
dBoard b =
let blen = length b
bsize = blen - 2
dRow rowNo row =
(chr (ord 'a' - 1 + rowNo)) : ' ' :
map dSquare (take bsize (tail row))
in
(" " ++ map (chr . ((ord 'a' - 1) +)) [1..bsize]) :
(" " ++ map (const ' ') [1..bsize]) :
zipWith dRow [1..bsize] tail b
mkPositions :: Int -> Int -> IO [Int]
mkPositions bsize nbombs = do
g <- newStdGen
let ps = randomRs (0, bsize-1) g
return $ take nbombs (nub ps)
posToCoord :: Int -> Int -> (Int, Int)
posToCoord bsize pos =
(pos `div` bsize +1, pos `mod` bsize +1)
mkBoard bsize nbombs = do
posns <- mkPositions bsize nbombs
let coords = map (posToCoord bsize) posns
mkRow rowNo = map (mkSquare rowNo) [0..bsize+1]
mkSquare rowNo colNo =
Hidden $
if (rowNo, colNo) `elem` coords
then Hidden Bomb
else Free (countBombs coords)
where
countBombs [] = 0
countBombs ((colB, rowB) : rest) =
let dCol = colB - colNo
dRow = rowB - rowNo
in
if (dCol == 0) && (dRow == 0)
then countBombs rest
else if (abs dCol < 2) && (abs dRow < 2)
then 1 + countBombs rest
else countBombs rest
return $ map mkRow [0..bsize+1]