176 lines
5.7 KiB
Python
176 lines
5.7 KiB
Python
# --- Day 8: Treetop Tree House ---
|
|
|
|
# The expedition comes across a peculiar patch of tall trees all planted
|
|
# carefully in a grid. The Elves explain that a previous expedition planted
|
|
# these trees as a reforestation effort. Now, they're curious if this would be
|
|
# a good location for a tree house.
|
|
|
|
# First, determine whether there is enough tree cover here to keep a tree house
|
|
# hidden. To do this, you need to count the number of trees that are visible
|
|
# from outside the grid when looking directly along a row or column.
|
|
|
|
# The Elves have already launched a quadcopter to generate a map with the
|
|
# height of each tree (your puzzle input). For example:
|
|
|
|
# 30373
|
|
# 25512
|
|
# 65332
|
|
# 33549
|
|
# 35390
|
|
|
|
# Each tree is represented as a single digit whose value is its height, where 0
|
|
# is the shortest and 9 is the tallest.
|
|
|
|
# A tree is visible if all of the other trees between it and an edge of the
|
|
# grid are shorter than it. Only consider trees in the same row or column; that
|
|
# is, only look up, down, left, or right from any given tree.
|
|
|
|
# All of the trees around the edge of the grid are visible - since they are
|
|
# already on the edge, there are no trees to block the view. In this example,
|
|
# that only leaves the interior nine trees to consider:
|
|
|
|
# The top-left 5 is visible from the left and top. (It isn't visible from
|
|
# the right or bottom since other trees of height 5 are in the way.)
|
|
# The top-middle 5 is visible from the top and right.
|
|
# The top-right 1 is not visible from any direction; for it to be visible,
|
|
# there would need to only be trees of height 0 between it and an edge.
|
|
# The left-middle 5 is visible, but only from the right.
|
|
# The center 3 is not visible from any direction; for it to be visible,
|
|
# there would need to be only trees of at most height 2 between it and an edge.
|
|
# The right-middle 3 is visible from the right.
|
|
# In the bottom row, the middle 5 is visible, but the 3 and 4 are not.
|
|
|
|
# With 16 trees visible on the edge and another 5 visible in the interior, a
|
|
# total of 21 trees are visible in this arrangement.
|
|
|
|
# Consider your map; how many trees are visible from outside the grid?
|
|
|
|
import numpy as np
|
|
|
|
with open("/home/xfeluser/AoC_2022/P8.txt") as f:
|
|
grid = [int(num) for line in f.read().strip().split() for num in line]
|
|
|
|
grid_arr = np.array(grid).reshape(int(len(grid) ** 0.5), int(len(grid) ** 0.5))
|
|
|
|
perimeter = grid_arr.shape[0] * 2 + (grid_arr.shape[0] - 2) * 2
|
|
|
|
|
|
def is_visible(arr, x, y):
|
|
point = arr[x, y]
|
|
top = arr[:x, y]
|
|
bottom = arr[x + 1 :, y]
|
|
left = arr[x, :y]
|
|
right = arr[x, y + 1 :]
|
|
|
|
return np.any(
|
|
[1 for pos in [top, bottom, left, right] if np.all(point - pos > 0)]
|
|
)
|
|
|
|
|
|
total = 0
|
|
for idx, element in enumerate(np.nditer(grid_arr[1:-1, 1:-1])):
|
|
x = 1 + (idx // grid_arr[1:-1, 1:-1].shape[0])
|
|
y = 1 + (idx % grid_arr[1:-1, 1:-1].shape[0])
|
|
if is_visible(grid_arr, x, y):
|
|
total += 1
|
|
|
|
print(perimeter + total)
|
|
|
|
|
|
# --- Part Two ---
|
|
|
|
# Content with the amount of tree cover available, the Elves just need to know
|
|
# the best spot to build their tree house: they would like to be able to see a
|
|
# lot of trees.
|
|
|
|
# To measure the viewing distance from a given tree, look up, down, left, and
|
|
# right from that tree; stop if you reach an edge or at the first tree that is
|
|
# the same height or taller than the tree under consideration. (If a tree is
|
|
# right on the edge, at least one of its viewing distances will be zero.)
|
|
|
|
# The Elves don't care about distant trees taller than those found by the rules
|
|
# above; the proposed tree house has large eaves to keep it dry, so they
|
|
# wouldn't be able to see higher than the tree house anyway.
|
|
|
|
# In the example above, consider the middle 5 in the second row:
|
|
|
|
# 30373
|
|
# 25512
|
|
# 65332
|
|
# 33549
|
|
# 35390
|
|
|
|
# Looking up, its view is not blocked; it can see 1 tree (of height 3).
|
|
# Looking left, its view is blocked immediately; it can see only 1 tree
|
|
# (of height 5, right next to it).
|
|
# Looking right, its view is not blocked; it can see 2 trees.
|
|
# Looking down, its view is blocked eventually; it can see 2 trees (one of
|
|
# height 3, then the tree of height 5 that blocks its view).
|
|
|
|
# A tree's scenic score is found by multiplying together its viewing distance
|
|
# in each of the four directions. For this tree, this is 4 (found by
|
|
# multiplying 1 * 1 * 2 * 2).
|
|
|
|
# However, you can do even better: consider the tree of height 5 in the middle
|
|
# of the fourth row:
|
|
|
|
# 30373
|
|
# 25512
|
|
# 65332
|
|
# 33549
|
|
# 35390
|
|
|
|
# Looking up, its view is blocked at 2 trees (by another tree with a height
|
|
# of 5).
|
|
# Looking left, its view is not blocked; it can see 2 trees.
|
|
# Looking down, its view is also not blocked; it can see 1 tree.
|
|
# Looking right, its view is blocked at 2 trees (by a massive tree of
|
|
# height 9).
|
|
|
|
# This tree's scenic score is 8 (2 * 2 * 1 * 2); this is the ideal spot for the
|
|
# tree house.
|
|
|
|
# Consider each tree on your map. What is the highest scenic score possible for
|
|
# any tree?
|
|
|
|
from math import prod
|
|
|
|
|
|
def visibility(arr, x, y):
|
|
point = arr[x, y]
|
|
top = arr[:x, y]
|
|
bottom = arr[x + 1 :, y]
|
|
left = arr[x, :y]
|
|
right = arr[x, y + 1 :]
|
|
|
|
return prod(
|
|
(
|
|
length_path(point, direction)
|
|
for direction in [top[::-1], bottom, left[::-1], right]
|
|
)
|
|
)
|
|
|
|
|
|
def length_path(p, direction):
|
|
path_length = 0
|
|
for pos in direction:
|
|
if p - pos >= 0:
|
|
path_length += 1
|
|
if p - pos == 0:
|
|
break
|
|
else:
|
|
path_length += 1
|
|
break
|
|
|
|
return path_length
|
|
|
|
|
|
total = 0
|
|
maximum_path = 0
|
|
for idx, element in enumerate(np.nditer(grid_arr[1:-1, 1:-1])):
|
|
x = 1 + (idx // grid_arr[1:-1, 1:-1].shape[0])
|
|
y = 1 + (idx % grid_arr[1:-1, 1:-1].shape[0])
|
|
maximum_path = max(visibility(grid_arr, x, y), maximum_path)
|
|
|
|
print(maximum_path)
|