mirror of
https://github.com/Crocmagnon/advent-of-code.git
synced 2024-11-22 06:28:11 +01:00
Solve day 8 part 2
This commit is contained in:
parent
97b3750d61
commit
2e9b092baa
1 changed files with 70 additions and 17 deletions
|
@ -1,5 +1,6 @@
|
||||||
import copy
|
import copy
|
||||||
from collections.abc import Iterable
|
from collections.abc import Iterable
|
||||||
|
from functools import partial
|
||||||
|
|
||||||
|
|
||||||
def main(filename: str, expected_part_1: int = None, expected_part_2: int = None):
|
def main(filename: str, expected_part_1: int = None, expected_part_2: int = None):
|
||||||
|
@ -8,19 +9,21 @@ def main(filename: str, expected_part_1: int = None, expected_part_2: int = None
|
||||||
data = f.read().strip().split("\n")
|
data = f.read().strip().split("\n")
|
||||||
|
|
||||||
data = parse_data(data)
|
data = parse_data(data)
|
||||||
solution_part_1 = solve_part_1(data)
|
visible_trees = solve_part_1(data)
|
||||||
|
solution_part_1 = len(visible_trees)
|
||||||
|
|
||||||
print(f"1. Found {solution_part_1}")
|
print(f"1. Found {solution_part_1}")
|
||||||
if expected_part_1:
|
if expected_part_1:
|
||||||
assert expected_part_1 == solution_part_1
|
assert expected_part_1 == solution_part_1
|
||||||
|
|
||||||
solution_part_2 = solve_part_2(data)
|
solution_part_2 = solve_part_2(data, visible_trees)
|
||||||
print(f"2. Found {solution_part_2}")
|
print(f"2. Found {solution_part_2}")
|
||||||
if expected_part_2:
|
if expected_part_2:
|
||||||
assert expected_part_2 == solution_part_2
|
assert expected_part_2 == solution_part_2
|
||||||
|
|
||||||
|
|
||||||
DataType = list[list[int]]
|
Forest = DataType = list[list[int]]
|
||||||
|
Tree = tuple[int, int]
|
||||||
|
|
||||||
|
|
||||||
def parse_data(data: list[str]) -> DataType:
|
def parse_data(data: list[str]) -> DataType:
|
||||||
|
@ -30,21 +33,19 @@ def parse_data(data: list[str]) -> DataType:
|
||||||
return grid
|
return grid
|
||||||
|
|
||||||
|
|
||||||
def solve_part_1(grid: DataType) -> int:
|
def solve_part_1(forest: DataType) -> set[Tree]:
|
||||||
visible = set()
|
visible = set()
|
||||||
grid = copy.deepcopy(grid)
|
forest = copy.deepcopy(forest)
|
||||||
visible.update(find_visible_in_rows(grid))
|
visible.update(find_visible_in_rows(forest))
|
||||||
|
|
||||||
grid = map(list, zip(*grid)) # transpose grid so cols become rows
|
forest = map(list, zip(*forest)) # transpose grid so cols become rows
|
||||||
visible.update(find_visible_in_rows(grid, swap=True))
|
visible.update(find_visible_in_rows(forest, swap=True))
|
||||||
return len(visible)
|
return visible
|
||||||
|
|
||||||
|
|
||||||
def find_visible_in_rows(
|
def find_visible_in_rows(forest: Iterable[list[int]], swap: bool = False) -> set[Tree]:
|
||||||
grid: Iterable[list[int]], swap: bool = False
|
|
||||||
) -> set[tuple[int, int]]:
|
|
||||||
visible = set()
|
visible = set()
|
||||||
for row, trees in enumerate(grid):
|
for row, trees in enumerate(forest):
|
||||||
max_height = -1
|
max_height = -1
|
||||||
for col, tree in enumerate(trees):
|
for col, tree in enumerate(trees):
|
||||||
if tree > max_height:
|
if tree > max_height:
|
||||||
|
@ -59,17 +60,69 @@ def find_visible_in_rows(
|
||||||
return visible
|
return visible
|
||||||
|
|
||||||
|
|
||||||
def visible_tree(row, col, swap):
|
def visible_tree(row: int, col: int, swap: bool) -> Tree:
|
||||||
if swap:
|
if swap:
|
||||||
return col, row
|
return col, row
|
||||||
else:
|
else:
|
||||||
return row, col
|
return row, col
|
||||||
|
|
||||||
|
|
||||||
def solve_part_2(data: DataType) -> int:
|
def solve_part_2(forest: DataType, visible_trees: set[Tree]) -> int:
|
||||||
return 0
|
# Hypothesis: the tree with the highest scenic score
|
||||||
|
# is visible from the outside.
|
||||||
|
max_scenic_score = 0
|
||||||
|
for tree in filter(partial(is_inside, forest=forest), visible_trees):
|
||||||
|
scenic_score = compute_scenic_score(tree, forest)
|
||||||
|
if scenic_score > max_scenic_score:
|
||||||
|
max_scenic_score = scenic_score
|
||||||
|
return max_scenic_score
|
||||||
|
|
||||||
|
|
||||||
|
def is_border(tree: Tree, forest: DataType) -> bool:
|
||||||
|
return 0 in tree or tree[0] == len(forest) - 1 or tree[1] == len(forest[0]) - 1
|
||||||
|
|
||||||
|
|
||||||
|
def is_inside(tree: Tree, forest: DataType) -> bool:
|
||||||
|
return not is_border(tree, forest)
|
||||||
|
|
||||||
|
|
||||||
|
def compute_scenic_score(tree: Tree, forest: Forest) -> int:
|
||||||
|
row, col = tree
|
||||||
|
reference = forest[row][col]
|
||||||
|
top = 0
|
||||||
|
while row > 0:
|
||||||
|
row -= 1
|
||||||
|
top += 1
|
||||||
|
visited = forest[row][col]
|
||||||
|
if visited >= reference:
|
||||||
|
break
|
||||||
|
row, col = tree
|
||||||
|
bottom = 0
|
||||||
|
while row < len(forest) - 1:
|
||||||
|
row += 1
|
||||||
|
bottom += 1
|
||||||
|
visited = forest[row][col]
|
||||||
|
if visited >= reference:
|
||||||
|
break
|
||||||
|
row, col = tree
|
||||||
|
left = 0
|
||||||
|
while col > 0:
|
||||||
|
col -= 1
|
||||||
|
left += 1
|
||||||
|
visited = forest[row][col]
|
||||||
|
if visited >= reference:
|
||||||
|
break
|
||||||
|
row, col = tree
|
||||||
|
right = 0
|
||||||
|
while col < len(forest[0]) - 1:
|
||||||
|
col += 1
|
||||||
|
right += 1
|
||||||
|
visited = forest[row][col]
|
||||||
|
if visited >= reference:
|
||||||
|
break
|
||||||
|
return right * left * top * bottom
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main("inputs/day08-test1", expected_part_1=21)
|
main("inputs/day08-test1", expected_part_1=21, expected_part_2=8)
|
||||||
main("inputs/day08", expected_part_1=1690)
|
main("inputs/day08", expected_part_1=1690)
|
||||||
|
|
Loading…
Reference in a new issue