-
Notifications
You must be signed in to change notification settings - Fork 0
/
Day14.hs
111 lines (95 loc) · 2.93 KB
/
Day14.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
module Day14
( part1
, part2
) where
import Data.Bifunctor (bimap, first)
import Data.List (minimumBy, partition)
import Data.List.Split (chunksOf)
import Data.Maybe (fromJust)
import Data.Ord (comparing)
import Data.Text (Text)
import Data.Tuple (swap)
import Data.Vector (Vector, generate)
import Helpers.Parsers.Text (signedInts)
import Math.NumberTheory.Moduli.Chinese (chinese)
import Statistics.Sample (variance)
data Robot =
Robot X Y Dx Dy
deriving (Show, Ord, Eq)
type X = Int
type Y = Int
type Dx = Int
type Dy = Int
width test
| test = 11
| otherwise = 101
height test
| test = 7
| otherwise = 103
buildBot :: [Int] -> Robot
buildBot [x, y, dx, dy] = Robot x y dx dy
pos :: Robot -> (X, Y)
pos (Robot x y _ _) = (x, y)
botsAtSec :: Int -> Bool -> [Robot] -> [Robot]
botsAtSec sec test =
map
(\(Robot x y dx dy) ->
Robot
((x + sec * dx) `mod` width test)
((y + sec * dy) `mod` height test)
dx
dy)
chineseFindTree :: [Robot] -> String
chineseFindTree robots =
(render . botsAtSec treeSec False $ robots) ++ show treeSec
where
treeSec =
fst . fromJust . chinese (xSecond, width False) $ (ySecond, height False)
botSeconds = take 103 . map (map pos) . iterate (map second) $ robots
xSecond =
fst
. minimumBy (comparing (variance . snd))
. zip [0 ..]
. map
((\list -> generate (width False) (list !!))
. map (fromIntegral . fst))
$ botSeconds
ySecond =
fst
. minimumBy (comparing (variance . snd))
. zip [0 ..]
. map
((\list -> generate (height False) (list !!))
. map (fromIntegral . snd))
$ botSeconds
render :: [Robot] -> String
render bots =
unlines . chunksOf (width False)
$ [ if (x, y) `elem` map pos bots
then '#'
else '.'
| y <- [0 .. height False - 1]
, x <- [0 .. width False - 1]
]
second :: Robot -> Robot
second (Robot x y dx dy) =
Robot ((x + dx) `mod` width False) ((y + dy) `mod` height False) dx dy
part1 :: Bool -> Text -> String
part1 test =
show
. uncurry (*)
. bimap
(uncurry (*)
. bimap length length
. partition ((< div (height test) 2) . snd))
(uncurry (*)
. bimap length length
. partition ((< div (height test) 2) . snd))
. partition ((< div (width test) 2) . fst)
. filter (\(x, y) -> x /= div (width test) 2 && y /= div (height test) 2)
. map pos
. botsAtSec 100 test
. map buildBot
. signedInts
part2 :: Bool -> Text -> String
part2 _ = chineseFindTree . map buildBot . signedInts