refactor part 1

This commit is contained in:
Dmitry Fedotov
2024-01-05 04:44:15 +03:00
parent ef41b90bec
commit b0a982c64d

View File

@@ -50,23 +50,24 @@ class Tile(object):
self.links = [S, E] self.links = [S, E]
def __str__(self): def __str__(self):
return self.val return f'{self.val} x: {self.x} y: {self.y}'
def opposite_end(self, d: Direction) -> Direction: def __eq__(self, obj) -> bool:
entry = d.opposite() return self.x == obj.x and self.y == obj.y
if not entry in self.links:
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 return None
if entry == self.links[0]: if d == self.links[0]:
return self.links[1] return self.links[1]
else: else:
return self.links[0] return self.links[0]
def has_link_from(self, d: Direction) -> bool: 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): class Field(object):
@@ -82,65 +83,82 @@ class Field(object):
out += ''.join([str(tile) for tile in row]) + '\n' out += ''.join([str(tile) for tile in row]) + '\n'
return out return out
def get(self, x, y: int) -> Tile: def _get(self, x, y: int) -> Tile:
if y >= len(self.grid) or x >= len(self.grid): if y < 0 or x < 0 or y >= len(self.grid) or x >= len(self.grid):
return None return None
return self.grid[y][x] 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): class Walker(Field):
def __init__(self, lines): def __init__(self, lines):
super().__init__(lines) super().__init__(lines)
self.loop = []
self.visited = set()
def _get_start(self) -> Tile: def _get_start(self) -> Tile:
for y in range(len(self.grid)): for y in range(len(self.grid)):
for x in range(len(self.grid[0])): for x in range(len(self.grid[0])):
t = self.get(x, y) t = self._get(x, y)
if t.val == START: if t.val == START:
return t return t
return None return None
def _walk_to_start(self, t: Tile, direction: Direction) -> (bool, int): def _find_loop(self):
self.visited = set() start = self._get_start()
steps = 0 for d in [N, E, S, W]:
while True: curr = start
x, y = t.x, t.y dir = d
self.visited.add((x, y)) self.loop = []
if direction == E: while True:
x += 1 self.loop.append(curr)
elif direction == S: nxt = self.get_adjacent(curr, dir)
y += 1 if not nxt or not nxt.has_link_from(dir.opposite()):
elif direction == W: break
x -= 1 if nxt.val == START:
elif direction == N: return
y -= 1 curr = nxt
nxt = self.get(x, y) dir = nxt.opposite_pipe_end(dir.opposite())
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_max_steps_in_loop(self) -> int: def find_max_steps_in_loop(self) -> int:
start = self._get_start() self._find_loop()
for direction in [N, E, S, W]: return len(self.loop) // 2
found, steps = self._walk_to_start(start, direction)
if found:
return steps // 2
def find_captured_by_loop(self) -> int: def find_captured_by_loop(self) -> int:
if not self.visited: if not self.loop:
self.find_max_steps_in_loop() # this fills self.loop slice
pass # 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
@@ -149,10 +167,10 @@ if __name__ == '__main__':
lines = r.read() lines = r.read()
w = Walker(lines) w = Walker(lines)
print(w)
steps = w.find_max_steps_in_loop() steps = w.find_max_steps_in_loop()
print(steps) print(steps)
print(w.visited) n = w.find_captured_by_loop()
print(n)
r = tools.Reader('input.txt') r = tools.Reader('input.txt')
lines = r.read() lines = r.read()
@@ -160,5 +178,5 @@ if __name__ == '__main__':
w = Walker(lines) w = Walker(lines)
steps = w.find_max_steps_in_loop() steps = w.find_max_steps_in_loop()
print(steps) print(steps)
# print(w.visited) # print(w.loop)