103 lines
2.7 KiB
Python
103 lines
2.7 KiB
Python
from typing import *
|
|
from aocpy import BaseChallenge
|
|
|
|
|
|
Coordinate = Tuple[int, int]
|
|
Forest = Dict[Coordinate, int]
|
|
|
|
|
|
def parse(instr: str) -> Tuple[Forest, Coordinate]:
|
|
res: Forest = {}
|
|
|
|
for x, line in enumerate(instr.strip().splitlines()):
|
|
for y, char in enumerate(line):
|
|
res[(x, y)] = int(char)
|
|
|
|
return res, (x, y)
|
|
|
|
|
|
def are_adjacents_lower(
|
|
forest: Forest,
|
|
initial_pos: Coordinate,
|
|
next_pos: Callable[[Coordinate], Coordinate],
|
|
) -> bool:
|
|
height = forest[initial_pos]
|
|
pos = next_pos(initial_pos)
|
|
while pos in forest:
|
|
if forest[pos] >= height:
|
|
return False
|
|
pos = next_pos(pos)
|
|
return True
|
|
|
|
|
|
def get_viewing_distance(
|
|
forest: Forest,
|
|
initial_pos: Coordinate,
|
|
next_pos: Callable[[Coordinate], Coordinate],
|
|
) -> int:
|
|
viewing_dist = 0
|
|
|
|
height = forest[initial_pos]
|
|
pos = next_pos(initial_pos)
|
|
while pos in forest:
|
|
viewing_dist += 1
|
|
if forest[pos] >= height:
|
|
break
|
|
pos = next_pos(pos)
|
|
|
|
return viewing_dist
|
|
|
|
|
|
class Challenge(BaseChallenge):
|
|
@staticmethod
|
|
def one(instr: str) -> int:
|
|
forest, (max_x, max_y) = parse(instr)
|
|
|
|
count = 0
|
|
for tree_pos in forest:
|
|
x, y = tree_pos
|
|
if x == 0 or y == 0 or x == max_x or y == max_y:
|
|
count += 1
|
|
continue
|
|
|
|
# left -x
|
|
if are_adjacents_lower(forest, tree_pos, lambda x: (x[0] - 1, x[1])):
|
|
count += 1
|
|
continue
|
|
# right +x
|
|
if are_adjacents_lower(forest, tree_pos, lambda x: (x[0] + 1, x[1])):
|
|
count += 1
|
|
continue
|
|
# up -y
|
|
if are_adjacents_lower(forest, tree_pos, lambda x: (x[0], x[1] - 1)):
|
|
count += 1
|
|
continue
|
|
# down +y
|
|
if are_adjacents_lower(forest, tree_pos, lambda x: (x[0], x[1] + 1)):
|
|
count += 1
|
|
continue
|
|
|
|
return count
|
|
|
|
@staticmethod
|
|
def two(instr: str) -> int:
|
|
forest, _ = parse(instr)
|
|
|
|
max_senic = 0
|
|
for tree_pos in forest:
|
|
view_left = get_viewing_distance(
|
|
forest, tree_pos, lambda x: (x[0] - 1, x[1])
|
|
)
|
|
view_right = get_viewing_distance(
|
|
forest, tree_pos, lambda x: (x[0] + 1, x[1])
|
|
)
|
|
view_up = get_viewing_distance(forest, tree_pos, lambda x: (x[0], x[1] - 1))
|
|
view_down = get_viewing_distance(
|
|
forest, tree_pos, lambda x: (x[0], x[1] + 1)
|
|
)
|
|
|
|
senic = view_left * view_right * view_up * view_down
|
|
if senic > max_senic:
|
|
max_senic = senic
|
|
|
|
return max_senic
|