Advent Of Code

Published

January 1, 2021

Day 1

Part 1

import pandas as pd
import requests as r
nums = (
    r.get("https://filebin.net/qjkb2njdu0gl7kxz/input.txt?t=kjulapu7")
    .text.strip()
    .split("\n")
)
nums = sorted(map(int, nums))
nums[:10] + ["-----"] + nums[-10:]
def main_two():
    n = len(nums)
    for i in range(n):
        for j in range(i + 1, n):
            a, b = nums[i], nums[n - j]
            #             print(a,b, a+b)
            if a + b < 2020:
                break  # break J
            if a + b == 2020:
                return a * b


main_two()
def main_three():
    n = len(nums)
    for i in range(n):
        for j in range(i + 1, n):
            for k in range(n):
                a = nums[i]
                b = nums[n - j]

                # iterate from middle(n//2) to +1, -1, +2, -2, and so on
                idx_middle = n // 2 + (-1) ** k * k // 2
                c = nums[idx_middle]

                if a + b + c == 2020:
                    return a * b * c


main_three()

Day 2

# part 1
def valid_pass(line):
    line = line.strip()
    if line == "":
        return False
    MIN, MAX, s, pwd = re.split("-| |: ", line)
    MIN, MAX = int(MIN), int(MAX)
    return MIN <= pwd.count(s) <= MAX


import re

with open("data/advent_of_code/2020/day2.txt") as f:
    line = f.readline()
    cnt = int(valid_pass(line))
    while line:
        line = f.readline()
        cnt += valid_pass(line)
cnt
# part 2
def valid_pass(line):
    line = line.strip()
    if line == "":
        return False
    i, j, s, pwd = re.split("-| |: ", line)
    i, j = int(i), int(j)
    return (pwd[i - 1] == s) ^ (pwd[j - 1] == s)


import re

with open("data/advent_of_code/2020/day2.txt") as f:
    line = f.readline()
    cnt = int(valid_pass(line))
    while line:
        line = f.readline()
        cnt += valid_pass(line)
cnt

Day 3

import numpy as np
s = """..##.......
#...#...#..
.#....#..#.
..#.#...#.#
.#...##..#.
..#.##.....
.#.#.#....#
.#........#
#.##...#...
#...##....#
.#..#...#.#"""
lst = [[int(c) for c in row] for row in s.replace(".", "0").replace("#", "1").split()]
sarr = np.array(lst)
sarr
n_steps = len(sarr) - 1
n_steps
full_map = np.hstack([sarr] * n_steps)
full_map.shape
full_map[:11, :11]
delta_y = 1
delta_x = 3
coord_x = coord_y = 0
def make_step(delta_x, delta_y):
    global coord_x
    global coord_y

    coord_x += delta_x
    coord_y += delta_y
full_map
num_trees = 0
for i in range(n_steps):
    make_step(delta_x, delta_y)
    num_trees += full_map[coord_y, coord_x]
    if full_map[coord_y, coord_x]:
        print(f"Tree encountered at step {i}. coords_xy = {coord_x, coord_y}")
    full_map[coord_y, coord_x] = 4

print(f"Num Trees = {num_trees}")

Part 1

import numpy as np

with open("data/advent_of_code/2020/day3.txt") as f:
    s = f.read()

lst = [[int(c) for c in row] for row in s.replace(".", "0").replace("#", "1").split()]
sarr = np.array(lst)
full_map = np.hstack([sarr] * len(sarr))


class Plane:
    def __init__(self, delta_x, delta_y):
        self.coord_x = 0
        self.coord_y = 0
        self.delta_x = delta_x
        self.delta_y = delta_y

    def step(self):
        self.coord_x += self.delta_x
        self.coord_y += self.delta_y


def calc_for_slope(delta_x, delta_y):
    p = Plane(delta_x, delta_y)
    num_trees = 0

    while p.coord_y < len(sarr) - delta_y:
        p.step()
        num_trees += full_map[p.coord_y, p.coord_x]
        if p.coord_y >= len(sarr) - delta_y:
            print("wow")

    print(f"Num Trees = {num_trees} for slope right={delta_x}, down={delta_y}")
    return num_trees


