-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrun.hs
87 lines (71 loc) · 2.17 KB
/
run.hs
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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TupleSections #-}
import AoC.Grid (readGrid)
import Data.List (tails, transpose, union)
import Data.HashMap.Strict (HashMap)
import qualified Data.HashMap.Strict as HashMap
-- Might be nicer to be a bit more imperative.
-- Use Vector for speed.
parseAll :: String -> [[Int]]
parseAll = readGrid @Int
visible :: Int -> [Int] -> [Int]
visible start = go start 0
where go top i =
\case [] -> []
x:xs
| x > top -> i:go x (i + 1) xs
| otherwise -> go top (i + 1) xs
visible' :: [Int] -> [Int]
visible' = map (\(y:ys) -> go y 0 ys) . filter (not . null) . tails
where go start count =
\case [] -> count
x:xs
| x >= start -> count + 1
| otherwise -> go start (count + 1) xs
visibleH :: Int -> [Int] -> [Int]
visibleH start xs =
let l = length xs
v1 = visible start xs
v2 = map ((l - 1) -) (visible start (reverse xs))
in v1 `union` v2
visibleH' :: [Int] -> [Int]
visibleH' xs =
let v1 = visible' xs
v2 = reverse (visible' (reverse xs))
in zipWith (*) v1 v2
allVisible :: [[Int]] -> [(Int, Int)]
allVisible grid =
let rows =
concat [map (i,) (visibleH (-1) r)
| (i, r) <- zip [0..] grid ]
cols =
concat [map (,i) (visibleH (-1) c)
| (i, c) <- zip [0..] (transpose grid) ]
in
rows `union` cols
scores :: [[Int]] -> HashMap (Int, Int) Int
scores grid =
let rows =
[((ri, ci), cnt)
| (ri, r) <- zip [0..] grid
, (ci, cnt) <- zip [0..] (visibleH' r)]
cols =
[((ri, ci), cnt)
| (ci, c) <- zip [0..] (transpose grid)
, (ri, cnt) <- zip [0..] (visibleH' c)]
in HashMap.fromListWith (*) (rows ++ cols)
part1 :: [[Int]] -> Int
part1 = length . allVisible
part2 :: [[Int]] -> Int
part2 = maximum . HashMap.elems . scores
main :: IO ()
main = main' "input.txt"
exampleMain :: IO ()
exampleMain = main' "example.txt"
main' :: FilePath -> IO ()
main' file = do
input <- parseAll <$> readFile file
print (part1 input)
print (part2 input)