{-# Language TemplateHaskell, ImportQualifiedPost, QuasiQuotes #-}
module Main (main) where
import Advent (counts, stageTH, times)
import Advent.Coord (Coord, north, east, south, west)
import Advent.Format (format)
import Data.Foldable (foldl')
import Data.Map (Map)
import Data.Map.Strict qualified as Map
import Data.Set (Set)
import Data.Set qualified as Set
data D = De | Dne | Dse | Dw | Dnw | Dsw
stageTH
main :: IO ()
IO ()
main =
do [[D]]
inp <- [format|2020 24 (@D*%n)*|]
let board :: Set Coord
board = [Coord] -> Set Coord
forall a. Ord a => [a] -> Set a
odds (([D] -> Coord) -> [[D]] -> [Coord]
forall a b. (a -> b) -> [a] -> [b]
map [D] -> Coord
walk [[D]]
inp)
Int -> IO ()
forall a. Show a => a -> IO ()
print (Set Coord -> Int
forall a. Set a -> Int
Set.size Set Coord
board)
Int -> IO ()
forall a. Show a => a -> IO ()
print (Set Coord -> Int
forall a. Set a -> Int
Set.size (Int -> (Set Coord -> Set Coord) -> Set Coord -> Set Coord
forall a. Int -> (a -> a) -> a -> a
times Int
100 Set Coord -> Set Coord
step Set Coord
board))
odds :: Ord a => [a] -> Set a
odds :: forall a. Ord a => [a] -> Set a
odds = Map a Int -> Set a
forall k a. Map k a -> Set k
Map.keysSet (Map a Int -> Set a) -> ([a] -> Map a Int) -> [a] -> Set a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Int -> Bool) -> Map a Int -> Map a Int
forall a k. (a -> Bool) -> Map k a -> Map k a
Map.filter Int -> Bool
forall a. Integral a => a -> Bool
odd (Map a Int -> Map a Int) -> ([a] -> Map a Int) -> [a] -> Map a Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [a] -> Map a Int
forall (f :: * -> *) a. (Foldable f, Ord a) => f a -> Map a Int
counts
step :: Set Coord -> Set Coord
step :: Set Coord -> Set Coord
step Set Coord
board
= Map Coord Int -> Set Coord
forall k a. Map k a -> Set k
Map.keysSet
(Map Coord Int -> Set Coord) -> Map Coord Int -> Set Coord
forall a b. (a -> b) -> a -> b
$ (Coord -> Int -> Bool) -> Map Coord Int -> Map Coord Int
forall k a. (k -> a -> Bool) -> Map k a -> Map k a
Map.filterWithKey Coord -> Int -> Bool
forall {a}. (Eq a, Num a) => Coord -> a -> Bool
rule
(Map Coord Int -> Map Coord Int) -> Map Coord Int -> Map Coord Int
forall a b. (a -> b) -> a -> b
$ (Int -> Int -> Int) -> [Map Coord Int] -> Map Coord Int
forall (f :: * -> *) k a.
(Foldable f, Ord k) =>
(a -> a -> a) -> f (Map k a) -> Map k a
Map.unionsWith Int -> Int -> Int
forall a. Num a => a -> a -> a
(+)
[(Coord -> Coord) -> Map Coord Int -> Map Coord Int
forall k1 k2 a. (k1 -> k2) -> Map k1 a -> Map k2 a
Map.mapKeysMonotonic (Coord
c Coord -> Coord -> Coord
forall a. Num a => a -> a -> a
+) Map Coord Int
neighborhood
| Coord
c <- Set Coord -> [Coord]
forall a. Set a -> [a]
Set.toList Set Coord
board]
where
rule :: Coord -> a -> Bool
rule Coord
k a
v = a
v a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
2 Bool -> Bool -> Bool
|| a
v a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
1 Bool -> Bool -> Bool
&& Coord -> Set Coord -> Bool
forall a. Ord a => a -> Set a -> Bool
Set.member Coord
k Set Coord
board
neighborhood :: Map Coord Int
neighborhood :: Map Coord Int
neighborhood = [Coord] -> Map Coord Int
forall (f :: * -> *) a. (Foldable f, Ord a) => f a -> Map a Int
counts ((D -> Coord) -> [D] -> [Coord]
forall a b. (a -> b) -> [a] -> [b]
map D -> Coord
translate [D
Dw,D
De,D
Dne,D
Dse,D
Dnw,D
Dsw])
walk :: [D] -> Coord
walk :: [D] -> Coord
walk = [Coord] -> Coord
forall a. Num a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum ([Coord] -> Coord) -> ([D] -> [Coord]) -> [D] -> Coord
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (D -> Coord) -> [D] -> [Coord]
forall a b. (a -> b) -> [a] -> [b]
map D -> Coord
translate
translate :: D -> Coord
translate :: D -> Coord
translate D
Dw = Coord
west
translate D
De = Coord
east
translate D
Dne = Coord
north Coord -> Coord -> Coord
forall a. Num a => a -> a -> a
+ Coord
east
translate D
Dse = Coord
south
translate D
Dnw = Coord
north
translate D
Dsw = Coord
south Coord -> Coord -> Coord
forall a. Num a => a -> a -> a
+ Coord
west