never executed always true always false
1 {-|
2 Module: Y2021.D03
3 Description: Advent of Code 2021 Day 03 Solutions.
4 License: MIT
5 Maintainer: @tylerjl
6
7 Solutions to the 2021 day 03 set of problems for <adventofcode.com>.
8 -}
9 module Y2021.D03 where
10
11 import Data.Text (Text)
12 import qualified Data.Text as T
13 import GHC.Exts
14 import Data.List (transpose, group, sort, sortOn, groupBy)
15 import Data.Function (on)
16
17 -- |For clearer function signatures.
18 type Bit = Int
19 -- |Also, for clearer function signatures.
20 type Bits = [Bit]
21
22 -- |Accept a list of bits and multiply the common indexes.
23 part3A :: Text -> Float
24 part3A (toBits -> input)
25 = bitsToDec (commonOn id input)
26 * bitsToDec (commonOn Down input)
27
28 -- |Accept a list of bits and multiply the matching value with the matching
29 -- common and least-common bits, respectively.
30 part3B :: Text -> Float
31 part3B (toBits -> input) = oxygen * co2
32 where oxygen = pinpoint 0 input id
33 co2 = pinpoint 0 input Down
34 pinpoint _ [] _ = error "couldn't find matching bits"
35 pinpoint _ [x] _ = bitsToDec x
36 pinpoint idx bits f = let common = commonOn f bits
37 in pinpoint (succ idx) (keepAt bits (common !! idx) idx) f
38
39 -- |Keep bit arrays that have a particular bit set at a particular index.
40 keepAt :: [Bits] -> Bit -> Int -> [Bits]
41 keepAt bitsList bit idx = filter ((==) bit . flip (!!) idx) bitsList
42
43 -- |Convert a bit array to a decimal value.
44 bitsToDec :: Bits -> Float
45 bitsToDec = go 0 . reverse
46 where go n (x:xs)
47 | x == 1 = 2 ** n + go (succ n) xs
48 | otherwise = go (succ n) xs
49 go _ [] = 0
50
51 -- |Big fugly function to take a list of bits and return the common bit set in
52 -- each position.
53 commonOn :: Ord b => (Int -> b) -> [Bits] -> Bits
54 commonOn f =
55 map ( head . head . head . map (sortOn (f . head))
56 . groupBy ((==) `on` length) . sortOn (f . length) . group . sort)
57 -- Turn rows into lists of each position
58 . transpose
59
60 -- |Input parser to accept newline-separated bits
61 toBits :: Text -> [Bits]
62 toBits = map (map toBit . toList) . T.lines
63
64 -- |Fail-fast char-to-int parser.
65 toBit :: Char -> Int
66 toBit '0' = 0
67 toBit '1' = 1
68 toBit _ = error "unknown value"
69
70 d3sample :: Text
71 d3sample = T.unlines
72 [ "00100"
73 , "11110"
74 , "10110"
75 , "10111"
76 , "10101"
77 , "01111"
78 , "00111"
79 , "11100"
80 , "10000"
81 , "11001"
82 , "00010"
83 , "01010"
84 ]