Added writeup links
[advent-of-code-21.git] / advent03 / Main.hs
1 -- Writeup at https://work.njae.me.uk/2021/12/03/advent-of-code-2021-day-3/
2
3 import Data.List
4 import Data.Char
5
6 main :: IO ()
7 main =
8 do numStrs <- readFile "data/advent03.txt"
9 let bits = map (map digitToInt) $ lines numStrs
10 print $ part1 bits
11 print $ part2 bits
12
13 part1 :: [[Int]] -> Int
14 part1 allBits = gamma * epsilon
15 where majorities = findMajorities allBits
16 gamma = bitsToNum majorities
17 epsilon = bitsToNum $ map not majorities
18
19 part2 :: [[Int]] -> Int
20 part2 allBits = oxygenRating * coFilterRating
21 where oxygenRating = bitsToNum $ oxygenFilter allBits 0
22 coFilterRating = bitsToNum $ coFilter allBits 0
23
24 findMajorities :: [[Int]] -> [Bool]
25 findMajorities allBits = map (>= threshold) columnSums
26 where addBits = zipWith (+)
27 columnSums = foldr1 addBits allBits
28 (t, m) = (length allBits) `divMod` 2
29 threshold = if m == 1 then t + 1 else t
30
31 bitsToNum :: [Bool] -> Int
32 bitsToNum bits = foldl' includeBit 0 bits
33 where includeBit n True = n * 2 + 1
34 includeBit n False = n * 2
35
36 oxygenFilter :: [[Int]] -> Int -> [Bool]
37 oxygenFilter = partFilter id
38
39 coFilter :: [[Int]] -> Int -> [Bool]
40 coFilter = partFilter not
41
42 partFilter :: (Bool -> Bool) -> [[Int]] -> Int -> [Bool]
43 partFilter filterFunc allBits n
44 | length allBits == 1 = majorities
45 | otherwise = partFilter filterFunc filteredBits (n + 1)
46 where majorities = findMajorities allBits
47 filterValue = if (filterFunc $ majorities !! n) then 1 else 0
48 filteredBits = filter (\bs -> bs !! n == filterValue) allBits