How to solve Advent of Code 2022 – Day 8 with Python

If you missed any previous days, click here for all my content about that: Advent of Code, if you want to know why you should participate and try to code the solution for yourself, click here: Advent Of Code 2022 – 7 Reasons why you should participate. If you’re here to see the solution of Day 8, continue reading 😉

GitHub Repository

https://github.com/GalaxyInfernoCodes/Advent_Of_Code_2022

I will upload all of my solutions there – in the form of Python (or Scala alternatives) notebooks. You have to use your own input for the “input.txt” since everyone gets their own and everyone needs to provide a different solution based on their input.

Day 8 Puzzle

On day 8 of Advent of Code, we had to count trees. Thankfully we could do so in nice array forms – automatically. However, the automatic part still had to be invented by us. So maybe not that automatically. The input was a top down view on the trees, with numbers indicating their height:

30373
25512
65332
33549
35390

As always, I read in all lines and then formed a 2-dimensional numpy array of the trees.

with open('input.txt', 'r') as f:
    lines = f.readlines()
    lines = [entry.strip() for entry in lines]

trees = np.zeros((len(lines), len(lines[0])), dtype=int)
for i, line in enumerate(lines):
    trees[i, :] = np.array(list(line))

Part 1

Here we needed to check how many trees would be visible from the edge of the forest. I solved that by iterating over the trees (except for the edges, which are always visible). For each tree, I selected its row and column and subtracted the height of the considered tree to get the difference to its neighboring trees. If all the values either to the left, right, top or bottom (routes) are negative, that means those trees are smaller than the current tree and it is therefore visible.

# the edges are always visible
visible_trees = 2*len(lines[0]) + 2 *(len(lines)-2)

# iterate over trees
for i in range(1, trees.shape[0]-1):
    for j in range(1, trees.shape[1]-1):
        tree_column = trees[:, j] - trees[i, j]
        tree_row = trees[i, :] - trees[i, j]
        routes = [tree_row[:j], tree_row[j+1:], tree_column[:i], tree_column[i+1:]]
        if sum(list(map(lambda route: (route<0).all(), routes))) > 0:
            visible_trees += 1
visible_trees

Part 2

Here we considered how many trees we could see from a given position within the forest to find the position where we have the best view (highest scenic score computed as the product of the trees visible in each direction). I took the following steps:

  • create a 2 dimensional array to save the scenic scores for each tree
  • go over all trees to compute scores
    • skip borders of the forest because those have scores of 0 due to one view-direction always having 0 trees)
  • consider all 4 view-directions as routes
    • some of those view-directions need to be inverted to make sure they all start at the location we are currently scoring (tree_row[j-1::-1] means “start at column j-1, all the way to the start of the array, in steps of -1, so from right to left)
    • for each route to the following (it’s applied to all routes through using map)
    • check which trees are taller or equally as tall (>=0 when considering the difference to the current tree)
    • get the first index that is taller or equally as tall, otherwise just take the full list of the view-route
  • multiply those 4 scores together with np.prod
scenic_scores = np.zeros((len(lines), len(lines[0])), dtype=int)

def compute_scenic_score(route):
    big_trees_array = list(route >= 0)
    if True in big_trees_array:
        return big_trees_array.index(True) + 1
    else:
        return len(big_trees_array)

# iterate over trees
for i in range(1, trees.shape[0]-1):
    for j in range(1, trees.shape[1]-1):
        tree_column = trees[:, j] - trees[i, j]
        tree_row = trees[i, :] - trees[i, j]
        # left, right, up, down
        routes = [tree_row[j-1::-1], tree_row[j+1:], tree_column[i-1::-1], tree_column[i+1:]]
        scenic_scores[i,j] = np.prod(list(map(compute_scenic_score, routes)))
    
np.max(scenic_scores)

Conclusion

I was looking forward to using numpy in these challenges – however I couldn’t figure out a good way to use numpy functions effectively, so it ended up a fight with sub-arrays anyways 😀

Leave a Reply

Consent Management Platform by Real Cookie Banner