calc_for_slope(3, 1)

Part 2

slopes = [
    (3, 1),
    (1, 2),
    (1, 1),
    (5, 1),
    (7, 1),
]

results = {slope: calc_for_slope(*slope) for slope in slopes}

ans = 1
for k, v in results.items():
    ans *= v
ans

Day 4

batch = """ecl:gry pid:860033327 eyr:2020 hcl:#fffffd
byr:1937 iyr:2017 cid:147 hgt:183cm

iyr:2013 ecl:amb cid:350 eyr:2023 pid:028048884
hcl:#cfa07d byr:1929

hcl:#ae17e1 iyr:2013
eyr:2024
ecl:brn pid:760753108 byr:1931
hgt:179cm

hcl:#cfa07d eyr:2025 pid:166559648
iyr:2011 ecl:brn hgt:59in"""
import re
passports = batch.split("\n\n")
p = passports[0]
necessary_keys = "byr iyr eyr hgt hcl ecl pid".split(" ")
necessary_keys
with open("data/advent_of_code/2020/day4.txt") as f:
    batch = f.read()
n_valid = 0

for p in batch.split("\n\n"):
    p_elems = [elem for elem in re.split(" |\n", p.strip())]
    for e in p_elems:
        if e == "":
            print("wow")
            pass

    dpass = dict()

    for kv in [e.split(":") for e in p_elems]:
        k, v = kv
        dpass[k] = v
    #     print(dpass)

    missing_keys = []
    for k in necessary_keys:
        if k not in dpass:
            missing_keys.append(k)

    if len(missing_keys):
        print(f"invalid, keys missing: {missing_keys}")
        pass
    else:
        #         print(f"valid")
        n_valid += 1

n_valid
def validate_pass(dpass):

    # step 1: all keys are present
    missing_keys = []
    for k in necessary_keys:
        if k not in dpass:
            return False

    # byr
    byr = dpass["byr"]
    if len(byr) != 4:
        return False

    byr = int(byr)
    if byr < 1920 or byr > 2002:
        return False

    # iyr
    iyr = dpass["iyr"]
    if len(iyr) != 4:
        return False
    iyr = int(iyr)
    if iyr < 2010 or iyr > 2020:
        return False
    # eyr

    eyr = dpass["eyr"]
    if len(eyr) != 4:
        return False
    eyr = int(eyr)
    if eyr < 2020 or eyr > 2030:
        return False

    # hgt
    hgt = dpass["hgt"]
    if hgt[-2:] not in ["cm", "in"]:
        return False

    n, unit = int(hgt[:-2]), hgt[-2:]
    if unit == "cm":
        if n < 150 or n > 193:
            return False
    elif unit == "in":
        if n < 59 or n > 76:
            return False
    else:
        raise ValueError()

    # hcl
    hcl = dpass["hcl"]
    pat = "#[0-9a-f]{6}"
    if re.fullmatch(pat, hcl) is None:
        return False

    # ecl
    ecl = dpass["ecl"]
    if ecl not in ["amb", "blu", "brn", "gry", "grn", "hzl", "oth"]:
        return False

    # pid
    pid = dpass["pid"]
    pat = "\d{9}"
    if re.fullmatch(pat, pid) is None:
        return False

    return True


validate_pass(
    {
        "hgt": "176cm",
        "iyr": "2013",
        "hcl": "#fffffd",
        "ecl": "amb",
        "byr": "2000",
        "eyr": "2030",
        "cid": "89",
        "pid": "934693255",
    }
)
batch = """eyr:1972 cid:100
hcl:#18171d ecl:amb hgt:170 pid:186cm iyr:2018 byr:1926

iyr:2019
hcl:#602927 eyr:1967 hgt:170cm
ecl:grn pid:012533040 byr:1946

hcl:dab227 iyr:2012
ecl:brn hgt:182cm pid:021572410 eyr:2020 byr:1992 cid:277

hgt:59cm ecl:zzz
eyr:2038 hcl:74454a iyr:2023
pid:3556412378 byr:2007"""
n_valid = 0

