示例#1
0
    hashed_integer += 1
    hashed = md5()
    hashed.update((door_id + str(hashed_integer)).encode())
    digest = hashed.hexdigest()

    # While the first 5 characters are not all 0s, increment the counter and generate a new hash
    while digest[:5] != "00000":
        hashed_integer += 1
        hashed = md5()
        hashed.update((door_id + str(hashed_integer)).encode())
        digest = hashed.hexdigest()

    code.append(digest[5])

# Print the password
aoc.p1("".join(code))


## Part 2

# Door ID which prefixes hashed value
door_id = "reyedfim"

# Starting value to hash
hashed_integer = -1

values_found = 0
code = [None, None, None, None, None, None, None, None]
while values_found < 8:
    hashed_integer += 1
    hashed = md5()
示例#2
0

for n in numbers_drawn:
    bingo_cards = [
        [[b[r][c] if b[r][c] != n else None for c in range(5)] for r in range(5)]
        for b in bingo_cards
    ]
    finished_cards = list(filter(is_bingo, bingo_cards))

    if finished_cards:
        last_drawn = n
        bingo = finished_cards[0]
        break

unmarked = sum(filter(None, flatten(bingo)))
aoc.p1(unmarked * last_drawn)

# Part 2

bingo_cards = chunk(5, list(filter(None, data.numbers_by_line()[1:])))

for n in numbers_drawn:
    bingo_cards = [
        [[b[r][c] if b[r][c] != n else None for c in range(5)] for r in range(5)]
        for b in bingo_cards
    ]
    unfinished_cards = list(filter(lambda x: not is_bingo(x), bingo_cards))

    if len(bingo_cards) == 1 and len(unfinished_cards) == 0:
        last_drawn = n
        bingo = bingo_cards[0]
示例#3
0
data = aoc.load()

# Part 1

fish = data.nums()
for _ in range(80):
    nfish = []
    for f in fish:
        if f == 0:
            nfish.append(6)
            nfish.append(8)
        else:
            nfish.append(f - 1)
    fish = nfish

aoc.p1(len(fish))

# Part 2

fish = [0] * 9

for f in data.nums():
    fish[f] += 1

for _ in range(256):
    nfish = [0] * 9
    for i, f in enumerate(fish[1:]):
        nfish[i] = f
    nfish[6] += fish[0]
    nfish[8] = fish[0]
    fish = nfish
示例#4
0
            flashed.add((x, y))
            for adj in Position(x, y).adjacent():
                if adj.tuple not in flashed:
                    # Octo's can only flash once in a step, so skip if they've already flashed
                    needs_increment.append(adj.tuple)

    clear_flashed(octos)
    return octos, len(flashed)


# Part 1

total = 0
for _ in range(100):
    octos, flash_count = step(octos)
    total += flash_count

aoc.p1(total)

# Part 2

octos = data.digits_by_line()

flash_count = 0
step_count = 0
while flash_count != 100:
    octos, flash_count = step(octos)
    step_count += 1

aoc.p2(step_count)
示例#5
0
            moving_water.append(under_left)
        else:
            spilled_water.add(under_left)

    under_right = under(right_edge)
    if not right_enclosed:
        if in_range(under_right) and (not moving_water
                                      or moving_water[-1] != under_right):
            moving_water.append(under_right)
        else:
            spilled_water.add(under_right)

    if left_enclosed and right_enclosed:
        moving_water.append(above(water))

aoc.p1(touched)

## Part 2

clay = set()
left = right = 500
min_height = max_height = 1

for l in data.lines():
    values = numbers_from(l)
    if l[0] == "x":
        x = values[0]
        left = min(left, x)
        right = max(right, x)
        min_height = min(min_height, values[1])
        max_height = max(max_height, values[2])
示例#6
0
def command_ship(ship, dir, ins, val):
    if ins in ["L", "R"]:
        return ship, turn_ship(dir, ins, val)
    elif ins == "F":
        return move_ship(ship, Direction[dir].position, val), dir
    else:
        return move_ship(ship, Direction[ins].position, val), dir


