Done day 24 part 1
authorNeil Smith <NeilNjae@users.noreply.github.com>
Thu, 26 Dec 2024 10:03:17 +0000 (10:03 +0000)
committerNeil Smith <NeilNjae@users.noreply.github.com>
Thu, 26 Dec 2024 10:03:17 +0000 (10:03 +0000)
advent24/Main.hs [new file with mode: 0644]
adventofcode24.cabal

diff --git a/advent24/Main.hs b/advent24/Main.hs
new file mode 100644 (file)
index 0000000..b33ddd0
--- /dev/null
@@ -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
index 0d0bc3218d23d52dfb50a4e606e8d94003a5768f..d582171abda9ad8c4a7c9107a74b94a8549b867d 100644 (file)
@@ -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