Advertisement
Guest User

AoC 2022 Day 8

a guest
Dec 15th, 2022
465
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 3.43 KB | None | 0 0
  1. # aoc202208.py
  2.  
  3. import pathlib
  4. import sys
  5.  
  6. import numpy as np
  7.  
  8. # Typing aliases
  9. M = list[list[int]]
  10.  
  11.  
  12. def parse(puzzle_input: str) -> M:
  13.     """ Parse input """
  14.     return [[int(x) for x in row] for row in puzzle_input.splitlines()]
  15.  
  16.  
  17. def mark_visible(arr, tree) -> None:
  18.     """ Mark matching trees in given array """
  19.     max_height = arr[0]
  20.     for i, v in enumerate(arr[:-1]):
  21.         if max_height < arr[i + 1]:
  22.             max_height = arr[i + 1]
  23.             if tree[i + 1] == 0:
  24.                 tree[i + 1] = 1
  25.  
  26.  
  27. def add_trees(arr, grid) -> None:
  28.     """ Mark matching trees in grid """
  29.     rows, cols = arr.shape
  30.     grid[0] = [1 for n in range(cols)]
  31.     grid[-1] = [1 for n in range(cols)]
  32.     for n in range(1, rows - 1):
  33.         mark_visible(arr[n], grid[n])
  34.         mark_visible(arr[n][::-1], grid[n][::-1])
  35.  
  36.  
  37. def visible_trees(heights):
  38.     """ Return grid of matching trees """
  39.     matches = np.zeros(heights.shape, dtype=int)
  40.     add_trees(heights, matches)
  41.     add_trees(np.transpose(heights), np.transpose(matches))
  42.     return matches
  43.  
  44.  
  45. def part1(data: M) -> int:
  46.     """ Solve part 1 """
  47.     tree_heights = np.array(data)
  48.     return np.count_nonzero(visible_trees(tree_heights))
  49.  
  50.  
  51. def find_candidates(matrix):
  52.     """ Return coordinates of peaks """
  53.     coords: list[tuple[int, int]] = []
  54.     last_index: int = matrix.shape[1] - 1
  55.     for coord in np.argwhere(matrix):
  56.         # Remove edges
  57.         if not any([coord[0] in (0, last_index), coord[1] in (0, last_index)]):
  58.             coords.append([coord[0], coord[1]])
  59.     return coords
  60.  
  61.  
  62. def view_count(value: int, span: list[int], level: bool = False) -> int:
  63.     """ Return score of visible trees """
  64.     count: int = 0
  65.     for n in span:
  66.         if level:
  67.             continue
  68.         count += 1
  69.         if n == value:
  70.             level = True
  71.         if n > value:
  72.             break
  73.     return count
  74.  
  75.  
  76. def scenic_score(arr: list, idx: int) -> tuple[int, int]:
  77.     """ Return scenic score for one tree """
  78.     v: int = arr[idx]
  79.     to_start: list[int] = arr[:idx][::-1]
  80.     to_end: list[int] = arr[idx + 1:]
  81.     return view_count(v, to_start), view_count(v, to_end)
  82.  
  83.  
  84. def get_scores(matrix, coords) -> list[int]:
  85.     """ get a lits of scenic scores for all candidate trees """
  86.     scores: list[int] = []
  87.     flipped = np.transpose(matrix)
  88.     for row, col in coords:
  89.         # left, right, up, down are ints
  90.         left, right = scenic_score(matrix[row], col)
  91.         up, down = scenic_score(flipped[col], row)
  92.         scores.append(np.prod([up, left, down, right]))
  93.     return scores
  94.  
  95.  
  96. def part2(data: M) -> int:
  97.     """ Solve part 2 """
  98.     tree_heights = np.array(data)
  99.     candidate_trees: list[tuple[int, int]] = find_candidates( visible_trees(tree_heights))
  100.     scores: list[int] = get_scores(tree_heights, candidate_trees)
  101.     return max(scores)
  102.  
  103.  
  104. def solve(puzzle_input: str) -> tuple[int, int]:
  105.     """ Solve the puzzle for the given input """
  106.     data: M = parse(puzzle_input)
  107.     solution1: int = part1(data)  # Correct answer was 1717 (with my data)
  108.     solution2: int = part2(data)  # Correct answer was 321975 (with my data)
  109.  
  110.     return solution1, solution2
  111.  
  112.  
  113. if __name__ == "__main__":
  114.     for path in sys.argv[1:]:
  115.         print(f"{path}:")
  116.         puzzle_input = pathlib.Path(path).read_text().strip()
  117.         solutions = solve(puzzle_input)
  118.         print('\n'.join(str(solution) for solution in solutions))
  119.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement