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,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)