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
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
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
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())
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)
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
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)
def solve(text): xs = aoc.parse_ints(text) aoc.trace(xs) return sum(map(sum, xs))
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"
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)
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