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]