{-# Language QuasiQuotes #-}
{-|
Module      : Main
Description : Day 2 solution
Copyright   : (c) Eric Mertens, 2019
License     : ISC
Maintainer  : emertens@gmail.com

<https://adventofcode.com/2019/day/2>

-}
module Main (main) where

import Advent.Format (format)
import Intcode

-- | >>> :main
-- 7210630
-- 3892
main :: IO ()
IO ()
main =
  do Machine
pgm <- [Int] -> Machine
new ([Int] -> Machine) -> IO [Int] -> IO Machine
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [format|2019 2 %d&,%n|]
     Int -> IO ()
forall a. Show a => a -> IO ()
print (Int -> Int -> Machine -> Int
startup Int
12 Int
2 Machine
pgm)
     Int -> IO ()
forall a. Show a => a -> IO ()
print ([Int] -> Int
forall a. HasCallStack => [a] -> a
head [ Int
100 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
noun Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
verb
                 | Int
noun <- [Int
0..Int
99]
                 , Int
verb <- [Int
0..Int
99]
                 , Int -> Int -> Machine -> Int
startup Int
noun Int
verb Machine
pgm Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
19690720 ])

-- | Run the given program after assigning the given noun and verb.
startup :: Int {- ^ noun -} -> Int {- ^ verb -} -> Machine -> Int
startup :: Int -> Int -> Machine -> Int
startup Int
noun Int
verb
  = (Machine -> Int -> Int
! Int
0)
  (Machine -> Int) -> (Machine -> Machine) -> Machine -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Machine -> Machine
runPgm
  (Machine -> Machine) -> (Machine -> Machine) -> Machine -> Machine
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Int -> Machine -> Machine
set Int
1 Int
noun
  (Machine -> Machine) -> (Machine -> Machine) -> Machine -> Machine
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Int -> Machine -> Machine
set Int
2 Int
verb

-- | Run the given program starting at the given program counter
-- returning the initial memory value once the program halts.
--
-- >>> let check = memoryList . runPgm . new
-- >>> check [1,0,0,0,99]
-- [2,0,0,0,99]
-- >>> check [2,3,0,3,99]
-- [2,3,0,6,99]
-- >>> check [2,4,4,5,99,0]
-- [2,4,4,5,99,9801]
-- >>> check [1,1,1,4,99,5,6,0,99]
-- [30,1,1,4,2,5,6,0,99]
-- >>> check [1,9,10,3,2,3,11,0,99,30,40,50]
-- [3500,9,10,70,2,3,11,0,99,30,40,50]
runPgm :: Machine -> Machine
runPgm :: Machine -> Machine
runPgm Machine
mach =
  case Machine -> Step
step Machine
mach of
    Step Machine
mach'     -> Machine -> Machine
runPgm Machine
mach'
    Step
StepHalt       -> Machine
mach
    Step
_              -> String -> Machine
forall a. HasCallStack => String -> a
error String
"Unexpected step on day 2"