50 lines
2.0 KiB
Haskell
50 lines
2.0 KiB
Haskell
module Commons where
|
|
|
|
import GHC.IO.Handle (isEOF)
|
|
import Data.Array (Array, listArray, (!), Ix (inRange), bounds, array, indices, assocs)
|
|
|
|
|
|
data Tile = Plot { reachable :: Bool } | Rock deriving (Eq, Show)
|
|
type Garden = Array (Int, Int) Tile
|
|
|
|
|
|
parseLine :: String -> [Tile]
|
|
parseLine = map (\case
|
|
'S' -> Plot {reachable = False}
|
|
'.' -> Plot {reachable = False}
|
|
'#' -> Rock)
|
|
|
|
parseGarden :: IO [[Tile]]
|
|
parseGarden = do done <- isEOF
|
|
if done
|
|
then return []
|
|
else do line <- getLine
|
|
let gardenLine = parseLine line
|
|
garden <- parseGarden
|
|
return (gardenLine: garden)
|
|
|
|
parse :: IO Garden
|
|
parse = do garden <- parseGarden
|
|
return $ listArray ((1, 1), (length garden, length $ head garden)) $ concat garden
|
|
|
|
|
|
move :: [(Int, Int)] -> Garden -> [((Int, Int), Tile)]
|
|
move [] _ = []
|
|
move ((y, x): t) garden = if garden ! (y, x) == Rock then ((y, x), Rock): move t garden
|
|
else let r1 = inRange (bounds garden) (y + 1, x) && (garden ! (y + 1, x) == Plot True)
|
|
r2 = inRange (bounds garden) (y - 1, x) && (garden ! (y - 1, x) == Plot True)
|
|
r3 = inRange (bounds garden) (y, x + 1) && (garden ! (y, x + 1) == Plot True)
|
|
r4 = inRange (bounds garden) (y, x - 1) && (garden ! (y, x - 1) == Plot True)
|
|
in ((y, x), Plot {reachable = r1 || r2 || r3 || r4}): move t garden
|
|
|
|
applyMove :: Garden -> Garden
|
|
applyMove garden = array (bounds garden) $ move (indices garden) garden
|
|
|
|
applyNMove :: Int -> Garden -> Garden
|
|
applyNMove 0 garden = garden
|
|
applyNMove n garden = applyNMove (n - 1) $ applyMove garden
|
|
|
|
getReachableAfterNMove :: Int -> Garden -> [((Int, Int), Tile)]
|
|
getReachableAfterNMove n garden = let finalGarden = applyNMove n garden
|
|
in filter (\ (_, t) -> t == Plot True) $ assocs finalGarden
|