Ejemplo n.º 1
0
def path_to_coords(path):
    if path == '':
        return Vec(0, 0)
    return path_to_coords(path[:-1]) + {
        'U': Vec(0, -1),
        'D': Vec(0, 1),
        'L': Vec(-1, 0),
        'R': Vec(1, 0)
    }[path[-1]]
Ejemplo n.º 2
0
def part2(inp):
    y_candidates = []
    for i in range(min(0, inp.lower[1] - 1),
                   max(abs(y) for _, y in [inp.lower, inp.upper]) + 1):
        if check_y_hit(Vec(0, i), inp):
            y_candidates.append(i)
    x_candidates = []
    for i in range(min(0, inp.lower[0] - 1), max(0, inp.upper[0] + 1)):
        if check_x_hit(Vec(i, 0), inp):
            x_candidates.append(i)
    return sum(
        check_hit(Vec(x, y), inp) for x in x_candidates for y in y_candidates)
Ejemplo n.º 3
0
def part1(inp):
    y_vel = 0
    for i in range(min(0, inp.lower[1] - 1),
                   max(abs(y) for _, y in [inp.lower, inp.upper]) + 1):
        if check_y_hit(Vec(0, i), inp):
            y_vel = i
    max_y = 0
    pos = Vec(0, 0)
    vel = Vec(0, y_vel)
    while True:
        pos, vel = step(pos, vel)
        if pos[1] < max_y:
            return max_y
        max_y = pos[1]
Ejemplo n.º 4
0
def enhance(img, alg):
    xmin = min(x for x, _ in img) - 1
    xmax = max(x for x, _ in img) + 1
    ymin = min(y for _, y in img) - 1
    ymax = max(y for _, y in img) + 1
    if img.default_factory():
        default = alg[-1]
    else:
        default = alg[0]
    return defaultdict(
        lambda: default, {
            Vec(x, y): alg[int(
                ''.join('1' if img[(Vec(x, y) + c)] else '0'
                        for c in square), 2)]
            for x in range(xmin, xmax + 1) for y in range(ymin, ymax + 1)
        })
Ejemplo n.º 5
0
def part2(inp):
    mapp = {}
    lx, ly = max(x for x, _ in inp) + 1, max(y for _, y in inp) + 1
    for (x, y), v in inp.items():
        for a, b in product(range(5), repeat=2):
            nv = (v + a + b) % 9
            mapp[Vec(x + a * lx, y + b * ly)] = 9 if nv == 0 else nv
    return find_shortest_path(mapp)
Ejemplo n.º 6
0
def check_hit(vel, target):
    pos = Vec(0, 0)
    while True:
        pos, vel = step(pos, vel)
        if pos in target:
            return True
        elif pos[1] < target.lower[1] and vel[1] < 0:
            return False
Ejemplo n.º 7
0
def check_x_hit(vel, target):
    pos = Vec(0, 0)
    while True:
        pos, vel = step(pos, vel)
        if target.lower[0] <= pos[0] <= target.upper[0]:
            return True
        elif vel[0] == 0:
            return False
Ejemplo n.º 8
0
def part2(inp):
    return reduce(
        operator.mul,
        reduce(
            operator.add,
            map(
                lambda x: Vec(x[1], x[0] * x[1]),
                zip(accumulate(dirs[d][1] * n for d, n in inp),
                    (dirs[d][0] * n for d, n in inp)))))
Ejemplo n.º 9
0
def part2(inp):
    boundary = {Vec(1, 1)}
    visited = boundary.copy()
    for _ in range(50):
        nb = set()
        for b in boundary:
            for d in dirs4:
                nc = b + d
                if nc not in visited and is_non_negative(nc) and not is_wall(
                        nc, inp):
                    nb.add(nc)
                    visited.add(nc)
        boundary = nb
    return len(visited)
Ejemplo n.º 10
0
def part1(inp):
    boundary = {Vec(1, 1)}
    visited = boundary.copy()
    for i in count(1):
        nb = set()
        for b in boundary:
            for d in dirs4:
                nc = b + d
                if nc == (31, 39):
                    return i
                if nc not in visited and is_non_negative(nc) and not is_wall(
                        nc, inp):
                    nb.add(nc)
                    visited.add(nc)
        boundary = nb