for p in batch.split("\n\n"):
    # build dict
    p_elems = [elem for elem in re.split(" |\n", p.strip())]
    dpass = dict()
    for kv in [e.split(":") for e in p_elems]:
        k, v = kv
        dpass[k] = v

    # validate
    n_valid += validate_pass(dpass)

n_valid
batch = """pid:087499704 hgt:74in ecl:grn iyr:2012 eyr:2030 byr:1980
hcl:#623a2f

eyr:2029 ecl:blu cid:129 byr:1989
iyr:2014 pid:896056539 hcl:#a97842 hgt:165cm

hcl:#888785
hgt:164cm byr:2001 iyr:2015 cid:88
pid:545766238 ecl:hzl
eyr:2022

iyr:2010 hgt:158cm hcl:#b6652a ecl:blu byr:1944 eyr:2021 pid:093154719"""
n_valid = 0

for p in batch.split("\n\n"):
    # build dict
    p_elems = [elem for elem in re.split(" |\n", p.strip())]
    dpass = dict()
    for kv in [e.split(":") for e in p_elems]:
        k, v = kv
        dpass[k] = v

    # validate
    n_valid += validate_pass(dpass)

n_valid
with open("data/advent_of_code/2020/day4.txt") as f:
    batch = f.read()

n_valid = 0

for p in batch.split("\n\n"):
    # build dict
    p_elems = [elem for elem in re.split(" |\n", p.strip())]
    dpass = dict()
    for kv in [e.split(":") for e in p_elems]:
        k, v = kv
        dpass[k] = v

    # validate
    n_valid += validate_pass(dpass)

n_valid

Day 5

