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
    }