Good Morning AoC! Day 3. So, continuing our journey to our vacation, we solved the password for toboggan system, now we can get ourselves to the airport sliding down a toboggan.
Day 3: Toboggan Trajectory
https://adventofcode.com/2020/day/3
There is a map that shows the location of all trees in the region, lovingly available in plain text. Trees are marked with the character “#” and open spaces with “.”.
The rate of descent also, according to the studies of the toboggan department, is 3 spaces to the right 1 downwards. The genetics of the region is also peculiar, it is repeated to the right, thus facilitating the graphical representation of the map. Here is a sample map:
1..##....... ..##....... ..##....... ..##....... ..##....... ..##....... --->
2#...#...#.. #...#...#.. #...#...#.. #...#...#.. #...#...#.. #...#...#..
3.#....#..#. .#....#..#. .#....#..#. .#....#..#. .#....#..#. .#....#..#.
4..#.#...#.# ..#.#...#.# ..#.#...#.# ..#.#...#.# ..#.#...#.# ..#.#...#.#
5.#...##..#. .#...##..#. .#...##..#. .#...##..#. .#...##..#. .#...##..#.
6..#.##..... ..#.##..... ..#.##..... ..#.##..... ..#.##..... ..#.##..... --->
7.#.#.#....# .#.#.#....# .#.#.#....# .#.#.#....# .#.#.#....# .#.#.#....#
8.#........# .#........# .#........# .#........# .#........# .#........#
9#.##...#... #.##...#... #.##...#... #.##...#... #.##...#... #.##...#...
10#...##....# #...##....# #...##....# #...##....# #...##....# #...##....#
11.#..#...#.# .#..#...#.# .#..#...#.# .#..#...#.# .#..#...#.# .#..#...#.# --->
12.#.#.#....# .#.#.#....# .#.#.#....# .#.#.#....# .#.#.#....# .#.#.#....#
13.#........# .#........# .#........# .#........# .#........# .#........#
14#.##...#... #.##...#... #.##...#... #.##...#... #.##...#... #.##...#...
15#...##....# #...##....# #...##....# #...##....# #...##....# #...##....#
The first task is “You start on the open square (.) in the top-left corner and need to reach the bottom (below the bottom-most row on your map). From your starting position at the top-left, check the position that is right 3 and down 1. Then, check the position that is right 3 and down 1 from there, and so on until you go past the bottom of the map.”
Starting at the top-left corner of your map and following a slope of right 3 and down 1, how many trees would you encounter?
Task 1 - Down the slope
This task can be easily solved with a loop and couple counters, one for column and one for row. After this, just a matter to check if the character on (row, column) is a tree ("#"), how? Our sample map have 11 columns and 15 lines, more rows than columns! The trick for this step is how do we emulate the tree pattern repetition to the right. We have to use modular division trick to emulate this pattern.
The modular division operator (in Python %
) return the remainder of a division between two numbers. This operation is useful to get, for example, every 4th item highlighted, known if a number is odd or not or repeat a pattern. Let’s see how. Let’s create a table with all modular division between 0..14
lines and 0..10
columns.
1 0 % 11 = 0
2 1 % 11 = 1
3 2 % 11 = 2
4 3 % 11 = 3
5 4 % 11 = 4
6 5 % 11 = 5
7 6 % 11 = 6
8 7 % 11 = 7
9 8 % 11 = 8
10 9 % 11 = 9
1110 % 11 = 10
1211 % 11 = 0
1312 % 11 = 1
1413 % 11 = 2
1514 % 11 = 3
So, using this artifice, we ask to reset the column counter every time the string ends, simulating the pattern repeat. The code to solve the first task should be like this one:
1def traverse(right, down):
2 col, line, tree_count = 0, 0, 0
3 while line < len(map):
4 if map[line][col % len(map[0])] == '#':
5 tree_count = tree_count + 1
6 col = col + right
7 line = line + down
8 return tree_count
9
10traverse(3, 1)
The code works fine, with the modular division. but, do not represent a pythonic code. Started my research how to solve it using Python advanced features (not external libraries). The main problem with this algorithm is the double counters (line and column), the first prototype I created works, and only works when down slope is 1. I created a logic that the column counter was depended on line counter value. So, how can I have two detached counters inside a List Comprehension?
Reading about list operations and iterators, I found a built-in function called enumerate
. This function receives as parameter a iterator object (sequence, iterator or a object that supports iteration) and returns an enumerate object. Use can use this object to returns a tuple containing a count (from start which defaults to 0) and the values obtained from iterating over iterable. Look how it works.
1> a = range(0, 100, 10)
2> list(enumerate(a))
3[(0, 0),
4 (1, 10),
5 (2, 20),
6 (3, 30),
7 (4, 40),
8 (5, 50),
9 (6, 60),
10 (7, 70),
11 (8, 80),
12 (9, 90)]
We can use the new counter as our column counter, but the line counter? Python list object are pretty interesting kind of object. We are used a Python technic called list slicing via x::y
list operator, where x
is where in the list the slicing will start and with step of y
. Like this:
1> a = list(range(0, 20))
2> print(a)
3[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
4> print(a[0::4])
5[0, 4, 8, 12, 16]
Second counter solved. Now we just have to rewrite the function using a lambda expression and problem done!
1traverse_new = lambda right, down: len(
2 [1 for i, line in enumerate(map[::down]) if line[i*right % len(map[i])] == '#']
3)
4print(f'Part 1: {traverse_new(3, 1)}')
Task 1 done… gimme my ⭐!
Task 2 - “Easy Peasy Lemon Squeezy”.
The Task 2 we gonna use our function to solve multiple slopes requirements and multiply all results.
-
Right 1, down 1.
-
Right 3, down 1.
-
Right 5, down 1.
-
Right 7, down 1.
-
Right 1, down 2.
1print(f'Part 2: {(
2 traverse_new(1,1) *
3 traverse_new(3,1) *
4 traverse_new(5,1) *
5 traverse_new(7, 1) *
6 traverse_new(1,2)
7)}')
Task 2 done… now I got my 2nd ⭐! Super Mario 64 feelings.
See you all on day 4.
Z
Comments