-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrun.hs
103 lines (85 loc) · 2.32 KB
/
run.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
100
101
102
103
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE TypeApplications #-}
import AoC
import AoC.Grid
import Data.Functor
import Data.Bits (xor)
import Data.Ord (comparing)
import Data.Bifunctor
import Data.Maybe
import Data.List
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as Map
import Data.Sequence (Seq)
import qualified Data.Sequence as Seq
import Data.Set (Set)
import qualified Data.Set as Set
import Data.IntSet (IntSet)
import qualified Data.IntSet as IntSet
import Data.Void
import Text.Megaparsec
import Text.Megaparsec.Char
-- e, se, sw, w, nw, and ne
data Dir = E | SE | SW | W | NW | NE
deriving (Show, Read, Eq, Enum, Bounded)
dirs :: [Dir]
dirs = [minBound..maxBound]
type Tile = V2 Int
type Parser = Parsec Void String
dirP :: Parser Dir
dirP =
choice [ E <$ string "e"
, W <$ string "w"
, SE <$ string "se"
, SW <$ string "sw"
, NW <$ string "nw"
, NE <$ string "ne" ]
asVec :: Dir -> V2 Int
asVec = \case E -> v2 ( 1, 0)
W -> v2 (-1, 0)
SE -> v2 ( 0, 1)
SW -> v2 (-1, 1)
NE -> v2 ( 1, -1)
NW -> v2 ( 0, -1)
vecDirs :: [V2 Int]
vecDirs = map asVec dirs
parseAll :: String -> [[Dir]]
parseAll =
map (\(Right x) -> x)
. map (parse (many dirP <* eof) "")
. lines
setup :: [[Dir]] -> Set Tile
setup =
Map.keysSet
. Map.filter (\c -> (c `mod` 2) == 1)
. counter
. map (foldl' (+) 0 . map asVec)
aliveNeighbors :: Tile -> Set Tile -> Set Tile
aliveNeighbors t tiles =
Set.intersection tiles (Set.fromList $ map (+ t) vecDirs)
rule :: Tile -> Set Tile -> Bool
rule t tiles =
let nbs = aliveNeighbors t tiles
alive = t `Set.member` tiles
in case (Set.size nbs, alive) of
(n, True) | n == 0 -> False
| n > 2 -> False
(n, False) | n == 2 -> True
_ -> alive
step :: Set Tile -> Set Tile
step tiles =
Set.filter (flip rule tiles)
. Set.fromList
. concatMap (\t -> t:map (+ t) vecDirs)
$ Set.toList tiles
part1 :: [[Dir]] -> Int
part1 = Set.size . setup
part2 :: [[Dir]] -> Int
part2 input = Set.size (iterateN' 100 step (setup input))
main = main' "input.txt"
exampleMain = main' "example.txt"
main' file = do
input <- parseAll <$> readFile file
print (part1 input)
print (part2 input)