Files
adventofcode-2019/day02/Day02.hs

82 lines
2.7 KiB
Haskell
Raw Normal View History

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)
-}