コード例 #1
0
ファイル: d04.py プロジェクト: Randdalf/aoc20

def parse(data):
    for batch in data.split('\n\n'):
        passport = {}
        for pair in batch.split():
            key, value = pair.split(':')
            passport[key] = value
        yield passport


def has_required_fields(passport):
    return passport.keys() >= required_fields


def num_valid_passports(passports):
    return sum(has_required_fields(p) for p in passports)


def num_valid_passports_strict(passports):
    num = 0
    for passport in passports:
        if has_required_fields(passport):
            num += sum(validators[field](value)
                       for field, value in passport.items()) == len(passport)
    return num


if __name__ == "__main__":
    solve(4, parse, num_valid_passports, num_valid_passports_strict)
コード例 #2
0
ファイル: d23.py プロジェクト: Randdalf/aoc20
            next[cup] = dest_next
            next[dest] = cup
            prev[dest_next] = cup
            dest = cup

    if verbose:
        print('-- final --')
        print_cups(next, head)

    return next


def crab_cups_100(cups):
    next = simulate(cups, 100)
    result = ''
    cup = next[1]
    for i in range(len(cups) - 1):
        result += str(cup)
        cup = next[cup]
    return result


def crab_cups_10m(cups):
    cups.extend(range(max(cups) + 1, 1000001))
    next = simulate(cups, 10000000)
    return next[1] * next[next[1]]


if __name__ == "__main__":
    solve(23, parse, crab_cups_100, crab_cups_10m)
コード例 #3
0
ファイル: d25.py プロジェクト: Randdalf/aoc20
#!/usr/bin/env python
"""Advent of Code 2020, Day 25"""

from aoc import solve


def parse(data):
    return [int(x) for x in data.split('\n')]


def encryption_key(keys):
    n = 1
    encryption_key = 1
    while n != keys[0]:
        n = (n * 7) % 20201227
        encryption_key = (encryption_key * keys[1]) % 20201227
    return encryption_key


if __name__ == "__main__":
    solve(25, parse, encryption_key)
コード例 #4
0
ファイル: d02.py プロジェクト: Randdalf/aoc20

def parse(data):
    pattern = re.compile(r'(\d+)-(\d+) (\w): (\w+)')
    for line in data.split('\n'):
        match = pattern.match(line)
        yield (
            int(match.group(1)),
            int(match.group(2)),
            match.group(3),
            match.group(4)
        )


def num_valid_passwords_wrong(passwords):
    return sum(
        low <= sum(c == repeated for c in password) <= high
        for low, high, repeated, password in passwords
    )


def num_valid_passwords_right(passwords):
    return sum(
        (password[a-1] == once) ^ (password[b-1] == once)
        for a, b, once, password in passwords
    )


if __name__ == "__main__":
    solve(2, parse, num_valid_passwords_wrong, num_valid_passwords_right)
コード例 #5
0
ファイル: d22.py プロジェクト: Randdalf/aoc20
                print(f"...anyway, back to game {game}.")
        else:
            winner = max(enumerate(plays), key=lambda x: x[1])[0]

        if verbose:
            print(f"Player {winner+1} wins round {round} of game {game}!")

        decks[winner].append(plays[winner])
        decks[winner].append(plays[1 - winner])
        round += 1

    if verbose:
        print(f"The winner of game {game} is player {winner+1}!")
        print()

    if game == 1:
        if verbose:
            print()
            print(f"== Post-game results ==")
            print(f"Player 1's deck:", ', '.join(map(str, decks[0])))
            print(f"Player 2's deck:", ', '.join(map(str, decks[1])))
        deck = max(decks, key=lambda x: len(x))
        deck.reverse()
        return sum((i+1)*x for i, x in enumerate(deck))
    else:
        return winner


if __name__ == "__main__":
    solve(22, parse, combat, recursive_combat)
