aoc2018/day13.py
2023-11-27 06:18:31 +01:00

117 lines
3.4 KiB
Python

from tools.aoc import AOCDay
from tools.coordinate import Coordinate
from typing import Any
from tools.grid import Grid
DIRS = [
Coordinate(-1, 0),
Coordinate(0, -1),
Coordinate(1, 0),
Coordinate(0, 1),
] # left, up, right, down
class Cart:
def __init__(self, num: int, pos: Coordinate, cur_dir: int = 0):
self.destroyed = False
self.cur_dir = cur_dir
self.next_turn = 0
self.pos = pos
self.num = num
def crossing_turn(self):
self.cur_dir = (self.cur_dir + self.next_turn - 1) % 4
self.next_turn = (self.next_turn + 1) % 3
def corner_turn(self, corner: tuple):
self.cur_dir = (self.cur_dir + corner[self.cur_dir]) % 4
def move(self):
self.pos += DIRS[self.cur_dir]
def __str__(self):
return "Cart(%s, %s, %s)" % (self.num, self.pos, self.cur_dir)
class Day(AOCDay):
inputs = [
[
("7,3", "input13_test"),
("53,133", "input13"),
],
[
("6,4", "input13_test2"),
("111,68", "input13"),
],
]
def parse_input(self) -> (Grid, set[Cart]):
grid = Grid()
carts = set()
num = 0
for y, line in enumerate(self.getInput()):
for x, c in enumerate(line):
if c == " ":
continue
elif c == "/":
grid.set(Coordinate(x, y), (-1, 1, -1, 1))
elif c == "\\":
grid.set(Coordinate(x, y), (1, -1, 1, -1))
elif c == "+":
grid.set(Coordinate(x, y), (1,))
elif c == "|" or c == "-":
grid.set(Coordinate(x, y), (0,))
elif c in ["^", "<", "v", ">"]:
grid.set(Coordinate(x, y), (0,))
carts.add(
Cart(num, Coordinate(x, y), ["<", "^", ">", "v"].index(c))
)
num += 1
return grid, carts
def get_crash(self, return_first: bool) -> str:
track, carts = self.parse_input()
while True:
if len(carts) == 1:
winner = carts.pop()
return "%s,%s" % (winner.pos.x, winner.pos.y)
cart_order = list(sorted(carts, key=lambda c: c.pos))
cart_pos = [c.pos for c in cart_order]
for cart in cart_order:
if cart.destroyed:
continue
cart.move()
if cart.pos in cart_pos:
if return_first:
return "%s,%s" % (cart.pos.x, cart.pos.y)
carts.remove(cart)
cart.destroyed = True
for x in cart_order:
if x.pos == cart.pos and cart.num != x.num:
x.destroyed = True
carts.remove(x)
break
cart_pos = [c.pos for c in carts]
track_pos = track.get(cart.pos)
if len(track_pos) > 1:
cart.corner_turn(track_pos)
elif track_pos[0] == 1:
cart.crossing_turn()
def part1(self) -> Any:
return self.get_crash(True)
def part2(self) -> Any:
return self.get_crash(False)
if __name__ == "__main__":
day = Day(2018, 13)
day.run(verbose=True)