Example #1
0
def solve(text, N=2020):
    xs = aoc.parse_ints_flatten(text)
    aoc.trace(xs)
    for i, x in enumerate(xs):
        for y in xs[i + 1:]:
            if x + y == N:
                return x * y
Example #2
0
def solve(text, N=10000000, M=1000000):
    cups = Node(0)
    p = cups.extend(map(int, text.strip()))
    last = p.extend(range(len(text.strip()) + 1, M + 1))
    cups = cups.next
    last.next = cups

    nodes = {cups.value: cups}
    it = cups.next
    while it != cups:
        nodes[it.value] = it
        it = it.next

    for round in range(N):
        if round % 100000 == 0:
            aoc.trace(round)
        x = cups.value
        while True:
            it = cups
            for _ in range(4):
                if x == it.value:
                    x = (x - 2) % M + 1
                    break
                it = it.next
            else:
                break
        it = nodes[x]
        it.xpaste(cups, 3)
        cups = cups.next

    it = nodes[1].next
    x, it = it.value, it.next
    y = it.value
    return x * y
Example #3
0
def solve(text):
    # program = [(n, int(x)) for s in text.strip().splitlines() for n,x in [s.split()]]
    program = [(n, int(x)) for n, x in re.findall(r'([a-z]+)\s+([\+\-]\d+)', text)]
    aoc.trace(program)

    state = State(program)
    acc = run_program(state)
    return acc
Example #4
0
def dump(grid, z):
    so = io.StringIO()
    print(f'z={z}', file=so)
    qs = {k for k,v in grid.items() if v}
    minx = min(x for z,y,x in qs)
    maxx = max(x for z,y,x in qs)
    miny = min(y for z,y,x in qs)
    maxy = max(y for z,y,x in qs)
    for y in range(miny, maxy+1):
        for x in range(minx, maxx+1):
            c = '#' if grid.get((z, y, x)) else '.'
            so.write(c)
        so.write('\n')
    aoc.trace(so.getvalue())
Example #5
0
def solve(text, G=7):
    p1, p2 = map(int, text.strip().split())

    def xmas(x, N):
        return pow(x, N, 20201227)

    def getloop(x, p):
        for i in range(10**10):
            if p == xmas(x, i):
                return i

    x = getloop(G, p1)
    aoc.trace(x)
    y = getloop(G, p2)
    aoc.trace(y)
    return xmas(xmas(G, y), x)
Example #6
0
def run_program(program):
    acc = 0
    ip = 0
    seen = set()
    while 0 <= ip < len(program):
        if ip in seen: break
        seen.add(ip)
        op, x = program[ip]
        aoc.trace(ip, op, x)

        if op == 'acc':
            acc += x
            ip += 1
        elif op == 'jmp':
            ip += x
        elif op == 'nop':
            ip += 1
    return acc
Example #7
0
def solve(text):
    program = [(n, int(x)) for s in text.strip().splitlines() for n,x in [s.split()]]
    aoc.trace(program)
    return run_program(program)
Example #8
0
def solve(text):
    xs = aoc.parse_ints(text)
    aoc.trace(xs)
    return sum(map(sum, xs))
Example #9
0
        text = rules[int(rule)]
        if (m := re.fullmatch(r'"(a|b)"', text)):
            return m[1]

        def seq(text):
            return ''.join(map(emit, text.split()))

        parts = [seq(p) for p in text.split('|')]
        if len(parts) > 1:
            s = '|'.join(parts)
            return f'(?:{s})'
        return ''.join(parts)


    rx0 = f'^{emit(0)}$'
    aoc.trace(rx0)
    rx0 = re.compile(rx0)

    return sum(bool(rx0.search(s)) for s in messages.splitlines())


