82 lines
2.7 KiB
Haskell
82 lines
2.7 KiB
Haskell
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)
|
|
-}
|