-- import Debug.Trace import Prelude hiding (round) import Control.Monad import Control.Monad.ST import Data.STRef import qualified Data.Vector.Unboxed.Mutable as V main :: IO () main = do let seed = [20, 0, 1, 11, 6, 3] -- print seed print $ part1 seed print $ part2 seed part1 seed = runGame seed 2020 part2 seed = runGame seed 30000000 zeroInt :: Int zeroInt = 0 seedGame seed historySize = do round <- newSTRef $ length seed word <- newSTRef $ last seed history <- V.replicate historySize zeroInt forM_ (zip (init seed) [1..]) $ \(t, s) -> V.write history t s return (round, word, history) runGame seed roundsNeeded = runST $ do (round, word, history) <- seedGame seed roundsNeeded gameStep roundsNeeded round word history readSTRef word gameStep :: Int -> STRef s Int -> STRef s Int -> V.MVector s Int -> ST s () gameStep targetRound round word history = do roundVal <- readSTRef round if roundVal == targetRound then return () else do wordVal <- readSTRef word wordH <- V.read history wordVal let word' = speakWord wordH roundVal V.write history wordVal roundVal modifySTRef round (+1) writeSTRef word word' gameStep targetRound round word history speakWord :: Int -> Int -> Int speakWord 0 _ = 0 speakWord prev now = now - prev