aboutsummaryrefslogtreecommitdiff
path: root/2020/11b.hs
diff options
context:
space:
mode:
authorAria <me@aria.rip>2023-01-02 21:58:56 +0000
committerAria <me@aria.rip>2023-01-02 21:58:56 +0000
commit5eb58ad076f2cd435b11b140820da224b60b73d5 (patch)
tree2a67939595fbf993ff04f69b9cd3f0aa20827d96 /2020/11b.hs
initial commit
Diffstat (limited to '2020/11b.hs')
-rw-r--r--2020/11b.hs62
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 ();