It’s day 3 already! As before, all my solutions are available on https://git.sr.ht/~schnouki/advent-of-code.
Today we’ll talk about toboggan trajectories!1 In typical AoC fashion, our input is a map in ASCII art. What’s important to us is its size and the position of the trees… So we’ll parse this input and store just that: the width and height of the map, and the coordinates of all trees as a set of
(x, y) tuples.
from dataclasses import dataclass from typing import Set, Tuple Coord = Tuple[int, int] @dataclass class Map: w: int h: int trees: Set[Coord] def add_line(self, line: str): w = len(line) if self.w == 0: self.w = w elif self.w != w: raise ValueError() for x in range(w): if line[x] == "#": self.trees.add((x, self.h)) self.h += 1 data = Map(0, 0, set()) for line in raw_data.splitlines(): data.add_line(line) return data
We need to count trees on a trajectory with a given slope. Basically, go right, go down, and if there’s a tree at this position, increment a counter. As the map “repeats” horizontally, we calculate horizontal coordinates modulo the map width.
We end up with this very simple and generic method for our
@dataclass class Map: ... def count_trees(self, right: int, down: int) -> int: n = 0 x = 0 for y in range(down, self.h, down): x = (x + right) % self.w if (x, y) in self.trees: n += 1 return n ... print(data.count_trees(3, 1))
That’s it. 0.04 ms.
Same things, but with several different slops, and we must multiply the results together. Easy enough, thanks to that generic
slopes = ((1, 1), (3, 1), (5, 1), (7, 1), (1, 2)) res = 1 for right, down in slopes: res *= data.count_trees(right, down) print(res)
And we’re done. 0.16 ms.
What a weird sentence to write. ↩︎