Ejemplo n.º 11
0
def part2(inp):
    mapp = {
        Vec(x, y)
        for y in range(128) for x, c in enumerate(knothash(f'{inp}-{y}'))
        if c == '1'
    }
    regions = 0
    while mapp:
        regions += 1
        boundary = {mapp.pop()}
        while boundary:
            current = boundary.pop()
            for d in dirs4:
                if d + current in mapp:
                    mapp.remove(d + current)
                    boundary.add(d + current)
    return regions
Ejemplo n.º 12
0
def find_shortest_path(mapp):
    start = Vec(0, 0)
    goal = max(mapp, key=sum)

    open_set = PriorityQueue()
    open_set.put(start, 0)
    g_score = defaultdict(lambda: math.inf, {start: 0})

    while open_set:
        current = open_set.get()
        if current == goal:
            return g_score[current]
        for neighbor in (current + d for d in dirs4 if (current + d) in mapp):
            tentative_g_score = g_score[current] + mapp[neighbor]
            if tentative_g_score < g_score[neighbor]:
                g_score[neighbor] = tentative_g_score
                f_score = tentative_g_score + (neighbor - goal).manhatten()
                open_set.put(neighbor, f_score)
Ejemplo n.º 13
0
def part2(inp):
    mapp = inp.copy()
    hole, holecap = next((c, a) for c, (u, a) in mapp.items() if u == 0)
    boundary = {(hole, Vec(max(x for x, y in mapp if y == 0), 0))}
    visited = boundary.copy()
    for i in count(1):
        nb = set()
        for h, t in boundary:
            for d in dirs4:
                if h == (0, 0) and t == h + d:
                    return i
                if mapp.get(h + d, (holecap + 1, 0))[0] <= holecap:
                    if h + d == t:
                        ns = (h + d, h)
                    else:
                        ns = (h + d, t)
                    if ns not in visited:
                        nb.add(ns)
                        visited.add(ns)
        boundary = nb
Ejemplo n.º 14
0
def shortest_distance(pos, collected):
    try:
        return min(d + shortest_distance(p, collected.union({p}))
                   for p, d in distances_from_point(find(pos)).items() if p not in collected and p != '0')
    except ValueError:
        return 0


def part1():
    return shortest_distance('0', frozenset())


@cache
def shortest_distance_return(pos, collected):
    try:
        return min(d + shortest_distance_return(p, collected.union({p}))
                   for p, d in distances_from_point(find(pos)).items() if p not in collected and p != '0')
    except ValueError:
        return distances_from_point(find(pos))['0']


def part2():
    return shortest_distance_return('0', frozenset())


if __name__ == '__main__':
    data = get_data(day=24, year=2016)
    mapp = {Vec(x, y): c for y, l in enumerate(data.splitlines()) for x, c in enumerate(l)}
    print(part1())
    print(part2())
Ejemplo n.º 15
0
def part1(inp):
    return max(map(abs, sum(map(dirs.get, inp), start=Vec(0, 0, 0))))
Ejemplo n.º 16
0
from itertools import accumulate

from aoc_utils import Vec
from aocd import get_data

# Use Hexagonal Cube Coordinates: https://www.redblobgames.com/grids/hexagons/
dirs = {
    'n': Vec(0, -1, 1),
    'ne': Vec(1, -1, 0),
    'se': Vec(1, 0, -1),
    's': Vec(0, 1, -1),
    'sw': Vec(-1, 1, 0),
    'nw': Vec(-1, 0, 1)
}


def part1(inp):
    return max(map(abs, sum(map(dirs.get, inp), start=Vec(0, 0, 0))))


def part2(inp):
    return max(
        map(lambda x: max(abs(i) for i in x), accumulate(map(dirs.get, inp))))


if __name__ == '__main__':
    data = get_data(day=11, year=2017)
    inp = data.split(',')
    print(part1(inp))
    print(part2(inp))
