From e9c419ab86387cb099da93f06bf493c524bcb35c Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Mon, 9 Dec 2019 23:50:42 +0100 Subject: [PATCH] Add 2019 day 7p1 and day 8 --- y2019/src/Day2.hs | 35 ++------------ y2019/src/Day5.hs | 105 ++--------------------------------------- y2019/src/Day7.hs | 30 ++++++++++++ y2019/src/Day8.hs | 44 +++++++++++++++++ y2019/src/DayPicker.hs | 4 ++ y2019/src/Intcode.hs | 101 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 188 insertions(+), 131 deletions(-) create mode 100644 y2019/src/Day7.hs create mode 100644 y2019/src/Day8.hs create mode 100644 y2019/src/Intcode.hs diff --git a/y2019/src/Day2.hs b/y2019/src/Day2.hs index dd5a53e..09a6a5a 100644 --- a/y2019/src/Day2.hs +++ b/y2019/src/Day2.hs @@ -1,36 +1,9 @@ -module Day2 - ( day2 - ) where +module Day2 (day2) where -import Data.List.Split - -replaceNth :: Int -> a -> [a] -> [a] -replaceNth _ _ [] = [] -replaceNth n newVal (x:xs) - | n == 0 = newVal:xs - | otherwise = x:replaceNth (n-1) newVal xs - -processInput :: [Int] -> Int -> [Int] -processInput input index - | opcode == 1 = let operand1 = input !! (input !! (index + 1)) - operand2 = input !! (input !! (index + 2)) - resultIndex = input !! (index + 3) - result = operand1 + operand2 - newInput = replaceNth resultIndex result input - in processInput newInput newIndex - | opcode == 2 = let operand1 = input !! (input !! (index + 1)) - operand2 = input !! (input !! (index + 2)) - resultIndex = input !! (index + 3) - result = operand1 * operand2 - newInput = replaceNth resultIndex result input - in processInput newInput newIndex - | opcode == 99 = input - | opcode > 0 = input - where opcode = input !! index - newIndex = index + 4 +import Intcode computeVerbNoun :: Int -> Int -> [Int] -> Int -computeVerbNoun noun verb input = (processInput newInput 0) !! 0 +computeVerbNoun noun verb input = (fst (computer [] newInput [] 0)) !! 0 where newInput = replaceNth 1 noun . replaceNth 2 verb $ input bruteforce :: Int -> Int -> [Int] -> Int -> Int @@ -46,7 +19,7 @@ day2 = do putStr "Enter input >" input <- getLine putStrLn "" - let intCodes = map (read :: String -> Int) (splitOn "," input) + let intCodes = parseProgram input putStr "Part 1: " print (computeVerbNoun 12 2 intCodes) diff --git a/y2019/src/Day5.hs b/y2019/src/Day5.hs index 3952974..9f4a9f3 100644 --- a/y2019/src/Day5.hs +++ b/y2019/src/Day5.hs @@ -1,101 +1,6 @@ -module Day5 (day5, computeOpCode) where +module Day5 (day5) where -import Data.List.Split --- import Debug.Trace -trace _ x = x - -replaceNth :: Int -> a -> [a] -> [a] -replaceNth _ _ [] = [] -replaceNth n newVal (x:xs) - | n == 0 = newVal:xs - | otherwise = x:replaceNth (n-1) newVal xs - --- computeOpCode: Take an INT and returns a tuple4: --- - Int = opcode --- - Subsequent bools = Mode of nth param (True = direct / False = pos mode) -computeOpCode :: Int -> (Int, Bool, Bool, Bool) -computeOpCode input = trace ("ComputeOpCode " ++ show input ++ " -> " ++ show result) result - where opcode = input `mod` 100 - digits = show input - len = length digits - firstParamMode = if len > 2 then (digits !! (len - 3)) == '1' else False - secondParamMode = if len > 3 then (digits !! (len - 4)) == '1' else False - thirdParamMode = if len > 4 then (digits !! (len - 5)) == '1' else False - result = (opcode, firstParamMode, secondParamMode, thirdParamMode) - -getValue :: [Int] -> (Int, Bool) -> Int -getValue _ (n, True) = n -getValue r (n, False) = r !! n - --- opcode 1 -opcodeAddition :: [Int] -> (Int, Int, Int) -> [Int] -opcodeAddition regs (operand1, operand2, resultIndex) = replaceNth resultIndex result regs - where result = operand1 + operand2 - --- opcode 2 -opcodeMultiplication :: [Int] -> (Int, Int, Int) -> [Int] -opcodeMultiplication regs (operand1, operand2, resultIndex) = replaceNth resultIndex result regs - where result = operand1 * operand2 - --- opcode 7 -opcodeLessThan :: [Int] -> (Int, Int, Int) -> [Int] -opcodeLessThan regs (operand1, operand2, resultIndex) = replaceNth resultIndex result regs - where result = if operand1 < operand2 then 1 else 0 - --- opcode 8 -opcodeEqual :: [Int] -> (Int, Int, Int) -> [Int] -opcodeEqual regs (operand1, operand2, resultIndex) = replaceNth resultIndex result regs - where result = if operand1 == operand2 then 1 else 0 - -processInput :: Int -> [Int] -> [Int] -> Int -> ([Int], [Int]) -processInput inputValue input output index - | opcode == 1 = let newInput = opcodeAddition input (p1, p2, p3) - p1 = getValue' (val1, mode1) - p2 = getValue' (val2, mode2) - p3 = getValue' (val3, True) - newIndex = index + 4 - in trace ("Opcode1 (add) (" ++ show p1 ++ ") + (" ++ show p2 ++ ") -> @" ++ show p3) processInput' newInput output newIndex - | opcode == 2 = let newInput = opcodeMultiplication input (p1, p2, p3) - p1 = getValue' (val1, mode1) - p2 = getValue' (val2, mode2) - p3 = getValue' (val3, True) - newIndex = index + 4 - in trace ("Opcode2 (mult) (" ++ show p1 ++ ") * (" ++ show p2 ++ ") -> @" ++ show p3) (processInput' newInput output newIndex) - | opcode == 3 = let newInput = replaceNth p1 inputValue input - p1 = getValue' (val1, True) - newIndex = index + 2 - in trace ("Opcode3 (read) (1) -> @" ++ show p1) processInput' newInput output newIndex - | opcode == 4 = let newOutput = p1:output - p1 = getValue' (val1, mode1) - newIndex = index + 2 - in trace ("Opcode4 (output) " ++ show p1) processInput' input newOutput newIndex - | opcode == 5 = let p1 = getValue' (val1, mode1) - p2 = getValue' (val2, mode2) - newIndex = if p1 /= 0 then p2 else index + 3 - in trace ("Opcode5 (jump-if-true) " ++ show p1 ++ " != 0 ? -> JMP @" ++ show p2) processInput' input output newIndex - | opcode == 6 = let p1 = getValue' (val1, mode1) - p2 = getValue' (val2, mode2) - newIndex = if p1 == 0 then p2 else index + 3 - in trace ("Opcode6 (jump-if-false) " ++ show p1 ++ " == 0 ? -> JMP @" ++ show p2) processInput' input output newIndex - | opcode == 7 = let p1 = getValue' (val1, mode1) - p2 = getValue' (val2, mode2) - p3 = getValue' (val3, True) - newInput = opcodeLessThan input (p1, p2, p3) - newIndex = index + 4 - in trace ("Opcode7 (less-than) " ++ show p1 ++ " < " ++ show p2 ++ " ? -> @" ++ show p3) processInput' newInput output newIndex - | opcode == 8 = let p1 = getValue' (val1, mode1) - p2 = getValue' (val2, mode2) - p3 = getValue' (val3, True) - newInput = opcodeEqual input (p1, p2, p3) - newIndex = index + 4 - in trace ("Opcode7 (equal) " ++ show p1 ++ " == " ++ show p2 ++ " ? -> @" ++ show p3) processInput' newInput output newIndex - | otherwise = (input, output) - where (opcode, mode1, mode2, mode3) = computeOpCode (input !! index) - getValue' = getValue input - val1 = input !! (index + 1) - val2 = input !! (index + 2) - val3 = input !! (index + 3) - processInput' = processInput inputValue +import Intcode day5 :: IO () day5 = do @@ -104,10 +9,10 @@ day5 = do input <- getLine putStrLn "" - let intCodes = map (read :: String -> Int) (splitOn "," input) + let intCodes = parseProgram input - let (_, outputP1) = processInput 1 intCodes [] 0 + let (_, outputP1) = computer [1] intCodes [] 0 putStrLn ("Part1: " ++ show (outputP1 !! 0)) - let (_, outputP2) = processInput 5 intCodes [] 0 + let (_, outputP2) = computer [5] intCodes [] 0 putStrLn ("Part2: " ++ show (outputP2 !! 0)) diff --git a/y2019/src/Day7.hs b/y2019/src/Day7.hs new file mode 100644 index 0000000..ba65c8e --- /dev/null +++ b/y2019/src/Day7.hs @@ -0,0 +1,30 @@ +module Day7 (day7) where + +import Data.List +import Intcode + +processProgram :: [Int] -> [Int] -> Int +processProgram program inputs = head outputs + where (_, outputs) = computer inputs program [] 0 + +chainProcesses :: [Int] -> [Int] -> Int -> Int +chainProcesses program (phase:phases) signal + | null phases = newSignal + | otherwise = chainProcesses program phases newSignal + where newSignal = processProgram program [phase, signal] + +testCombinations :: [Int] -> [([Int], Int)] +testCombinations program = map (\p -> (p, chainProcesses program p 0)) phasesPerm + where phasesPerm = permutations [0..4] + +day7 :: IO () +day7 = do + putStrLn $ "AoC 2019 day 7" + input <- getLine + + let program = parseProgram input + let combinations = testCombinations program + + let p1 = maximumBy (\(_, a) (_, b) -> compare a b) combinations + + putStrLn $ "Part 1: " ++ (show p1) diff --git a/y2019/src/Day8.hs b/y2019/src/Day8.hs new file mode 100644 index 0000000..36368d5 --- /dev/null +++ b/y2019/src/Day8.hs @@ -0,0 +1,44 @@ +module Day8 (day8) where + +import Data.List.Split +import Data.List + +width :: Int +width = 25 + +height :: Int +height = 6 + +buildLayers :: String -> Int -> Int -> [[Char]] +buildLayers "" _ _ = [] +buildLayers input w h = front:(buildLayers back w h) + where (front, back) = splitAt (w * h) input + +decodeLayers :: [String] -> String +decodeLayers layers = foldl decodeLayers' (replicate (width * height) '2') layers + where decodeLayers' acc layer = map (\(a, l) -> if a == '2' then l else a) (zip acc layer) + +day8 :: IO () +day8 = do + putStrLn $ "AoC 2019 day 8" + input <- getLine + + let layers = buildLayers input width height + + let countDigit d = length . (filter (== d)) + + let min0layer = minimumBy (\ a b -> (countDigit '0' a) `compare` (countDigit '0' b)) layers + + let p1nbOf1 = countDigit '1' min0layer + let p1nbOf2 = countDigit '2' min0layer + + putStrLn $ "Part 1: " ++ (show (p1nbOf1 * p1nbOf2)) + + putStrLn "Part 2:" + + let decoded = unlines (chunksOf width (decodeLayers layers)) + + let repl '0' = ' ' + repl '1' = '#' + repl c = c + in putStrLn $ map repl decoded diff --git a/y2019/src/DayPicker.hs b/y2019/src/DayPicker.hs index 952b0fe..25183e6 100644 --- a/y2019/src/DayPicker.hs +++ b/y2019/src/DayPicker.hs @@ -11,6 +11,8 @@ import Day3 import Day4 import Day5 import Day6 +import Day7 +import Day8 -- TODO Better way? load :: [String] -> IO () @@ -21,6 +23,8 @@ load ("3":_) = day3 load ("4":_) = day4 load ("5":_) = day5 load ("6":_) = day6 +load ("7":_) = day7 +load ("8":_) = day8 load _ = putStrLn "Unavailable date" dayPicker :: IO () diff --git a/y2019/src/Intcode.hs b/y2019/src/Intcode.hs new file mode 100644 index 0000000..a604f5c --- /dev/null +++ b/y2019/src/Intcode.hs @@ -0,0 +1,101 @@ +module Intcode (computer, parseProgram, replaceNth) where + +import Data.List.Split + +-- import Debug.Trace +trace _ x = x + +replaceNth :: Int -> a -> [a] -> [a] +replaceNth _ _ [] = [] +replaceNth n newVal (x:xs) + | n == 0 = newVal:xs + | otherwise = x:replaceNth (n-1) newVal xs + +-- computeOpCode: Take an INT and returns a tuple4: +-- - Int = opcode +-- - Subsequent bools = Mode of nth param (True = direct / False = pos mode) +computeOpCode :: Int -> (Int, Bool, Bool, Bool) +computeOpCode input = trace ("ComputeOpCode " ++ show input ++ " -> " ++ show result) result + where opcode = input `mod` 100 + digits = show input + len = length digits + firstParamMode = if len > 2 then (digits !! (len - 3)) == '1' else False + secondParamMode = if len > 3 then (digits !! (len - 4)) == '1' else False + thirdParamMode = if len > 4 then (digits !! (len - 5)) == '1' else False + result = (opcode, firstParamMode, secondParamMode, thirdParamMode) + +getValue :: [Int] -> (Int, Bool) -> Int +getValue _ (n, True) = n +getValue r (n, False) = r !! n + +-- opcode 1 +opcodeAddition :: [Int] -> (Int, Int, Int) -> [Int] +opcodeAddition regs (operand1, operand2, resultIndex) = replaceNth resultIndex result regs + where result = operand1 + operand2 + +-- opcode 2 +opcodeMultiplication :: [Int] -> (Int, Int, Int) -> [Int] +opcodeMultiplication regs (operand1, operand2, resultIndex) = replaceNth resultIndex result regs + where result = operand1 * operand2 + +-- opcode 7 +opcodeLessThan :: [Int] -> (Int, Int, Int) -> [Int] +opcodeLessThan regs (operand1, operand2, resultIndex) = replaceNth resultIndex result regs + where result = if operand1 < operand2 then 1 else 0 + +-- opcode 8 +opcodeEqual :: [Int] -> (Int, Int, Int) -> [Int] +opcodeEqual regs (operand1, operand2, resultIndex) = replaceNth resultIndex result regs + where result = if operand1 == operand2 then 1 else 0 + +computer :: [Int] -> [Int] -> [Int] -> Int -> ([Int], [Int]) +computer readValues input output index + | opcode == 1 = let newInput = opcodeAddition input (p1, p2, p3) + p1 = getValue' (val1, mode1) + p2 = getValue' (val2, mode2) + p3 = getValue' (val3, True) + newIndex = index + 4 + in trace ("Opcode1 (add) (" ++ show p1 ++ ") + (" ++ show p2 ++ ") -> @" ++ show p3) computer readValues newInput output newIndex + | opcode == 2 = let newInput = opcodeMultiplication input (p1, p2, p3) + p1 = getValue' (val1, mode1) + p2 = getValue' (val2, mode2) + p3 = getValue' (val3, True) + newIndex = index + 4 + in trace ("Opcode2 (mult) (" ++ show p1 ++ ") * (" ++ show p2 ++ ") -> @" ++ show p3) (computer readValues newInput output newIndex) + | opcode == 3 = let newInput = replaceNth p1 (head readValues) input + p1 = getValue' (val1, True) + newIndex = index + 2 + in trace ("Opcode3 (read) (1) -> @" ++ show p1) computer (tail readValues) newInput output newIndex + | opcode == 4 = let newOutput = p1:output + p1 = getValue' (val1, mode1) + newIndex = index + 2 + in trace ("Opcode4 (output) " ++ show p1) computer readValues input newOutput newIndex + | opcode == 5 = let p1 = getValue' (val1, mode1) + p2 = getValue' (val2, mode2) + newIndex = if p1 /= 0 then p2 else index + 3 + in trace ("Opcode5 (jump-if-true) " ++ show p1 ++ " != 0 ? -> JMP @" ++ show p2) computer readValues input output newIndex + | opcode == 6 = let p1 = getValue' (val1, mode1) + p2 = getValue' (val2, mode2) + newIndex = if p1 == 0 then p2 else index + 3 + in trace ("Opcode6 (jump-if-false) " ++ show p1 ++ " == 0 ? -> JMP @" ++ show p2) computer readValues input output newIndex + | opcode == 7 = let p1 = getValue' (val1, mode1) + p2 = getValue' (val2, mode2) + p3 = getValue' (val3, True) + newInput = opcodeLessThan input (p1, p2, p3) + newIndex = index + 4 + in trace ("Opcode7 (less-than) " ++ show p1 ++ " < " ++ show p2 ++ " ? -> @" ++ show p3) computer readValues newInput output newIndex + | opcode == 8 = let p1 = getValue' (val1, mode1) + p2 = getValue' (val2, mode2) + p3 = getValue' (val3, True) + newInput = opcodeEqual input (p1, p2, p3) + newIndex = index + 4 + in trace ("Opcode7 (equal) " ++ show p1 ++ " == " ++ show p2 ++ " ? -> @" ++ show p3) computer readValues newInput output newIndex + | otherwise = (input, output) + where (opcode, mode1, mode2, mode3) = computeOpCode (input !! index) + getValue' = getValue input + val1 = input !! (index + 1) + val2 = input !! (index + 2) + val3 = input !! (index + 3) + +parseProgram :: String -> [Int] +parseProgram input = map read (splitOn "," input)