ship, direction = Position(0, 0), "E"
for instruction in data.parse_lines(r"(\w)(\d+)"):
    ship, direction = command_ship(ship, direction, instruction[0],
                                   int(instruction[1]))

aoc.p1(abs(ship.x) + abs(ship.y))

# Part 2


def rotate_waypoint(waypoint, ins, val):
    while val >= 90:
        if ins == "R":
            waypoint = Position(-waypoint.y, waypoint.x)
        if ins == "L":
            waypoint = Position(waypoint.y, -waypoint.x)
        val -= 90
    return waypoint


def command_waypoint(ship, waypoint, ins, val):
示例#7
0
    visited = set([start])
    while q:
        risk, pos = heappop(q)

        if pos == end:
            return risk

        for adj in pos.adjacent(diagonal=False):
            if adj not in visited:
                new_risk = risk + grid[adj.y][adj.x]
                visited.add(adj)
                heappush(q, (new_risk, adj))


base_grid = data.digits_by_line()
aoc.p1(least_risk_path(base_grid))

full_grid = [[0 for _ in range(len(base_grid[0]) * 5)]
             for _ in range(len(base_grid) * 5)]

# Generate first row for full_grid
for y, row in enumerate(base_grid):
    for i in range(5):
        for x, value in enumerate(row):
            full_grid[y][x + i * len(row)] = (value + i - 1) % 9 + 1

# Copy first X rows to rest of full_grid
for i in range(5):
    for y, row in enumerate(full_grid[:len(base_grid)]):
        for x, value in enumerate(row):
            full_grid[y + i * len(base_grid)][x] = (value + i - 1) % 9 + 1
示例#8
0
def resolve_rule(r):
    @lru_cache
    def resolver(r):
        if type(rules[r][0]) is str:
            return rules[r][0]
        else:
            return (
                "(" +
                "|".join(["".join([resolver(y) for y in x])
                          for x in rules[r]]) + ")")

    return "^" + resolver(r) + "$"


rule_zero = resolve_rule(0)
aoc.p1(len([1 for x in chunks[1] if re.match(rule_zero, x)]))

# Part 2

rules[8] = [[42], [42, 8]]
rules[11] = [[42, 31], [42, 11, 31]]


