adventofcode-2020/day8/main.hs

99 lines
2.8 KiB
Haskell
Raw Normal View History

2020-12-08 21:26:09 +01:00
#! /usr/bin/env -S"ANSWER=42" nix-shell
#! nix-shell -p ghcid
2020-12-09 13:04:43 +01:00
#! nix-shell -p "haskellPackages.ghcWithPackages (p: with p; [pretty-simple vector containers])"
2020-12-09 18:59:35 +01:00
#! nix-shell -i "ghcid -c 'ghci' -T main"
2020-12-08 21:26:09 +01:00
2020-12-09 18:59:35 +01:00
{-# OPTIONS_GHC -Wall -Wincomplete-uni-patterns #-}
{-# OPTIONS_GHC -Wno-unused-top-binds #-}
2020-12-08 21:26:09 +01:00
{-# LANGUAGE OverloadedStrings #-}
2020-12-09 13:04:43 +01:00
import Text.Pretty.Simple
-- import Data.List.NonEmpty (NonEmpty(..))
-- import qualified Data.List.NonEmpty as NE
import Data.Vector (Vector)
import Debug.Trace (trace)
import Data.List (unfoldr)
2020-12-09 18:59:35 +01:00
import Data.IntMap.Strict (IntMap)
2020-12-09 13:04:43 +01:00
import qualified Data.Vector as V
2020-12-09 18:59:35 +01:00
import qualified Data.IntMap.Strict as M
2020-12-09 13:04:43 +01:00
data Op = OpNop
| OpJmp !Int
| OpAcc !Int
deriving (Show, Ord, Eq)
data VMState = VMRun
deriving (Show, Ord, Eq)
data VirtualMachine = VM
{ pgmCounter :: !Int
, pgmAccumulator :: !Int
, pgmInstructions :: Vector Op
, vmState :: VMState
}
deriving (Show, Ord, Eq)
initialVM :: Vector Op -> VirtualMachine
initialVM ins = VM 1 0 ins VMRun
stepVM :: VirtualMachine -> Maybe (VirtualMachine, VirtualMachine)
stepVM vm@(VM c a ins VMRun) = Just (vm, go (ins V.! (c-1)))
where
go OpNop = VM (c+1) a ins VMRun
go (OpJmp n) = VM (c+n) a ins VMRun
go (OpAcc n) = VM (c+1) (a+n) ins VMRun
exampleData :: [String]
exampleData =
[ "nop +0"
, "acc +1"
, "jmp +4"
, "acc +3"
, "jmp -3"
, "acc -99"
, "acc +1"
, "jmp -4"
, "acc +6"
]
vmFromInput :: [String] -> VirtualMachine
vmFromInput input = initialVM (ins input)
where
ins = V.fromList . (map (parseOp . (\(x,y)-> (x,tail y)) . break (== ' ')))
parseOp :: (String,String) -> Op
parseOp ("nop",_) = OpNop
parseOp ("acc",'+':s) = OpAcc (read s :: Int)
parseOp ("jmp",'+':s) = OpJmp (read s :: Int)
parseOp ("acc",s) = OpAcc (read s :: Int)
parseOp ("jmp",s) = OpJmp (read s :: Int)
parseOp s@_ = trace (show s) $ undefined
-- Find smallest looping prefix in list of Int, returns associated pgmAccumulator
solvePart1 :: VirtualMachine -> Int
2020-12-09 18:59:35 +01:00
solvePart1 vm0 =
snd . last $ shortestCycleOn $ (\vm -> (pgmCounter vm, pgmAccumulator vm)) <$> unfoldr stepVM vm0
2020-12-09 13:04:43 +01:00
2020-12-09 13:05:30 +01:00
-- Shortest cycle in [Int]
2020-12-09 18:59:35 +01:00
shortestCycle :: [Int] -> [Int]
shortestCycle ix = reverse $ go M.empty ix []
where
go :: (IntMap ()) -> [Int] -> [Int] -> [Int]
go mem (x:_ ) ys | (mem M.!? x) /= Nothing = ys
go mem (x:xs) ys | otherwise = go (M.insert x () mem) xs (x:ys)
go _ [] ys = ys
shortestCycleOn :: [(Int,Int)] -> [(Int,Int)]
shortestCycleOn tx = zip (shortestCycle cx) ax
where
(cx, ax) = unzip tx
2020-12-09 13:05:30 +01:00
2020-12-08 21:26:09 +01:00
main :: IO ()
main = do
putStrLn "Day 8 - Part 1"
2020-12-09 13:04:43 +01:00
putStrLn ":: Tests"
pPrint exampleData
putStrLn ":: Solving part 1"
2020-12-09 18:59:35 +01:00
pPrint $ solvePart1 (vmFromInput exampleData)
input <- lines <$> readFile "day8/input"
pPrint $ solvePart1 (vmFromInput input)