module Minesweeper where import System.Random type Square = (Int, Int) type Grid = [[Bool]] data Board = Board { size :: Int , mines :: Grid , uncovered :: Grid , flagged :: Grid } deriving (Show) -- Creates a board given a size (width/height), mine ratio and random generator createBoard :: Int -> Float -> StdGen -> Board createBoard size mineRatio rng = Board size (seedGrid rng mineRatio (createGrid size)) (createGrid size) (createGrid size) -- Creates a 2D list of booleans of given size, initialised to False createGrid :: Int -> Grid createGrid size = replicate size (replicate size False) -- Functions relating to seeding a grid with mines seedGrid :: StdGen -> Float -> Grid -> Grid seedGrid _ _ [] = [] seedGrid rng p (l:ls) = newL : seedGrid rng2 p ls where (rng1, rng2) = split rng (newL, _) = seedList rng1 p l seedList :: StdGen -> Float -> [Bool] -> ([Bool], StdGen) seedList rng p (l:ls) = (newBool : seedList2 newRng p ls, newRng) where (newBool, newRng) = randomlyTrue rng p seedList2 :: StdGen -> Float -> [Bool] -> [Bool] seedList2 _ _ [] = [] seedList2 rng p (l:ls) = newBool : seedList2 newRng p ls where (newBool, newRng) = randomlyTrue rng p randomlyTrue :: StdGen -> Float -> (Bool, StdGen) randomlyTrue rng p = (generatedFloat <= p, newRng) where (generatedFloat, newRng) = randomR (0.0, 1.0) rng -- Functions for determing status of a square -- N.B. (r,c) = (row, column) hasMine :: Board -> Square -> Bool hasMine b (r,c) | validSquare b (r,c) = (mines b !! r) !! c | otherwise = False isUncovered :: Board -> Square -> Bool isUncovered b (r,c) = (uncovered b !! r) !! c isFlagged :: Board -> Square -> Bool isFlagged b (r,c) = (flagged b !! r) !! c validSquare :: Board -> Square -> Bool validSquare b (r,c) = r >= 0 && c >= 0 && r < size b && c < size b squareAscii :: Board -> Square -> String squareAscii b (r,c) | hasMine b (r,c) = "X" | otherwise = show $ adjacentBombs b (r,c) squareColour :: Board -> Square -> String squareColour b (r,c) | hasMine b (r,c) = "red" | otherwise = "green" adjacentBombs :: Board -> Square -> Int adjacentBombs board (row,col) = let tl = boolToInt $ hasMine board (row-1,col-1) t = boolToInt $ hasMine board (row-1,col) tr = boolToInt $ hasMine board (row-1,col+1) l = boolToInt $ hasMine board (row,col-1) r = boolToInt $ hasMine board (row,col+1) bl = boolToInt $ hasMine board (row+1,col-1) b = boolToInt $ hasMine board (row+1,col) br = boolToInt $ hasMine board (row+1,col+1) in tl + t + tr + l + r + bl + b + br boolToInt :: Bool -> Int boolToInt x | x = 1 | otherwise = 0 -- Functions for turning a board into a string for debug purposes printBoard :: Board -> String printBoard b = printBoardGrid (mines b) printBoardGrid :: Grid -> String printBoardGrid [] = "" printBoardGrid (l:ls) = printBoardLine l ++ "\n" ++ printBoardGrid ls printBoardLine :: [Bool] -> String printBoardLine [] = "" printBoardLine (x:xs) = (if x then " x" else " .") ++ printBoardLine xs