LoginSignup
31
28

More than 5 years have passed since last update.

ぷよぷよ in Lens

Posted at

Lenshttp://hackage.haskell.org/package/lensの練習にちょうどいいなあと思って。
30分はかかってない気がします。

import           Control.Lens
import           Control.Monad
import           Control.Monad.State
import           Data.List
import qualified Data.Map            as M

paint :: M.Map (Int, Int) Char -> (Int, Int) -> Int
paint mm pos = evalState (go pos) mm where
  go (i, j) = do
    b <- use $ at (i, j)
    if b == M.lookup pos mm then do
      at (i, j) ?= 'x'
      vs <- forM [(1, 0), (-1, 0), (0, 1), (0, -1)] $ \(di, dj) ->
        go (i + di, j + dj)
      return $ 1 + sum vs
      else do
      return 0

erase :: [String] -> [String]
erase bd =
  [ [ if paint mm (i, j) >= 4 then ' ' else c
    | (j, c) <- zip [0..] r
    ]
  | (i, r) <- zip [0..] bd
  ]
  where
    mm = M.fromList $ do
      (i, r) <- zip [0..] bd
      (j, c) <- zip [0..] r
      return $ ((i, j), c)

drops :: [String] -> [String]
drops = transpose . map (reverse . f . reverse) . transpose where
  f = take 13 . (++ repeat ' ') . filter (/= ' ')

next :: [String] -> [String]
next = drops . erase

main :: IO ()
main = do
  forM_ (take 20 $ iterate next input) $ \b -> do
    mapM_ putStrLn b
    putStrLn "======"

-----

input :: [String]
input =
  [ "  GYRR"
  , "RYYGYG"
  , "GYGYRR"
  , "RYGYRG"
  , "YGYRYG"
  , "GYRYRG"
  , "YGYRYR"
  , "YGYRYR"
  , "YRRGRG"
  , "RYGYGG"
  , "GRYGYR"
  , "GRYGYR"
  , "GRYGYR"
  ]
31
28
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
31
28