Part 1


In [24]:
import numpy as np

In [25]:
def parse(fn):
    levels = []
    with open(fn, 'rt') as f:
        for l in f.readlines():
            levels.append(l.rstrip('\n'))
    return levels

In [69]:
class BluePrint:
    
    def __init__(self, fn):
        self.tracks = {}
        self.carts  = []
        levels = parse(fn)
        under = dict(zip('^v<>|-/\\+ ', '||--|-/\\+ '))
        for j, lev in enumerate(levels):
            lev = list(lev)
            for i, c in enumerate(lev):
                pos = (i, j)
                if c in '^>v<':
                    self.carts.append(Cart(pos, c))
                self.tracks[pos] = under[c]

class Cart:
    
    def __init__(self, pos, face):
        self.pos       = pos
        self.face      = face
        self.turn      = 'l'
        
    def step(self):
        
        clockwise = [[0,-1],[1,0],[0,1],[-1,0]]
        moves     = dict(zip('^>v<', map(np.array, clockwise)))
        left      = dict(zip('^<v>', '<v>^'))
        right     = dict(zip('^>v<', '>v<^'))
        straight  = dict(zip('^<v>', '^<v>'))
        turn      = dict(zip('lsr', [left, straight, right]))
        next_turn = dict(zip('lsr', 'srl'))
        corner    = {'/': dict(zip('^>v<', '>^<v')), '\\': dict(zip('^>v<', '<v>^'))}
    
        self.pos = tuple(np.array(self.pos) + moves[self.face])
        new = blueprint.tracks[self.pos]
        if new == '+':
            self.face = turn[self.turn][self.face]
            self.turn = next_turn[self.turn]
        if new in ['/', '\\']:
            self.face = corner[new][self.face]

def first_collision():
    
    carts = blueprint.carts
    keep_moving = True
    while keep_moving:
        carts     = sorted(carts, key=lambda x: x.pos[::-1])
        counter   = len(carts)
        current   = list(map(lambda x: x.pos, carts))
        while counter > 0:
            cart = carts.pop(0)
            current.pop(0)
            cart.step()
            carts.append(cart)
            if cart.pos in current:
                print(','.join(map(str, cart.pos)))
                keep_moving = False
                break
            else:
                current.append(cart.pos)
                counter -= 1

Test


In [80]:
blueprint = BluePrint('input_test1.txt')
first_collision()


7,3

Solution


In [81]:
blueprint = BluePrint('input.txt')
first_collision()


41,17

Part 2


In [87]:
def cartnage():
    
    carts = blueprint.carts
    while len(carts) > 1:
        carts     = sorted(carts, key=lambda x: x.pos[::-1])
        tick      = [1 for x in carts]
        current   = list(map(lambda x: x.pos, carts))
        while sum(tick) > 0:
            cart = carts.pop(0)
            current.pop(0)
            tick.pop(0)
            cart.step()
            if cart.pos in current:
                indices = [i for i, c in enumerate(carts) if c.pos != cart.pos]
                carts = [carts[i] for i in indices]
                tick = [tick[i] for i in indices]
                current = [x.pos for x in carts]
            else:
                current.append(cart.pos)
                carts.append(cart)
                tick.append(0)
    print(','.join(map(str, cart.pos)))

Test


In [88]:
blueprint = BluePrint('input_test2.txt')
cartnage()


6,4

In [89]:
blueprint = BluePrint('input.txt')
cartnage()


134,117