[hs] Solve 2020_15 part 2
This commit is contained in:
parent
26d2a1b9fd
commit
7746d81fde
1 changed files with 58 additions and 9 deletions
|
|
@ -1,8 +1,11 @@
|
|||
{-# LANGUAGE NumericUnderscores #-}
|
||||
{-# LANGUAGE Strict #-}
|
||||
|
||||
module Aoc.Y2020.D15
|
||||
( day
|
||||
) where
|
||||
|
||||
import Data.List
|
||||
import qualified Data.Map as Map
|
||||
|
||||
import Aoc.Day
|
||||
import Aoc.Parse
|
||||
|
|
@ -10,19 +13,65 @@ import Aoc.Parse
|
|||
parser :: Parser [Int]
|
||||
parser = (decimal `sepBy` char ',') <* newline
|
||||
|
||||
step :: [Int] -> [Int]
|
||||
step [] = error "list must not be empty"
|
||||
step (x:xs) = case elemIndex x xs of
|
||||
Nothing -> 0 : x : xs
|
||||
Just i -> (i + 1) : x : xs
|
||||
data State = State
|
||||
{ sIdx :: Int
|
||||
, sNum :: Int
|
||||
, sLastSeen :: Map.Map Int Int
|
||||
} deriving (Show)
|
||||
|
||||
stepUntil :: Int -> [Int] -> [Int]
|
||||
stepUntil amount nums = iterate step nums !! (amount - length nums)
|
||||
-- nums must not be empty
|
||||
newState :: [Int] -> State
|
||||
newState nums = State
|
||||
{ sIdx = length nums - 1
|
||||
, sNum = last nums
|
||||
, sLastSeen = Map.fromList $ zip (init nums) [0..]
|
||||
}
|
||||
|
||||
step :: State -> State
|
||||
step s =
|
||||
let newNum = case sLastSeen s Map.!? sNum s of
|
||||
Nothing -> 0
|
||||
Just idx -> sIdx s - idx
|
||||
in State
|
||||
{ sIdx = sIdx s + 1
|
||||
, sNum = newNum
|
||||
, sLastSeen = Map.insert (sNum s) (sIdx s) $ sLastSeen s
|
||||
}
|
||||
|
||||
replicateF :: Int -> (a -> a) -> a -> a
|
||||
replicateF n f a
|
||||
| n <= 0 = a
|
||||
| otherwise = replicateF (n - 1) f (f a)
|
||||
|
||||
stepUntil :: Int -> State -> IO State
|
||||
stepUntil amount s = stepUntilIo (amount - sIdx s - 1) s
|
||||
|
||||
-- | A Helper for stepUntil that prints how many steps are left in regular
|
||||
-- intervals. Don't call it directly.
|
||||
stepUntilIo :: Int -> State -> IO State
|
||||
stepUntilIo amount s | amount <= 0 = pure s
|
||||
stepUntilIo amount s = do
|
||||
putStrLn $ show amount ++ " left"
|
||||
let width = min amount 100_000
|
||||
stepUntilIo (amount - width) $ replicateF width step s
|
||||
|
||||
solver :: [Int] -> IO ()
|
||||
solver nums = do
|
||||
let s = newState nums
|
||||
|
||||
putStrLn ">> Part 1"
|
||||
print $ head $ stepUntil 2020 $ reverse nums
|
||||
p1 <- sNum <$> stepUntil 2020 s
|
||||
print p1
|
||||
|
||||
putStrLn ""
|
||||
putStrLn ">> Part 2"
|
||||
p2 <- sNum <$> stepUntil 30_000_000 s
|
||||
print p2
|
||||
|
||||
putStrLn ""
|
||||
putStrLn ">> Summary"
|
||||
putStrLn $ "Part 1: " ++ show p1
|
||||
putStrLn $ "Part 2: " ++ show p2
|
||||
|
||||
day :: Day
|
||||
day = dayParse parser solver
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue