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   ]