This repository was archived by the owner on Nov 17, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathDay10.hs
65 lines (58 loc) · 2.19 KB
/
Day10.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
-- |
-- Module : AOC.Challenge.Day10
-- License : BSD3
--
-- Stability : experimental
-- Portability : non-portable
--
-- Day 10. See "AOC.Solver" for the types used in this module!
module AOC.Challenge.Day10 (
day10a
, day10b
) where
import AOC.Common (Point, parseAsciiMap, maximumValNE, lineTo, drop')
import AOC.Solver ((:~>)(..))
import Control.Monad (guard)
import Data.Foldable (toList)
import Data.List (sortOn, unfoldr)
import Data.Maybe (listToMaybe)
import Data.Semigroup (Max(..))
import Data.Semigroup.Foldable (foldMap1)
import Data.Set.NonEmpty (NESet)
import Linear (V2(..))
import qualified Data.Map as M
import qualified Data.Map.NonEmpty as NEM
import qualified Data.Set.NonEmpty as NES
angleTo :: Point -> Point -> Double
angleTo p0 p1 = atan2 (-fromIntegral dx) (fromIntegral dy)
where
V2 dx dy = p1 - p0
viewableIn :: NESet Point -> Point -> [Point]
viewableIn s p = filter good . toList . NES.delete p $ s
where
good q = all (`NES.notMember` s) (lineTo p q)
day10a :: NESet Point :~> Int
day10a = MkSol
{ sParse = NES.nonEmptySet . M.keysSet . parseAsciiMap (\c -> guard (c == '#'))
, sShow = show
, sSolve = \as -> Just . getMax . foldMap1 (Max . length . viewableIn as) $ as
}
day10b :: NESet Point :~> Point
day10b = MkSol
{ sParse = NES.nonEmptySet . M.keysSet . parseAsciiMap (\c -> guard (c == '#'))
, sShow = \case V2 x y -> show $ x * 100 + y
, sSolve = \as ->
let (station, _) = maximumValNE $ NEM.fromSet (length . viewableIn as) as
as' = NES.delete station as
in listToMaybe . drop' 199 $
unfoldr (uncurry (shootFrom station)) (Nothing, as')
}
where
shootFrom p aim as = do
as' <- NES.nonEmptySet as
let targ:next:_ = dropper . cycle . sortOn (angleTo p) $ viewableIn as' p
pure (targ, (Just next, NES.delete targ as'))
where
dropper = case aim of
Nothing -> id
Just a -> dropWhile (/= a)