[hs] Clean up 2020_11 further

This commit is contained in:
Joscha 2020-12-11 10:43:29 +00:00
parent 89ecc14f17
commit a44a86178d

View file

@ -1,5 +1,3 @@
{-# LANGUAGE TupleSections #-}
module Aoc.Y2020.D11 module Aoc.Y2020.D11
( day ( day
) where ) where
@ -11,64 +9,63 @@ import qualified Data.Map.Strict as Map
import Aoc.Day import Aoc.Day
import Aoc.Parse import Aoc.Parse
data Seat = Empty | Occupied type Pos = (Int, Int)
deriving (Show, Eq)
isOccupied :: Seat -> Bool
isOccupied Occupied = True
isOccupied Empty = False
data Field = Field data Field = Field
{ fMap :: Map.Map (Int, Int) Seat { fMap :: Map.Map Pos Bool
, fSize :: (Int, Int) , fSize :: Pos
} deriving (Show, Eq) } deriving (Show, Eq)
parser :: Parser Field parser :: Parser Field
parser = do parser = do
ls <- manyLines $ many pSeat ls <- manyLines $ many $ (Nothing <$ char '.') <|> (Just False <$ char 'L')
let dims = (length $ head ls, length ls) let dims = (length $ head ls, length ls)
lsWithCoords = concat $ zipWith (\y -> zipWith (\x -> ((x, y),)) [0..]) [0..] ls lsWithCoords = concat $ zipWith (\y -> zipWith (\x -> (,) (x, y)) [0..]) [0..] ls
m = Map.fromList [(xy, s) | (xy, Just s) <- lsWithCoords] m = Map.fromList [(pos, s) | (pos, Just s) <- lsWithCoords]
pure $ Field m dims pure $ Field m dims
where
pSeat = (Nothing <$ char '.') <|> (Just Empty <$ char 'L')
step :: (Field -> (Int, Int) -> Seat -> Seat) -> Field -> Field step :: (Field -> Pos -> Bool -> Bool) -> Field -> Field
step f field = field { fMap = m' } step f field = field { fMap = Map.mapWithKey (f field) $ fMap field }
where
m' = Map.fromList $ map (\(xy, s) -> (xy, f field xy s)) $ Map.toList $ fMap field
stepSeatP1 :: Field -> (Int, Int) -> Seat -> Seat add :: Pos -> Pos -> Pos
stepSeatP1 field (x, y) s add (x1, y1) (x2, y2) = (x1 + x2, y1 + y2)
| s == Empty && occupied == 0 = Occupied
| s == Occupied && occupied >= 4 = Empty directions :: [Pos]
directions = [(-1, -1), (-1, 0), (-1, 1), (0, 1), (1, 1), (1, 0), (1, -1), (0, -1)]
countOccupied :: [Bool] -> Int
countOccupied = length . filter id
stepSeatP1 :: Field -> Pos -> Bool -> Bool
stepSeatP1 field pos s
| not s && occupied == 0 = True
| s && occupied >= 4 = False
| otherwise = s | otherwise = s
where where
adjacent = mapMaybe (fMap field Map.!?) $ filter (/= (x, y)) $ (,) <$> [x-1,x,x+1] <*> [y-1,y,y+1] occupied = countOccupied $ mapMaybe ((fMap field Map.!?) . add pos) directions
occupied = length $ filter isOccupied adjacent
potAdjacent :: Field -> (Int, Int) -> [[(Int, Int)]] potentialAdjacent :: Field -> Pos -> [[Pos]]
potAdjacent field xy = map towards [(-1, -1), (-1, 0), (-1, 1), (0, 1), (1, 1), (1, 0), (1, -1), (0, -1)] potentialAdjacent field pos = map towards directions
where where
(mx, my) = fSize field (mx, my) = fSize field
towards (dx, dy) towards delta
= takeWhile (\(x, y) -> 0 <= x && x < mx && 0 <= y && y < my) = takeWhile (\(x, y) -> 0 <= x && x < mx && 0 <= y && y < my)
$ drop 1 $ drop 1
$ iterate (\(x, y) -> (x + dx, y + dy)) xy $ iterate (add delta) pos
firstJust :: [Maybe a] -> Maybe a firstJust :: [Maybe a] -> Maybe a
firstJust [] = Nothing firstJust = foldr (<|>) Nothing
firstJust (Just a : _) = Just a
firstJust (Nothing : as) = firstJust as
stepSeatP2 :: Field -> (Int, Int) -> Seat -> Seat stepSeatP2 :: Field -> Pos -> Bool -> Bool
stepSeatP2 field xy s stepSeatP2 field pos s
| s == Empty && occupied == 0 = Occupied | not s && occupied == 0 = True
| s == Occupied && occupied >= 5 = Empty | s && occupied >= 5 = False
| otherwise = s | otherwise = s
where where
adjacent = mapMaybe (firstJust . map (fMap field Map.!?)) $ potAdjacent field xy occupied
occupied = length $ filter isOccupied adjacent = countOccupied
$ mapMaybe (firstJust . map (fMap field Map.!?))
$ potentialAdjacent field pos
iterateUntilSettled :: (Eq a) => (a -> a) -> a -> a iterateUntilSettled :: (Eq a) => (a -> a) -> a -> a
iterateUntilSettled f a iterateUntilSettled f a
@ -80,13 +77,11 @@ iterateUntilSettled f a
solver :: Field -> IO () solver :: Field -> IO ()
solver field = do solver field = do
putStrLn ">> Part 1" putStrLn ">> Part 1"
let field1 = iterateUntilSettled (step stepSeatP1) field print $ countOccupied $ Map.elems $ fMap $ iterateUntilSettled (step stepSeatP1) field
print $ length $ filter isOccupied $ Map.elems $ fMap field1
putStrLn "" putStrLn ""
putStrLn ">> Part 2" putStrLn ">> Part 2"
let field2 = iterateUntilSettled (step stepSeatP2) field print $ countOccupied $ Map.elems $ fMap $ iterateUntilSettled (step stepSeatP2) field
print $ length $ filter isOccupied $ Map.elems $ fMap field2
day :: Day day :: Day
day = dayParse parser solver day = dayParse parser solver