You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

132 lines
3.1 KiB
Python

from pprint import pprint
from copy import deepcopy
from time import sleep
from asciimatics.screen import Screen
from random import randint
m = []
fix_map = {
'\n': ' ',
'^': '|',
'v': '|',
'>': '-',
'<': '-'
}
r_turns = { '^': '>', '>': 'v', 'v': '<', '<': '^' }
l_turns = { '^': '<', '>': '^', 'v': '>', '<': 'v' }
cart_symbols = ['^', 'v', '>', '<']
carts = []
class Cart:
def __init__(self, x, y, dir):
self.x = x
self.y = y
self.dir = dir
self.turn_counter = 0
@property
def pos(self):
return (self.y, self.x)
def turn_intersection(self):
if self.turn_counter == 0:
self.dir = l_turns[self.dir]
if self.turn_counter == 2:
self.dir = r_turns[self.dir]
self.turn_counter = (self.turn_counter + 1) % 3
def turn_corner(self, corner):
my_map = {
('/', '^'): '>',
('/', '>'): '^',
('/', 'v'): '<',
('/', '<'): 'v',
('\\', '^'): '<',
('\\', '>'): 'v',
('\\', 'v'): '>',
('\\', '<'): '^',
}
self.dir = my_map[(corner, self.dir)]
def move(self):
if self.dir == '^':
self.y -= 1
elif self.dir == '>':
self.x += 1
elif self.dir == 'v':
self.y += 1
elif self.dir == '<':
self.x -= 1
symbol = m[self.y][self.x]
if symbol in ['/', '\\']:
self.turn_corner(symbol)
if symbol == '+':
self.turn_intersection()
with open('input.txt', 'r') as f:
for y, line in enumerate(f.readlines()):
row = []
for x, symbol in enumerate(line):
row.append(fix_map.get(symbol) or symbol)
if symbol in cart_symbols:
carts.append(Cart(x, y, symbol))
m.append(row)
def print_map(screen):
m_cpy = deepcopy(m)
for cart in carts:
m_cpy[cart.y][cart.x] = cart.dir
for i, row in enumerate(m_cpy):
screen.print_at(''.join(row), 0, i)
def anim(screen):
while 1:
carts.sort(key=lambda x: x.pos)
for cart in carts:
cart.move()
# sleep(1)
print_map(screen)
ev = screen.get_key()
if ev in (ord('Q'), ord('q')):
return
screen.refresh()
# Screen.wrapper(anim)
def crashers():
to_rem = set()
for c1 in carts:
for c2 in carts:
if c1 is not c2 and c1.pos == c2.pos:
# print('crash at:', c1.pos)
to_rem.add(c1)
to_rem.add(c2)
return to_rem
def get_remaining():
while len(carts) > 1:
num_carts = len(carts)
carts.sort(key=lambda x: x.pos)
to_rem = set()
for cart in carts:
cart.move()
to_rem = to_rem.union(crashers())
for cart in to_rem:
carts.remove(cart)
if len(carts) != num_carts:
print(f'Reduces carts from {num_carts} to {len(carts)}')
return carts[0]
pos = get_remaining().pos
print(f'{pos[1]},{pos[0]}')