{-# Language QuasiQuotes #-}
{-|
Module      : Main
Description : Day 18 solution
Copyright   : (c) Eric Mertens, 2021
License     : ISC
Maintainer  : emertens@gmail.com

<https://adventofcode.com/2016/day/18>

Run Rule 90, a cellular automaton, for a few generations and count how many
cells are turned on.

<https://en.wikipedia.org/wiki/Rule_90>

-}
module Main (main) where

import Advent (count, format)

-- | >>> :main
-- 2005
-- 20008491
main :: IO ()
IO ()
main =
 do [Char]
input <- [format|2016 18 %s%n|]
    Int -> IO ()
forall a. Show a => a -> IO ()
print ([Char] -> Int -> Int
solve [Char]
input     Int
40)
    Int -> IO ()
forall a. Show a => a -> IO ()
print ([Char] -> Int -> Int
solve [Char]
input Int
400000)

-- | Given a seed and number of generations, count the safe tiles in the map.
solve ::
  String {- ^ seed -} ->
  Int {- ^ generations -} ->
  Int {- ^ total safe tiles -}
solve :: [Char] -> Int -> Int
solve [Char]
input Int
n = Char -> [Char] -> Int
forall (f :: * -> *) a. (Foldable f, Eq a) => a -> f a -> Int
count Char
'.' ([[Char]] -> [Char]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat (Int -> [[Char]] -> [[Char]]
forall a. Int -> [a] -> [a]
take Int
n (([Char] -> [Char]) -> [Char] -> [[Char]]
forall a. (a -> a) -> a -> [a]
iterate [Char] -> [Char]
next [Char]
input)))

-- | Update logic for rule 90 based on previous cell values.
rule90 :: Char {- ^ left -} -> Char {- ^ center -} -> Char {- ^ right -} -> Char
rule90 :: Char -> Char -> Char -> Char
rule90 Char
x Char
_ Char
y
  | Char
x Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= Char
y    = Char
'^'
  | Bool
otherwise = Char
'.'

-- | Compute the next generation.
next :: String -> String
next :: [Char] -> [Char]
next (Char
x:[Char]
xs) = Char -> Char -> [Char] -> [Char]
go Char
'.' Char
x [Char]
xs
  where
    go :: Char -> Char -> [Char] -> [Char]
go Char
a Char
b [] = [Char -> Char -> Char -> Char
rule90 Char
a Char
b Char
'.']
    go Char
a Char
b (Char
c:[Char]
cs) = Char -> Char -> Char -> Char
rule90 Char
a Char
b Char
c Char -> [Char] -> [Char]
forall a. a -> [a] -> [a]
: Char -> Char -> [Char] -> [Char]
go Char
b Char
c [Char]
cs