Coverage for src\aoc2022\days\day8.py: 100%
91 statements
« prev ^ index » next coverage.py v7.0.0, created at 2022-12-23 05:19 +0000
« prev ^ index » next coverage.py v7.0.0, created at 2022-12-23 05:19 +0000
1from typing import Set, Tuple
3import numpy as np
5from src.aoc2022 import utils
8def parse_data_to_array(raw_data: str) -> np.ndarray:
9 """
10 Parse the raw data into a 2D list of lists
12 :param raw_data: Raw data containing numerical data
13 :type raw_data: str
15 :return: parsed matrix of values
16 :rtype: List[List[int]]
17 """
18 outer_list = []
19 for line in raw_data.split("\n"):
20 inner_list = [int(e) for e in line]
21 outer_list.append(inner_list)
23 return np.array(outer_list)
26def scan_height_row(height_map: np.ndarray) -> Set[int]:
27 """
28 Scan a list of heights to determine which trees are visible from either
29 side
31 :param height_map: 1D array of heights
32 :type height_map: np.ndarray
34 :return: Set of positions that are visible from either side
35 :rtype: Set[int]
36 """
37 left_max = -1
38 right_max = -1
39 n = len(height_map)
41 visible_positions = set()
43 for i in range(n):
44 left_idx = i
45 right_idx = n - (1 + i)
47 left_val = height_map[left_idx]
48 right_val = height_map[right_idx]
50 if left_val > left_max:
51 left_max = left_val
52 visible_positions.add(left_idx)
53 if right_val > right_max:
54 right_max = right_val
55 visible_positions.add(right_idx)
56 return visible_positions
59def count_visible_trees(height_map: np.ndarray) -> int:
60 """
61 Count number of trees visible from perimeter
63 :param height_map: 2D array of heights
64 :type height_map: np.ndarray
66 :return: Total count of trees visible from perimeter
67 :rtype: int
68 """
69 visible_positions: Set[Tuple[int, int]] = set()
71 height, width = height_map.shape
73 for row in range(height):
74 row_data = height_map[row, :]
75 visible_in_row = scan_height_row(row_data)
76 for pos in visible_in_row:
77 visible_positions.add((row, pos))
79 for col in range(width):
80 col_data = height_map[:, col]
81 visible_in_col = scan_height_row(col_data)
82 for pos in visible_in_col:
83 visible_positions.add((pos, col))
85 return len(visible_positions)
88def compute_scenic_score(height_map: np.ndarray, pos: Tuple[int, int]) -> int:
89 """
90 Compute the scenic view given a starting position
92 :param height_map: 2D array of heights
93 :type height_map: np.ndarray
95 :param pos: tuple of (x, y) positions in the grid
96 :type pos: Tuple[int, int]
98 :return: Scenic score of the position given
99 :rtype: int
100 """
101 height, width = height_map.shape
102 x, y = pos
103 start_height = height_map[y, x]
105 left_view = 0
106 right_view = 0
107 top_view = 0
108 bot_view = 0
110 i = x + 1
111 while i < width:
112 if height_map[y, i] < start_height:
113 right_view += 1
114 elif height_map[y, i] >= start_height:
115 right_view += 1
116 break
117 i += 1
119 i = x - 1
120 while i >= 0:
121 if height_map[y, i] < start_height:
122 left_view += 1
123 elif height_map[y, i] >= start_height:
124 left_view += 1
125 break
126 i -= 1
128 j = y + 1
129 while j < height:
130 if height_map[j, x] < start_height:
131 bot_view += 1
132 elif height_map[y, x] >= start_height:
133 bot_view += 1
134 break
135 j += 1
137 j = y - 1
138 while j >= 0:
139 if height_map[j, x] < start_height:
140 top_view += 1
141 elif height_map[y, x] >= start_height:
142 top_view += 1
143 break
144 j -= 1
146 return top_view * bot_view * left_view * right_view
149def get_max_scenic_score(height_map: np.ndarray) -> int:
150 """
151 Find the maximum scenic score given the height map
153 :param height_map: 2D array of heights
154 :type height_map: np.ndarray
156 :return: Maximum possible scenic score
157 :rtype: int
158 """
159 max_ = 0
160 height, width = height_map.shape
161 for x in range(width):
162 for y in range(height):
163 pos = (x, y)
164 view = compute_scenic_score(height_map, pos)
165 if view > max_:
166 max_ = view
167 return max_
170if __name__ == "__main__": # pragma: no cover
172 data = utils.get_raw_data("./src/aoc2022/data/day8.txt")
174 parsed_array = parse_data_to_array(data)
175 vis_trees = count_visible_trees(parsed_array)
177 print(f"There are {vis_trees} visible trees.")
179 compute_scenic_score(parsed_array, (2, 3))
180 max_view = get_max_scenic_score(parsed_array)
182 print(f"The best view is {max_view}.")