コード例 #6
0
    offsets.remove(tuple(0 for x in range(dim)))
    for cycle in range(cycles):
        neighbors = set()
        for pos in active:
            for offset in offsets:
                neighbors.add(tuple(a + b for a, b in zip(pos, offset)))
        new = set()
        for pos in neighbors:
            n = 0
            for offset in offsets:
                neighbor = tuple(a + b for a, b in zip(pos, offset))
                n += neighbor in active
            if pos in active and n in [2, 3]:
                new.add(pos)
            elif pos not in active and n == 3:
                new.add(pos)
        active = new
    return len(active)


def sim3(init):
    return simulate(init, dim=3)


def sim4(init):
    return simulate(init, dim=4)


if __name__ == "__main__":
    solve(17, parse, sim3, sim4)
コード例 #7
0
ファイル: d10.py プロジェクト: Randdalf/aoc20
from aoc import solve


def parse(data):
    return [int(x) for x in data.split('\n')]


def compute_diffs(adapters):
    jolts = [0] + sorted(adapters) + [3 + max(adapters)]
    return [jolts[i] - jolts[i-1] for i in range(1, len(jolts))]


def jolt_1_3(adapters):
    diffs = compute_diffs(adapters)
    return diffs.count(1) * diffs.count(3)


def num_combos(n):
    return 1 if n == 0 else sum(num_combos(n-k-1) for k in range(min(n, 3)))


def arrangements(adapters):
    diffs = compute_diffs(adapters)
    runs = [len(list(g)) for k, g in groupby(diffs, lambda x: x == 1) if k]
    return reduce(lambda x, y: x*y, (num_combos(n) for n in runs))


if __name__ == "__main__":
    solve(10, parse, jolt_1_3, arrangements)
コード例 #8
0
#!/usr/bin/env python

"""Advent of Code 2020, Day 15"""

from aoc import solve


def parse(data):
    return [int(x) for x in data.split(',')]


def memory_game(start, max_turns=2020):
    spoken = {n: i for i, n in enumerate(start[:-1])}
    prev = start[-1]
    for turn in range(len(start), max_turns):
        n = turn - spoken[prev] - 1 if prev in spoken else 0
        spoken[prev] = turn - 1
        prev = n
    return prev


def challenge(start):
    return memory_game(start, max_turns=30000000)


if __name__ == "__main__":
    solve(15, parse, memory_game, challenge)
コード例 #9
0
def initialize(program):
    mem = defaultdict(int)
    for a, b in program:
        if a == 'mask':
            mask_out = int(b.replace('1', '0').replace('X', '1'), 2)
            mask_in = int(b.replace('X', '0'), 2)
        else:
            mem[a] = (b & mask_out) | mask_in
    return sum(mem.values())


def initialize_v2(program):
    mem = defaultdict(int)
    for a, b in program:
        if a == 'mask':
            c = b.count('X')
            masks = []
            for n in range(1 << b.count('X')):
                mask = b
                for bit in f'{n:0{c}b}':
                    mask = mask.replace('X', bit, 1)
                masks.append(int(mask, 2))
        else:
            for mask in masks:
                mem[(a & ~masks[-1]) | mask] = b
    return sum(mem.values())


if __name__ == "__main__":
    solve(14, parse, initialize, initialize_v2)
コード例 #10
0
ファイル: d03.py プロジェクト: Randdalf/aoc20
    def get(slf, pos):
        return slf.tiles[Vec2(pos.x % slf.w, pos.y)]


def parse(data):
    return Terrain(data)


def count_trees(terrain, pos=Vec2(0, 0), slope=Vec2(3, 1)):
    num_trees = 0
    while pos.y < terrain.h:
        num_trees += terrain.get(pos) == '#'
        pos += slope
    return num_trees


def check_slopes(terrain):
    results = [
        count_trees(terrain, slope=Vec2(1, 1)),
        count_trees(terrain, slope=Vec2(3, 1)),
        count_trees(terrain, slope=Vec2(5, 1)),
        count_trees(terrain, slope=Vec2(7, 1)),
        count_trees(terrain, slope=Vec2(1, 2))
    ]
    return reduce(lambda x, y: x*y, results)


if __name__ == "__main__":
    solve(3, parse, count_trees, check_slopes)
コード例 #11
0
ファイル: d06.py プロジェクト: Randdalf/aoc20
#!/usr/bin/env python
"""Advent of Code 2020, Day 6"""

from functools import reduce

from aoc import solve


def parse(data):
    return [[set(p) for p in g.split('\n')] for g in data.split('\n\n')]


def anyone_answers(groups):
    return sum(len(reduce(lambda x, y: x | y, g)) for g in groups)


def everyone_answers(groups):
    return sum(len(reduce(lambda x, y: x & y, g)) for g in groups)


if __name__ == "__main__":
    solve(6, parse, anyone_answers, everyone_answers)
コード例 #12
0
ファイル: d05.py プロジェクト: Randdalf/aoc20
def parse(data):
    yield from data.split('\n')


def bsp(d0, d1, s):
    return int(s.replace(d0, '0').replace(d1, '1'), 2)


def seat_coord(seat):
    return (bsp('F', 'B', seat[:7]), bsp('L', 'R', seat[7:]))


def seat_id(row, col):
    return row * 8 + col


def high_seat_id(seats):
    return max(seat_id(*seat_coord(seat)) for seat in seats)


def find_my_seat(seats):
    filled = set(seat_coord(seat) for seat in seats)
    for row in range(9, 120):
        for col in range(8):
            if (row, col) not in filled:
                return seat_id(row, col)


if __name__ == "__main__":
    solve(5, parse, high_seat_id, find_my_seat)
コード例 #13
0
ファイル: d19.py プロジェクト: Randdalf/aoc20
                    new.extend(repeat('31', n11))
                    new.append(')')
                else:
                    new.append('(')
                    new.extend(rules[c])
                    new.append(')')
            else:
                new.append(c)
        if len(new) == len(expanded):
            return re.compile('^' + ''.join(new) + '$')
        expanded = new


def part1(input):
    pattern = to_regex(input.rules)
    return sum(pattern.match(msg) is not None for msg in input.messages)


def part2(input):
    patterns = [to_regex(input.rules, fix=True, n11=i) for i in range(1, 10)]
    matches = set()
    for pattern in patterns:
        for msg in input.messages:
            if pattern.match(msg):
                matches.add(msg)
    return len(matches)


if __name__ == "__main__":
    solve(19, parse, part1, part2)
コード例 #14
0
            black.remove(tile)
        else:
            black.add(tile)
    return len(black) if num else black


def adjacencies(tile):
    yield from (tile + dir for dir in dirs.values())


def art_exhibit(instrs, days=100, verbose=False):
    black = flip_tiles(instrs, num=False)
    for day in range(1, days + 1):
        new_black = set()
        for tile in {adj for tile in black for adj in adjacencies(tile)}:
            n = sum(adj in black for adj in adjacencies(tile))
            if tile in black and 1 <= n <= 2:
                new_black.add(tile)
            elif tile not in black and n == 2:
                new_black.add(tile)
        black = new_black
        if verbose and (day <= 10 or day % 10 == 0):
            print(f'Day {day}: {len(black)}')
            if day == 10:
                print()
    return len(black)


if __name__ == "__main__":
    solve(24, parse, flip_tiles, art_exhibit)
コード例 #15
0
def find_inert(foods):
    dangerous = set()
    for a in {a for _, alls in foods for a in alls}:
        dangerous |= reduce(and_, (ings for ings, alls in foods if a in alls))
    return {i for ings, _ in foods for i in ings} - dangerous


def num_inert(foods):
    inert = find_inert(foods)
    return sum(i in inert for ings, _ in foods for i in ings)


def danger_list(foods):
    ignore = find_inert(foods)
    open = {a for _, alls in foods for a in alls}
    map = {}
    while open:
        for a in list(open):
            contains = reduce(and_, (ings - ignore
                                     for ings, alls in foods if a in alls))
            if len(contains) == 1:
                ing = contains.pop()
                map[a] = ing
                open.remove(a)
                ignore.add(ing)
    return ','.join(map[k] for k in sorted(map.keys()))


