2019-12-05 18:35:01 +01:00
import Data.List.Split
2019-12-05 20:56:16 +01:00
import Data.Char as Char
2019-12-05 18:35:01 +01:00
main = do
2019-12-05 23:40:54 +01:00
content <- getList <$> getContents
2019-12-06 00:29:41 +01:00
let input = [ 5 ]
2019-12-05 23:04:58 +01:00
let output = operation content content 0 input []
2019-12-05 19:11:49 +01:00
mapM putStrLn ( map show output )
2019-12-05 18:35:01 +01:00
getList :: String -> [ Int ]
getList = map read . splitOn " , "
changeInput :: [ Int ] -> Int -> Int -> [ Int ]
changeInput ( begin : _ : _ : input ) input1 input2 = [ begin ] ++ [ input1 ] ++ [ input2 ] ++ input
func :: [ Int ] -> Int -> Int -> Int
func xs x y = do
let input = changeInput xs x y
2019-12-05 19:11:49 +01:00
head ( compute input input 0 [] [] )
2019-12-05 18:35:01 +01:00
2019-12-05 19:11:49 +01:00
compute :: [ Int ] -> [ Int ] -> Int -> [ Int ] -> [ Int ] -> [ Int ]
2019-12-05 23:04:58 +01:00
compute ( 99 : _ ) state index input output = state
2019-12-05 19:11:49 +01:00
compute ( op : x : y : z : _ ) state index input output =
compute ( drop newindex state ) newstate newindex input output
2019-12-05 18:35:01 +01:00
where
sum = if op == 1 then
( state !! x ) + ( state !! y )
else
( state !! x ) * ( state !! y )
split = splitAt z state
newstate = ( fst split ) ++ [ sum ] ++ ( drop 1 ( snd split ) )
newindex = index + 4
2019-12-05 19:11:49 +01:00
operation :: [ Int ] -> [ Int ] -> Int -> [ Int ] -> [ Int ] -> [ Int ]
operation ( 99 : _ ) state index input output =
2019-12-05 23:40:54 +01:00
output
2019-12-05 20:56:16 +01:00
operation ( op : x : y : z : _ ) state index input output
2019-12-05 23:04:58 +01:00
| last ( digits op ) == 1 = do
let newindex = index + 4
let newstate = add ( fillup ( revertdigs op ) 5 ) x y z state
operation ( drop newindex newstate ) newstate newindex input output
| last ( digits op ) == 2 = do
let newindex = index + 4
let newstate = mult ( fillup ( revertdigs op ) 5 ) x y z state
operation ( drop newindex newstate ) newstate newindex input output
| last ( digits op ) == 3 = do
let newindex = index + 2
let newstate = put ( fillup ( revertdigs op ) 3 ) x ( head input ) state
let newinput = drop 1 input
operation ( drop newindex newstate ) newstate newindex newinput output
| last ( digits op ) == 4 = do
let newindex = index + 2
let newoutput = out ( fillup ( revertdigs op ) 3 ) output x state
let newinput = drop 1 input
operation ( drop newindex state ) state newindex input newoutput
2019-12-06 00:29:41 +01:00
| ( last ( digits op ) == 5 ) = do
let newindex = jumpif ( fillup ( revertdigs op ) 4 ) x y index state
operation ( drop newindex state ) state newindex input output
| ( last ( digits op ) == 6 ) = do
let newindex = jumpifnot ( fillup ( revertdigs op ) 4 ) x y index state
operation ( drop newindex state ) state newindex input output
| ( last ( digits op ) == 7 ) = do
let newindex = index + 4
let newstate = lessthan ( fillup ( revertdigs op ) 5 ) x y z state
operation ( drop newindex newstate ) newstate newindex input output
| ( last ( digits op ) == 8 ) = do
let newindex = index + 4
let newstate = equal ( fillup ( revertdigs op ) 5 ) x y z state
operation ( drop newindex newstate ) newstate newindex input output
2019-12-05 20:56:16 +01:00
add :: [ Int ] -> Int -> Int -> Int -> [ Int ] -> [ Int ]
2019-12-05 23:04:58 +01:00
add ( op1 : op2 : m1 : m2 : m3 : _ ) p1 p2 p3 state =
insert state sum p3
2019-12-05 20:56:16 +01:00
where
2019-12-05 23:04:58 +01:00
sum = ( getValue m1 p1 state ) + ( getValue m2 p2 state )
2019-12-05 20:56:16 +01:00
mult :: [ Int ] -> Int -> Int -> Int -> [ Int ] -> [ Int ]
2019-12-05 23:04:58 +01:00
mult ( op1 : op2 : m1 : m2 : m3 : _ ) p1 p2 p3 state =
insert state sum p3
2019-12-05 20:56:16 +01:00
where
2019-12-05 23:04:58 +01:00
sum = ( getValue m1 p1 state ) * ( getValue m2 p2 state )
2019-12-05 20:56:16 +01:00
2019-12-05 23:04:58 +01:00
put :: [ Int ] -> Int -> Int -> [ Int ] -> [ Int ]
put ( op1 : op2 : m1 : _ ) p1 input state =
insert state input p1
2019-12-05 20:56:16 +01:00
2019-12-05 23:04:58 +01:00
out :: [ Int ] -> [ Int ] -> Int -> [ Int ] -> [ Int ]
out ( op1 : op2 : m1 : _ ) output p1 state =
2019-12-05 23:40:54 +01:00
output ++ [ ( getValue m1 p1 state ) ]
2019-12-05 18:35:01 +01:00
2019-12-06 00:29:41 +01:00
jumpif :: [ Int ] -> Int -> Int -> Int -> [ Int ] -> Int
jumpif ( op1 : op2 : m1 : m2 : _ ) p1 p2 index state
| ( getValue m1 p1 state ) /= 0 = getValue m2 p2 state
| otherwise = index + 3
jumpifnot :: [ Int ] -> Int -> Int -> Int -> [ Int ] -> Int
jumpifnot ( op1 : op2 : m1 : m2 : _ ) p1 p2 index state
| ( getValue m1 p1 state ) == 0 = getValue m2 p2 state
| otherwise = index + 3
lessthan :: [ Int ] -> Int -> Int -> Int -> [ Int ] -> [ Int ]
lessthan ( op1 : op2 : m1 : m2 : m3 : _ ) p1 p2 p3 state
| ( getValue m1 p1 state ) < ( getValue m2 p2 state ) = insert state 1 p3
| otherwise = insert state 0 p3
equal :: [ Int ] -> Int -> Int -> Int -> [ Int ] -> [ Int ]
equal ( op1 : op2 : m1 : m2 : m3 : _ ) p1 p2 p3 state
| ( getValue m1 p1 state ) == ( getValue m2 p2 state ) = insert state 1 p3
| otherwise = insert state 0 p3
2019-12-05 18:35:01 +01:00
insert :: [ Int ] -> Int -> Int -> [ Int ]
insert xs value index = do
let split = splitAt index xs
( fst split ) ++ [ value ] ++ ( drop 1 ( snd split ) )
2019-12-05 20:56:16 +01:00
digits :: Int -> [ Int ]
digits = map Char . digitToInt . show
revertdigs :: Int -> [ Int ]
2019-12-05 23:04:58 +01:00
revertdigs 0 = []
revertdigs x = x ` mod ` 10 : revertdigs ( x ` div ` 10 )
2019-12-05 20:56:16 +01:00
fillup :: [ Int ] -> Int -> [ Int ]
2019-12-05 23:04:58 +01:00
fillup array x = array ++ ( replicate ( x - ( length array ) ) 0 )
2019-12-05 20:56:16 +01:00
getValue :: Int -> Int -> [ Int ] -> Int
getValue 0 index array = array !! index
getValue 1 index array = index