41 lines
1.3 KiB
Haskell
Raw Normal View History

2025-12-03 11:18:04 +00:00
module Puzzles.Day3 (puzzle) where
2025-12-08 12:48:49 +00:00
import Pre
2025-12-03 14:39:39 +00:00
import Data.List.NonEmpty qualified as NE
2025-12-03 11:18:04 +00:00
puzzle :: Puzzle
puzzle =
Puzzle
{ number = 3
, parser = const $ (Bank <$> some1 digit) `sepEndBy` newline
2025-12-03 11:18:04 +00:00
, parts =
( sum
2025-12-03 17:13:47 +00:00
. map (digitsToInt . fromMaybe (error "battery list too short") . maxBatteries 2)
)
/\ ( sum
. map (digitsToInt . fromMaybe (error "battery list too short") . maxBatteries 12)
)
/\ nil
2025-12-04 21:16:46 +00:00
, extraTests = mempty
2025-12-03 11:18:04 +00:00
}
2025-12-03 14:39:39 +00:00
newtype Bank = Bank (NonEmpty Battery)
deriving newtype (Eq, Ord, Show, NFData)
2025-12-03 14:39:39 +00:00
newtype Battery = Battery Word8
deriving newtype (Eq, Ord, Show, Num, Enum, Real, Integral, NFData)
2025-12-03 14:39:39 +00:00
2025-12-03 17:13:47 +00:00
-- maximal n-digit subsequence
-- returns `Nothing` if list isn't long enough (>= n)
maxBatteries :: Int -> Bank -> Maybe [Battery]
2025-12-08 12:48:49 +00:00
maxBatteries n0 (Bank bs0) = flip unfoldrM (n0, toList bs0) \case
2025-12-03 17:13:47 +00:00
(0, _) -> pure Nothing
(n, bs) -> do
2025-12-19 15:56:04 +00:00
(i, b) <- findMax <$> nonEmpty (dropEnd (n - 1) bs)
2025-12-03 17:13:47 +00:00
pure $ Just (b, (n - 1, drop (i + 1) bs))
2025-12-03 14:39:39 +00:00
-- returns the leftmost element in case of a tie
2025-12-19 15:56:04 +00:00
findMax :: (Ord a) => NonEmpty a -> (Int, a)
findMax = maximumBy (comparing snd) . NE.reverse . NE.zip (0 :| [1 ..])