AoC 2020

Day 1: Report Repair

A = []
with open('./input.txt') as input:
    A = [int(line.strip()) for line in input]

def sum2(exclude = -1, t = 2020, seen = set()):
    for i, x in enumerate(A):
        if i == exclude:
            continue
        y = t - x
        if y in seen:
            return x * y
        seen.add(x)
    return -1

def sum3(t = 2020):
    for i, x in enumerate(A):
        y = t - x
        z = sum2(i, y)
        if z != -1:
            return x * z
    return -1

print(f'Part 1: {sum2()}')  # Part 1: 1006875
print(f'Part 2: {sum3()}')  # Part 2: 165026160 

Day 2: Password Philosophy

from collections import Counter

A = []
with open('./input.txt') as input:
    A = [line.strip() for line in input]

one = 0
two = 0
for range, ch, word in [line.split(' ') for line in A]:
    lo, hi = map(int, range.split('-'))
    ch = ch[0]  # ignore ':'
    m = Counter(word)
    if ch in m and lo <= m[ch] <= hi:
        one += 1
    if (lo <= len(word) and ch == word[lo - 1]) ^ (hi <= len(word) and ch == word[hi - 1]):
        two += 1
print(f'Part 1: {one}')  # Part 1: 460
print(f'Part 2: {two}')  # Part 2: 251

Day 3: Toboggan Trajectory

A = []
with open('./input.txt') as input:
    A = [line.strip() for line in input]
M = len(A)
N = len(A[0])

def traverse(down = 1, right = 3):
    cnt = 0
    i = 0
    j = 0
    while i < M:
        if A[i][j] == '#':
            cnt += 1
        i += down
        j += right; j %= N
    return cnt

print(f'Part 1: {traverse()}')
print(f'Part 2: {traverse(1, 1) * traverse(1, 3) * traverse(1, 5) * traverse(1, 7) * traverse(2, 1)}')

# Part 1: 232
# Part 2: 3952291680

Day 4: Passport Processing

import re

A = []
with open('./input.txt') as input:
    A = [line.strip() for line in input]
A.append('')  # sentinel delimiter

m = {}
one = 0
two = 0
ok1 = lambda m: 'byr' in m and 'iyr' in m and 'eyr' in m and 'hgt' in m and 'hcl' in m and 'ecl' in m and 'pid' in m
byr = lambda m: 'byr' in m and 1920 <= int(m['byr']) <= 2002
iyr = lambda m: 'iyr' in m and 2010 <= int(m['iyr']) <= 2020
eyr = lambda m: 'eyr' in m and 2020 <= int(m['eyr']) <= 2030
def hgt(m):
    if not 'hgt' in m:
        return False
    height = m['hgt']
    val = height[:-2]
    unit = height[-2:]
    if unit == 'cm': return 150 <= int(val) <= 193
    if unit == 'in': return 59 <= int(val) <= 76
    return False
def hcl(m):
    if not 'hcl' in m:
        return False
    match = re.search('^#[0-9a-f]{6}$', m['hcl'])
    return True if match else False
ecl = lambda m: 'ecl' in m and m['ecl'] in ['amb', 'blu', 'brn', 'gry', 'grn', 'hzl', 'oth']
def pid(m):
    if not 'pid' in m:
        return False
    match = re.search('^[0-9]{9}$', m['pid'])
    return True if match else False
ok2 = lambda m: byr(m) and iyr(m) and eyr(m) and hgt(m) and hcl(m) and ecl(m) and pid(m)
for line in A:
    if not len(line):
        if ok1(m): one += 1
        if ok2(m): two += 1
        m = {}
    else:
        for pair in line.split(' '):
            key, val = pair.split(':')
            m[key] = val

print(f'Part 1: {one}')  # Part 1: 182
print(f'Part 2: {two}')  # Part 2: 109

Day 5: Binary Boarding

A = []
with open('./input.txt') as input:
    A = [line.strip() for line in input]

def row(s):
    i = 0
    j = 128
    for c in s:
        k = (i + j) // 2
        if c == 'B': i = k
        if c == 'F': j = k
    return i

def col(s):
    i = 0
    j = 8
    for c in s:
        k = (i + j) // 2
        if c == 'R': i = k
        if c == 'L': j = k
    return i

best = 0
seats = []
for s in A:
    seat = 8 * row(s) + col(s)
    best = max(best, seat)
    seats.append(seat)

target = 0
seats.sort()
for i in range(1, len(seats)):
    if abs(seats[i - 1] - seats[i]) == 2:
        target = seats[i - 1] + 1
        break

print(f'Part 1: {best}')    # Part 1: 953
print(f'Part 2: {target}')  # Part 2: 615

Day 6: Custom Customs

A = []
with open('./input.txt') as input:
    A = [line.strip() for line in input]
A.append('')  # sentinel delimiter

m, cnt = {}, 0
one = 0
two = 0
for line in A:
    if not len(line):
        one += len(m)
        two += sum([1 for c in m if m[c] == cnt])
        m = {}; cnt = 0
    else:
        for c in line:
            m[c] = m[c] + 1 if c in m else 1
        cnt += 1

print(f'Part 1: {one}')  # Part 1: 6542
print(f'Part 2: {two}')  # Part 2: 3299