George Thomas 415055dcc2 Allow output types to vary for different parts of same day
For now this applies to Haskell only, and it may turn out to be tricky for the Rust implementation.

In practice, the limitation hasn't turned out to be important, and we could even go the other way and use `Integer` everywhere. This does however at least help with debugging, as well as just being conceptually right.

The `nil` and `(/\)` functions are intended to be overloaded to work for other list-like things in a later commit, and from there we will investigate using `OverloadedLists` and `RebindableSyntax` to recover standard list syntax, although there are probably limitations due to `(:)` being special.
2025-12-16 16:15:11 +00:00

46 lines
1.8 KiB
Haskell

module Puzzles.Day7 (puzzle) where
import Pre
import Data.IntMap qualified as IM
import Data.IntSet qualified as IS
puzzle :: Puzzle
puzzle =
Puzzle
{ number = 7
, parser = const do
line1 <- some $ (single '.' $> False) <|> (single 'S' $> True)
start <- maybe (fail "start not found") (pure . fst) $ find snd $ zip [0 ..] line1
void newline
rows <- (some $ (single '.' $> False) <|> (single '^' $> True)) `sepEndBy1` newline
let splitters = map (IS.fromList . map fst . filter snd . zip [0 ..]) rows
pure (start, splitters)
, parts =
( uncurry \start ->
flip execState (0 :: Int)
. foldlM
( \beams splitters ->
IS.fromList . concat <$> for (IS.toList beams) \x -> do
let hit = x `IS.member` splitters
when hit $ modify succ
pure if hit then [x - 1, x + 1] else [x]
)
(IS.singleton start)
)
/\ ( uncurry \start ->
sum
. map snd
. IM.toList
. foldl
( \beams splitters ->
IM.fromListWith (+) . concat $ flip map (IM.toList beams) \(x, n) -> do
let hit = x `IS.member` splitters
zip (if hit then [x - 1, x + 1] else [x]) (repeat n)
)
(IM.singleton start (1 :: Int))
)
/\ nil
, extraTests = mempty
}