Done day 3
[advent-of-code-22.git] / advent03 / Main.hs
1 -- Writeup at https://work.njae.me.uk/2022/12/03/advent-of-code-2022-day-3/
2
3 import System.Environment
4 import Data.Char
5 import qualified Data.Set as S
6 import Data.List
7 import Data.List.Split
8
9 type Contents = S.Set Char
10 data Rucksack = Rucksack String String deriving (Show, Eq)
11
12 main :: IO ()
13 main =
14 do dataFileName <- getDataFileName
15 text <- readFile dataFileName
16 let rucksacks = fmap mkRucksack $ lines text
17 print $ part1 rucksacks
18 print $ part2 rucksacks
19
20 getDataFileName :: IO String
21 getDataFileName =
22 do args <- getArgs
23 progName <- getProgName
24 let baseDataName = if null args
25 then progName
26 else head args
27 let dataFileName = "data/" ++ baseDataName ++ ".txt"
28 return dataFileName
29
30 part1 :: [Rucksack] -> Int
31 part1 = sum . fmap (priority . commonItem)
32
33 part2 :: [Rucksack] -> Int
34 part2 rucksacks = sum $ fmap priority badges
35 where groups = chunksOf 3 rucksacks
36 badges = fmap badgeOf groups
37
38 merge :: Rucksack -> Contents
39 merge (Rucksack contents1 contents2) =
40 S.union (S.fromList contents1) (S.fromList contents2)
41
42 badgeOf :: [Rucksack] -> Char
43 badgeOf rucksacks = S.findMin $ intersections (fmap merge rucksacks)
44
45 intersections :: [Contents] -> Contents
46 intersections sets = foldl1' S.intersection sets
47
48
49 mkRucksack :: String -> Rucksack
50 mkRucksack contents = Rucksack (take n contents) (drop n contents)
51 where n = length contents `div` 2
52
53 commonItem :: Rucksack -> Char
54 commonItem (Rucksack contents1 contents2) = S.findMin (c1 `S.intersection` c2)
55 where c1 = S.fromList contents1
56 c2 = S.fromList contents2
57
58 priority :: Char -> Int
59 priority item
60 | item >= 'a' = ord item - ord 'a' + 1
61 | otherwise = ord item - ord 'A' + 27