refactor part 1
This commit is contained in:
124
day10/day10.py
124
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)
|
||||
|
||||
|
Reference in New Issue
Block a user