-
Notifications
You must be signed in to change notification settings - Fork 0
/
Day17.hs
119 lines (103 loc) · 3.26 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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
module Day17
( part1
, part2
) where
import Text.Regex.TDFA ((=~))
import Data.List.Split (chunksOf)
import Data.Map as M (Map, empty, findWithDefault, insert,
keys, lookup)
import Data.Maybe (Maybe (Just, Nothing), fromJust, isNothing)
import Data.Sequence (fromList)
import Helpers.Search (findPattern)
import Linear.V2 (V2 (..))
type Pos = V2 Int
type Cave = Map Pos Bool
type Height = Int
type Rocks = [[Pos]]
type Jets = [Pos]
data State =
State
{ cave :: Cave
, height :: Height
, jets :: Jets
, rocks :: Rocks
}
deriving (Show, Eq)
initialRocks =
cycle
[ [V2 x 0 | x <- [0 .. 3]]
, [V2 x y | x <- [0 .. 2], y <- [0 .. 2], x == 1 || y == 1]
, [V2 x y | x <- [0 .. 2], y <- [0 .. 2], x == 2 || y == 0]
, [V2 0 y | y <- [0 .. 3]]
, [V2 x y | x <- [0, 1], y <- [0, 1]]
]
lottaRocks = 1000000000000
fallRock :: State -> State
fallRock state = State newCave newHeight newJets rs
where
(rock:rs) = rocks state
startPos = map (\a -> a + V2 2 (3 + height state)) rock
curCave = cave state
newCave = foldl (\a b -> insert b True a) curCave movedRock
newHeight =
max (height state) ((maximum . map (\(V2 _ y) -> y) $ movedRock) + 1)
(movedRock, newJets) = jetFall (startPos, jets state)
jetFall (s, j:js)
| isNothing . fall . jet j $ s = (jet j s, js)
| otherwise = jetFall (fromJust . fall . jet j $ s, js)
jet j s
| canjet = jetted
| otherwise = s
where
jetted = map (+ j) s
canjet =
all (\(V2 x _) -> x >= 0) jetted &&
all (\(V2 x _) -> x <= 6) jetted &&
all (\p -> isNothing . M.lookup p $ curCave) jetted
fall s
| canFall = Just fell
| otherwise = Nothing
where
fell = map (+ V2 0 (-1)) s
canFall =
all (\p -> isNothing . M.lookup p $ curCave) fell &&
all (\(V2 _ y) -> y >= 0) fell
patternHeight :: [State] -> Int -> Int
patternHeight states patLength =
height (states !! (1000 + patLength)) - height (states !! 1000)
predictHeight :: [State] -> Int -> Int -> Int
predictHeight states jetLength numRocks = prediction
where
patL =
findPattern
1000
1
(\a b ->
(head . rocks $ a) == (head . rocks $ b) &&
take jetLength (jets a) == take jetLength (jets b)) $
fromList states
patH = patternHeight states patL
toFall = numRocks - 1000
(times, remainder) = divMod toFall patL
supp = height (states !! (1000 + remainder))
prediction = times * patH + supp
jetsList :: String -> [Pos]
jetsList input =
cycle .
map
(\x ->
if x == '<'
then V2 (-1) 0
else V2 1 0) $
(input =~ "[<>]+")
part1 :: Bool -> String -> String
part1 _ input =
show . height . last . take 2023 . iterate fallRock $ initialState
where
initialState = State empty 0 (jetsList input) initialRocks
part2 :: Bool -> String -> String
part2 _ input = show $ predictHeight alot jetCycle lottaRocks
where
alot = take 10000 . iterate fallRock $ initialState
initialState = State empty 0 (jetsList input) initialRocks
jetCycle = length (input =~ "[<>]+" :: String)