--- Day 18 Solutions ---

Haskell:

import Data.Array.Unboxed
import Data.Ix

count x = length . filter (==x)

adjacents :: ((Int, Int), (Int, Int)) -> (Int, Int) -> [(Int, Int)]
adjacents bds (i, j) = [ (x, y)
                       | x <- [i-1 .. i+1]
                       , y <- [j-1 .. j+1]
                       , (x, y) /= (i, j)
                       , inRange bds (x, y)
                       ]

nextState :: (UArray (Int, Int) Char -> (Int, Int) -> String -> Char)
          -> UArray (Int, Int) Char -> UArray (Int, Int) Char
nextState f a = array bds [ (xy, f a xy adjStates)
                          | xy <- range bds
                          , let adjStates = map (a !) $ adjacents bds xy
                          ]
    where bds = bounds a

part1 = count '#' . elems . (!! 100) . iterate (nextState f) . makeGrid
    where makeGrid = listArray ((0, 0), (99, 99)) . concat . lines
          f a xy adjStates
              | a ! xy == '#' && not (lightsOn `elem` [2, 3]) = '.'
              | a ! xy == '.' && lightsOn == 3                = '#'
              | otherwise                                     = a ! xy
              where lightsOn = count '#' adjStates

part2 = count '#' . elems . (!! 100) . iterate (nextState f) . makeGrid
    where corners = [(0, 0), (0, 99), (99, 0), (99, 99)]
          bds = ((0, 0), (99, 99))
          makeGrid = accumArray (flip const) '.' bds . (++ (zip corners $ repeat '#'))
                     . zip (range bds) . concat . lines
          f a xy adjStates
              | xy `elem` corners                             = '#'
              | a ! xy == '#' && not (lightsOn `elem` [2, 3]) = '.'
              | a ! xy == '.' && lightsOn == 3                = '#'
              | otherwise                                     = a ! xy
              where lightsOn = count '#' adjStates

main = do
  input <- readFile "input.txt"
  print $ part1 input
  print $ part2 input
/r/adventofcode Thread