mirror of
https://github.com/mx42/adventofcode.git
synced 2026-01-14 05:49:52 +01:00
50 lines
2.1 KiB
Haskell
50 lines
2.1 KiB
Haskell
module Y2020.Day08 (y20day08) where
|
|
|
|
import Data.List
|
|
import Data.List.Split
|
|
import qualified Data.Map as M
|
|
|
|
data Instr = Acc Int | Jmp Int | Nop Int deriving (Show)
|
|
|
|
-- current offset, current acc, visited offsets
|
|
type State = (Int, Int, [Int])
|
|
|
|
runInstructions :: M.Map Int Instr -> State -> (Bool, Int)
|
|
runInstructions instr (cur, acc, visited)
|
|
| cur `elem` visited = (False, acc) -- looping
|
|
| cur `M.notMember` instr = (True, acc) -- terminated
|
|
| otherwise = runInstructions instr (newCur, newAcc, newVisited)
|
|
where newVisited = cur:visited
|
|
(newCur, newAcc) = case (instr M.! cur) of
|
|
Nop _ -> (cur + 1, acc)
|
|
Acc qty -> (cur + 1, acc + qty)
|
|
Jmp ofs -> (cur + ofs, acc)
|
|
|
|
parseInput :: String -> Instr
|
|
parseInput input
|
|
| "nop" `isPrefixOf` input = Nop nb
|
|
| "acc" `isPrefixOf` input = Acc nb
|
|
| "jmp" `isPrefixOf` input = Jmp nb
|
|
where nb = (sign raw_sign) 0 number :: Int
|
|
(raw_sign:raw_number) = (splitOn " " input) !! 1
|
|
sign '+' = (+)
|
|
sign '-' = (-)
|
|
number = read raw_number :: Int
|
|
|
|
testSwappedNopJmp :: M.Map Int Instr -> Int -> Int
|
|
testSwappedNopJmp original offset = case original M.! offset of
|
|
Acc _ -> next
|
|
Jmp qty -> resWithSwap (Nop qty)
|
|
Nop qty -> resWithSwap (Jmp qty)
|
|
where next = testSwappedNopJmp original (offset + 1)
|
|
resWithSwap swapped = case (runInstructions (swappedInput swapped) (0, 0, [])) of
|
|
(True, acc) -> acc
|
|
(False, _) -> next
|
|
swappedInput new = M.insert offset new original
|
|
|
|
y20day08 :: [String] -> (String, String)
|
|
y20day08 input = (part1, part2)
|
|
where part1 = show $ snd $ runInstructions ops (0, 0, [])
|
|
part2 = show $ testSwappedNopJmp ops 0
|
|
ops = M.fromList $ zip (iterate (+ 1) 0) $ map parseInput input
|