DEV Community

Discussion on: AoC Day 13: Mine Cart Madness

Collapse
 
easyaspython profile image
Dane Hillard • Edited

This one seemed like the hardest one so far on first reading, but I ended up grasping it better than a couple of the previous puzzles. I ended up using a deque to make the turning directions easier to muck with:

#!/usr/bin/env python

from collections import deque


class Cart:
    def __init__(self, x, y, current_direction):
        self.x = x
        self.y = y
        self.current_direction = current_direction
        self.num_intersections_reached = 0
        self.directions = deque(['<', 'v', '>', '^'])
        self.collided = False
        while self.directions[0] != self.current_direction:
            self.directions.rotate()

    def move(self):
        self.x += 1 if self.current_direction == '>' else -1 if self.current_direction == '<' else 0
        self.y += 1 if self.current_direction == 'v' else -1 if self.current_direction == '^' else 0

    def turn_left(self):
        self.directions.rotate(-1)
        self.current_direction = self.directions[0]

    def turn_right(self):
        self.directions.rotate(1)
        self.current_direction = self.directions[0]

    def update_direction(self, track):
        track_piece = track[self.y][self.x]

        if track_piece == '+':
            self.num_intersections_reached += 1
            self.num_intersections_reached %= 3

            if self.num_intersections_reached  == 1:
                self.turn_left()
            elif self.num_intersections_reached  == 0:
                self.turn_right()
        elif track_piece == '/':
            if self.current_direction in {'^', 'v'}:
                self.turn_right()
            else:
                self.turn_left()
        elif track_piece == '\\':
            if self.current_direction in {'^', 'v'}:
                self.turn_left()
            else:
                self.turn_right()


def get_next_state(track_state, carts):
    carts.sort(key=lambda cart: (cart.y, cart.x))

    for cart in carts:
        cart.move()
        cart.update_direction(track_state)

        for other_cart in carts:
            if cart != other_cart and cart.x == other_cart.x and cart.y == other_cart.y:
                cart.collided = other_cart.collided = True
                print(f'Crash: {cart.x},{cart.y}')

    carts = [cart for cart in carts if not cart.collided]

    return track_state, carts


def run(track_state, carts):
    while True:
        track_state, carts = get_next_state(track_state, carts)
        if len(carts) == 1:
            print(f'Last cart standing: {carts[0].x},{carts[0].y}')
            return track_state


if __name__ == '__main__':
    with open('input.txt') as track_file:
        track_state = [
            [char for char in line]
            for line in track_file.read().splitlines()
        ]

    carts = []
    for y, row in enumerate(track_state):
        for x, char in enumerate(row):
            if char in {'^', 'v', '>', '<'}:
                carts.append(Cart(x, y, char))

            if char in {'<', '>'}:
                track_state[y][x] = '-'
            elif char in {'^', 'v'}:
                track_state[y][x] = '|'

    track_state = run(track_state, carts)