if __name__ == "__main__":
    solve(21, parse, num_inert, danger_list)
コード例 #16
0
ファイル: d13.py プロジェクト: Randdalf/aoc20
        slf.timestamp = int(lines[0])
        slf.buses = [
            (i, int(id)) for i, id in enumerate(lines[1].split(','))
            if id != 'x'
        ]


def parse(data):
    return Notes(data)


def earliest_bus(notes):
    bus = min(
        ((id - notes.timestamp % id, id) for off, id in notes.buses),
        key=lambda x: x[0]
    )
    return bus[0] * bus[1]


def contest(notes):
    step = t = 1
    for n in range(len(notes.buses)):
        while not all((t + off) % id == 0 for off, id in notes.buses[:n+1]):
            t += step
        step *= notes.buses[n][1]
    return t


if __name__ == "__main__":
    solve(13, parse, earliest_bus, contest)
コード例 #17
0
        for v in ticket:
            if not valid(doc, v):
                error_rate += v
    return error_rate


def identify(doc):
    tickets = [t for t in doc.nearby if all(valid(doc, v) for v in t)]
    fields = set(doc.fields.keys())
    positions = set(range(len(doc.ticket)))
    assigned = {}
    while len(fields) > 0:
        for field in list(fields):
            rules = doc.fields[field]
            possible = []
            for p in positions:
                n = sum(lo <= t[p] <= hi for t in tickets for lo, hi in rules)
                if n == len(tickets):
                    possible.append(p)
            if len(possible) == 1:
                position = possible.pop()
                assigned[field] = position
                fields.remove(field)
                positions.remove(position)
    return reduce(mul, (doc.ticket[assigned[f]]
                        for f in assigned if f.startswith('departure')))


if __name__ == "__main__":
    solve(16, parse, error_rate, identify)
コード例 #18
0
ファイル: d07.py プロジェクト: Randdalf/aoc20
from aoc import solve


def parse(data):
    bag_pattern = re.compile(r'(\d+) (\w+ \w+) bags?')
    rules = {}
    for rule in data.split('\n'):
        color, bags = rule.split(' bags contain ')
        rules[color] = {c: int(n) for n, c in bag_pattern.findall(bags)}
    return rules


def has_target(rules, color, target):
    rule = rules[color]
    return target in rule or any(
        has_target(rules, c, target) for c in rule.keys())


def num_colors_that_fit(rules, target='shiny gold'):
    return sum(has_target(rules, color, target) for color in rules.keys())


def bags_within(rules, target='shiny gold'):
    return sum(n * (1 + bags_within(rules, color))
               for color, n in rules[target].items())


if __name__ == "__main__":
    solve(7, parse, num_colors_that_fit, bags_within)
コード例 #19
0
    visited = set()
    while pc not in visited and pc < len(prog):
        visited.add(pc)
        instr, val = prog[pc]
        if instr == 'acc':
            acc += int(val)
            pc += 1
        elif instr == 'jmp':
            pc += int(val)
        else:
            pc += 1
    if error and (pc in visited or pc > len(prog)):
        raise BadTerminationError()
    return acc


def repair(prog):
    for pc, (instr, val) in enumerate(prog):
        if instr == 'nop':
            prog[pc] = ('jmp', val)
        elif instr == 'jmp':
            prog[pc] = ('nop', val)
        try:
            return exec(prog, True)
        except BadTerminationError:
            prog[pc] = (instr, val)


if __name__ == "__main__":
    solve(8, parse, exec, repair)
コード例 #20
0
ファイル: d20.py プロジェクト: Randdalf/aoc20
                    if oriented[pos] == '#':
                        matches.add(pos)
                if len(matches) == len(monster):
                    monsters.update(matches)
        if len(monsters) > 0:
            return sum(c == '#' for pos, c in oriented.items()
                       if pos not in monsters)


