2022-12-08 - Treetop Tree House
(original .ipynb)
Day 8 puzzle input is a grid of numbers representing tree heights (mine is here). Part 1 involves finding whether any tree is "visible" (taller than all trees either above, below, left or right of it). Part 2 involves calculating a "scenic score" based on the product of the number of trees smaller than it in all directions.
puzzle_input_str = open("./puzzle_input/day8.txt").read() test_input_str = """30373 25512 65332 33549 35390""" def visible_horizontal(grid, r, c): if c == 0 or c == len(grid[r])-1: return True left = all(grid[r][c] > tree for tree in grid[r][:c]) right = all(grid[r][c] > tree for tree in grid[r][1+c:]) return right or left def visible_vertical(grid, r, c): if r == 0 or r == len(grid)-1: return True up = all(grid[r][c] > grid[xr][c] for xr in range(r)) down = all(grid[r][c] > grid[xr][c] for xr in range(r+1, len(grid))) return up or down def part_one(input_str): grid = [ [int(s) for s in line] for line in input_str.splitlines() ] return sum( sum(1 for c, col in enumerate(row) if visible_horizontal(grid, r, c) or visible_vertical(grid, r, c)) for r, row in enumerate(grid) ) assert 21 == part_one(test_input_str) print("part one:", part_one(puzzle_input_str))
part one: 1698
from functools import reduce def trees_above(grid, r, c): count = 0 tree = grid[r][c] r -= 1 while r >= 0: count += 1 if tree <= grid[r][c]: break r -= 1 return count def trees_below(grid, r, c): count = 0 tree = grid[r][c] r += 1 while r < len(grid): count += 1 if tree <= grid[r][c]: break r += 1 return count def trees_left(grid, r, c): count = 0 tree = grid[r][c] c -= 1 while c >= 0: count += 1 if tree <= grid[r][c]: break c -= 1 return count def trees_right(grid, r, c): count = 0 tree = grid[r][c] c += 1 while c < len(grid[0]): count += 1 if tree <= grid[r][c]: break c += 1 return count def scenic_score(grid, r, c): return reduce(lambda acc, s: acc*s, [f(grid, r, c) for f in [trees_above, trees_below, trees_left, trees_right]]) def get_all_scores(grid): for r, row in enumerate(grid): for c, col in enumerate(row): yield scenic_score(grid, r, c) def part_two(input_str): grid = [ [int(s) for s in line] for line in input_str.splitlines() ] return max(get_all_scores(grid)) assert 8 == part_two(test_input_str) print("part two:", part_two(puzzle_input_str))
part two: 672280
# Have I found a CPython bug!? I tightened up my implementation but weirdly # the next_c/next_r calls never change. Need to come back to this one. from functools import reduce def count_trees(grid, r, c, next_r, next_c, not_done): count = 0 tree = grid[r][c] # note: this always prints the below, even though I use different next_c/next_r funcs # next_r(10) 10 # next_c(10) 11 print("next_r(10)", next_r(10)) print("next_c(10)", next_c(10)) r = next_r(r) c = next_c(c) while not_done(grid, r, c): count += 1 if tree <= grid[r][c]: break r = next_r(r) c = next_c(c) return count directions = [ (lambda c: c, lambda r: r-1, lambda g,r,c: r >= 0), (lambda c: c, lambda r: r+1, lambda g,r,c: r < len(g)), (lambda c: c-1, lambda r: r, lambda g,r,c: c >= 0), (lambda c: c+1, lambda r: r, lambda g,r,c: c < len(g[0])), ] all_tree_ops = [ lambda grid, r, c: count_trees(grid, r, c, next_c, next_r, not_done) for next_c, next_r, not_done in directions ] def get_all_scores(grid): for r, row in enumerate(grid): for c, col in enumerate(row): yield reduce(lambda acc,s: acc*s, [f(grid, r, c) for f in all_tree_ops]) def part_two(input_str): grid = [ [int(s) for s in line] for line in input_str.splitlines() ] return max(get_all_scores(grid)) assert 8 == part_two(test_input_str) print("part two:", part_two(puzzle_input_str))
next_r(10) 11 next_c(10) 10 next_r(10) 11 next_c(10) 10 next_r(10) 11 next_c(10) 10 next_r(10) 11 next_c(10) 10 next_r(10) 11 next_c(10) 10 next_r(10) 11 next_c(10) 10 next_r(10) 11 next_c(10) 10 next_r(10) 11 next_c(10) 10 next_r(10) 11 next_c(10) 10 next_r(10) 11 next_c(10) 10 next_r(10) 11 next_c(10) 10 next_r(10) 11 next_c(10) 10 next_r(10) 11 next_c(10) 10 next_r(10) 11 next_c(10) 10 next_r(10) 11 next_c(10) 10 next_r(10) 11 next_c(10) 10 next_r(10) 11 next_c(10) 10 next_r(10) 11 next_c(10) 10 next_r(10) 11 next_c(10) 10 next_r(10) 11 next_c(10) 10 next_r(10) 11 next_c(10) 10 next_r(10) 11 next_c(10) 10 next_r(10) 11 next_c(10) 10 next_r(10) 11 next_c(10) 10 next_r(10) 11 next_c(10) 10 next_r(10) 11 next_c(10) 10 next_r(10) 11 next_c(10) 10 next_r(10) 11 next_c(10) 10 next_r(10) 11 next_c(10) 10 next_r(10) 11 next_c(10) 10 next_r(10) 11 next_c(10) 10 next_r(10) 11 next_c(10) 10 next_r(10) 11 next_c(10) 10 next_r(10) 11 next_c(10) 10 next_r(10) 11 next_c(10) 10 next_r(10) 11 next_c(10) 10 next_r(10) 11 next_c(10) 10 next_r(10) 11 next_c(10) 10 next_r(10) 11 next_c(10) 10 next_r(10) 11 next_c(10) 10 next_r(10) 11 next_c(10) 10