Beispiel #1
0
You have a shiny gold bag. If you wanted to carry it in at least one other bag, how many different bag colors would be valid for the outermost bag? (In other words: how many colors can, eventually, contain at least one shiny gold bag?)

In the above rules, the following options would be available to you:

A bright white bag, which can hold your shiny gold bag directly.
A muted yellow bag, which can hold your shiny gold bag directly, plus some other bags.
A dark orange bag, which can hold bright white and muted yellow bags, either of which could then hold your shiny gold bag.
A light red bag, which can hold bright white and muted yellow bags, either of which could then hold your shiny gold bag.
So, in this example, the number of bag colors that can eventually contain at least one shiny gold bag is 4.

How many bag colors can eventually contain at least one shiny gold bag? (The list of rules is quite long; make sure you get all of it.)
"""

from utils import tokenise_input_file, time_me

rules = tokenise_input_file('Inputs/day7.txt')


def process_rule(rule):
    result = list()
    k, other = rule.split(' bags contain ')
    if other == 'no other bags.':
        return k, tuple()
    for part in other.split(', '):
        num, colour = part.split(' ', 1)
        num = int(num)
        for text in ('bags', 'bag', '.'):
            colour = colour.replace(text, '')
        colour = colour.strip()
        result.append((colour, num))
    return k, tuple(result)
Beispiel #2
0
     7      +     44
            51

Here are a few more examples:

    2 * 3 + (4 * 5) becomes 26.
    5 + (8 * 3 + 9 + 3 * 4 * 3) becomes 437.
    5 * 9 * (7 * 3 * 3 + 9 * 3 + (8 + 6 * 4)) becomes 12240.
    ((2 + 4 * 9) * (6 + 9 * 8 + 6) + 6) + 2 + 4 * 2 becomes 13632.

Before you can help with the homework, you need to understand it yourself. Evaluate the expression on each line of the homework; what is the sum of the resulting values?
"""

from utils import time_me, tokenise_input_file

lines = tokenise_input_file('Inputs/day18.txt')


class T:
    def __init__(self, v):
        self.v = v

    def __add__(self, other):
        return T(self.v + other.v)

    def __sub__(self, other):
        return T(self.v * other.v)

    def __mul__(self, other):
        return T(self.v + other.v)
Beispiel #3
0
7
9
4
2
34
10
3

In this larger example, in a chain that uses all of the adapters, there are 22 differences of 1 jolt and 10 differences of 3 jolts.

Find a chain that uses all of your adapters to connect the charging outlet to your device's built-in adapter and count the joltage differences between the charging outlet, the adapters, and your device. What is the number of 1-jolt differences multiplied by the number of 3-jolt differences?
"""
from utils import tokenise_input_file, time_me
from collections import defaultdict

nums = [0,] + sorted(map(int, tokenise_input_file('Inputs/day10.txt')))
nums.append(max(nums)+3)

@time_me
def part1(nums):
    difs = defaultdict(int)
    i = 1
    while i < len(nums):
        dif = nums[i] - nums[i-1]
        difs[dif] += 1
        i += 1
    return difs[1] * difs[3]

print(part1(nums))

"""
Beispiel #4
0
7,1,14

nearby tickets:
7,3,47
40,4,50
55,2,20
38,6,12

It doesn't matter which position corresponds to which field; you can identify invalid nearby tickets by considering only whether tickets contain values that are not valid for any field. In this example, the values on the first nearby ticket are all valid for at least one field. This is not true of the other three nearby tickets: the values 4, 55, and 12 are are not valid for any field. Adding together all of the invalid values produces your ticket scanning error rate: 4 + 55 + 12 = 71.

Consider the validity of the nearby tickets you scanned. What is your ticket scanning error rate?
"""

from utils import time_me, tokenise_input_file

groups = tokenise_input_file('Inputs/day16.txt', '\n\n')

groups_test = '''class: 0-1 or 4-19
row: 0-5 or 8-19
seat: 0-13 or 16-19

your ticket:
11,12,13

nearby tickets:
3,9,18
15,1,5
5,14,9'''.split('\n\n')


@time_me
Beispiel #5
0
Here are a few more examples:

Given the starting numbers 1,3,2, the 2020th number spoken is 1.
Given the starting numbers 2,1,3, the 2020th number spoken is 10.
Given the starting numbers 1,2,3, the 2020th number spoken is 27.
Given the starting numbers 2,3,1, the 2020th number spoken is 78.
Given the starting numbers 3,2,1, the 2020th number spoken is 438.
Given the starting numbers 3,1,2, the 2020th number spoken is 1836.
Given your starting numbers, what will be the 2020th number spoken?

Your puzzle input is 17,1,3,16,19,0.
"""

from utils import time_me, tokenise_input_file

nums = list(map(int, tokenise_input_file('Inputs/day15.txt', ',')))

@time_me
def do_part(nums, dist):
    last, c = nums[-1], {n: i for i, n in enumerate(nums)}
    for i in range(len(nums) - 1, dist - 1):
        c[last], last = i, i - c.get(last, i)
    return last

print(do_part(nums, 2020))

"""
--- Part Two ---
Impressed, the Elves issue you a challenge: determine the 30000000th number spoken. For example, given the same starting numbers as above:

Given 0,3,6, the 30000000th number spoken is 175594.
Beispiel #6
0
944      .       .       D       .       .
945      D       .       .       .       .
946      .       .       .       .       .
947      .       .       .       .       .
948      .       .       .       .       .
949      .       D       .       .       .

The earliest bus you could take is bus ID 59. It doesn't depart until timestamp 944, so you would need to wait 944 - 939 = 5 minutes before it departs. Multiplying the bus ID by the number of minutes you'd need to wait gives 295.

What is the ID of the earliest bus you can take to the airport multiplied by the number of minutes you'll need to wait for that bus?
"""

