Skip to content

Commit fd2c94c

Browse files
committed
refactor(2020.15-haskell): adopt advent-of-code-api, break partTwo
1 parent 1aa29ce commit fd2c94c

File tree

3 files changed

+70
-38
lines changed

3 files changed

+70
-38
lines changed

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2024.7.2.86
1+
2024.7.2.87

src/AdventOfCode/Puzzle.hs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,6 @@ evalPuzzle input initialState =
4747

4848
evaluatingPuzzle :: (MonadIO m, Monoid s) => Puzzle r s a -> r -> m a
4949
evaluatingPuzzle puzzle input = evalPuzzle input mempty puzzle
50+
51+
withPuzzle :: (r' -> r) -> Puzzle r s a -> Puzzle r' s a
52+
withPuzzle f puzzle = Puzzle $ withReaderT f (runPuzzle puzzle)

src/AdventOfCode/Year2020/Day15.hs

Lines changed: 66 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
{-# LANGUAGE BlockArguments #-}
2+
{-# LANGUAGE OverloadedStrings #-}
3+
{-# LANGUAGE StrictData #-}
4+
{-# LANGUAGE NoImplicitPrelude #-}
5+
16
module AdventOfCode.Year2020.Day15
27
( main,
38
getInput,
@@ -6,47 +11,71 @@ module AdventOfCode.Year2020.Day15
611
)
712
where
813

9-
import Control.Monad.State (State, evalState, execState, get, put)
10-
import Data.IntMap (IntMap)
11-
import Data.IntMap qualified as IM
14+
import AdventOfCode.Input (parseInputAoC)
15+
import AdventOfCode.Puzzle
16+
import Control.Lens (makeLenses, use, uses, (%=), (+=), (.=), (<~))
17+
import Control.Monad.Logger (logDebug)
18+
import Data.IntMap qualified as IntMap
19+
import Relude
20+
import Text.Printf (printf)
21+
import Text.Trifecta (commaSep, natural)
22+
23+
data PuzzleState
24+
= PuzzleState
25+
{ _numbersToSay :: NonEmpty Int,
26+
_turn :: Int,
27+
_spokenNumbers :: IntMap Int
28+
}
29+
deriving (Eq, Generic, Show)
30+
31+
makeLenses ''PuzzleState
32+
33+
mkState :: NonEmpty Int -> PuzzleState
34+
mkState input = PuzzleState input 0 IntMap.empty
1235

1336
main :: IO ()
1437
main =
15-
do
16-
input <- getInput
17-
putStr "Part One: "
18-
print (partOne input)
19-
putStr "Part Two: "
20-
print (partTwo input)
38+
getInput <&> (id &&& mkState) >>= \(input, initialState) ->
39+
evalPuzzle input initialState do
40+
putStr "Part One: "
41+
print =<< partOne
42+
putStr "Part Two: "
43+
print =<< partTwo
2144

22-
getInput :: IO [Int]
23-
getInput = pure [0, 14, 1, 3, 7, 9]
45+
getInput :: IO (NonEmpty Int)
46+
getInput = fromList <$> parseInputAoC 2020 15 (commaSep posInt)
47+
where
48+
posInt = fromInteger <$> natural
2449

25-
partOne :: [Int] -> Int
50+
partOne :: Puzzle (NonEmpty Int) PuzzleState Int
2651
partOne = memoryGame 2020
2752

28-
partTwo :: [Int] -> Int
29-
partTwo = memoryGame 30000000
30-
31-
memoryGame :: Int -> [Int] -> Int
32-
memoryGame n input =
33-
evalState memoryRound $
34-
(!! pred n) $
35-
iterate (execState memoryRound) (input, 1, IM.empty)
36-
37-
memoryRound :: State ([Int], Int, IntMap Int) Int
38-
memoryRound =
39-
do
40-
(input, now, seen) <- get
41-
case input of
42-
[] -> put ([0], now, seen) *> memoryRound
43-
current : rest ->
44-
case IM.lookup current seen of
45-
Nothing ->
46-
do
47-
put (rest, now + 1, IM.insert current now seen)
48-
pure current
49-
Just before ->
50-
do
51-
put (now - before : rest, now + 1, IM.insert current now seen)
52-
pure current
53+
partTwo :: Puzzle (NonEmpty Int) PuzzleState Int
54+
partTwo = memoryGame 30_000_000
55+
56+
memoryGame :: Int -> Puzzle (NonEmpty Int) PuzzleState Int
57+
memoryGame n = loop <* (numbersToSay <~ ask)
58+
where
59+
loop = do
60+
turn += 1
61+
number <- withPuzzle (const (max 1 (n `div` 100))) memoryRound
62+
uses turn (== n) >>= bool loop (pure number)
63+
64+
memoryRound :: Puzzle Int PuzzleState Int
65+
memoryRound = do
66+
number :| numbers <- use numbersToSay
67+
uses spokenNumbers (IntMap.lookup number) >>= \case
68+
Just before ->
69+
numbersToSay <~ uses turn (subtract before >>> (:| numbers))
70+
Nothing ->
71+
numbersToSay .= fromMaybe (0 :| []) (nonEmpty numbers)
72+
say number
73+
74+
say :: Int -> Puzzle Int PuzzleState Int
75+
say number =
76+
use turn >>= \i -> do
77+
spokenNumbers %= IntMap.insert number i
78+
m <- ask
79+
when (i `mod` m == 0 || i `div` m >= 99)
80+
$ $(logDebug) (fromString (printf "%d: %d" i number))
81+
pure number

0 commit comments

Comments
 (0)