Advent of Code: Day 20

For Day 20, the challenge is to simulate some particles, removing those that collide.

import re
import copy

STABLE = 500

class Particle:
    def __init__(self, id, p, v, a):
        self.id = id
        self.p = p
        self.v = v
        self.a = a
        self.collided = False

    def tick(self):
        self.v[0] += self.a[0]
        self.v[1] += self.a[1]
        self.v[2] += self.a[2]
        self.p[0] += self.v[0]
        self.p[1] += self.v[1]
        self.p[2] += self.v[2]

    @property
    def distance(self):
        return sum([abs(i) for i in self.p])

    @property
    def moving(self):
        return not self.v[0] == 0 or not self.v[1] == 0 or not self.v[2] == 0

def toint(lst):
    return [int(i) for i in lst]

particles = []

with open("input.txt", "r") as o:
    i = 0
    for line in o.readlines():
        parts = re.findall("\<(.*?)\>", line)
        particles.append(Particle(i, toint(parts[0].split(",")), toint(parts[1].split(",")), toint(parts[2].split(","))))
        i += 1

def simulate(particles, remove_on_collision=False):
    moving = particles[:]
    last_count = len(moving)
    since_change = 0

    while len(moving) > 0:
        if remove_on_collision:
            by_position = {}

        if len(moving) == last_count:
            since_change += 1
        else:
            last_count = len(moving)
            since_change = 0

        if since_change == STABLE:
            break
        to_remove = []
        for m in moving:
            m.tick()
            if not m.moving:
                to_remove.append(m)

            if remove_on_collision:
                pos = tuple(m.p)
                if not pos in by_position:
                    by_position[pos] = []
                by_position[pos].append(m)

        if remove_on_collision:
            for pos in by_position.keys():
                if len(by_position[pos]) > 1:
                    for m in by_position[pos]:
                        m.collided = True
                        to_remove.append(m)

        for m in to_remove:
            moving.remove(m)

part1 = [copy.deepcopy(p) for p in particles]
simulate(part1)
min_i = 0
min_distance = 9999999
for p in part1:
    if p.distance < min_distance:
        min_i = p.id
        min_distance = p.distance

simulate(particles, True)

uncollided = [p for p in particles if not p.collided]

print "Part 1", min_i
print "Part 2", len(uncollided)

Advent of Code runs every day up to Christmas, you should join in!.

Show Comments

Get the latest posts delivered right to your inbox.