From 9f2922fc6e59914f011560dbf02fd25814987abf Mon Sep 17 00:00:00 2001 From: Neil Smith Date: Thu, 26 Dec 2024 10:03:17 +0000 Subject: [PATCH] Done day 24 part 1 --- advent24/Main.hs | 95 ++++++++++++++++++++++++++++++++++++++++++++ adventofcode24.cabal | 5 +++ 2 files changed, 100 insertions(+) create mode 100644 advent24/Main.hs diff --git a/advent24/Main.hs b/advent24/Main.hs new file mode 100644 index 0000000..b33ddd0 --- /dev/null +++ b/advent24/Main.hs @@ -0,0 +1,95 @@ +-- Writeup at https://work.njae.me.uk/2024/12/25/advent-of-code-2024-day-23/ + +import AoC + +import Data.Text (Text) +import qualified Data.Text.IO as TIO +import Data.Attoparsec.Text hiding (take) +import Control.Applicative +import qualified Data.Map.Strict as M +import qualified Data.Set as S +import Data.List +import Data.Bits (xor, (.&.), (.|.), (.<<.)) + +type Wires = M.Map String Int + +data GateType = And | Or | Xor + deriving (Show, Eq) + +data Gate = Gate { gType :: GateType, inputs :: [String], output :: String } + deriving (Show, Eq) + +type Device = [Gate] + +main :: IO () +main = + do dataFileName <- getDataFileName + text <- TIO.readFile dataFileName + let (wires, device) = successfulParse text + -- print wires + -- print device + -- print $ simulate wires device + -- print $ wiresOutput $ simulate wires device + print $ part1 wires device + +part1 :: Wires -> Device -> Int +part1 wires device = wiresOutput $ simulate wires device + +simulate :: Wires -> Device -> Wires +simulate wires device = wires' + where (wires', []) = until (null . snd) simulateOnce (wires, device) + +simulateOnce :: (Wires, Device) -> (Wires, Device) +simulateOnce (wires, device) = (wires', remaining) + where + (run, remaining) = partition (canActivateGate wires) device + wires' = foldl simulateGate wires run + +canActivateGate :: Wires -> Gate -> Bool +canActivateGate wires gate = all (`M.member` wires) gate.inputs + +simulateGate :: Wires -> Gate -> Wires +simulateGate wires gate = M.insert gate.output result wires + where [i1, i2] = gate.inputs + result = case gate.gType of + And -> (wires M.! i1) .&. (wires M.! i2) + Or -> (wires M.! i1) .|. (wires M.! i2) + Xor -> (wires M.! i1) `xor` (wires M.! i2) + +isOutputWire :: String -> Bool +isOutputWire (x:_) = x == 'z' + +wiresOutput :: Wires -> Int +wiresOutput wires = M.foldlWithKey' go 0 outWires + where outWires = M.filterWithKey (\k _ -> isOutputWire k) wires + outShift w = read $ drop 1 w + go acc w v = acc .|. (v .<<. outShift w) + +-- parse the input file + +wiresDeviceP :: Parser (Wires, Device) +wiresP :: Parser Wires +wireP :: Parser (String, Int) +nameP :: Parser String +deviceP :: Parser Device +gateP :: Parser Gate +gateTypeP :: Parser GateType + +wiresDeviceP = (,) <$> wiresP <* endOfLine <* endOfLine <*> deviceP + +wiresP = M.fromList <$> wireP `sepBy` endOfLine +wireP = (,) <$> nameP <* string ": " <*> decimal + +nameP = many1 (letter <|> digit) + +deviceP = gateP `sepBy` endOfLine +gateP = gateify <$> nameP <* space <*> gateTypeP <* space <*> nameP <* string " -> " <*> nameP + where gateify i1 g i2 o = Gate g [i1, i2] o + +gateTypeP = (And <$ "AND") <|> (Or <$ "OR") <|> (Xor <$ "XOR") + +successfulParse :: Text -> (Wires, Device) +successfulParse input = + case parseOnly wiresDeviceP input of + Left _err -> (M.empty, []) -- TIO.putStr $ T.pack $ parseErrorPretty err + Right wiresDevice -> wiresDevice diff --git a/adventofcode24.cabal b/adventofcode24.cabal index 0d0bc32..d582171 100644 --- a/adventofcode24.cabal +++ b/adventofcode24.cabal @@ -218,3 +218,8 @@ executable advent23 import: warnings, common-extensions, build-directives, common-modules main-is: advent23/Main.hs build-depends: attoparsec, text, containers, combinatorial + +executable advent24 + import: warnings, common-extensions, build-directives, common-modules + main-is: advent24/Main.hs + build-depends: attoparsec, text, containers \ No newline at end of file -- 2.34.1