From 1f714736f57c134645b20fe660c34fc4b3c3cdf6 Mon Sep 17 00:00:00 2001 From: dece Date: Thu, 3 Dec 2020 17:02:39 +0100 Subject: [PATCH] Day 3 --- 2020/__init__.py | 0 2020/day3.py | 40 +++++++++++++++++++++++++++++++++++ 2020/grid.py | 55 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+) create mode 100644 2020/__init__.py create mode 100644 2020/day3.py create mode 100644 2020/grid.py diff --git a/2020/__init__.py b/2020/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/2020/day3.py b/2020/day3.py new file mode 100644 index 0000000..468b201 --- /dev/null +++ b/2020/day3.py @@ -0,0 +1,40 @@ +from grid import Grid + + +def main(): + with open("day3.txt", "rt") as f: + lines = [line.rstrip() for line in f.readlines()] + g = Grid(lambda: ".") + g.load(lines) + g_width = len(lines[0]) + g_height = len(lines) + + # Part 1 + x, y = 0, 0 + num_trees = 0 + while y < g_height: + x += 3 + x %= g_width + y += 1 + if g.getv(x, y) == "#": + num_trees += 1 + print("Trees encountered:", num_trees) + + # Part 2 + v = 1 + for xx, yy in [(1, 1), (3, 1), (5, 1), (7, 1), (1, 2)]: + x, y = 0, 0 + num_trees = 0 + while y < g_height: + x += xx + x %= g_width + y += yy + if g.getv(x, y) == "#": + num_trees += 1 + print(f"Slope ({xx}, {yy}), trees encountered:", num_trees) + v *= num_trees + print("Value:", v) + + +if __name__ == "__main__": + main() diff --git a/2020/grid.py b/2020/grid.py new file mode 100644 index 0000000..87d7829 --- /dev/null +++ b/2020/grid.py @@ -0,0 +1,55 @@ +"""Generic 2D grid with a few helpers.""" + +from collections import defaultdict + + +class Grid: + + def __init__(self, value_factory=int, lines=None): + self.g = defaultdict(lambda: defaultdict(value_factory)) + if lines: + self.load(lines) + + def getv(self, x, y): + return self.g[y][x] + + def setv(self, x, y, value): + self.g[y][x] = value + + def load(self, lines, f=lambda v: v): + for y, line in enumerate(lines): + for x, c in enumerate(line.rstrip()): + self.g[y][x] = f(c) + + def values_gen(self): + for y, row in self.g.items(): + for x, v in row.items(): + yield (x, y, v) + + def near_objects(self, p): + """Return a dict of neighbor positions to values (U, L, D, R).""" + return {q: self.g[q[1]][q[0]] for q in Grid.near(p)} + + def dumb_print(self, f=lambda v: v): + for row in self.g.values(): + for x in row.values(): + print(f(x), end="") + print() + + def print_near(self, p, view_size=2): + """Print near values in an area of view_size. Works iff keys support addition.""" + for dy in range(-view_size, view_size + 1): + print("".join([ + self.g[p[1] + dy][p[0] + dx] + for dx in range(-view_size, view_size + 1) + ])) + + @staticmethod + def near(p): + """Return a tuple of neighbor positions (up, left, down, right).""" + return ( + (p[0] , p[1] - 1), + (p[0] + 1, p[1] ), + (p[0] , p[1] + 1), + (p[0] - 1, p[1] ), + )