Ejemplo n.º 17
0
    for i in count(1):
        nb = set()
        for h, t in boundary:
            for d in dirs4:
                if h == (0, 0) and t == h + d:
                    return i
                if mapp.get(h + d, (holecap + 1, 0))[0] <= holecap:
                    if h + d == t:
                        ns = (h + d, h)
                    else:
                        ns = (h + d, t)
                    if ns not in visited:
                        nb.add(ns)
                        visited.add(ns)
        boundary = nb


if __name__ == '__main__':
    data = get_data(day=22, year=2016)
    inp = {
        Vec(x, y): (u, a)
        for x, y, u, a in (tuple(
            map(
                int,
                re.match(
                    r'^/dev/grid/node-x(\d+)-y(\d+)\s+\d+T\s+(\d+)T\s+(\d+)T\s+\d+%$',
                    l).groups())) for l in data.splitlines()[2:])
    }
    print(part1(inp))
    print(part2(inp))
Ejemplo n.º 18
0
from aoc_utils import Vec
from aocd import get_data


def part1(inp):
    return min(((a.manhatten(), v.manhatten(), p.manhatten(), n) for n, (p, v, a) in enumerate(inp)))[3]


def move(p):
    pos, vel, acc = p
    vel += acc
    pos += vel
    return pos, vel, acc


def part2(inp):
    parts = inp
    for _ in range(100):
        collisions = [p for p, n in Counter(p for p, _, _ in parts).items() if n > 1]
        parts = [move(p) for p in parts if p[0] not in collisions]
    return len(parts)


if __name__ == '__main__':
    data = get_data(day=20, year=2017)
    inp = [tuple(map(lambda x: Vec(*map(int, x.split(','))),
                     re.match(r'^p=<([\d,-]+)>, v=<([\d,-]+)>, a=<([\d,-]+)>$', l).groups()))
           for l in data.splitlines()]
    print(part1(inp))
    print(part2(inp))
Ejemplo n.º 19
0
        if c.isalpha():
            res += c


def part2(mapp):
    pos = next(c for c, v in mapp.items() if c[1] == 0 and v == '|')
    d = Dir.DOWN
    res = 1
    while True:
        if mapp.get(pos + d.value, None):
            pass
        elif mapp.get(pos + d.turn_left().value, None):
            d = d.turn_left()
        elif mapp.get(pos + d.turn_right().value, None):
            d = d.turn_right()
        else:
            return res
        pos += d.value
        res += 1


if __name__ == '__main__':
    data = get_data(day=19, year=2017)
    inp = {
        Vec(x, y): c
        for y, l in enumerate(data.splitlines()) for x, c in enumerate(l)
        if c != ' '
    }
    print(part1(inp))
    print(part2(inp))
Ejemplo n.º 20
0
        pos, vel = step(pos, vel)
        if pos[1] < max_y:
            return max_y
        max_y = pos[1]


def part2(inp):
    y_candidates = []
    for i in range(min(0, inp.lower[1] - 1),
                   max(abs(y) for _, y in [inp.lower, inp.upper]) + 1):
        if check_y_hit(Vec(0, i), inp):
            y_candidates.append(i)
    x_candidates = []
    for i in range(min(0, inp.lower[0] - 1), max(0, inp.upper[0] + 1)):
        if check_x_hit(Vec(i, 0), inp):
            x_candidates.append(i)
    return sum(
        check_hit(Vec(x, y), inp) for x in x_candidates for y in y_candidates)


if __name__ == '__main__':
    data = get_data(day=17, year=2021)
    inp = tuple(
        map(
            int,
            re.match(r'^target area: x=(-?\d+)..(-?\d+), y=(-?\d+)..(-?\d+)$',
                     data).groups()))
    inp = Rect(Vec(inp[0], inp[2]), Vec(inp[1], inp[3]))
    print(part1(inp))
    print(part2(inp))
Ejemplo n.º 21
0
        for neighbor in (current + d for d in dirs4 if (current + d) in mapp):
            tentative_g_score = g_score[current] + mapp[neighbor]
            if tentative_g_score < g_score[neighbor]:
                g_score[neighbor] = tentative_g_score
                f_score = tentative_g_score + (neighbor - goal).manhatten()
                open_set.put(neighbor, f_score)