def test():
    aoc.test_subject(solve)
    aoc.test("""
0: 4 1 5
1: 2 3 | 3 2
2: 4 4 | 5 5
3: 4 5 | 5 4
4: "a"
5: "b"
Example #10
0
def solve(text):
    def parse(s):
        h, *xs = s.strip().splitlines()
        n = int(re.findall(r'\d+', h)[0])
        xs = tuple(tuple(int(x == '#') for x in row) for row in xs)
        top, bottom = xs[0], xs[-1]
        left = tuple(row[0] for row in xs)
        right = tuple(row[-1] for row in xs)
        sig = (
            min(packbits(top), packbits(top[::-1])),
            min(packbits(right), packbits(right[::-1])),
            min(packbits(bottom), packbits(bottom[::-1])),
            min(packbits(left), packbits(left[::-1])),
        )
        return n, Tile(n, xs, sig)
    tiles = dict(parse(s) for s in text.strip().split('\n\n'))

    edges = defaultdict(set)
    for tile in tiles.values():
        for s in tile.sig:
            edges[s].add(tile.n)

    side = int(math.sqrt(len(tiles)))
    grid = [[[None, None] for x in range(side)] for y in range(side)]
    orient = [[[None, None] for x in range(side)] for y in range(side)]
    corner = next(t for n, t in tiles.items() if sum(len(edges[x]) for x in t.sig) == 6)
    grid[0][0] = corner.n
    down, right = set(), set()
    y, x = [s for s in corner.sig if len(edges[s]) > 1]
    down.add(y)
    right.add(x)
    orient[0][0] = (None, x, y, None)
    for y in range(side):
        for x in range(side):
            if x > 0:
                t = tiles[grid[y][x-1]]
                q, s = next((tiles[q],s) for s in t.sig if s in right for q in edges[s] if q != t.n)
                grid[y][x] = q.n
                i = q.sig.index(s)
                r = q.sig[(i+2)%4]
                d = q.sig[(i+1)%4]
                if d in down:
                    u = d
                    down.remove(u)
                    d = q.sig[(i+3)%4]
                elif len(edges[d]) == 1:
                    u = d
                    d = q.sig[(i+3)%4]
                else:
                    u = q.sig[(i+3)%4]
                    down.discard(u)
                ox = (u, r, d, s)
                right.remove(s)
                right.add(r)
                down.add(d)
                orient[y][x] = ox
            elif y > 0:
                t = tiles[grid[y-1][x]]
                q, s = next((tiles[q],s) for s in t.sig if s in down for q in edges[s] if q != t.n)
                grid[y][x] = q.n
                i = q.sig.index(s)
                d = q.sig[(i+2)%4]
                r = q.sig[(i+1)%4]
                if r in right:
                    l = r
                    right.remove(l)
                    r = q.sig[(i+3)%4]
                elif len(edges[r]) == 1:
                    l = r
                    r = q.sig[(i+3)%4]
                else:
                    l = q.sig[(i+3)%4]
                    right.discard(l)
                ox = (s, r, d, l)
                down.remove(s)
                down.add(d)
                right.add(r)
                orient[y][x] = ox

    def drot(tile):
        return Tile(tile.n, tuple(zip(*tile.xs)), tile.sig[::-1])
    def flipy(tile):
        sig = (tile.sig[2], tile.sig[1], tile.sig[0], tile.sig[3])
        return Tile(tile.n, tile.xs[::-1], sig)
    def rot(tile):
        return flipy(drot(tile))

    transops = [
        lambda tile: tile,
        lambda tile: rot(tile),
        lambda tile: rot(rot(tile)),
        lambda tile: rot(rot(rot(tile))),
        lambda tile: flipy(tile),
        lambda tile: rot(flipy(tile)),
        lambda tile: rot(rot(flipy(tile))),
        lambda tile: rot(rot(rot(flipy(tile)))),
    ]
    def transforms(tile):
        for op in transops: yield op(tile)

    def pack_image(grid, orient):
        side = len(grid)
        tile_size = len(tiles[grid[0][0]].xs) - 2
        pxside = side * tile_size
        def pix(px, py):
            gy, y = divmod(py, tile_size)
            gx, x = divmod(px, tile_size)
            n = grid[gy][gx]
            ox = orient[gy][gx]
            t = tiles[n]
            for q in transforms(t):
                if q.sig[1:3] == ox[1:3]:
                    return q.xs[y+1][x+1]
        return [[pix(px, py) for px in range(pxside)] for py in range(pxside)]

    pic = pack_image(grid, orient)

    def find_monsters(pic):
        mw = max(x for y,x in monster) + 1
        mh = max(y for y,x in monster) + 1
        pxside = len(pic)
        for y in range(pxside - mh + 1):
            for x in range(pxside - mw + 1):
                if all(pic[y+dy][x+dx] for dy,dx in monster):
                    yield (y, x)

    def count_monsters(pic):
        return sum(1 for _ in find_monsters(pic))

    for t in transforms(Tile(0, pic, sig=(0,0,0,0))):
        monsters = set(find_monsters(t.xs))
        if monsters:
            aoc.trace(ink(pic, monsters))
            return sum(x for row in t.xs for x in row) - len(monsters) * len(monster)
Example #11
0
            ip += x
        elif op == 'nop':
            ip += 1
    return acc


def solve(text):
    program = [(n, int(x)) for s in text.strip().splitlines() for n,x in [s.split()]]
    patches = ((i, ('nop' if op == 'jmp' else 'jmp'), x) for i, (op, x) in enumerate(program) if op in ('jmp', 'nop'))

    mem = list(program)
    while (acc := run_program(mem)) is None:
        mem = list(program)
        i, op, x = next(patches)
        mem[i] = (op, x)
    aoc.trace('patch', i, op, x)
    return acc


def test():
    aoc.test_subject(solve)
    aoc.test("""
nop +0
acc +1
jmp +4
acc +3
jmp -3
acc -99
acc +1
jmp -4
acc +6