diff --git a/day08/solve.py b/day08/solve.py new file mode 100644 index 0000000..3e79ec6 --- /dev/null +++ b/day08/solve.py @@ -0,0 +1,91 @@ +# Day 08: Treetop Tree House + +import os + +def get_path(): + return os.path.join(os.path.dirname(__file__), 'data.txt') + +def build_grid(): + grid = [] + with open(get_path()) as fp: + for line in fp: + grid.append(map(int, line.strip())) + return grid + +def get_column(grid, col_idx): + return map(lambda row: row[col_idx], grid) + +def is_visible(grid, row_idx, col_idx): + # all edge trees are visible + if row_idx == 0 or row_idx == len(grid) -1 \ + or col_idx == 0 or col_idx == len(grid[0]) - 1: + return True + cell = grid[row_idx][col_idx] + # check the left side + if all([item < cell for item in grid[row_idx][:col_idx]]): + return True + # check the right side + if all([item < cell for item in grid[row_idx][col_idx+1:]]): + return True + # check the top + if all([item < cell for item in get_column(grid, col_idx)[:row_idx]]): + return True + # check the bottom + if all([item < cell for item in get_column(grid, col_idx)[row_idx+1:]]): + return True + return False + +def score_row(height, row): + score = 0 + for item in row: + score += 1 + if item >= height: + break + return score + +def get_score(grid, row_idx, col_idx): + # all edge trees will have at least one size with a 0 score + if row_idx == 0 or row_idx == len(grid) -1 \ + or col_idx == 0 or col_idx == len(grid[0]) - 1: + return 0 + + height = grid[row_idx][col_idx] + left_score = score_row(height, grid[row_idx][:col_idx][::-1]) # [::-1] reverses a slice. who knew? + right_score = score_row(height, grid[row_idx][col_idx+1:]) + top_score = score_row(height, get_column(grid, col_idx)[:row_idx][::-1]) # reverse it because we are looking "backwards" + bottom_score = score_row(height, get_column(grid, col_idx)[row_idx+1:]) + total_score = left_score * right_score * top_score * bottom_score + # print ('grid[%d][%d] = %d, (%d, %d, %d, %d) = %d' % (row_idx, col_idx, height, left_score, right_score, top_score, bottom_score, total_score)) + return total_score + +def solve_part1(): + total = 0 + + grid = build_grid() + # print('height %d, width %d' % (len(grid), len(grid[0]))) + for row_idx in range(0, len(grid)): + for col_idx in range(0, len(grid[row_idx])): + if is_visible(grid, row_idx, col_idx): + total += 1 + + print('Day 08: Part 1') + print('GOAL: Count the number of trees that are visible from outside the grid when looking directly along a row or column.') + print('ANSWER: How many trees are visible from outside the grid?') + print('Total: %d' % (total)) + +def solve_part2(): + best_score = 0 + grid = build_grid() + for row_idx in range(0, len(grid)): + for col_idx in range(0, len(grid[row_idx])): + score = get_score(grid, row_idx, col_idx) + best_score = score if score > best_score else best_score + + print('Day 08: Part 2') + print('GOAL: Consider each tree on your map.') + print('ANSWER: What is the highest scenic score possible for any tree?') + print('Best Score: %d' % (best_score)) + +if __name__ == '__main__': + solve_part1() + solve_part2() \ No newline at end of file diff --git a/day08/tests.py b/day08/tests.py new file mode 100644 index 0000000..1d25ecf --- /dev/null +++ b/day08/tests.py @@ -0,0 +1,20 @@ +import unittest +import solve + +class Day08TestMethods(unittest.TestCase): + def setUp(self): + pass + + def test_score_row(self): + test_cases = [ + [1, 5, [3]], + [1, 5, [5,2]], + [2, 5, [1,2]], + [2, 5, [3,5,3]], + [2, 5, [3,3]] + ] + for [expected, height, row] in test_cases: + self.assertEqual(solve.score_row(height, row), expected) + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/tests.py.template b/tests.py.template index 54adc7c..dd22ae4 100644 --- a/tests.py.template +++ b/tests.py.template @@ -1,4 +1,5 @@ import unittest +import solve class Day#DAY#TestMethods(unittest.TestCase): def setUp(self): @@ -6,7 +7,11 @@ class Day#DAY#TestMethods(unittest.TestCase): # Does a thing def test_true(self): - self.assertEqual(True, False) + test_cases = [ + [True, False] + ] + for [expected, value] in test_cases: + self.assertEqual(expected, value) if __name__ == '__main__': unittest.main() \ No newline at end of file