-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDay18.hs
89 lines (76 loc) · 2.43 KB
/
Day18.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
module Day18
( part1
, part2
) where
import Data.Array.Unboxed (assocs)
import Data.List as L (filter, map)
import Data.Map as M (Map, elems, empty, filter,
foldrWithKey, fromList, insert,
lookup, map, size)
import Data.Sequence as S (fromList)
import Helpers.Graph (Pos, east, north, south, west)
import Helpers.Parsers (arrayFromString)
import Helpers.Search (findPattern)
type Scan = Map Pos State
data State
= Open
| Wooded
| Lumberyard
deriving (Ord, Eq)
instance Show State where
show Open = "."
show Wooded = "|"
show Lumberyard = "#"
adjacent =
[ north
, south
, east
, west
, north + east
, north + west
, south + east
, south + west
]
longTime = 1000000000
minute :: Scan -> Scan
minute scan = foldrWithKey evolve scan scan
where
evolve p Open ns
| (>= 3) . length . L.filter (== Just Wooded) $ neighbours =
insert p Wooded ns
| otherwise = ns
where
neighbours = L.map (\a -> M.lookup (p + a) scan) adjacent
evolve p Wooded ns
| (>= 3) . length . L.filter (== Just Lumberyard) $ neighbours =
insert p Lumberyard ns
| otherwise = ns
where
neighbours = L.map (\a -> M.lookup (p + a) scan) adjacent
evolve p Lumberyard ns
| Just Lumberyard `elem` neighbours && Just Wooded `elem` neighbours = ns
| otherwise = insert p Open ns
where
neighbours = L.map (\a -> M.lookup (p + a) scan) adjacent
parseInput :: String -> Scan
parseInput = M.map readState . M.fromList . assocs . arrayFromString
where
readState '.' = Open
readState '|' = Wooded
readState '#' = Lumberyard
score1 :: Scan -> Int
score1 s = wooded * lumberyards
where
wooded = size . M.filter (== Wooded) $ s
lumberyards = size . M.filter (== Lumberyard) $ s
score2 :: [Scan] -> Int
score2 s = wooded * lumberyards
where
wooded = size . M.filter (== Wooded) $ pat
lumberyards = size . M.filter (== Lumberyard) $ pat
period = findPattern 1000 50 (==) . S.fromList $ s
pat = s !! (1000 + mod (longTime - 1000) period)
part1 :: Bool -> String -> String
part1 _ = show . score1 . last . take 11 . iterate minute . parseInput
part2 :: Bool -> String -> String
part2 _ = show . score2 . take 10000 . iterate minute . parseInput