Files
advent-of-code-2023/day10/day10.py
Dmitry Fedotov ef41b90bec day 10 part one
2024-01-05 00:40:13 +03:00

165 lines
3.9 KiB
Python

import sys
sys.path.append('../lib')
import tools
START = 'S'
class Direction(object):
def __init__(self, val: str):
self.val = val
def __eq__(self, other):
return self.val == other.val
def __hash__(self):
return hash(self.val)
def opposite(self):
if self == N:
return S
elif self == S:
return N
elif self == E:
return W
elif self == W:
return E
N = Direction('N')
E = Direction('E')
S = Direction('S')
W = Direction('W')
class Tile(object):
def __init__(self, val: str, x, y):
self.val = val
self.x = x
self.y = y
self.links = []
if val == '|':
self.links = [N, S]
elif val == '-':
self.links = [E, W]
elif val == 'L':
self.links = [N, E]
elif val == 'J':
self.links = [N, W]
elif val == '7':
self.links = [W, S]
elif val == 'F':
self.links = [S, E]
def __str__(self):
return self.val
def opposite_end(self, d: Direction) -> Direction:
entry = d.opposite()
if not entry in self.links:
return None
if entry == 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)
def is_pipe(self):
return self.val != '.'
class Field(object):
def __init__(self, lines: list[str]):
self.grid = [list(l) for l in lines]
for y in range(len(self.grid)):
for x in range(len(self.grid[0])):
self.grid[y][x] = Tile(self.grid[y][x], x, y)
def __str__(self):
out = 'Field:\n'
for row in self.grid:
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):
return None
return self.grid[y][x]
class Walker(Field):
def __init__(self, lines):
super().__init__(lines)
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)
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_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
def find_captured_by_loop(self) -> int:
if not self.visited:
self.find_max_steps_in_loop()
pass
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)
r = tools.Reader('input.txt')
lines = r.read()
w = Walker(lines)
steps = w.find_max_steps_in_loop()
print(steps)
# print(w.visited)