X-Git-Url: https://git.njae.me.uk/?a=blobdiff_plain;f=advent03%2FMain.hs;fp=advent03%2FMain.hs;h=409ca338c6cc396c83e41b9ab1be4b055582cf50;hb=4df30f4f37244271ea01f3e64c1fba6c36c20e94;hp=0000000000000000000000000000000000000000;hpb=ec5050108d9c636018dabb874aae6114ce59b5c2;p=advent-of-code-22.git

diff --git a/advent03/Main.hs b/advent03/Main.hs
new file mode 100644
index 0000000..409ca33
--- /dev/null
+++ b/advent03/Main.hs
@@ -0,0 +1,61 @@
+-- Writeup at https://work.njae.me.uk/2022/12/03/advent-of-code-2022-day-3/
+
+import System.Environment
+import Data.Char
+import qualified Data.Set as S
+import Data.List
+import Data.List.Split
+
+type Contents = S.Set Char
+data Rucksack = Rucksack String String deriving (Show, Eq)
+
+main :: IO ()
+main = 
+  do  dataFileName <- getDataFileName
+      text <- readFile dataFileName
+      let rucksacks = fmap mkRucksack $ lines text
+      print $ part1 rucksacks
+      print $ part2 rucksacks
+
+getDataFileName :: IO String
+getDataFileName =
+  do args <- getArgs
+     progName <- getProgName
+     let baseDataName =  if null args
+                         then progName
+                         else head args 
+     let dataFileName = "data/" ++ baseDataName ++ ".txt"
+     return dataFileName
+
+part1 :: [Rucksack] -> Int
+part1 = sum . fmap (priority . commonItem)
+
+part2 :: [Rucksack] -> Int
+part2 rucksacks = sum $ fmap priority badges
+  where groups = chunksOf 3 rucksacks
+        badges = fmap badgeOf groups
+
+merge :: Rucksack -> Contents
+merge (Rucksack contents1 contents2) = 
+  S.union (S.fromList contents1) (S.fromList contents2)
+
+badgeOf :: [Rucksack] -> Char
+badgeOf rucksacks = S.findMin $ intersections (fmap merge rucksacks)
+
+intersections :: [Contents] -> Contents
+intersections sets = foldl1' S.intersection sets
+
+
+mkRucksack :: String -> Rucksack
+mkRucksack contents = Rucksack (take n contents) (drop n contents)
+  where n = length contents `div` 2
+
+commonItem :: Rucksack -> Char
+commonItem (Rucksack contents1 contents2) = S.findMin (c1 `S.intersection` c2)
+  where c1 = S.fromList contents1
+        c2 = S.fromList contents2
+
+priority :: Char -> Int
+priority item 
+  | item >= 'a' = ord item - ord 'a' + 1
+  | otherwise = ord item - ord 'A' + 27