module Main where
import Advent (countBy, arrIx, times, getInputArray)
import Advent.Coord (Coord(C), neighbors)
import Data.Array.Unboxed (Ix(range), IArray(bounds), UArray, (!), amap, array, elems)
type Lights = UArray Coord Bool
main :: IO ()
IO ()
main =
do UArray Coord Bool
input <- (Char -> Bool) -> UArray Coord Char -> UArray Coord Bool
forall (a :: * -> * -> *) e' e i.
(IArray a e', IArray a e, Ix i) =>
(e' -> e) -> a i e' -> a i e
amap (Char
'#'Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
==) (UArray Coord Char -> UArray Coord Bool)
-> IO (UArray Coord Char) -> IO (UArray Coord Bool)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Int -> Int -> IO (UArray Coord Char)
getInputArray Int
2015 Int
18
Int -> IO ()
forall a. Show a => a -> IO ()
print (Int -> IO ()) -> Int -> IO ()
forall a b. (a -> b) -> a -> b
$ UArray Coord Bool -> Int
countLights (UArray Coord Bool -> Int) -> UArray Coord Bool -> Int
forall a b. (a -> b) -> a -> b
$ Int
-> (UArray Coord Bool -> UArray Coord Bool)
-> UArray Coord Bool
-> UArray Coord Bool
forall a. Int -> (a -> a) -> a -> a
times Int
100 (Rule -> UArray Coord Bool -> UArray Coord Bool
applyRule Rule
life) UArray Coord Bool
input
Int -> IO ()
forall a. Show a => a -> IO ()
print (Int -> IO ()) -> Int -> IO ()
forall a b. (a -> b) -> a -> b
$ UArray Coord Bool -> Int
countLights (UArray Coord Bool -> Int) -> UArray Coord Bool -> Int
forall a b. (a -> b) -> a -> b
$ Int
-> (UArray Coord Bool -> UArray Coord Bool)
-> UArray Coord Bool
-> UArray Coord Bool
forall a. Int -> (a -> a) -> a -> a
times Int
100 (Rule -> UArray Coord Bool -> UArray Coord Bool
applyRule (Rule -> Rule
addCorners Rule
life)) UArray Coord Bool
input
countLights :: Lights -> Int
countLights :: UArray Coord Bool -> Int
countLights = (Bool -> Bool) -> [Bool] -> Int
forall (f :: * -> *) a. Foldable f => (a -> Bool) -> f a -> Int
countBy Bool -> Bool
forall a. a -> a
id ([Bool] -> Int)
-> (UArray Coord Bool -> [Bool]) -> UArray Coord Bool -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. UArray Coord Bool -> [Bool]
forall (a :: * -> * -> *) e i. (IArray a e, Ix i) => a i e -> [e]
elems
type Rule = Lights -> Coord -> Bool
applyRule :: Rule -> Lights -> Lights
applyRule :: Rule -> UArray Coord Bool -> UArray Coord Bool
applyRule Rule
f UArray Coord Bool
a = (Coord, Coord) -> [(Coord, Bool)] -> UArray Coord Bool
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
(i, i) -> [(i, e)] -> a i e
array (UArray Coord Bool -> (Coord, Coord)
forall i. Ix i => UArray i Bool -> (i, i)
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> (i, i)
bounds UArray Coord Bool
a) [(Coord
i, Rule
f UArray Coord Bool
a Coord
i) | Coord
i <- (Coord, Coord) -> [Coord]
forall a. Ix a => (a, a) -> [a]
range (UArray Coord Bool -> (Coord, Coord)
forall i. Ix i => UArray i Bool -> (i, i)
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> (i, i)
bounds UArray Coord Bool
a)]
life :: Rule
life :: Rule
life UArray Coord Bool
a Coord
c = Int
n Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
3 Bool -> Bool -> Bool
||
Int
n Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
2 Bool -> Bool -> Bool
&& UArray Coord Bool
aRule
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> i -> e
!Coord
c
where
n :: Int
n = (Coord -> Bool) -> [Coord] -> Int
forall (f :: * -> *) a. Foldable f => (a -> Bool) -> f a -> Int
countBy (\Coord
x -> UArray Coord Bool -> Coord -> Maybe Bool
forall (a :: * -> * -> *) e i (f :: * -> *).
(IArray a e, Ix i, Alternative f) =>
a i e -> i -> f e
arrIx UArray Coord Bool
a Coord
x Maybe Bool -> Maybe Bool -> Bool
forall a. Eq a => a -> a -> Bool
== Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
True) (Coord -> [Coord]
neighbors Coord
c)
addCorners :: Rule -> Rule
addCorners :: Rule -> Rule
addCorners Rule
f UArray Coord Bool
a i :: Coord
i@(C Int
y Int
x)
| Int
x Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
xlo Bool -> Bool -> Bool
|| Int
x Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
xhi
, Int
y Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
ylo Bool -> Bool -> Bool
|| Int
y Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
yhi = Bool
True
| Bool
otherwise = Rule
f UArray Coord Bool
a Coord
i
where
(C Int
ylo Int
xlo, C Int
yhi Int
xhi) = UArray Coord Bool -> (Coord, Coord)
forall i. Ix i => UArray i Bool -> (i, i)
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> (i, i)
bounds UArray Coord Bool
a