summaryrefslogtreecommitdiff
path: root/2020/17.hs
blob: 24bbe6fb44499bc84a8f3c485cef95bab1d2c819 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE ViewPatterns #-}
module Main where

import qualified Data.Array.Unboxed as A
import Data.List (delete)
import qualified Data.Ix as Ix
import Data.Ix (Ix)
import Data.Maybe (catMaybes, fromMaybe)
import Data.Word (Word8)

import Input


generate :: Ix i => (i, i) -> (i -> e) -> A.Array i e
generate r f = A.array r [(i, f i) | i <- Ix.range r]

(!?) :: Ix i => A.Array i e -> i -> Maybe e
arr !? i | Ix.inRange (A.bounds arr) i = Just (arr A.! i)
         | otherwise = Nothing

class Ix i => Coordinate i where
    expand1 :: (i, i) -> (i, i)
    neighbourhood :: i -> [i]

instance Coordinate () where
    expand1 = id
    neighbourhood = pure

instance Coordinate i => Coordinate (i, Int) where
    expand1 ((idx1, i1), (idx2, i2)) =
        let (idx1', idx2') = expand1 (idx1, idx2)
        in ((idx1', i1 - 1), (idx2', i2 + 1))

    neighbourhood (idx, i) = [(idx', i + di) | idx' <- neighbourhood idx, di <- [-1..1]]


newtype Board i = Board (A.Array i Word8)
  deriving (Show)

fromInput :: [String] -> Board (((), Int), Int)
fromInput lns =
    let w = length (head lns)
        h = length lns
    in Board (A.array ((((), 0), 0), (((), w - 1), h - 1))
                      [((((), x), y), b2w (c == '#')) | (y, row) <- zip [0..] lns, (x, c) <- zip [0..] row])
  where b2w = fromIntegral . fromEnum :: Bool -> Word8

backpermute :: (Ix i, Ix j) => (j, j) -> (j -> i) -> Board i -> Board j
backpermute r f (Board arr) = Board (generate r (\j -> arr A.! f j))

addDimension :: Coordinate i => Board i -> Board (i, Int)
addDimension (Board arr@(A.bounds -> (i, j))) = backpermute ((i, 0), (j, 0)) fst (Board arr)

evolve :: Coordinate i => Board i -> Board i
evolve (Board prev) = Board vec
  where vec = generate (expand1 (A.bounds prev))
                       (\index ->
                           let cell = fromMaybe 0 (prev !? index)
                               nb = sum (catMaybes (map (prev !?) (delete index (neighbourhood index))))
                           in if (cell /= 0 && nb == 2) || nb == 3 then 1 else 0)

numActive :: Ix i => Board i -> Int
numActive (Board arr) = sum (map fromIntegral (A.elems arr))

main :: IO ()
main = do
    bd2 <- fromInput <$> getInput 17
    let bd3 = addDimension bd2
        bd4 = addDimension bd3
    print (numActive (iterate evolve bd3 !! 6))
    print (numActive (iterate evolve bd4 !! 6))