139 lines
3.0 KiB
Python
139 lines
3.0 KiB
Python
import sys
|
|
sys.path.append('../aoclib')
|
|
|
|
from aoclib import Input
|
|
from time import sleep
|
|
|
|
D_U = '^'
|
|
D_R = '>'
|
|
D_D = 'v'
|
|
D_L = '<'
|
|
|
|
|
|
class Guard(object):
|
|
dirs = [D_U, D_R, D_D, D_L]
|
|
def __init__(self, x, y, dir: str):
|
|
self.d = dir
|
|
self.x = x
|
|
self.y = y
|
|
|
|
def turn(self):
|
|
self.d = self.dirs[(self.dirs.index(self.d) + 1) % len(self.dirs)]
|
|
|
|
def curr(self):
|
|
return self.x, self.y
|
|
|
|
def want(self):
|
|
if self.d == D_U:
|
|
return self.x, self.y-1
|
|
elif self.d == D_R:
|
|
return self.x+1, self.y
|
|
elif self.d == D_D:
|
|
return self.x, self.y+1
|
|
elif self.d == D_L:
|
|
return self.x-1, self.y
|
|
|
|
def next(self):
|
|
self.x, self.y = self.want()
|
|
|
|
def __str__(self):
|
|
return self.d
|
|
|
|
|
|
class Map(list):
|
|
def __init__(self, l: list):
|
|
super().__init__(l)
|
|
|
|
def has_obstacle(self, x, y: int) -> bool:
|
|
return self[y][x] == '#'
|
|
|
|
def out_of_bounds(self, x, y):
|
|
return (x < 0 or y < 0) or (x >= len(self[0]) or y >= len(self))
|
|
|
|
|
|
class Lab(object):
|
|
def __init__(self, m: Map, g: Guard):
|
|
self.m = m
|
|
self.g = g
|
|
self.visited = set()
|
|
self.print_visited = False
|
|
self.g_init = Guard(g.x, g.y, g.d)
|
|
|
|
def next(self) -> bool:
|
|
self.visited.add(self.g.curr())
|
|
|
|
x, y = self.g.want()
|
|
if self.m.out_of_bounds(x, y):
|
|
return False
|
|
elif self.m.has_obstacle(x, y):
|
|
self.g.turn()
|
|
return True
|
|
|
|
self.g.next()
|
|
return True
|
|
|
|
def reset(self):
|
|
self.visited = set()
|
|
self.g = Guard(self.g_init.x, self.g_init.y, self.g_init.d)
|
|
|
|
|
|
def solve_part1(self):
|
|
while self.next():
|
|
pass
|
|
return len(self.visited)
|
|
|
|
def animate(self, visited=False):
|
|
'''
|
|
Just wanted to show kids what it looks like
|
|
'''
|
|
cls = lambda: print(chr(27) + "[2J")
|
|
self.print_visited = visited
|
|
|
|
cls()
|
|
print('Watch this')
|
|
sleep(1)
|
|
|
|
cls()
|
|
print(self)
|
|
while self.next():
|
|
cls()
|
|
print(self)
|
|
sleep(0.5)
|
|
|
|
def __str__(self):
|
|
out = [l.copy() for l in self.m]
|
|
if self.print_visited:
|
|
for t in self.visited:
|
|
x, y = t
|
|
out[y][x] = 'X'
|
|
out[self.g.y][self.g.x] = self.g.__str__()
|
|
return '\n'.join([''.join(line) for line in out])
|
|
|
|
|
|
def parse_input(lst) -> (Lab):
|
|
g, m = None, None
|
|
for y, l in enumerate(lst):
|
|
if D_U in l:
|
|
x = l.index('^')
|
|
g = Guard(x, y, D_U)
|
|
lst[y][x] = '.'
|
|
m = Map(lst)
|
|
return Lab(m, g)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
lines = Input('input_test.txt').lines_as_lists()
|
|
#lines = Input('input.txt').lines_as_lists()
|
|
|
|
lab = parse_input(lines)
|
|
|
|
#lab.animate(True)
|
|
lab.animate()
|
|
lab.reset()
|
|
|
|
#part 1
|
|
print('part 1:', lab.solve_part1())
|
|
|
|
#part 2
|
|
print('part 2:', '')
|