def water_roughness(tiles, print_image=False):
    grid, size = assemble(tiles)
    image, size = reconstruct(grid, size)

    if print_image:
        print()
        for y in range(size):
            for x in range(size):
                pos = Vec2(x, y)
                if pos in image:
                    print(image[pos], end='')
                else:
                    print(' ', end='')
            print()

    monster, w, h = get_sea_monster()
    return find_monsters(image, size, monster, w, h)


if __name__ == "__main__":
    solve(20, parse, corner_ids, water_roughness)
コード例 #21
0
ファイル: d01.py プロジェクト: Randdalf/aoc20
#!/usr/bin/env python

"""Advent of Code 2020, Day 1"""

from functools import reduce
from itertools import product

from aoc import solve


def parse(data):
    return [int(x) for x in data.split('\n')]


def find_sum_2020(expenses, n):
    for p in product(expenses, repeat=n):
        if sum(p) == 2020:
            return reduce(lambda x, y: x*y, p)


if __name__ == "__main__":
    solve(1,  parse, lambda x: find_sum_2020(x, 2), lambda x: find_sum_2020(x, 3))
コード例 #22
0
from itertools import combinations

from aoc import solve


def parse(data):
    return [int(x) for x in data.split('\n')]


def invalid(numbers, preamble=25):
    for i, n in enumerate(numbers[preamble:]):
        if n not in {
                a + b
                for a, b in combinations(numbers[i:i + preamble], 2)
        }:
            return n


def weakness(numbers, preamble=25):
    v = invalid(numbers, preamble)
    s = [sum(numbers[:i]) for i in range(len(numbers))]
    for i in range(len(s)):
        for j in range(i + 1, len(s)):
            if s[j] - s[i] == v:
                r = numbers[i:j]
                return min(r) + max(r)


if __name__ == "__main__":
    solve(9, parse, invalid, weakness)
コード例 #23
0
            slf.waypoint = slf.waypoint.rot90left()

    def R(slf, value):
        for i in range(value // 90):
            slf.waypoint = slf.waypoint.rot90right()

    def F(slf, value):
        slf.pos += value * slf.waypoint


def parse(data):
    return [(instr[0], int(instr[1:])) for instr in data.split('\n')]


def navigate(ship, instrs):
    for action, value in instrs:
        getattr(ship, action)(value)
    return manhattan(ship.pos, Vec2(0, 0))


def navigate1(instrs):
    return navigate(Ship1(), instrs)


def navigate2(instrs):
    return navigate(Ship2(), instrs)


if __name__ == "__main__":
    solve(12, parse, navigate1, navigate2)
コード例 #24
0
        q.append(ops.pop())
    return q


def eval(q):
    n = []
    for c in q:
        if c == '+':
            n.append(n.pop() + n.pop())
        elif c == '*':
            n.append(n.pop() * n.pop())
        else:
            n.append(c)
    return n[0]


def sum_eval(exprs, prec):
    return sum(eval(shunting_yard(x, prec)) for x in exprs)


def part1(exprs):
    return sum_eval(exprs, prec={'+': 0, '*': 0})


def part2(exprs):
    return sum_eval(exprs, prec={'+': 1, '*': 0})


if __name__ == "__main__":
    solve(18, parse, part1, part2)
コード例 #25
0
                changed = True
            elif seat == OCCUPIED_SEAT and vision.count(OCCUPIED_SEAT) >= 5:
                seat = EMPTY_SEAT
                changed = True
            new_seats[pos] = seat
        slf.seats = new_seats
        return changed

    def occupied(slf):
        return list(slf.seats.values()).count(OCCUPIED_SEAT)


def parse(data):
    return SeatLayout(data=data)


def occupied_seats1(layout):
    while layout.step1():
        pass
    return layout.occupied()


def occupied_seats2(layout):
    while layout.step2():
        pass
    return layout.occupied()


if __name__ == "__main__":
    solve(11, parse, occupied_seats1, occupied_seats2)