blob: 3488d697000fb842c74b59ffcd5e1cc127b802c9 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
|
module Main where
import Control.Applicative (ZipList (ZipList, getZipList))
import Data.Char (digitToInt)
import Data.List (maximumBy, minimumBy)
import Data.Ord (comparing)
import Utils
convert :: [Int] -> Int
-- Convert binary (list of zeros and ones) to decimal
convert [] = 0
convert (x : xs) = x + 2 * convert xs
toIntMatrix :: [[Char]] -> [[Int]]
toIntMatrix = map (map digitToInt)
transpose :: [[a]] -> [[a]]
transpose = getZipList . traverse ZipList
mostCommon :: [Int] -> Int
-- Appending [0, 1] is a hack to make maximumBy choose 1 in a tie due to semantics
mostCommon lst = maximumBy (comparing (\x -> length $ filter (x ==) lst)) (lst ++ [0, 1])
leastCommon :: [Int] -> Int
-- Prepending [0, 1] is a hack to make minimumBy choose 0 in a tie due to semantics
leastCommon lst = minimumBy (comparing (\x -> length $ filter (x ==) lst)) ([0, 1] ++ lst)
e1 :: [String] -> Int
e1 input =
let mtx = toIntMatrix input $> transpose
gamma = mtx $> map mostCommon .> reverse .> convert
epsilon = mtx $> map leastCommon .> reverse .> convert
in gamma * epsilon
recur :: ([Int] -> Int) -> [[Int]] -> Int -> Int
-- Recurse through the matrix from left to right (i = [0..columnN - 1]) and filter out
-- rows not matching the criteria. If filter results in only one resulting value, stop recursion.
recur criteriaFn mtx i =
let column = map (!! i) mtx
crit = criteriaFn column
filtered = filter (\row -> row !! i == crit) mtx
in if length filtered == 1
then convert $ reverse $ head filtered
else recur criteriaFn filtered (i + 1)
e2 :: [String] -> Int
e2 input =
let mtx = input $> toIntMatrix
oxyr = recur mostCommon mtx 0
co2r = recur leastCommon mtx 0
in oxyr * co2r
main :: IO ()
main =
do
contents <- getContents
let input =
contents
$> lines
e1 input $> print
e2 input $> print
|