content: -- |
  -- Module      : AOC.Challenge.Day02
  -- License     : BSD3
  --
  -- Stability   : experimental
  -- Portability : non-portable
  --
  -- Day 2.  See "AOC.Solver" for the types used in this module!
  
  module AOC.Challenge.Day02 (
      day02a
    , day02b
    ) where
  
  import           AOC.Common.Intcode        (Memory(..), IErr(..), parseMem, stepForever)
  import           AOC.Common.Search         (binaryMinSearch)
  import           AOC.Solver                ((:~>)(..), dyno_)
  import           AOC.Util                  (eitherToMaybe)
  import           Control.Monad.Except      (throwError)
  import           Data.Conduino             (runPipe, (.|), (|.))
  import qualified Data.Conduino.Combinators as C
  import qualified Data.Map                  as M
  
  setMem :: Maybe Int -> Maybe Int -> Memory -> Memory
  setMem noun verb m = m { mRegs = maybe id (M.insert 2) verb
                                 . maybe id (M.insert 1) noun
                                 $ mRegs m
                         }
  
  
  runProg :: Memory -> Maybe Int
  runProg m = eitherToMaybe . runPipe $
          throwError IENoInput
       .| ((M.! 0) . mRegs <$> stepForever m)
       |. C.sinkNull
  
  day02a :: Memory :~> Int
  day02a = MkSol
      { sParse = parseMem
      , sShow  = show
      , sSolve = runProg
               . setMem (Just (dyno_ "noun" 12)) (Just (dyno_ "verb" 2))
      }
  
  day02b :: Memory :~> (Int, Int)
  day02b = MkSol
      { sParse = parseMem
      , sShow  = \(noun,verb) -> show $ noun * 100 + verb
      , sSolve = \m -> do
          -- for my code, noun makes big jumps and verb makes small ones
          -- search for noun first
          noun <- binaryMinSearch (\i ->
              (> Just moon) . runProg . setMem (Just (i + 1)) Nothing $ m
            ) 0 99
          let m' = setMem (Just noun) Nothing m
          -- search for verb next
          verb <- binaryMinSearch (\j ->
              (> Just moon) . runProg . setMem Nothing (Just (j + 1)) $ m'
            ) 0 99
          pure (noun, verb)
      }
    where
      moon = 19690720
  
  