42 lines
1.6 KiB
Haskell
42 lines
1.6 KiB
Haskell
{-# LANGUAGE BangPatterns, ScopedTypeVariables #-}
|
|
import Data.HashMap.Strict (HashMap, lookupDefault, insert, empty)
|
|
|
|
data Direction = North | East | South | West deriving (Bounded, Enum)
|
|
data Node = Weakened | Infected | Flagged | Clean deriving (Bounded, Enum, Eq)
|
|
type Grid = HashMap (Int, Int) Node
|
|
type State = (Grid, (Int, Int), Direction, Int)
|
|
(%) = mod; infixl 5 %
|
|
|
|
succn :: forall a. (Bounded a, Enum a) => Int -> a -> a
|
|
succn n = toEnum . (% 1 + fromEnum (maxBound :: a)) . (+ n) . fromEnum
|
|
|
|
incrementPosition :: Direction -> (Int, Int) -> (Int, Int)
|
|
incrementPosition dir (x, y) = case dir of
|
|
North -> (x, y - 1)
|
|
East -> (x + 1, y)
|
|
South -> (x, y + 1)
|
|
West -> (x - 1, y)
|
|
|
|
nextState :: State -> State
|
|
nextState (grid, pos, dir, count) =
|
|
let currNode = lookupDefault Clean pos grid
|
|
newDir = succn (fromEnum currNode) dir
|
|
newGrid = insert pos (succn 1 currNode) grid
|
|
newPos = incrementPosition newDir pos
|
|
!newCount = count + fromEnum (currNode == Weakened)
|
|
in (newGrid, newPos, newDir, newCount)
|
|
|
|
stricterate :: Int -> State -> Int
|
|
stricterate 0 (_, _, _, count) = count
|
|
stricterate n state = let !next = nextState state in stricterate (n-1) next
|
|
|
|
parseRow :: (Int, [(Int, Char)]) -> Grid -> Grid
|
|
parseRow (y, xs) grid = foldr (\(x, c) currGrid -> insert (x, y) (charToEnum c) currGrid) grid xs
|
|
where charToEnum c = case c of
|
|
'.' -> Clean
|
|
'#' -> Infected
|
|
|
|
main :: IO ()
|
|
main = do
|
|
grid <- foldr parseRow empty . zip [-12..12] . map (zip [-12..12]) . lines <$> readFile "22.txt"
|
|
print $ stricterate 10000000 (grid, (0, 0), North, 0) |