From b0a982c64dd66ed04d8aa5490d203374e58f6edc Mon Sep 17 00:00:00 2001 From: Dmitry Fedotov Date: Fri, 5 Jan 2024 04:44:15 +0300 Subject: [PATCH] refactor part 1 --- day10/day10.py | 124 ++++++++++++++++++++++++++++--------------------- 1 file changed, 71 insertions(+), 53 deletions(-) diff --git a/day10/day10.py b/day10/day10.py index a5a2cf1..984d129 100644 --- a/day10/day10.py +++ b/day10/day10.py @@ -50,25 +50,26 @@ class Tile(object): self.links = [S, E] def __str__(self): - return self.val + return f'{self.val} x: {self.x} y: {self.y}' - def opposite_end(self, d: Direction) -> Direction: - entry = d.opposite() - if not entry in self.links: + def __eq__(self, obj) -> bool: + return self.x == obj.x and self.y == obj.y + + def __hash__(self): + return hash((self.x, self.y)) + + def opposite_pipe_end(self, d: Direction) -> Direction: + if not d in self.links: return None - if entry == self.links[0]: + if d == self.links[0]: return self.links[1] else: return self.links[0] def has_link_from(self, d: Direction) -> bool: - return (d.opposite() in self.links) + return (d in self.links) - def is_pipe(self): - return self.val != '.' - - class Field(object): def __init__(self, lines: list[str]): self.grid = [list(l) for l in lines] @@ -82,77 +83,94 @@ class Field(object): out += ''.join([str(tile) for tile in row]) + '\n' return out - def get(self, x, y: int) -> Tile: - if y >= len(self.grid) or x >= len(self.grid): + def _get(self, x, y: int) -> Tile: + if y < 0 or x < 0 or y >= len(self.grid) or x >= len(self.grid): return None return self.grid[y][x] + def get_adjacent(self, t: Tile, d: Direction) -> Tile: + x, y = t.x, t.y + if d == E: + x += 1 + elif d == S: + y += 1 + elif d == W: + x -= 1 + elif d == N: + y -= 1 + return self._get(x, y) + + + class Walker(Field): def __init__(self, lines): super().__init__(lines) + self.loop = [] + self.visited = set() def _get_start(self) -> Tile: for y in range(len(self.grid)): for x in range(len(self.grid[0])): - t = self.get(x, y) + t = self._get(x, y) if t.val == START: return t return None - def _walk_to_start(self, t: Tile, direction: Direction) -> (bool, int): - self.visited = set() - steps = 0 - while True: - x, y = t.x, t.y - self.visited.add((x, y)) - if direction == E: - x += 1 - elif direction == S: - y += 1 - elif direction == W: - x -= 1 - elif direction == N: - y -= 1 - nxt = self.get(x, y) - if (not nxt): - break - - steps += 1 - if nxt.val == START: - return True, steps - if not nxt.has_link_from(direction): - break - - t = nxt - d = nxt.opposite_end(direction) - direction = d - return False, steps + def _find_loop(self): + start = self._get_start() + for d in [N, E, S, W]: + curr = start + dir = d + self.loop = [] + while True: + self.loop.append(curr) + nxt = self.get_adjacent(curr, dir) + if not nxt or not nxt.has_link_from(dir.opposite()): + break + if nxt.val == START: + return + curr = nxt + dir = nxt.opposite_pipe_end(dir.opposite()) def find_max_steps_in_loop(self) -> int: - start = self._get_start() - for direction in [N, E, S, W]: - found, steps = self._walk_to_start(start, direction) - if found: - return steps // 2 + self._find_loop() + return len(self.loop) // 2 def find_captured_by_loop(self) -> int: - if not self.visited: - self.find_max_steps_in_loop() - pass + if not self.loop: + # this fills self.loop slice + # with loop tiles + self._find_loop() + self.visited = set(self.loop) + inside_loop = set() + for t in self.loop: + for d in [N, E, S, W]: + newt = self.get_adjacent(t, d) + if not newt or newt in self.visited: + continue + if self._is_inside_loop(newt): + inside_loop.add(newt) + self.visited.add(newt) + return len(inside_loop) + + + def _is_inside_loop(self, t: Tile) -> bool: + # TODO + return True + - if __name__ == '__main__': r = tools.Reader('test_input.txt') lines = r.read() w = Walker(lines) - print(w) steps = w.find_max_steps_in_loop() print(steps) - print(w.visited) + n = w.find_captured_by_loop() + print(n) r = tools.Reader('input.txt') lines = r.read() @@ -160,5 +178,5 @@ if __name__ == '__main__': w = Walker(lines) steps = w.find_max_steps_in_loop() print(steps) - # print(w.visited) + # print(w.loop)