⚠️ SPOILER ALERT
This is a post with my solutions and learnings from the puzzle. Don't continue
reading if you haven't tried the puzzle on your own yet.
If you want to do the puzzle, visit adventofcode.com/2020/day/3.
My programming language of choice is
python and all examples below are in python.
- Functions and abstraction
Part 1 is solved using the learning from the previous days. Part 2 introduces a new key learning. By asking us to calculate several slopes it forces us to rewrite the code from part 1 and generalize it. This encourages us to create a function for the calculation and use a good code structure.
The puzzle is about counting amount of trees you'll encounter if you travel through a "forest" in a straight line. The input is a map over the forest where
# is a tree and
. is an open space.
The map is repeating horizontally. In this puzzle you can see it as returning to the left side once you reach the right edge of the map.
..##....... #...#...#.. .#....#..#. ..#.#...#.# .#...##..#. ..#.##.....
The angle you should travel in is described as a
right 3 and down 1. The answer is how many trees you'll hit if you traverse the map in this slope.
First step is to save the input in a local file and parse it in python:
# Open the input file inputfile = open('03.input', 'r') # Parse lines data = [x.strip() for x in inputfile.readlines()]
def part1(data): x = 0 # X is current column total = 0 # Count of trees map_width = len(data) map_height = len(data) for y in range(map_height): # Iterate each row if data[y][x] == '#': # Use x,y as coordinates to check for tree total += 1 # Count if tree x = (x + 3) % map_width # Jump 3 steps right (modulus to keep within map) return total print "Solution part 1: %d" % part1(data)
The second puzzle has the same input. Now you have to try multiple slopes:
- Right 1, down 1
- Right 3, down 1
- Right 5, down 1
- Right 7, down 1
- Right 1, down 2
The answer is
product of multiplying amount of trees encountered in the above slopes.
In this stage you'll realize it's easier to refactor your code into a function with the slope as parameter.
The last slope with
down 2 forces us to use both columns and rows skipped as parameters to your function.
def part2(data): def traverse(right, down): # Define a function for generalizing x = 0 total = 0 for i in range(len(data)): if i % down != 0: # Skip rows according to "down"-variable continue if data[i][x] == '#': total += 1 x = (x + right) % len(data) # Use right-parameter return total # Use function to get values for each slope return traverse(1,1) * traverse(3,1) * traverse(5,1) * traverse(7,1) * traverse(1,2)
A more functional approach would be:
def part1(data): def encountered((idx, row)): x_position = (idx * 3) % len(row) return row[x_position] == '#' trees_encountered = filter(encountered, enumerate(data)) return len(trees_encountered) def part2(data): def traverse(right, down): # Filter out jumped rows def filter_row((idx, row)): return idx % down == 0 rows_hit = filter(filter_row, enumerate(data)) # Filter out rows where we encounter a tree def encountered((idx, row)): x_position = (idx * right) % len(row) return row[x_position] == '#' trees_encountered = filter(encountered, rows_hit) return len(trees_encountered) return traverse(1,1) * traverse(3,1) * traverse(5,1) * traverse(7,1) * traverse(1,2)
Python has a nice feature of list comprehensions. Once you get used to the syntax it is easy to follow. Though a lot happens in one row, so be careful to not overuse so that it gets hard to grasp.
def part2(data): def traverse(right, down): # Filter out jumped rows rows_hit = [ row for idx, row in enumerate(data) if idx % down == 0 ] # Filter out rows where we encounter a tree trees_encountered = [ idx for idx, row in enumerate(rows_hit) if row[(idx * right) % len(row)] == '#' ] return len(trees_encountered) return traverse(1,1) * traverse(3,1) * traverse(5,1) * traverse(7,1) * traverse(1,2)
I hope these solutions were helpful for you. Just ask if anything was hard to grasp.
Complete code can be found at: github.com/cNille/AdventOfCode/blob/master/2020/03.py