-
Notifications
You must be signed in to change notification settings - Fork 0
/
run.hs
86 lines (70 loc) · 2.24 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
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE TypeApplications #-}
import AoC
import AoC.Grid
import Data.Foldable
import Data.List
import Data.List.Split (splitOn)
import Data.Maybe
type TargetArea = (V2 Int, V2 Int)
-- TODO: Optimize, the bounds in the solution could be better.
-- TODO: Replace each V2 in the target area with Ix?
parseRange str =
case splitOn ".." (drop 2 str ) of
[l, h] -> v2 (read @Int l, read @Int h)
parse input =
case stripPrefix "target area: " (head . lines $ input) of
Just xy -> case splitOn ", " xy of
[x, y] -> (parseRange x, parseRange y)
inRange :: V2 Int -> Int -> Ordering
inRange (V2 (rl, rh)) p
| p < rl = LT
| p > rh = GT
| otherwise = EQ
status :: TargetArea -> V2 Int -> (Ordering, Ordering)
status (txr, tyr) (V2 (px, py)) = (inRange txr px, inRange tyr py)
step :: (V2 Int, V2 Int) -> (V2 Int, V2 Int)
step (vel@(V2 (vx, vy)), pos) =
(V2 (max 0 (vx - 1), vy - 1), pos + vel)
simulate :: V2 Int -> V2 Int -> TargetArea -> [(V2 Int, V2 Int)]
simulate vel pos target =
takeWhile (not . noReturn) $ iterate step (vel, pos)
where noReturn (v, p) =
case (v, status target p) of
(_, (GT, _)) -> True
(_, (_, LT)) -> True
(V2 (0, _), (LT, _)) -> True
_ -> False
reachesTarget :: TargetArea -> [(V2 Int, V2 Int)] -> Maybe (V2 Int, V2 Int)
reachesTarget target = find ((== (EQ, EQ)) . status target . snd)
part1 target@(trx, try) =
let maxx = maximum trx
minx = 0
maxy = 500
miny = 0
candidates = (,) <$> [minx..maxx] <*> [miny..maxy]
in
maximum
. map (\(_, V2 (_, y)) -> y)
. concat
. filter (isJust . reachesTarget target)
. map (\c -> simulate (v2 c) 0 target)
$ candidates
part2 target@(trx, try) =
let maxx = maximum trx
minx = 0
maxy = 500
miny = minimum try
candidates = (,) <$> [minx..maxx] <*> [miny..maxy]
in
length
. filter (isJust . reachesTarget target)
. map (\c -> simulate (v2 c) 0 target)
$ candidates
main = main' "input.txt"
exampleMain = main' "example.txt"
main' file = do
input <- parse <$> readFile file
print (part1 input)
print (part2 input)