def search(arr, op, vrb=False):
    n = len(arr)
    if op == "lower":
        return arr[: n // 2]
    elif op == "upper":
        return arr[n // 2 :]
def locate_row(seq):
    assert len(seq) == 7, f"Len = {len(seq)}, expected 7"
    rows = list(range(128))

    mapper = {"F": "lower", "B": "upper"}

    for op in seq:
        rows = search_rows(rows, mapper[op])

    assert len(rows) == 1

    return rows[0]
locate_row("FBFBBFF")
def locate_col(seq):
    assert len(seq) == 3, f"Len = {len(seq)}, expected 3"
    cols = list(range(8))

    mapper = {"L": "lower", "R": "upper"}

    for op in seq:
        cols = search_rows(cols, mapper[op])

    assert len(rows) == 1

    return cols[0]
locate_col("RLR")
def decode(seq):
    row = locate_row(seq[:7])
    col = locate_col(seq[7:])
    return {"row": row, "col": col, "sid": row * 8 + col, "code": seq}
decode("FBFBBFFRLR")
decode("BFFFBBFRRR")
decode("FFFBBBFRRR")
decode("BBFFBBFRLL")
with open("data/advent_of_code/2020/day5.txt") as f:
    codes = f.read().strip().split("\n")

myTicket = sorted([decode(c) for c in codes], key=lambda x: x["sid"], reverse=True)[0]
myTicket
seat_ids = [decode(s)["sid"] for s in codes]
lo = min(seat_ids)
hi = max(seat_ids)
print([x for x in range(lo, hi) if x not in seat_ids])  # find empty seat

Day 6

s = """abc

a
b
c

ab
ac

a
a
a
a

b
"""
sum([len(set(group.replace("\n", ""))) for group in s.split("\n\n")])
[group.split("\n") for group in s.strip().split("\n\n")]
def common_chars_in_group(people):
    common = set(people[0])
    for person in people:
        common &= set(person)
    return common
groups = [group.split("\n") for group in s.strip().split("\n\n")]
commons = [common_chars_in_group(g) for g in groups]
commons
sum([len(c) for c in commons])
with open("data/advent_of_code/2020/day6.txt") as f:
    s = f.read()
sum([len(set(group.replace("\n", ""))) for group in s.split("\n\n")])
groups = [group.split("\n") for group in s.strip().split("\n\n")]
commons = [common_chars_in_group(g) for g in groups]
sum([len(c) for c in commons])

Day 7

import re
s_rules = """light red bags contain 1 bright white bag, 2 muted yellow bags.
dark orange bags contain 3 bright white bags, 4 muted yellow bags.
bright white bags contain 1 shiny gold bag.
muted yellow bags contain 2 shiny gold bags, 9 faded blue bags.
shiny gold bags contain 1 dark olive bag, 2 vibrant plum bags.
dark olive bags contain 3 faded blue bags, 4 dotted black bags.
vibrant plum bags contain 5 faded blue bags, 6 dotted black bags.
faded blue bags contain no other bags.
dotted black bags contain no other bags.
"""
with open("data/advent_of_code/2020/day7.txt") as f:
    s_rules = f.read()
lines = [l for l in re.split("\.|\n", s_rules.strip()) if l != ""]
lines[-3:]
['bright green bags contain 4 drab green bags, 3 drab indigo bags, 5 dull blue bags',
 'posh violet bags contain 5 wavy white bags',
 'clear brown bags contain no other bags']
graph = {}
lines = [l for l in re.split("\.|\n", s_rules.strip()) if l != ""]
for line in lines:
    line = line.strip("\n.")
    logics = re.split("bags|bag|,|contain", line)
    logics = [x.strip() for x in logics if x.strip() != ""]

    target = logics[0]
    can_contain = logics[1:]
    target, can_contain

    graph[target] = dict()
    for rule in can_contain:
        if rule == "no other":
            break
        else:
            nbr = int(rule[0])
            color = rule[2:]
            graph[target][color] = nbr
graph["shiny gold"]  # can contain
{'clear brown': 5, 'plaid fuchsia': 5, 'bright teal': 4, 'striped white': 1}
from collections import defaultdict

inverted_graph = defaultdict(list)

for bag, can_contain in graph.items():
    for color in can_contain:
        inverted_graph[color].append(bag)

inverted_graph["shiny gold"]  # can be stored in
['shiny orange',
 'mirrored crimson',
 'drab blue',
 'dark aqua',
 'mirrored purple']
variations = list()
def dfs(color, current_path=""):
    if current_path == "":
        current_path = color
    else:
        current_path += f" <- {color}"

    if outer_bags := inverted_graph[color]:
        for bag in outer_bags:
            dfs(bag, current_path)
    else:
        variations.append(current_path)


dfs("shiny gold")
variations
['shiny gold <- shiny orange <- pale aqua <- mirrored gold <- dark maroon',
 'shiny gold <- shiny orange <- pale aqua <- mirrored gold <- dotted olive <- bright silver',
 'shiny gold <- shiny orange <- pale aqua <- mirrored gold <- faded chartreuse',
 'shiny gold <- shiny orange <- pale aqua <- plaid lime',
 'shiny gold <- shiny orange <- pale aqua <- dim salmon <- posh lavender',
 'shiny gold <- shiny orange <- pale aqua <- dim salmon <- mirrored lavender <- muted violet <- light lime <- light gold <- mirrored red',
 'shiny gold <- shiny orange <- pale aqua <- dim salmon <- mirrored lavender <- muted violet <- light lime <- bright gold',
 'shiny gold <- shiny orange <- pale aqua <- dim salmon <- mirrored lavender <- muted violet <- light lime <- dull lime <- striped red <- bright silver',
 'shiny gold <- shiny orange <- pale aqua <- dim salmon <- mirrored lavender <- muted violet <- light lime <- dull lime <- striped red <- plaid white <- posh coral <- dim aqua',
 'shiny gold <- shiny orange <- pale aqua <- dim salmon <- mirrored lavender <- muted violet <- light lime <- dull lime <- drab olive <- dotted salmon <- wavy beige <- striped cyan <- wavy lavender',
 'shiny gold <- shiny orange <- pale aqua <- dim salmon <- mirrored lavender <- muted violet <- dotted purple',
 'shiny gold <- shiny orange <- pale aqua <- dim salmon <- mirrored lavender <- muted violet <- faded silver',
 'shiny gold <- shiny orange <- pale aqua <- dim salmon <- mirrored lavender <- dotted black',
 'shiny gold <- shiny orange <- pale aqua <- dim salmon <- mirrored lavender <- plaid yellow',
 'shiny gold <- shiny orange <- pale aqua <- faded orange',
 'shiny gold <- shiny orange <- pale aqua <- wavy gold <- mirrored purple <- bright lavender <- posh purple <- shiny purple <- faded olive',
 'shiny gold <- shiny orange <- pale aqua <- wavy gold <- mirrored purple <- bright lavender <- vibrant lavender <- vibrant orange',
 'shiny gold <- shiny orange <- pale aqua <- wavy gold <- mirrored purple <- bright lavender <- vibrant lavender <- plaid teal',
 'shiny gold <- shiny orange <- pale aqua <- wavy gold <- mirrored purple <- bright lavender <- dotted olive <- bright silver',
 'shiny gold <- shiny orange <- pale aqua <- wavy gold <- mirrored purple <- bright lavender <- dull gray <- muted gray',
 'shiny gold <- shiny orange <- plaid gray <- dull salmon',
 'shiny gold <- shiny orange <- plaid gray <- light olive <- shiny salmon <- dull green',
 'shiny gold <- shiny orange <- plaid gray <- light olive <- pale blue',
 'shiny gold <- shiny orange <- plaid gray <- light olive <- vibrant purple',
 'shiny gold <- shiny orange <- plaid gray <- light olive <- dark cyan <- faded blue <- plaid magenta',
 'shiny gold <- shiny orange <- plaid gray <- muted gray',
 'shiny gold <- shiny orange <- plaid gray <- striped aqua',
 'shiny gold <- shiny orange <- plaid gray <- dotted lavender <- mirrored white <- drab red',
 'shiny gold <- shiny orange <- plaid gray <- dotted lavender <- dotted aqua',
 'shiny gold <- shiny orange <- plaid gray <- dotted lavender <- mirrored lime <- dim chartreuse <- mirrored chartreuse',
 'shiny gold <- shiny orange <- plaid gray <- dotted lavender <- mirrored lime <- vibrant brown <- clear turquoise <- pale violet',
 'shiny gold <- shiny orange <- drab maroon <- shiny cyan <- mirrored yellow',
 'shiny gold <- shiny orange <- drab maroon <- dull white <- shiny magenta <- muted salmon',
 'shiny gold <- shiny orange <- drab maroon <- dull white <- muted plum <- shiny gray <- mirrored beige',
 'shiny gold <- shiny orange <- drab maroon <- dull white <- muted plum <- shiny gray <- plaid tomato',
 'shiny gold <- shiny orange <- drab maroon <- dull white <- mirrored lime <- dim chartreuse <- mirrored chartreuse',
 'shiny gold <- shiny orange <- drab maroon <- dull white <- mirrored lime <- vibrant brown <- clear turquoise <- pale violet',
 'shiny gold <- shiny orange <- drab maroon <- plaid silver <- pale indigo <- shiny beige',
 'shiny gold <- shiny orange <- drab maroon <- plaid silver <- pale indigo <- dull plum <- clear gold',
 'shiny gold <- shiny orange <- drab maroon <- plaid silver <- pale indigo <- dull plum <- wavy blue <- dotted coral <- dotted magenta',
 'shiny gold <- shiny orange <- drab maroon <- plaid silver <- pale indigo <- dull plum <- light turquoise <- dark yellow',
 'shiny gold <- shiny orange <- drab maroon <- plaid silver <- pale indigo <- dull plum <- light turquoise <- shiny tomato',
 'shiny gold <- shiny orange <- drab maroon <- plaid silver <- pale indigo <- bright turquoise',
 'shiny gold <- shiny orange <- drab maroon <- plaid silver <- pale indigo <- dull tomato',
 'shiny gold <- shiny orange <- drab maroon <- plaid silver <- pale indigo <- clear green',
 'shiny gold <- shiny orange <- drab maroon <- plaid silver <- pale indigo <- muted red <- muted aqua',
 'shiny gold <- shiny orange <- drab maroon <- plaid silver <- pale indigo <- muted red <- vibrant purple',
 'shiny gold <- shiny orange <- drab maroon <- plaid silver <- pale indigo <- muted red <- dark cyan <- faded blue <- plaid magenta',
 'shiny gold <- shiny orange <- drab maroon <- plaid silver <- posh beige <- plaid chartreuse',
 'shiny gold <- shiny orange <- drab maroon <- plaid silver <- posh beige <- dotted violet',
 'shiny gold <- shiny orange <- drab maroon <- striped lime <- faded magenta <- dotted gray',
 'shiny gold <- shiny orange <- drab maroon <- striped lime <- dark brown <- muted coral <- dotted black',
 'shiny gold <- shiny orange <- dim gray <- posh green <- vibrant blue',
 'shiny gold <- shiny orange <- dim gray <- posh green <- muted salmon',
 'shiny gold <- shiny orange <- dim gray <- posh green <- muted orange',
 'shiny gold <- shiny orange <- dotted lime <- faded plum <- shiny cyan <- mirrored yellow',
 'shiny gold <- mirrored crimson <- faded salmon <- muted lavender',
 'shiny gold <- mirrored crimson <- faded salmon <- muted violet <- light lime <- light gold <- mirrored red',
 'shiny gold <- mirrored crimson <- faded salmon <- muted violet <- light lime <- bright gold',
 'shiny gold <- mirrored crimson <- faded salmon <- muted violet <- light lime <- dull lime <- striped red <- bright silver',
 'shiny gold <- mirrored crimson <- faded salmon <- muted violet <- light lime <- dull lime <- striped red <- plaid white <- posh coral <- dim aqua',
 'shiny gold <- mirrored crimson <- faded salmon <- muted violet <- light lime <- dull lime <- drab olive <- dotted salmon <- wavy beige <- striped cyan <- wavy lavender',
 'shiny gold <- mirrored crimson <- faded salmon <- muted violet <- dotted purple',
 'shiny gold <- mirrored crimson <- faded salmon <- muted violet <- faded silver',
 'shiny gold <- mirrored crimson <- dull lime <- striped red <- bright silver',
 'shiny gold <- mirrored crimson <- dull lime <- striped red <- plaid white <- posh coral <- dim aqua',
 'shiny gold <- mirrored crimson <- dull lime <- drab olive <- dotted salmon <- wavy beige <- striped cyan <- wavy lavender',
 'shiny gold <- mirrored crimson <- wavy violet <- drab orange <- wavy gray',
 'shiny gold <- mirrored crimson <- wavy violet <- dark yellow',
 'shiny gold <- mirrored crimson <- wavy violet <- faded olive',
 'shiny gold <- mirrored crimson <- faded orange',
 'shiny gold <- mirrored crimson <- striped beige <- posh black <- shiny lime',
 'shiny gold <- mirrored crimson <- striped beige <- dim tomato',
 'shiny gold <- mirrored crimson <- dim beige <- dark silver <- dark blue',
 'shiny gold <- mirrored crimson <- dim beige <- clear silver',
 'shiny gold <- drab blue <- wavy silver <- shiny aqua',
 'shiny gold <- dark aqua',
 'shiny gold <- mirrored purple <- bright lavender <- posh purple <- shiny purple <- faded olive',
 'shiny gold <- mirrored purple <- bright lavender <- vibrant lavender <- vibrant orange',
 'shiny gold <- mirrored purple <- bright lavender <- vibrant lavender <- plaid teal',
 'shiny gold <- mirrored purple <- bright lavender <- dotted olive <- bright silver',
 'shiny gold <- mirrored purple <- bright lavender <- dull gray <- muted gray']
len(set(variations))
82