@ -0,0 +1,55 @@ | |||
module Intcode | |||
( parseProg | |||
, compute | |||
, computeTilHalt | |||
, startingState | |||
) where | |||
import Data.List as List | |||
import Data.Maybe | |||
import Data.Ord | |||
import Data.List.Split | |||
import qualified Data.Map.Strict as Map | |||
parseProg :: String -> Map.Map Int Int | |||
parseProg str = Map.fromList $ List.zip [0..] $ map (read :: String -> Int) $ splitOn "," str | |||
compute :: (Map.Map Int Int, Int, Int) -> ([Int], [Int]) -> ((Map.Map Int Int, Int, Int), ([Int], [Int])) | |||
compute (x, y, z) (input_orig, output) = | |||
if op == 99 | |||
then ((x, -1, z), (input_orig, output)) | |||
else if op == 1 || op == 2 | |||
then compute ((Map.insert dest ((if op == 1 then (+) else (*)) left right) x), (y+4), z) (input_orig, output) | |||
else if op == 3 | |||
then compute ((Map.insert dest input x), (y+2), z) (inputs, output) | |||
else if op == 4 | |||
then ((x, y+2, z), (input_orig, (left:output))) | |||
else if op == 5 || op == 6 | |||
then compute (x, (if (if op == 5 then (/=) else (==)) left 0 then right else (y+3)), z) (input_orig, output) | |||
else if op == 7 || op == 8 | |||
then compute ((Map.insert dest (if (if op == 7 then (<) else (==)) left right then 1 else 0) x), (y+4), z) (input_orig, output) | |||
else if op == 9 | |||
then compute (x, y+2, z+left) (input_orig, output) | |||
else | |||
((Map.empty, -1, z), (input_orig, output)) | |||
where | |||
(input:inputs) = if Prelude.length input_orig > 0 then input_orig else (0:input_orig) | |||
indexOfIndex y = Map.findWithDefault 0 (x Map.! y) x | |||
digits = Prelude.reverse $ Prelude.map (read . return) $ show $ x Map.! y | |||
op = (if Prelude.length digits > 1 then 10 * digits!!1 else 0) + digits!!0 | |||
left = if Prelude.length digits > 2 && digits!!2 == 1 then x Map.! (y+1) | |||
else if Prelude.length digits > 2 && digits!!2 == 2 then x Map.! (z+(x Map.! (y+1))) | |||
else indexOfIndex (y+1) | |||
right = if Prelude.length digits > 3 && digits!!3 == 1 then x Map.! (y+2) | |||
else if Prelude.length digits > 3 && digits!!3 == 2 then x Map.! (z+(x Map.! (y+2))) | |||
else indexOfIndex (y+2) | |||
dest = if op == 3 then (if Prelude.length digits > 2 && digits!!2 == 2 then z+(x Map.! (y+1)) else x Map.! (y+1)) | |||
else (if Prelude.length digits > 4 && digits!!4 == 2 then z else 0)+(x Map.! (y+3)) | |||
computeTilHalt :: ((Map.Map Int Int, Int, Int), ([Int], [Int])) -> [Int] | |||
computeTilHalt ((prog, y, z), (inputs, outputs)) = | |||
if y == -1 then outputs | |||
else computeTilHalt $ compute (prog, y, z) (inputs, outputs) | |||
startingState :: Map.Map Int Int -> [Int] -> ((Map.Map Int Int, Int, Int), ([Int], [Int])) | |||
startingState prog input = ((prog, 0, 0), (input, [])) |
@ -1,47 +1,24 @@ | |||
import System.Environment | |||
import Data.List.Split | |||
import Data.Sequence | |||
import qualified Data.Map.Strict as Map | |||
parse :: String -> Seq Int | |||
parse = fromList . map (read :: String -> Int) . splitOn "," | |||
import Intcode | |||
compute :: Seq Int -> Int -> Seq Int | |||
compute x y = do | |||
let op = x `index` y | |||
let indexOfIndex y = index x $ index x y | |||
let left = indexOfIndex (y+1) | |||
let right = indexOfIndex (y+2) | |||
if op == 99 | |||
then x | |||
else if op /= 1 && op /= 2 | |||
then fromList [] | |||
else | |||
compute (update (x `index` (y+3)) ((if op == 1 then (+) else (*)) left right) x) (y+4) | |||
computeTilHalt2 :: ((Map.Map Int Int, Int, Int), ([Int], [Int])) -> Int | |||
computeTilHalt2 ((prog, y, z), io) = | |||
if y == -1 then prog Map.! 0 | |||
else computeTilHalt2 $ compute (prog, y, z) io | |||
-- Brute force to find answer based on any array input and any desired answer | |||
findParamsBrute :: Seq Int -> Int -> [Int] -> Int | |||
findParamsBrute x y [p1,p2] = do | |||
let computed = compute (update 1 p1 $ update 2 p2 x) 0 | |||
let ans = computed `index` 0 | |||
if y == ans | |||
then 100*p1 + p2 | |||
else if ans > y | |||
then -1 | |||
else if y `mod` 1000 > ans `mod` 1000 | |||
then findParamsBrute x y [p1, p2 + 1] | |||
else | |||
findParamsBrute x y [p1+1, p2] | |||
-- Use the gradients of each parameter in the goal to calculate the answer in O(1) | |||
findParams :: Int -> Int | |||
findParams goal = do | |||
let first = (goal-493708) `div` 243000 | |||
let second = goal - 493708 - 243000*first | |||
100*first + second | |||
findParams goal = 100*first + second | |||
where | |||
first = (goal-493708) `div` 243000 | |||
second = goal - 493708 - 243000*first | |||
main = do | |||
input <- getArgs | |||
let x = parse $ input!!0 | |||
print $ (x `compute` 0) `index` 0 | |||
let parsed = parseProg $ input!!0 | |||
let map = Map.insert 1 12 parsed | |||
let newMap = Map.insert 2 2 map | |||
print $ computeTilHalt2 $ startingState newMap [] | |||
print $ findParams 19690720 |
@ -1,3 +1,3 @@ | |||
#!/bin/sh | |||
runhaskell answer.hs `< input` | |||
runhaskell -i$(dirname $(pwd))/00-utils answer.hs `< input` |
@ -1,43 +1,10 @@ | |||
import Data.Sequence | |||
import System.Environment | |||
import Data.List.Split | |||
parse :: String -> Seq Int | |||
parse = fromList . map (read :: String -> Int) . splitOn "," | |||
revDigits :: Int -> [Int] | |||
revDigits = Prelude.reverse . Prelude.map (read . return) . show | |||
compute :: Seq Int -> Int -> IO (Seq Int) | |||
compute x y = do | |||
let indexOfIndex y = index x $ index x y | |||
let digits = revDigits $ x `index` y | |||
let op = (if Prelude.length digits > 1 then 10 * digits!!1 else 0) + digits!!0 | |||
let left = if Prelude.length digits > 2 && digits!!2 == 1 then x `index` (y+1) else indexOfIndex (y+1) | |||
let right = if Prelude.length digits > 3 && digits!!3 == 1 then x `index` (y+2) else indexOfIndex (y+2) | |||
let dest = if op == 3 then x `index` (y+1) else x `index` (y+3) | |||
if op == 99 | |||
then return (x) | |||
else if op == 1 || op == 2 | |||
then compute (update dest ((if op == 1 then (+) else (*)) left right) x) (y+4) | |||
else if op == 3 | |||
then do | |||
print "Input:" | |||
input <- getLine | |||
compute (update dest (read input::Int) x) (y+2) | |||
else if op == 4 | |||
then do | |||
print "Output:" | |||
print left | |||
compute x (y+2) | |||
else if op == 5 || op == 6 | |||
then compute x (if (if op == 5 then (/=) else (==)) left 0 then right else (y+3)) | |||
else if op == 7 || op == 8 | |||
then compute (update dest (if (if op == 7 then (<) else (==))left right then 1 else 0) x) (y+4) | |||
else | |||
return (fromList []) | |||
import Intcode | |||
main = do | |||
input <- getArgs | |||
let x = parse $ input!!0 | |||
x `compute` 0 >>= print | |||
let parsed = parseProg $ input!!0 | |||
print $ flip (!!) 0 $ computeTilHalt $ startingState parsed [1] | |||
print $ flip (!!) 0 $ computeTilHalt $ startingState parsed [5] |
@ -1,3 +1,3 @@ | |||
#!/bin/sh | |||
runhaskell answer.hs `< input` | |||
runhaskell -i$(dirname $(pwd))/00-utils answer.hs `< input` |
@ -1,3 +1,3 @@ | |||
#!/bin/sh | |||
runhaskell answer.hs `< input` | |||
runhaskell -i$(dirname $(pwd))/00-utils answer.hs `< input` |
@ -1,71 +1,14 @@ | |||
import System.Environment | |||
import Data.Sequence | |||
import Data.List | |||
import Data.List.Split | |||
import Data.Ord | |||
import qualified Data.Map.Strict as Map | |||
parse :: String -> Seq Int | |||
parse = fromList . map (read :: String -> Int) . splitOn "," | |||
revDigits :: Int -> [Int] | |||
revDigits = Prelude.reverse . Prelude.map (read . return) . show | |||
extendSeq :: Int -> Seq Int -> Seq Int | |||
extendSeq x input = input >< (fromList $ Prelude.take x (repeat 0)) | |||
compute :: (Seq Int, Int, Int) -> ([Int], [Int]) -> ((Seq Int, Int, Int), ([Int], [Int])) | |||
compute (x, y, z) (input_orig, output) = do | |||
let (input:inputs) = if Prelude.length input_orig > 0 then input_orig else (0:input_orig) | |||
let indexOfIndex y = index x $ index x y | |||
let digits = revDigits $ x `index` y | |||
let op = (if Prelude.length digits > 1 then 10 * digits!!1 else 0) + digits!!0 | |||
let left = if Prelude.length digits > 2 && digits!!2 == 1 then x `index` (y+1) else if Prelude.length digits > 2 && digits!!2 == 2 then x `index` (z+(x `index` (y+1))) else indexOfIndex (y+1) | |||
let right = if Prelude.length digits > 3 && digits!!3 == 1 then x `index` (y+2) else if Prelude.length digits > 3 && digits!!3 == 2 then x `index` (z+(x `index` (y+2))) else indexOfIndex (y+2) | |||
let dest = if op == 3 then (if digits!!2 == 2 then z+(x `index` (y+1)) else x `index` (y+1)) else (if Prelude.length digits > 4 && digits!!4 == 2 then z else 0)+(x `index` (y+3)) | |||
let newX = if dest+1 > Data.Sequence.length x then extendSeq ((dest+1)-(Data.Sequence.length x)) x else x | |||
if op == 99 | |||
then ((newX, -1, z), (input_orig, output)) | |||
else if op == 1 || op == 2 | |||
then compute ((update dest ((if op == 1 then (+) else (*)) left right) newX), (y+4), z) (input_orig, output) | |||
else if op == 3 | |||
then compute ((update dest input newX), (y+2), z) (inputs, output) | |||
else if op == 4 | |||
then ((newX, y+2, z), (input_orig, (left:output))) | |||
else if op == 5 || op == 6 | |||
then compute (newX, (if (if op == 5 then (/=) else (==)) left 0 then right else (y+3)), z) (input_orig, output) | |||
else if op == 7 || op == 8 | |||
then compute ((update dest (if (if op == 7 then (<) else (==))left right then 1 else 0) newX), (y+4), z) (input_orig, output) | |||
else if op == 9 | |||
then compute (newX, y+2, z+left) (input_orig, output) | |||
else | |||
((fromList [], -1, z), (input_orig, output)) | |||
startingState :: Seq Int -> [Int] -> [Int] -> Seq ((Seq Int, Int, Int), ([Int], [Int])) | |||
startingState prog comps inps = do | |||
let out = fromList $ map (\i -> ((prog, 0, 0), ([i], []))) comps | |||
let (prog, (input, output)) = out `index` 0 | |||
update 0 (prog, (input ++ inps, output)) out | |||
runSeries :: Seq ((Seq Int, Int, Int), ([Int], [Int])) -> [Int] -> Int -> [Int] | |||
runSeries states comps idx = do | |||
let (prog, (newInput, newOutput:outputs)) = uncurry compute $ index states idx | |||
let newStates = update idx (prog, (newInput, newOutput:outputs)) states | |||
let newIdx = if idx+1 == Data.List.length comps then 0 else idx+1 | |||
let ((nextProg, nextY, nextZ), (nextInput, nextOutput)) = index newStates newIdx | |||
if nextY == -1 | |||
then (newOutput:outputs) | |||
else | |||
runSeries (update newIdx ((nextProg, nextY, nextZ), (nextInput ++ [newOutput], nextOutput)) newStates) comps newIdx | |||
runSingle :: Seq Int -> [Int] -> [Int] | |||
runSingle prog inputs = runSeries (startingState prog inputs []) [0] 0 | |||
findMax :: Seq Int -> [[Int]] -> ([Int], Int) | |||
findMax prog comps = maximumBy (comparing snd) $ map (\i -> (i, (runSeries (startingState prog i [0]) i 0)!!0)) comps | |||
import Intcode | |||
main = do | |||
input <- getArgs | |||
let x = parse $ input!!0 | |||
let parsed = parseProg $ input!!0 | |||
print $ runSingle x [1] | |||
print $ runSingle x [2] | |||
print $ flip (!!) 0 $ computeTilHalt $ startingState parsed [1] | |||
print $ flip (!!) 0 $ computeTilHalt $ startingState parsed [2] |
@ -1,3 +1,3 @@ | |||
#!/bin/sh | |||
runhaskell answer.hs `< input` | |||
runhaskell -i$(dirname $(pwd))/00-utils answer.hs `< input` |
@ -1,3 +1,3 @@ | |||
#!/bin/sh | |||
runhaskell answer.hs `< input` | |||
runhaskell -i$(dirname $(pwd))/00-utils answer.hs `< input` |
@ -1,3 +1,3 @@ | |||
#!/bin/sh | |||
runhaskell answer.hs `< input` | |||
runhaskell -i$(dirname $(pwd))/00-utils answer.hs `< input` |
@ -1,3 +1,3 @@ | |||
#!/bin/sh | |||
runhaskell answer.hs `< input` | |||
runhaskell -i$(dirname $(pwd))/00-utils answer.hs `< input` |