-
Notifications
You must be signed in to change notification settings - Fork 0
/
day17.hs
100 lines (81 loc) · 2.83 KB
/
day17.hs
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
import Data.List
import Data.List.Split hiding (sepBy)
import Data.Functor
import Control.Applicative hiding (many)
import Data.Either
import Text.Megaparsec
import Text.Megaparsec.Char
import qualified Text.Megaparsec.Char.Lexer as L
import Data.Void
import Control.Monad
import Control.Monad.Combinators
import Data.Set (Set)
import qualified Data.Set as Set
-- ===========================================================================
-- Data
-- ===========================================================================
type Parser = Parsec Void String
data Cube = Active | Inactive deriving (Eq)
pCube = (char '#' $> Active) <|> (char '.' $> Inactive)
pCLine :: Parser [Cube]
pCLine = many pCube
getCLine s = fromRight undefined $ runParser pCLine "" s
-- ===========================================================================
-- pt. 1
-- ===========================================================================
type Coord3 = (Int, Int, Int)
neighbors3 (x,y,z) = Set.fromList $ do
x1 <- [-1..1]
y1 <- [-1..1]
z1 <- [-1..1]
pure (x+x1, y+y1, z+z1)
neighborsNoN3 n = Set.delete n $ neighbors3 n
needsAttention3 :: Set Coord3 -> Set Coord3
needsAttention3 s = Set.unions $ neighbors3 <$> Set.toList s
isActive3 :: Set Coord3 -> Coord3 -> Bool
isActive3 s c =
let
cb = Set.member c s
nsb = length $ filter (flip Set.member s) (Set.toList $ neighborsNoN3 c)
in if cb then nsb == 2 || nsb == 3 else nsb == 3
doTick3 s =
let
nats = Set.toList $ needsAttention3 s
in Set.fromList $ filter (isActive3 s) nats
-- ===========================================================================
-- pt. 2
-- ===========================================================================
type Coord4 = (Int, Int, Int, Int)
neighbors4 (x,y,z,w) = Set.fromList $ do
x1 <- [-1..1]
y1 <- [-1..1]
z1 <- [-1..1]
w1 <- [-1..1]
pure (x+x1, y+y1, z+z1, w+w1)
neighborsNoN4 n = Set.delete n $ neighbors4 n
needsAttention4 :: Set Coord4 -> Set Coord4
needsAttention4 s = Set.unions $ neighbors4 <$> Set.toList s
isActive4 :: Set Coord4 -> Coord4 -> Bool
isActive4 s c =
let
cb = Set.member c s
nsb = length $ filter (flip Set.member s) (Set.toList $ neighborsNoN4 c)
in if cb then nsb == 2 || nsb == 3 else nsb == 3
doTick4 s =
let
nats = Set.toList $ needsAttention4 s
in Set.fromList $ filter (isActive4 s) nats
-- ===========================================================================
main = do
f <- readFile "inputs/day17.txt"
let ls = lines f
let csList = getCLine <$> ls
let len = length ls
let hasActive = (do
x <- [0..len-1]
y <- [0..len-1]
if csList!!y!!x == Active then [(x,y,0)] else []) :: [Coord3]
let s = Set.fromList hasActive
print $ Set.size $ (iterate doTick3 s)!!6
let s4 = Set.fromList $ (\(x,y,z) -> (x,y,z,0)) <$> hasActive
print $ Set.size $ (iterate doTick4 s4)!!6