def get_neighbors(grid, x, y): neighbors = [] if y > 0: neighbors.append(point(x, y - 1)) if y < len(grid) - 1: neighbors.append(point(x, y + 1)) if x > 0: neighbors.append(point(x - 1, y)) if x < len(grid[0]) - 1: neighbors.append(point(x + 1, y)) return neighbors
def clone(self) -> grid: cl = grid(self.width, self.height, self.get(point(0, 0))) for y in range(self.height): for x in range(self.width): cl.set(point(x, y), self.get(point(x, y))) return cl
def move_east(cucumbers: grid) -> grid: step: grid = cucumbers.clone() eastie_bois = cucumbers.find_all(lambda cell: cell == '>') for boi in eastie_bois: x = (boi.x + 1) % cucumbers.width if cucumbers.get(point(x, boi.y)) == '.': step.set(point(boi.x, boi.y), '.') step.set(point(x, boi.y), '>') return step
def move_south(cucumbers: grid) -> grid: step: grid = cucumbers.clone() eastie_bois = cucumbers.find_all(lambda cell: cell == 'v') for boi in eastie_bois: y = (boi.y + 1) % cucumbers.height if cucumbers.get(point(boi.x, y)) == '.': step.set(point(boi.x, boi.y), '.') step.set(point(boi.x, y), 'v') return step
def find_all( self, predicate: Callable[[T], bool] = lambda _: True) -> list[point]: return [ point(x, y) for x in range(self.width) for y in range(self.height) if predicate(self.matrix[y][x]) ]
def find_basin(grid, x, y): visited = [point(x, y)] basin = [point(x, y)] tovisit = get_neighbors(grid, x, y) while tovisit: p = tovisit.pop() if p in visited: continue visited.append(p) if grid[p.y][p.x] == 9: continue basin.append(p) neighbors = get_neighbors(grid, p.x, p.y) tovisit.extend([n for n in neighbors if n not in visited]) return basin
def process(velocity: point, target: rect) -> point: max_x = target.x + target.w min_y = target.y pos = point(0, 0) i = 0 while pos.x >= 0 and pos.x <= max_x and pos.y >= min_y: i += 1 pos = step(velocity, i) yield pos
def part1(target): total_max_y = 0 for x in range(target.x): for y in range(target.x): velocity = point(x, y) steps: list[point] = [step for step in process(velocity, target)] if any(step.in_rect(target) for step in steps): highest = max(steps, key=lambda p: p.y) total_max_y = max(total_max_y, highest.y) print(total_max_y)
def neighbors(self, p: point, diag: bool = False) -> list[point]: other: list[point] = [ point(p.x, p.y - 1), point(p.x, p.y + 1), point(p.x - 1, p.y), point(p.x + 1, p.y) ] if diag: other.extend([ point(p.x - 1, p.y - 1), point(p.x + 1, p.y - 1), point(p.x - 1, p.y + 1), point(p.x + 1, p.y + 1) ]) return [p for p in other if self.in_grid(p)]
def fold_vert(dots, x): copy = [p for p in dots if p.x < x] for p in [p for p in dots if p.x > x]: copy.append(point(x - (p.x - x), p.y)) return copy
def fold_hor(dots, y): copy = [p for p in dots if p.y < y] for p in [p for p in dots if p.y > y]: copy.append(point(p.x, y - (p.y - y))) return copy
from aoc.grid import grid import re pattern = '^(\d+),(\d+)$' pattern_fold = '^fold along (\w)=(\d+)' lines = aoc.read_lines('data/13.txt') dots = [] folds = [] for line in lines: digits = re.match(pattern, line) if digits: x, y = digits.groups() dots.append(point(int(x), int(y))) continue fold_instr = re.match(pattern_fold, line) if fold_instr: axis, num = fold_instr.groups() folds.append((axis, int(num))) def print_dots(dots): x_max = max([p.x for p in dots]) y_max = max([p.y for p in dots]) g = grid(x_max + 1, y_max + 1, '.') for dot in dots: g.set(dot, '#') g.print_condensed()
def step(velocity: point, n: int): return point(sum_ap_x(velocity.x, n, -1), sum_ap_y(velocity.y, n, -1))