main.hs 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. -- Mine Sweeper Lab
  2. -- Import section
  3. import Data.Char
  4. import Data.Set ( Set )
  5. import qualified Data.Set as S
  6. import Data.Universe.Helpers ( cartesianProduct ) -- Need to be installed : `cabal install universe`
  7. import Data.List ( foldl1' )
  8. -- Types
  9. data Cell = Covered Int Bool Bool -- number of bombs around ; has bomb ; has flag
  10. | Uncovered Int -- number of bombs around
  11. | Selected
  12. data Grid = Grid [[Cell]]
  13. data StdGen = SG -- TODO : replace
  14. type Mat = [[Int]]
  15. -- Methods
  16. instance Show Cell where
  17. show ( Covered _ _ hasFlag ) = if hasFlag then "[F]" else "[ ]"
  18. show ( Uncovered n ) = ['(', intToDigit n, ')']
  19. show Selected = ">x<"
  20. instance Show Grid where
  21. show (Grid a) = unlines $ map (unwords . map show) a
  22. -- Functions
  23. randSet::Int -> StdGen -> StdGen -> Int -> Int -> Set (Int, Int)
  24. randSet n sg1 sg2 h w =
  25. let byl = randomRs (0, h - 1) sg1 in
  26. let bxl = randomRs (0, w - 1) sg2 in
  27. let bl = zip byl bxl in
  28. let biggerSets = scanl (flip S.insert) S.empty bl in
  29. head (dropWhile (\s -> S.size s < n) biggerSets)
  30. grid::Int -> Int -> Set (Int, Int) -> Grid
  31. grid h w s = Grid [ [Covered 0 (S.member (y, x) s) False | x <- [0..w-1] ] | y <- [0..h-1] ]
  32. randomRs (x, y) sg = [x + mod k (y - x) | k <- [1..y] ] -- TODO : replace
  33. mineIndic::Cell -> Int
  34. mineIndic c = let Covered _ b _ = c in if b then 1 else 0
  35. mines::Grid -> Mat
  36. mines g = let Grid m = g in map (map mineIndic) m
  37. moveUp::Mat -> Mat
  38. moveUp m = concat [tail m, [[0 | _ <- [1..length (m!!0)]]]]
  39. moveDown::Mat -> Mat
  40. moveDown m = concat [[[0 | _ <- [1..length (m!!0)]]], init m]
  41. moveRight::Mat -> Mat
  42. moveRight m = map (\l -> 0 : init l) m
  43. moveLeft::Mat -> Mat
  44. moveLeft m = map (\l -> concat [tail l, [0]]) m
  45. gridMoves::Mat -> [Mat]
  46. gridMoves m =
  47. let hMov = [id, moveUp, moveDown] in
  48. let wMov = [id, moveLeft, moveRight] in
  49. let allMov = tail $ cartesianProduct (.) hMov wMov in
  50. map (\f -> f m) allMov
  51. matrixSum::Mat -> Mat -> Mat
  52. matrixSum m1 m2 = zipWith (zipWith (+)) m1 m2
  53. neighbourMap::Grid -> Mat
  54. neighbourMap g =
  55. let Grid cm = g in
  56. let m = map (map mineIndic) cm in
  57. foldl1' matrixSum (gridMoves m)
  58. updateCell::Cell -> Int -> Cell
  59. updateCell c n = case c of
  60. Covered _ bomb flag -> Covered n bomb flag
  61. Uncovered _ -> Uncovered n
  62. Selected -> Selected
  63. updateGrid::Grid -> Mat -> Grid
  64. updateGrid g m =
  65. let Grid cm = g in
  66. Grid (zipWith (zipWith updateCell) cm m)
  67. applyi::(a -> a) -> Int -> [a] -> [a]
  68. applyi f i xs =
  69. let (xs1, xs2) = splitAt i xs in
  70. concat [xs1, ( (f (head xs2)) : tail xs2 )]
  71. applyij::(a -> a) -> Int -> Int -> [[a]] -> [[a]]
  72. applyij f i j xss = applyi (applyi f j) i xss
  73. uncover::(Int, Int) -> Grid -> Grid
  74. uncover (i, j) g =
  75. let Grid cm = g in
  76. let neighbours = tail [(i', j') | i' <- [0, -1, 1], j' <- [0, -1, 1]] in
  77. let uncoverOneCell = \c -> case c of
  78. Covered 0 _ _ -> Uncovered 0 -- TODO : recursion
  79. Covered n _ _ -> Uncovered n
  80. in
  81. Grid (applyij uncoverOneCell i j cm)
  82. -- 5) Main Loop
  83. covIndic::Cell -> Int
  84. covIndic (Covered _ _ _) = 1
  85. covIndic Selected = 1
  86. covIndic _ = 0
  87. won::Grid -> Int -> Bool
  88. won g nbMines =
  89. let Grid cm = g in
  90. let nbTotal = (length cm) * (length (cm!!0)) in
  91. let uncoBinMatrix = map (map covIndic) cm in
  92. let nbUnco = sum (map sum uncoBinMatrix) in
  93. nbUnco == nbTotal - nbMines
  94. toggleFlag::Cell -> Cell
  95. toggleFlag (Covered n b flag) = Covered n b (not flag)
  96. toggleFlag c = c
  97. loop::Int -> Int -> Int -> Grid -> IO ()
  98. loop i j n b@(Grid xs)
  99. | won n b = putStrLn " Victory !"
  100. | otherwise = do
  101. putStrLn $ show $ Grid $ applyij ( const Selected ) i j xs
  102. c <- getChar
  103. case c of
  104. 'i' -> loop (max (i - 1) 0) j n b -- move caret up
  105. 'k' -> loop (min (i + 1) ((length xs) - 1)) j n b -- move caret down
  106. 'j' -> loop i (max (j - 1) 0) n b -- move caret left
  107. 'l' -> loop i (min (j + 1) ((length (xs!!0)) - 1)) n b -- move caret right
  108. 'f' -> Grid $ applyij toggleFlag i j b -- toggle flag
  109. 'u' -> Grid $ applyij uncover i j b -- uncover tile
  110. otherwise -> loop i j n b -- do nothing
  111. -- Testing data
  112. dtTinyGrid = Grid [
  113. [Covered 1 True False, Uncovered 2, Covered 0 True False],
  114. [Uncovered 0, Uncovered 0, Covered 1 True True]
  115. ]
  116. dtRS = randSet 3 SG SG 4 5
  117. dtGridCover = grid 4 5 dtRS
  118. dtMines = mines dtGridCover