You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

115 lines
2.8KB

  1. {-# LANGUAGE FlexibleContexts #-}
  2. import qualified Data.Vector as V
  3. import Text.Parsec
  4. data Op = Acc Int
  5. | Jmp Int
  6. | Nop Int
  7. deriving Show
  8. main :: IO ()
  9. main = do
  10. raw <- readFile "day8.txt"
  11. let ops = V.fromList $ zip (repeat False)
  12. $ validate $ map (parse lineP []) $ lines raw
  13. ansA = solveA ops
  14. ansB = solveB ops
  15. in do
  16. putStrLn $ "day8a: " ++ (show ansA)
  17. putStrLn $ "day8b: " ++ (show ansB)
  18. solveA :: V.Vector (Bool, Op) -> Int
  19. solveA ops = runMachineA ops 0 0
  20. solveB :: V.Vector (Bool, Op) -> Int
  21. solveB ops = case testSwaps ops 0 of
  22. Nothing -> error "unsolvable?"
  23. Just x -> x
  24. runMachineA :: V.Vector (Bool, Op) -> Int -> Int -> Int
  25. runMachineA ops pc ac = do
  26. let (check,op) = ops V.! pc
  27. in case check of
  28. True -> ac
  29. _ -> do
  30. let nac = case op of
  31. (Acc x) -> ac + x
  32. _ -> ac
  33. npc = case op of
  34. (Jmp y) -> pc + y
  35. _ -> succ pc
  36. nops = ops V.// [(pc, (True, op))]
  37. in runMachineA nops npc nac
  38. swapOp :: V.Vector (Bool, Op) -> Int -> Maybe (V.Vector (Bool, Op))
  39. swapOp ops ind =
  40. case op of
  41. (Acc _) -> Nothing
  42. (Nop x) -> Just $ ops V.// [(ind, (check, Jmp x))]
  43. (Jmp x) -> Just $ ops V.// [(ind, (check, Nop x))]
  44. where
  45. (check,op) = ops V.! ind
  46. testSwaps :: V.Vector (Bool, Op) -> Int -> Maybe Int
  47. testSwaps ops ind
  48. | ind >= V.length ops = Nothing
  49. | otherwise =
  50. case res of
  51. Nothing -> testSwaps ops $ succ ind
  52. (Just nops) -> case (runMachineB nops 0 0) of
  53. Nothing -> testSwaps ops $ succ ind
  54. x -> x
  55. where
  56. res = swapOp ops ind
  57. runMachineB :: V.Vector (Bool, Op) -> Int -> Int -> Maybe Int
  58. runMachineB ops pc ac =
  59. if pc == V.length ops
  60. then Just ac
  61. else do
  62. let (check,op) = ops V.! pc
  63. in case check of
  64. True -> Nothing
  65. _ -> do
  66. let nac = case op of
  67. (Acc x) -> ac + x
  68. _ -> ac
  69. npc = case op of
  70. (Jmp y) -> pc + y
  71. _ -> succ pc
  72. nops = ops V.// [(pc, (True, op))]
  73. in runMachineB nops npc nac
  74. validate :: [Either ParseError Op] -> [Op]
  75. validate [] = []
  76. validate ((Left _):_) = error "invalid input"
  77. validate ((Right b):bs) = b:(validate bs)
  78. lineP :: Parsec String () Op
  79. lineP = do
  80. o <- opP
  81. whitespaces
  82. i <- intP
  83. whitespaces
  84. eof
  85. return $ o i
  86. intP :: Parsec String () Int
  87. intP = do
  88. s <- oneOf ['+','-']
  89. v <- many1 digit
  90. return $ (if s == '-' then -1 else 1) * (read v)
  91. opP :: Parsec String () (Int -> Op)
  92. opP = do
  93. o <- (string "acc") <|> (string "jmp") <|> (string "nop")
  94. case o of
  95. "acc" -> return Acc
  96. "jmp" -> return Jmp
  97. _ -> return Nop
  98. whitespaces :: Parsec String () String
  99. whitespaces = many $ char ' '