def resolve_infinite_rule(r):
    @lru_cache
    def manual_resolution(r):
        if r == 8:
            return "(" + resolver(42) + ")" + "+"
        elif r == 11:
            return ("(" + "|".join(
                [resolver(42) * i + resolver(31) * i
示例#9
0
from aoc import AOC
import math
from itertools import chain

aoc = AOC(year=2020, day=1)
data = aoc.load()

# Part 1

expenses = set(data.numbers())
product = math.prod([e for e in expenses if (2020 - e) in expenses])
aoc.p1(product)

# Part 2

product = math.prod(
    set(
        chain(*[[e for e in expenses if (2020 - f - e) in expenses]
                for f in expenses])))
aoc.p2(product)
示例#10
0
# Apply the process 40 times
for i in range(40):
    puzzle_output = ""

    # Get character repeated at start, number of times its repeated and add to output
    while len(puzzle_input) > 0:
        digits = re.search(r"(\d)\1*", puzzle_input)
        puzzle_input = puzzle_input[len(digits.group(0)):]
        puzzle_output = (puzzle_output + str(len(digits.group(0))) +
                         str(digits.group(0)[:1]))

    # Update input to iterate
    puzzle_input = puzzle_output

aoc.p1(len(puzzle_input))

## Part 2

# Input from the site
puzzle_input = "1113122113"

# Apply the process 50 times
for i in range(50):
    puzzle_output = ""

    # Get character repeated at start, number of times its repeated and add to output
    while len(puzzle_input) > 0:
        digits = re.search(r"(\d)\1*", puzzle_input)
        puzzle_input = puzzle_input[len(digits.group(0)):]
        puzzle_output = (puzzle_output + str(len(digits.group(0))) +
示例#11
0
aoc = AOC(year=2015, day=5)
data = aoc.load()

## Part 1

# Create regex to match the rules
# 1. Contains at least one pair of two letters that appears twice (non-overlapping)
# 2. At least one letter that repeats, with one letter between them
nicestring_regex = re.compile(
    r"^(?=\w*(\w)\w\1\w*)(\w*(\w\w)\w*\3\w*)$", flags=re.MULTILINE
)
total_nicestrings = len(re.findall(nicestring_regex, data.contents()))

# Print the total number of nice strings
aoc.p1(total_nicestrings)

## Part 2

# Create regex to match the rules
# 1. Contains at least 3 values
# 2. At least one letter that appears twice in a row
# 3. Does not contain 'ab', 'cd', 'pq', or 'xy'
nicestring_regex = re.compile(
    r"^(?=\w*(\w)\1)(?!\w*(ab|cd|pq|xy))((\w*[aeiou]\w*){3,})$", flags=re.MULTILINE
)
total_nicestrings = len(re.findall(nicestring_regex, data.contents()))

# Print the total number of nice strings
aoc.p2(total_nicestrings)
示例#12
0
aoc = AOC(year=2021, day=2)
data = aoc.load()

# Part 1

x, y = 0, 0
for command, value in data.parse(r"(\w+) (\d+)"):
    if command == "forward":
        x += value
    if command == "down":
        y += value
    if command == "up":
        y -= value

aoc.p1(x * y)

# Part 2

x, y, aim = 0, 0, 0
for command, value in data.parse(r"(\w+) (\d+)"):
    if command == "forward":
        x += value
        y += aim * value
    if command == "down":
        aim += value
    if command == "up":
        aim -= value

aoc.p2(x * y)
示例#13
0
    for b in bitstrings:
        bits[int(b[position])] += 1

    return 0 if bits[0] > bits[1] else 1


gamma = ""
for position in range(data.line_length):
    gamma += str(most_common_bit(data.lines(), position))

epsilon = "".join(["0" if g == "1" else "1" for g in gamma])

gamma = int(gamma, 2)
epsilon = int(epsilon, 2)

aoc.p1(gamma * epsilon)

# Part 2


def least_common_bit(bitstrings, position):
    bits = {0: 0, 1: 0}
    for b in bitstrings:
        bits[int(b[position])] += 1

    return 1 if bits[1] < bits[0] else 0


def reduce(bitstrings, position, bit_extractor):
    reduced = []
    comparator = str(bit_extractor(bitstrings, position))
示例#14
0

# Part 1

cups = get_cups(False)
lowest = min(cups.keys())
highest = max(cups.keys())
current = next(iter(cups.keys()))

for _ in range(100):
    step()

current = cups[1]["n"]
labels = []
while current != 1:
    labels.append(str(cups[current]["v"]))
    current = cups[current]["n"]
aoc.p1("".join(labels))

# Part 2

cups = get_cups(True)
lowest = min(cups.keys())
highest = max(cups.keys())
current = next(iter(cups.keys()))

for _ in range(10_000_000):
    step()

aoc.p2(cups[1]["n"] * cups[cups[1]["n"]]["n"])
示例#15
0
from aoc import AOC, chinese_remainder
import itertools
import re

aoc = AOC(year=2020, day=13)
contents = aoc.load().lines()

# Part 1


start_time = int(contents[0])
buses = [int(v) for v in re.findall(r"\d+", contents[1])]

for i in itertools.count(start_time):
    departing_bus = next((bid for bid in buses if (start_time + i) % bid == 0), False)
    if departing_bus:
        aoc.p1(departing_bus * i)
        break

# Part 2

buses = [int(b) if b != "x" else b for b in contents[1].split(",")]

n = [bid for bid in buses if bid != "x"]
a = [0] + [bid - (idx + 1) for idx, bid in enumerate(buses[1:]) if bid != "x"]

aoc.p2(chinese_remainder(n, a))
示例#16
0
# Part 1

comp = Computer(data)


def run_until_finished(comp):
    seen = set()
    while comp.position not in seen and not comp.is_finished():
        seen.add(comp.position)
        comp.step()
    return comp.is_finished()


run_until_finished(comp)
aoc.p1(comp.accumulator)

# Part 2

for idx, ins in enumerate(comp.instructions()):
    modified_comp = Computer(data)
    if ins[0] == "jmp":
        modified_comp.replace(idx, "nop")
    elif ins[0] == "nop":
        modified_comp.replace(idx, "jmp")

    if run_until_finished(modified_comp):
        break

aoc.p2(modified_comp.accumulator)
示例#17
0
code = []

for line in data.lines():
    for char in line:
        if char == "L":
            start = (start[0], max(start[1] - 1, 0))
        if char == "U":
            start = (max(start[0] - 1, 0), start[1])
        if char == "R":
            start = (start[0], min(start[1] + 1, 2))
        if char == "D":
            start = (min(start[0] + 1, 2), start[1])

    code.append(layout[start[0]][start[1]])

aoc.p1("".join([str(c) for c in code]))

## Part 2

# Keypad layout
layout = [
    [-1, -1, 1, -1, -1],
    [-1, 2, 3, 4, -1],
    [5, 6, 7, 8, 9],
    [-1, "A", "B", "C", -1],
    [-1, -1, "D", -1, -1],
]

# Initial position (number 5)
start = (2, 0)
code = []
示例#18
0
                updated_points[new_point] = [(xx, yy)]
    points = updated_points
    seconds += 1

    count -= 1
    if count == 0:
        count = 10
        ys = [x[0] for x in points.keys()]
        top, height = min(ys), max(ys)
        did_print = should_print
        should_print = abs(top - height) < 100
        if not should_print and did_print != should_print:
            break


aoc.p1("CRXKEZPZ")


## Part 2


points = {}
for l in data.numbers_by_line():
    x, y, xx, yy = l
    points[(x, y)] = [(xx, yy)]

xs = [x[0] for x in points.keys()]
ys = [x[0] for x in points.keys()]
left, width = min(xs), max(xs)
top, height = min(ys), max(ys)
示例#19
0
from math import prod
from aoc import AOC, mins

aoc = AOC(year=2015, day=2)
data = aoc.load()

## Part 1

total_square_feet = 0

for sides in data.numbers_by_line():
    first = sides[0] * sides[1]
    second = sides[1] * sides[2]
    third = sides[2] * sides[0]
    total_square_feet += 2 * (first + second + third) + min(
        first, second, third)

aoc.p1(total_square_feet)

## Part 2

# Initialize to 0 feet of ribbon
total_length = 0

for sides in data.numbers_by_line():
    total_length += sides[0] * sides[1] * sides[2] + (2 * sum(mins(sides, 2)))

aoc.p2(total_length)
示例#20
0
# Start with checking 1
lowest_positive_int = 1
hashed = md5()
hashed.update(("ckczppom" + str(lowest_positive_int)).encode())
digest = hashed.hexdigest()

# While the first 5 characters are not all 0s, increment the counter and generate a new hash
while digest[:5] != "00000":
    lowest_positive_int += 1
    hashed = md5()
    hashed.update((PUZZLE_INPUT + str(lowest_positive_int)).encode())
    digest = hashed.hexdigest()

# Print the lowest valid positive integer
aoc.p1(lowest_positive_int)

## Part 2

# Start with checking 1
lowest_positive_int = 1
hashed = md5()
hashed.update(("ckczppom" + str(lowest_positive_int)).encode())
digest = hashed.hexdigest()

# While the first 6 characters are not all 0s, increment the counter and generate a new hash
while digest[:6] != "000000":
    lowest_positive_int += 1
    hashed = md5()
    hashed.update((PUZZLE_INPUT + str(lowest_positive_int)).encode())
    digest = hashed.hexdigest()
示例#21
0
def play_round():
    p1 = first_hand.pop(0)
    p2 = second_hand.pop(0)

    if p1 > p2:
        first_hand.append(p1)
        first_hand.append(p2)
    else:
        second_hand.append(p2)
        second_hand.append(p1)


while first_hand and second_hand:
    play_round()

aoc.p1(calculate_score(first_hand if first_hand else second_hand))

# Part 2

first_hand = hands[0][:]
second_hand = hands[1][:]


def play_game(first_hand, second_hand):
    previous_deck_orders = set()
    while first_hand and second_hand:
        tuple_first = tuple(first_hand)
        tuple_second = tuple(second_hand)
        if (tuple_first, tuple_second) in previous_deck_orders:
            return 1
        previous_deck_orders.add((tuple_first, tuple_second))
示例#22
0
aoc = AOC(year=2020, day=4)
data = aoc.load()

passport_properties = set(["byr", "iyr", "eyr", "hgt", "hcl", "ecl", "pid"])

passports = [" ".join(c.splitlines()) for c in data.contents().split("\n\n")]
passports = [dict(x.split(":") for x in p.split(" ")) for p in passports]

# Part 1


def passes_basic_validation(passport):
    return (set(passport.keys()) - set(["cid"])) == passport_properties


aoc.p1(len([p for p in passports if passes_basic_validation(p)]))

# Part 2

validations = [
    lambda p: passes_basic_validation(p),
    lambda p: 1920 <= int(p["byr"]) <= 2002,
    lambda p: 2010 <= int(p["iyr"]) <= 2020,
    lambda p: 2020 <= int(p["eyr"]) <= 2030,
    lambda p: (p["hgt"][3:] == "cm" and 150 <= int(p["hgt"][0:3]) <= 193) or
    (p["hgt"][2:] == "in" and 59 <= int(p["hgt"][0:2]) <= 76),
    lambda p: re.search(r"^#[0-9a-fA-F]{6}$", p["hcl"]),
    lambda p: p["ecl"] in ["amb", "blu", "brn", "gry", "grn", "hzl", "oth"],
    lambda p: re.search(r"^[0-9]{9}$", p["pid"]),
]
示例#23
0
        "children": children,
        "metadata": metadata,
    }


root_node = build_node(data.numbers_by_line()[0])


def sum_metadata(node):
    total = sum(node["metadata"])
    for child in node["children"]:
        total += sum_metadata(child)
    return total


aoc.p1(sum_metadata(root_node))

## Part 2


def build_node(raw_node):
    header = {
        "children": raw_node[0],
        "metadata": raw_node[1],
    }

    node_length = 2
    children = []
    for _ in range(header["children"]):
        child = build_node(raw_node[node_length:-header["metadata"]])
        node_length += child["length"]
示例#24
0
        next_battle.player_turn(spell_names[index])

        if next_battle.check_game_over():
            if next_battle.boss.hp <= 0:
                minimum_mana = (
                    min(minimum_mana, next_battle.total_cost)
                    if minimum_mana != -1
                    else next_battle.total_cost
                )
            continue

        next_battle.boss_turn()
        battles.append(next_battle)

aoc.p1(minimum_mana)

## Part 2

# Initial stats of the player and the boss
boss_base_stats = {"hp": 58, "damage": 9}
player_base_stats = {"hp": 50, "mana": 500}
hard_mode_enabled = True


class Player:
    def __init__(self):
        self.hp = player_base_stats["hp"]
        self.mana = player_base_stats["mana"]

示例#25
0
aoc = AOC(year=2020, day=25)
data = aoc.load()

public_keys = [int(d) for d in data.lines()]
subs = [7, 7]
loop_sizes = []


def transform(sub, loop_size):
    value = 1
    for _ in range(loop_size):
        value = single_transform(value, sub)
    return value


def single_transform(value, sub):
    value = value * sub
    return value % 20201227


for sub, key in zip(subs, public_keys):
    value = 1
    loops = 0
    while value != key:
        value = single_transform(value, sub)
        loops += 1
    loop_sizes.append(loops)

aoc.p1(transform(public_keys[0], loop_sizes[1]))
示例#26
0
                best = max(get_best_score(updated_amounts, total_used + c),
                           best)
            return best
    return 0


# Pick an ingredient to start and recursively get the best score
best_score = 0
for item in ingredients:
    for count in range(101):
        score = get_best_score({item: count}, count)
        if score > best_score:
            best_score = score
    break

aoc.p1(best_score)

## Part 2

# Array indices
capacity = 0
durability = 1
flavor = 2
texture = 3
calorie = 4

# Regular expression to extract information about the ingredients
regex_ingredients = re.compile(
    r"(\w+): capacity ([-]?\d+), durability ([-]?\d+), flavor ([-]?\d+), texture ([-]?\d+), calories ([-]?\d+)"
)
ingredients = {}
示例#27
0
           range(int(m[3]),
                 int(m[4]) + 1)]
    for m in chunks[0]
}

# Part 1

all_rule_values = flatten(rules.values())


def is_valid_for_some_field(v):
    return any(v in x for x in all_rule_values)


aoc.p1(
    sum(
        sum(0 if is_valid_for_some_field(v) else v for v in t)
        for t in tickets))

# Part 2

tickets = [t for t in tickets if all(is_valid_for_some_field(v) for v in t)]
field_indices = {r: set(range(len(tickets[0]))) for r in rules.keys()}
confirmed_fields = set()

for t in tickets:
    for i, v in enumerate(t):
        for r in rules:
            if not any(v in x for x in rules[r]):
                field_indices[r].remove(i)

while True:
示例#28
0
hill = [list(line) for line in data.lines()]

# Part 1


def count_trees(slope):
    position = Position(0, 0)
    trees = 0
    while position.y < len(hill):
        if hill[position.y][position.x % len(hill[0])] == "#":
            trees += 1
        position = Position(position.x + slope.x, position.y + slope.y)
    return trees


aoc.p1(count_trees(Position(3, 1)))

# Part 2

aoc.p2(
    math.prod(
        [
            count_trees(slope)
            for slope in [
                Position(1, 1),
                Position(3, 1),
                Position(5, 1),
                Position(7, 1),
                Position(1, 2),
            ]
        ]
示例#29
0
        elif containers_total + remaining_containers[i] > target_eggnog:
            break
        # If the total is too small, keep iterating over the remaining containers
        elif i > 0:
            arrangements += get_arrangements(
                containers_total + remaining_containers[i],
                remaining_containers[:i])

    # Return the total number of arrangements made from this iteration
    return arrangements


# Gets the number of total container arrangements
total_arrangements = get_arrangements(0, PUZZLE_INPUT)

aoc.p1(total_arrangements)

## Part 2

# Initialize and sort the puzzle input
PUZZLE_INPUT = [
    33,
    14,
    18,
    20,
    45,
    35,
    16,
    35,
    1,
    13,
示例#30
0
from aoc import AOC

aoc = AOC(year=2018, day=23)
data = aoc.load()

## Part 1

nanobots = [((vals[0], vals[1], vals[2]), vals[3])
            for vals in data.numbers_by_line()]
nanobots.sort(key=lambda tup: tup[1], reverse=True)
strongest = nanobots[0]


def manhattan(first, second):
    return (abs(first[0][0] - second[0][0]) + abs(first[0][1] - second[0][1]) +
            abs(first[0][2] - second[0][2]))


in_range = sum(
    [1 if manhattan(x, strongest) <= strongest[1] else 0 for x in nanobots])

aoc.p1(in_range)