Advertisement
Guest User

Untitled

a guest
Jun 17th, 2019
77
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. {-# LANGUAGE InstanceSigs #-}
  2.  
  3. module Game
  4.   ( startGame
  5.   ) where
  6.  
  7. import Control.Monad (when)
  8. import Control.Monad.Reader (ReaderT, ask, lift, runReaderT)
  9. import Data.Foldable (forM_)
  10. import Data.IORef (IORef, modifyIORef, newIORef, readIORef, writeIORef)
  11. import qualified Data.Vector as V
  12. import qualified Data.Vector.Unboxed as VU
  13. import qualified Data.Vector.Unboxed.Mutable as MU
  14. import System.IO (BufferMode (..), hSetBuffering, stdin)
  15. import System.Random (newStdGen, randomRs)
  16.  
  17. data Move
  18.   = TopMove
  19.   | LeftMove
  20.   | RightMove
  21.   | DownMove
  22.  
  23. newtype Field =
  24.   Field (V.Vector (MU.IOVector Int))
  25.  
  26. data GameData = GameData
  27.   { field  :: Field
  28.   , score  :: IORef Integer
  29.   , logger :: Field -> IO ()
  30.   }
  31.  
  32. maxSize :: Int
  33. maxSize = 4
  34.  
  35. toVector :: [Int] -> IO (MU.IOVector Int)
  36. toVector list = VU.thaw $ VU.fromList list
  37.  
  38. toField :: [[Int]] -> IO Field
  39. toField list = do
  40.   lists <- traverse toVector list
  41.   return $ Field $ V.fromList lists
  42.  
  43. emptyField :: IO Field
  44. emptyField =
  45.   let line = replicate maxSize 0
  46.    in toField (replicate maxSize line)
  47.  
  48. equal :: Field -> Field -> IO Bool
  49. equal (Field a) (Field b) = do
  50.   ans <- newIORef True
  51.   forM_ [0 .. maxSize - 1] $ \i -> do
  52.     let rowA = a V.! i
  53.     let rowB = b V.! i
  54.     forM_ [0 .. maxSize - 1] $ \j -> do
  55.       elA <- MU.read rowA j
  56.       elB <- MU.read rowB j
  57.       when (elA /= elB) $ writeIORef ans False
  58.   readIORef ans
  59.  
  60. checkPredicate :: Field -> (Int -> Bool) -> IO Bool
  61. checkPredicate (Field a) f = do
  62.   ans <- newIORef False
  63.   forM_ [0 .. maxSize - 1] $ \i -> do
  64.     let rowA = a V.! i
  65.     forM_ [0 .. maxSize - 1] $ \j -> do
  66.       elA <- MU.read rowA j
  67.       when (f elA) $ writeIORef ans True
  68.   readIORef ans
  69.  
  70. isWin :: Field -> IO Bool
  71. isWin curField = checkPredicate curField (>= 2048)
  72.  
  73. hasEmpty :: Field -> IO Bool
  74. hasEmpty curField = checkPredicate curField (== 0)
  75.  
  76. isLose :: Field -> IO Bool
  77. isLose curField@(Field vector) = do
  78.   ans <- newIORef True
  79.   fieldHasEmpty <- hasEmpty curField
  80.   when fieldHasEmpty $ writeIORef ans False
  81.   forM_ [0 .. maxSize - 1] $ \i -> do
  82.     let row = vector V.! i
  83.     forM_ [0 .. maxSize - 1] $ \j -> do
  84.       el <- MU.read row j
  85.       when (j > 0) $ do
  86.         el' <- MU.read row (j - 1)
  87.        when (el == el') $ writeIORef ans False
  88.       when (j < maxSize - 1) $ do
  89.         el' <- MU.read row (j + 1)
  90.        when (el == el') $ writeIORef ans False
  91.       when (i > 0) $ do
  92.         let row' = vector V.! (i - 1)
  93.        el' <- MU.read row' j
  94.        when (el == el') $ writeIORef ans False
  95.       when (i < maxSize - 1) $ do
  96.         let row' = vector V.! (i + 1)
  97.        el' <- MU.read row' j
  98.        when (el == el') $ writeIORef ans False
  99.   readIORef ans
  100.  
  101. slideRowLeft :: [Int] -> [Int]
  102. slideRowLeft [] = []
  103. slideRowLeft [x] = [x]
  104. slideRowLeft (x:y:zs)
  105.   | x == 0 = slideRowLeft (y : zs) ++ [0]
  106.   | y == 0 = slideRowLeft (x : zs) ++ [0]
  107.   | x == y = (x + y) : slideRowLeft zs ++ [0]
  108.   | otherwise = x : slideRowLeft (y : zs)
  109.  
  110. vectorToList :: MU.IOVector Int -> IO [Int]
  111. vectorToList vector = do
  112.   immutableVector <- VU.freeze vector
  113.   return $ VU.toList immutableVector
  114.  
  115. fieldToList :: Field -> IO [[Int]]
  116. fieldToList (Field vector) = do
  117.   res <- newIORef []
  118.   forM_ [0 .. maxSize - 1] $ \i -> do
  119.     let row = vector V.! i
  120.     el <- vectorToList row
  121.     modifyIORef res (\x -> el : x)
  122.   list <- readIORef res
  123.   return $ reverse list
  124.  
  125. fieldColumnToList :: Field -> Int -> IO [Int]
  126. fieldColumnToList (Field vector) j = do
  127.   res <- newIORef []
  128.   forM_ [0 .. maxSize - 1] $ \i -> do
  129.     let row = vector V.! i
  130.     el <- MU.read row j
  131.     modifyIORef res (\x -> el : x)
  132.   list <- readIORef res
  133.   return $ reverse list
  134.  
  135. moveColumns :: Bool -> ReaderT GameData IO ()
  136. moveColumns toLeft = do
  137.   GameData {field = curField@(Field vector)} <- ask
  138.   lift $
  139.     forM_ [0 .. maxSize - 1] $ \j -> do
  140.       curColumn <- fieldColumnToList curField j
  141.       movedColumn <-
  142.         if toLeft
  143.           then toVector $ slideRowLeft curColumn
  144.           else toVector $ reverse $ slideRowLeft (reverse curColumn)
  145.       forM_ [0 .. maxSize - 1] $ \i -> do
  146.         let row = vector V.! i
  147.         movedEl <- MU.read movedColumn i
  148.         MU.write row j movedEl
  149.  
  150. moveRows :: Bool -> ReaderT GameData IO ()
  151. moveRows toLeft = do
  152.   GameData {field = (Field curField)} <- ask
  153.   lift $
  154.     forM_ [0 .. maxSize - 1] $ \i -> do
  155.       let row = curField V.! i
  156.       curRow <- vectorToList row
  157.       movedRow <-
  158.         if toLeft
  159.           then toVector $ slideRowLeft curRow
  160.           else toVector $ reverse $ slideRowLeft (reverse curRow)
  161.       forM_ [0 .. maxSize - 1] $ \j -> do
  162.         movedEl <- MU.read movedRow j
  163.         MU.write row j movedEl
  164.  
  165. moveImpl :: Move -> ReaderT GameData IO ()
  166. moveImpl TopMove   = moveColumns True
  167. moveImpl RightMove = moveRows False
  168. moveImpl DownMove  = moveColumns False
  169. moveImpl LeftMove  = moveRows True
  170.  
  171. move :: ReaderT GameData IO ()
  172. move = do
  173.   userAction <- lift getChar
  174.   lift $ putStrLn ""
  175.   case userAction of
  176.     'w' -> moveImpl TopMove
  177.     'd' -> moveImpl RightMove
  178.     's' -> moveImpl DownMove
  179.     'a' -> moveImpl LeftMove
  180.     'c' -> undefined
  181.     _   -> error ("Unexpected user action: " ++ show userAction)
  182.  
  183. turn :: Bool -> ReaderT GameData IO ()
  184. turn newCell = do
  185.   GameData {field = curField, logger = curLogger} <- ask
  186.   curIsWin <- lift $ isWin curField
  187.   curIsLose <- lift $ isLose curField
  188.   when curIsWin $ do
  189.     lift $ putStrLn "You win!"
  190.     return ()
  191.   when curIsLose $ do
  192.     lift $ putStrLn "You lose! :("
  193.     return ()
  194.   when (not curIsWin && not curIsLose) $ do
  195.     canAddCell <- lift $ hasEmpty curField
  196.     when (newCell && canAddCell) newRandomCell
  197.     savedFieldList <- lift $ fieldToList curField
  198.     savedField <- lift $ toField savedFieldList
  199.     lift $ curLogger curField
  200.     move
  201.     eq <- lift $ equal savedField curField
  202.     turn (not eq)
  203.  
  204. tuplify :: [a] -> (a, a)
  205. tuplify [x, y] = (x, y)
  206. tuplify _      = error "Expected list with 2 elements"
  207.  
  208. randomCellId :: IO (Int, Int)
  209. randomCellId = fmap tuplify $ take 2 . randomRs (0, maxSize - 1) <$> newStdGen
  210.  
  211. randomCell :: IO Int
  212. randomCell = do
  213.   randomCellProb <- randomCell'
  214.  return $
  215.    if randomCellProb <= 10
  216.      then 4
  217.      else 2
  218.  where
  219.    randomCell' :: IO Int
  220.     randomCell' = fmap head $ take 1 . randomRs (0, 100) <$> newStdGen
  221.  
  222. newRandomCell :: ReaderT GameData IO ()
  223. newRandomCell = do
  224.  GameData {field = (Field vector)} <- ask
  225.  randomCellValue <- lift randomCell
  226.  (i, j) <- lift randomCellId
  227.  let row = vector V.! i
  228.  el <- MU.read row j
  229.  if el == 0
  230.    then MU.write row j randomCellValue
  231.    else newRandomCell
  232.  
  233. simpleLogger :: Field -> IO ()
  234. simpleLogger (Field vector) =
  235.  forM_ [0 .. maxSize - 1] $ \i -> do
  236.    let row = vector V.! i
  237.    forM_ [0 .. maxSize - 1] $ \j -> do
  238.      el <- MU.read row j
  239.      putStr (show el ++ " ")
  240.    putStrLn ""
  241.  
  242. startGame :: IO ()
  243. startGame = do
  244.  hSetBuffering stdin NoBuffering
  245.  curScore <- newIORef 0 :: IO (IORef Integer)
  246.  curField <- emptyField
  247.  runReaderT (turn True) (GameData {field = curField, score = curScore, logger = simpleLogger})
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement