import Data.List import Data.List.Split main :: IO() main = do inputText <- getContents let program = map read $ splitOn "," inputText putStr "Part 1: " putStrLn $ show (part1 program) putStr "Part 2: " putStrLn $ show (part2 19690720 program) part1 :: [Int] -> Int part1 program = (runProgram program (12, 2)) !! 0 part2 :: Int -> [Int] -> Int part2 target program = do let testList = crossProduct [0..99] [0..99] let loadedProgram = runProgram program let solution = find (\(result, _) -> (result !! 0) == target) (map (\params -> (loadedProgram params, params)) testList) let (noun, verb) = case solution of Just (_, params) -> params Nothing -> error "could not find a solution" (noun * 100) + verb runProgram :: [Int] -> (Int, Int) -> [Int] runProgram program (noun, verb) = do let program' = (updateSlotAt 1 noun (updateSlotAt 2 verb program)) runProgram' 0 program' runProgram' :: Int -> [Int] -> [Int] runProgram' pc program = case program !! pc of 1 -> result 2 -> result 99 -> program _ -> error "bad opcode" where (op, in1, in2, out) = getOps pc program inValue1 = program !! in1 inValue2 = program !! in2 opResult = if op == 1 then inValue1 + inValue2 else inValue1 * inValue2 updatedProgram = updateSlotAt out opResult program result = runProgram' (pc + 4) updatedProgram updateSlotAt :: Int -> Int -> [Int] -> [Int] updateSlotAt n value program | n >= length program = error $ "bad program (tried to update at location " ++ (show n) ++ ")" | otherwise = do let (first, _ : trailing) = splitAt n program first ++ (value : trailing) getOps :: Int -> [Int] -> (Int, Int, Int, Int) getOps pc program = do let (ops, _) = splitAt (pc + 4) program case reverse ops of out : in2 : in1 : op : _ -> (op, in1, in2, out) _ -> error $ "bad program (tried to get values at location " ++ (show pc) ++ ")" crossProduct :: [a] -> [b] -> [(a, b)] crossProduct xs ys = [(x, y) | x <- xs, y <- ys] {- fmtProgram :: Int -> [Int] -> String fmtProgram hilight program = fmtProgram' hilight 0 program fmtProgram' :: Int -> Int -> [Int] -> String fmtProgram' _ _ [] = "" fmtProgram' hilight pc program = do --let (_, _, _, updates) = getOps pc program let (line, remaining) = splitAt 4 program let lineStr = if hilight == pc then "\ESC[47;1m" ++ (fmtLine line) ++ "\ESC[0m" else (fmtLine line) (show pc ) ++ " | " ++ lineStr ++ "\n" ++ (fmtProgram' hilight (pc + 4) remaining) fmtLine :: [Int] -> String fmtLine line = concat $ intersperse " " (map show line) -}