diff options
author | Aria <me@aria.rip> | 2023-01-02 21:58:56 +0000 |
---|---|---|
committer | Aria <me@aria.rip> | 2023-01-02 21:58:56 +0000 |
commit | 5eb58ad076f2cd435b11b140820da224b60b73d5 (patch) | |
tree | 2a67939595fbf993ff04f69b9cd3f0aa20827d96 /2020/11b.hs |
initial commit
Diffstat (limited to '2020/11b.hs')
-rw-r--r-- | 2020/11b.hs | 62 |
1 files changed, 62 insertions, 0 deletions
diff --git a/2020/11b.hs b/2020/11b.hs new file mode 100644 index 0000000..75f4bda --- /dev/null +++ b/2020/11b.hs @@ -0,0 +1,62 @@ +module Day11B where + +import System.Environment (getArgs) + +type AreaMap = [[Space]]; +data Space = Occupied | Empty | Floor + deriving (Show, Eq, Ord); + + +-- Keep applying f to a until the output stops changing +untilUnchanged :: Eq a => (a -> a) -> a -> a +untilUnchanged f a | n /= a = untilUnchanged f n + | otherwise = n + where n = f a + +-- Find if an occupied seat is visible from (x,y) looking along (dx, dy) +occupiedAlongDir :: AreaMap -> (Int, Int) -> (Int, Int) -> Bool +occupiedAlongDir ss (x, y) (dx, dy) | x >= length (head ss) || y >= length ss || x < 0 || y < 0 = False + | ss!!y!!x == Empty = False + | ss!!y!!x == Occupied = True + | otherwise = occupiedAlongDir ss (x + dx, y + dy) (dx, dy) + +-- Count the number of visible occupied seats from (x, y), looking along all directions incl diagonals. +visibleOccupied :: AreaMap -> (Int, Int) -> Int +visibleOccupied a (x, y) = length [(x', y') | x' <- [x-1..x+1], y' <- [y-1..y+1], x' /= x || y' /= y, occupiedAlongDir a (x', y') (x'-x, y'-y)] + +-- Mutate a space given its current state and its adjacent spaces +mutateSpace :: Space -> Int -> Space +mutateSpace Empty adj | adj == 0 = Occupied + | otherwise = Empty +mutateSpace Occupied adj | adj >= 5 = Empty + | otherwise = Occupied +mutateSpace x _ = x + +-- Mutate all spaces on the map +mutateAll :: AreaMap -> AreaMap +mutateAll rs = [[mutateSpace s (visibleOccupied rs (c, r)) | (c, s) <- zip [0..] ss] | (r, ss) <- zip [0..] rs] + +-- Read a map in from its string representation +readMap :: String -> AreaMap +readMap = map readLine . lines + where readLine [] = [] + readLine ('.':xs) = Floor : readLine xs + readLine ('L':xs) = Empty : readLine xs + readLine ('#':xs) = Occupied : readLine xs + +-- Read a map from the filename +mapFromFile :: String -> IO AreaMap +mapFromFile s = do + contents <- readFile s; + return $ readMap contents; + +main :: IO () +main = do + args <- getArgs; + m <- mapFromFile (head args); + + let final = untilUnchanged mutateAll m; + let occ = sum $ map (length . filter (== Occupied)) final; + + putStrLn $ "Occupied Seats: " ++ show occ; + return (); |