module AOC.Challenge.Day09 (
day09a
, day09b
) where
import AOC.Solver ((:~>)(..))
import Control.Lens (ix, (+~))
import Data.Bifunctor (second)
import Data.Function ((&))
import Data.List (foldl')
import Data.List.PointedList.Circular (PointedList(..))
import Data.Maybe (mapMaybe, fromJust)
import Text.Read (readMaybe)
import qualified Data.List.PointedList.Circular as PL
import qualified Data.Vector.Unboxed as V
place
:: Int
-> PointedList Int
-> (Int, PointedList Int)
place x l
| x `mod` 23 == 0
= let l' = PL.moveN (-7) l
toAdd = _focus l'
in (toAdd + x, fromJust (PL.deleteRight l'))
| otherwise
= (0, (PL.insertLeft x . PL.moveN 2) l)
run
:: Int
-> Int
-> V.Vector Int
run numPlayers maxPiece = fst
. foldl' go (V.replicate numPlayers 0, PL.singleton 0)
$ zip players toInsert
where
go (!scores, !tp) (!p, !i) = (scores & ix p +~ pts, tp')
where
(pts, tp') = place i tp
players = (`mod` numPlayers) <$> [0 ..]
toInsert = [1..maxPiece]
day09a :: (Int, Int) :~> Int
day09a = MkSol
{ sParse = parse
, sShow = show
, sSolve = Just . V.maximum . uncurry run
}
day09b :: _ :~> _
day09b = MkSol
{ sParse = parse
, sShow = show
, sSolve = Just . V.maximum . uncurry run . second (*100)
}
parse :: String -> Maybe (Int, Int)
parse xs = case mapMaybe readMaybe (words xs) of
[p, n] -> Just (p, n)
_ -> Nothing