def part1(inp):
    return find_shortest_path(inp)


def part2(inp):
    mapp = {}
    lx, ly = max(x for x, _ in inp) + 1, max(y for _, y in inp) + 1
    for (x, y), v in inp.items():
        for a, b in product(range(5), repeat=2):
            nv = (v + a + b) % 9
            mapp[Vec(x + a * lx, y + b * ly)] = 9 if nv == 0 else nv
    return find_shortest_path(mapp)


if __name__ == '__main__':
    data = get_data(day=15, year=2021)
    inp = {
        Vec(x, y): int(v)
        for y, l in enumerate(data.splitlines()) for x, v in enumerate(l)
    }
    print(part1(inp))
    print(part2(inp))
Ejemplo n.º 22
0
import math
from collections import defaultdict

from aoc_utils import Vec
from aocd import get_data

square = [
    Vec(-1, -1),
    Vec(0, -1),
    Vec(1, -1),
    Vec(-1, 0),
    Vec(0, 0),
    Vec(1, 0),
    Vec(-1, 1),
    Vec(0, 1),
    Vec(1, 1),
]


def enhance(img, alg):
    xmin = min(x for x, _ in img) - 1
    xmax = max(x for x, _ in img) + 1
    ymin = min(y for _, y in img) - 1
    ymax = max(y for _, y in img) + 1
    if img.default_factory():
        default = alg[-1]
    else:
        default = alg[0]
    return defaultdict(
        lambda: default, {
            Vec(x, y): alg[int(
Ejemplo n.º 23
0
def count_overlaps(inp, include_diagonals):
    lines_per_point = defaultdict(lambda: 0)
    for start, end in inp:
        d = simplify(end - start)
        if all(c != 0 for c in d) and not include_diagonals:
            continue
        lines_per_point[start] += 1
        pos = start
        while pos != end:
            pos += d
            lines_per_point[pos] += 1
    return sum(n >= 2 for n in lines_per_point.values())


def part1(inp):
    return count_overlaps(inp, False)


def part2(inp):
    return count_overlaps(inp, True)


if __name__ == '__main__':
    data = get_data(day=5, year=2021)
    inp = [(Vec(a, b), Vec(c, d)) for a, b, c, d in
           ((tuple(map(int, a))) for a in
            (re.match(r'(\d+),(\d+) -> (\d+),(\d+)', l).groups() for l in data.splitlines()))]
    print(part1(inp))
    print(part2(inp))
Ejemplo n.º 24
0
    boundary = {lowpoint}
    while boundary:
        nb = set()
        for p in boundary:
            for d in dirs4:
                if (p + d) not in basin and mapp.get(p + d, 9) < 9:
                    basin.add(p + d)
                    nb.add(p + d)
        boundary = nb
    return len(basin)


def part2(inp):
    return reduce(
        operator.mul,
        sorted(
            (calculate_basin_size(inp, p)
             for p in (p for p, v in inp.items()
                       if v < min(inp.get(p + d, math.inf) for d in dirs4))),
            reverse=True)[:3])


if __name__ == '__main__':
    data = get_data(day=9, year=2021)
    inp = {
        Vec(x, y): int(n)
        for y, l in enumerate(data.splitlines()) for x, n in enumerate(l)
    }
    print(part1(inp))
    print(part2(inp))
Ejemplo n.º 25
0
import operator
from functools import reduce
from itertools import accumulate

from aoc_utils import Vec
from aocd import get_data

dirs = {
    "forward": Vec(1, 0),
    "down": Vec(0, 1),
    "up": Vec(0, -1),
}


def part1(inp):
    return reduce(
        operator.mul,
        reduce(lambda a, b: tuple(map(operator.add, a, b)),
               (dirs[d] * n for d, n in inp)))


def part2(inp):
    return reduce(
        operator.mul,
        reduce(
            operator.add,
            map(
                lambda x: Vec(x[1], x[0] * x[1]),
                zip(accumulate(dirs[d][1] * n for d, n in inp),
                    (dirs[d][0] * n for d, n in inp)))))