-- |
-- Module      : AOC.Challenge.Day07
-- License     : BSD3
--
-- Stability   : experimental
-- Portability : non-portable
--
-- Day 7.  See "AOC.Solver" for the types used in this module!

module AOC.Challenge.Day07 (
    day07a
  , day07b
  ) where

import           AOC.Common.Intcode        (Memory, VM, IErr, untilHalt, stepForeverAndDie, parseMem, yieldAndDie, yieldAndPass)
import           AOC.Solver                ((:~>)(..))
import           AOC.Util                  (eitherToMaybe)
import           Control.Monad.Except      (MonadError)
import           Data.Conduino             ((.|), runPipePure, runPipe, awaitSurely, feedbackPipe)
import           Data.List                 (permutations)
import           Data.Semigroup            (Max(..))
import           Data.Void                 (Void)
import qualified Data.Conduino.Combinators as C

setupChain :: MonadError IErr m => Memory -> [Int] -> VM m Void
setupChain m = foldr ((.|) . prime) (C.map id)
  where
    prime i = yieldAndPass i
           .| stepForeverAndDie m

day07a :: Memory :~> Int
day07a = MkSol
    { sParse = parseMem
    , sShow  = show
    , sSolve = \m -> fmap getMax . flip foldMap (permutations [0..4]) $ \xs ->
        let res = runPipe $ yieldAndDie 0
                         .| setupChain m xs
                         .| awaitSurely
        in  Max <$> eitherToMaybe res
    }

day07b :: Memory :~> Int
day07b = MkSol
    { sParse = parseMem
    , sShow  = show
    , sSolve = \m -> fmap getMax . flip foldMap (permutations [5..9]) $ \xs ->
        let res = runPipePure $ untilHalt ( yieldAndDie 0
                                         .| feedbackPipe (setupChain m xs)
                                          )
                             .| C.last
        in  Max <$> res
    }