from utils import time_me, tokenise_input_file
from math import ceil

t, line = tokenise_input_file('Inputs/day13.txt')

line = [v for v in line.split(',')]
t = int(t)
bus_ids = [int(v) for v in line if v.isnumeric()]


@time_me
def part1(t, bus_ids):
    wait_time = float('inf')
    for bus_id in bus_ids:
        bus_wait = (ceil(t / bus_id) * bus_id) - t
        if bus_wait < wait_time:
            wait_time = bus_wait
            ans = wait_time * bus_id
    return wait_time, ans
Beispiel #7
0
..#.#....# ##.#.#.... ...##.....

For reference, the IDs of the above tiles are:

1951    2311    3079
2729    1427    2473
2971    1489    1171

To check that you've assembled the image correctly, multiply the IDs of the four corner tiles together. If you do this with the assembled tiles from the example above, you get 1951 * 3079 * 2971 * 1171 = 20899048083289.

Assemble the tiles into an image. What do you get if you multiply together the IDs of the four corner tiles?
"""

from utils import time_me, tokenise_input_file

tiles_str = tokenise_input_file('Inputs/day20.txt', '\n\n')


def centralise_tile(tile):
    xs = [x for x, _ in tile.keys()]
    ys = [y for _, y in tile.keys()]
    xcentre = (max(xs) + min(xs)) / 2
    ycentre = (max(ys) + min(ys)) / 2
    centrepoint_adjust = (xcentre * -1, ycentre * -1)
    tmp_tile = dict()
    for k, v in tile:
        xy = tuple(map(sum, zip(k, centrepoint_adjust)))
        tmp_tile[xy] = v
    return tmp_tile

Beispiel #8
0
acc -99 |
acc +1  | 4
jmp -4  | 5
acc +6  |
First, the nop +0 does nothing. Then, the accumulator is increased from 0 to 1 (acc +1) and jmp +4 sets the next instruction to the other acc +1 near the bottom. After it increases the accumulator from 1 to 2, jmp -4 executes, setting the next instruction to the only acc +3. It sets the accumulator to 5, and jmp -3 causes the program to continue back at the first acc +1.

This is an infinite loop: with this sequence of jumps, the program will run forever. The moment the program tries to run any instruction a second time, you know it will never terminate.

Immediately before the program would run an instruction a second time, the value in the accumulator is 5.

Run your copy of the boot code. Immediately before any instruction is executed a second time, what value is in the accumulator?
"""

from utils import tokenise_input_file, time_me

program = tokenise_input_file('Inputs/day8.txt')

program = [(s.split(' ', 1)[0], int(s.split(' ', 1)[1])) for s in program]


def process_command(i, program, acc):
    if program[i][0] == 'acc':
        acc += program[i][1]
        i += 1
    elif program[i][0] == 'jmp':
        i += program[i][1]
    elif program[i][0] == 'nop':
        i += 1
    else:
        raise ValueError('Invalid command provided')
    return i, acc
Beispiel #9
0
182
127
219
299
277
309
576
In this example, after the 5-number preamble, almost every number is the sum of two of the previous 5 numbers; the only number that does not follow this rule is 127.

The first step of attacking the weakness in the XMAS data is to find the first number in the list (after the preamble) which is not the sum of two of the 25 numbers before it. What is the first number that does not have this property?
"""

from itertools import combinations
from utils import time_me, tokenise_input_file

numbers = tuple(map(int, tokenise_input_file('Inputs/day9.txt')))


#Day 1 solution, no multiplication
def check_sum_target(num_list, comb_size, target):
    for comb in combinations(num_list, comb_size):
        if sum(comb) == target:
            return True
    return False


def slice_gen(long_list, length):
    i = length
    while i < len(long_list):
        yield long_list[i], long_list[i - length:i]
        i += 1
Beispiel #10
0
So, decoding FBFBBFFRLR reveals that it is the seat at row 44, column 5.

Every seat also has a unique seat ID: multiply the row by 8, then add the column. In this example, the seat has ID 44 * 8 + 5 = 357.

Here are some other boarding passes:

    BFFFBBFRRR: row 70, column 7, seat ID 567.
    FFFBBBFRRR: row 14, column 7, seat ID 119.
    BBFFBBFRLL: row 102, column 4, seat ID 820.

As a sanity check, look through your list of boarding passes. What is the highest seat ID on a boarding pass?
"""

from utils import time_me, tokenise_input_file

boarding_passes = tokenise_input_file('Inputs/day5.txt', '\n')


def code_to_seat(boarding_pass):
    for c in ('F', 'L'):
        boarding_pass = boarding_pass.replace(c, '0')
    for c in ('B', 'R'):
        boarding_pass = boarding_pass.replace(c, '1')
    return int(boarding_pass, 2)


@time_me
def part1(boarding_passes):
    return max(
        [code_to_seat(boarding_pass) for boarding_pass in boarding_passes])
Beispiel #11
0
1: 2 3 | 3 2
2: 4 4 | 5 5
3: 4 5 | 5 4
4: "a"
5: "b"

ababbb
bababa
abbbab
aaabbb
aaaabbb"""

from utils import time_me, tokenise_input_file
import re

rules, messages = tokenise_input_file('Inputs/day19.txt', '\n\n')

rules = dict([rule.split(': ', 1) for rule in rules.split('\n')])


def getre_p1(rulenum):
    rule = rules[rulenum]
    if re.fullmatch(r'"."', rule):
        return rule[1]
    else:
        parts = rule.split(' | ')
        res = []
        for part in parts:
            nums = part.split(' ')
            res.append(''.join(getre_p1(num) for num in nums))
        return '(?:' + '|'.join(res) + ')'