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