if seat == FREE and occupied == 0: new_map[i][j] = TAKEN changed = True elif seat == TAKEN and occupied >= max_occupied: new_map[i][j] = FREE changed = True return new_map, changed def solve(seat_map, count_f, n): changed = True while changed: seat_map, changed = crowding_pass(seat_map, count_f, n) return sum(row.count(TAKEN) for row in seat_map) @aoc_timer(1, 11, 2020) def solve_first(seat_map): return solve(seat_map, count_adjacent, 4) @aoc_timer(2, 11, 2020) def solve_second(seat_map): return solve(seat_map, count_seen, 5) if __name__ == '__main__': seat_map = parse_input(get_input(11, year=2020)) solve_first(seat_map) solve_second(seat_map)
def parse_input(input_str): return list(map(parse_policy, input_str.splitlines())) def valid_count(policy): count_low, count_high, letter, password = policy return int(count_low) <= password.count(letter) <= int(count_high) @aoc_timer(1, 2, 2020) def solve_first(policies): return sum(map(valid_count, policies)) def valid_position(policy): pos1, pos2, letter, password = policy char1 = password[int(pos1) - 1] char2 = password[int(pos2) - 1] return [char1, char2].count(letter) == 1 @aoc_timer(2, 2, 2020) def solve_second(policies): return sum(map(valid_position, policies)) if __name__ == '__main__': policies = parse_input(get_input(2, year=2020)) solve_first(policies) solve_second(policies)
zeroes = [0] * (N - 2) pocket = set((x, y, *zeroes) for x, y in product(range(pocket_length), repeat=2) if initial_state[x][y] == '#') for _ in range(6): counter = Counter(neighbour for coords in pocket for neighbour in neighbour_set(coords)) pocket = set(coords for coords, active in counter.items() if (active == 2 and coords in pocket) or active == 3) return len(pocket) @aoc_timer(1, 17, 2020) def solve_first(initial_state): return solve(initial_state, 3) @aoc_timer(2, 17, 2020) def solve_second(initial_state): return solve(initial_state, 4) def parse_input(input_str): return input_str.splitlines() if __name__ == '__main__': initial_state = parse_input(get_input(17, year=2020)) solve_first(initial_state) solve_second(initial_state)
@aoc_timer(2, 16, 2020) def solve_second(args): rules, my_ticket, nearby = args nearby = [t for t in nearby if valid_ticket(rules, t)] transposed = list(zip(*nearby)) header_sets = [set() for _ in range(len(transposed))] for header, in_range in rules: for col, values in enumerate(transposed): if all(map(in_range, values)): header_sets[col].add(header) header_mapping = {} while len(header_mapping) != len(transposed): for col, headers in enumerate(header_sets): if len(headers) != 1: continue header = headers.pop() for h in header_sets: h.discard(header) header_mapping[col] = header result = 1 for col, header in header_mapping.items(): if header.startswith('departure'): result *= my_ticket[col] return result if __name__ == '__main__': args = parse_input(get_input(16, year=2020)) solve_first(args) solve_second(args)
def calculate_id(bitstring): row = int(bitstring[:7], 2) col = int(bitstring[7:], 2) return row * 8 + col def parse_input(input_str): char_table = str.maketrans('FBLR', '0101') bitstrings = input_str.translate(char_table).splitlines() return list(map(calculate_id, bitstrings)) @aoc_timer(1, 5, 2020) def solve_first(boarding_ids): return max(boarding_ids) @aoc_timer(2, 5, 2020) def solve_second(boarding_ids): id_set = set(boarding_ids) for boarding_id in count(min(boarding_ids)): if boarding_id not in id_set: return boarding_id if __name__ == '__main__': boarding_passes = parse_input(get_input(5, year=2020)) solve_first(boarding_passes) solve_second(boarding_passes)
RULES = { "byr": lambda x: 1920 <= int(x) <= 2002, "iyr": lambda x: 2010 <= int(x) <= 2020, "eyr": lambda x: 2020 <= int(x) <= 2030, "hgt": validate_hgt, "hcl": lambda x: re.match("^#[0-9a-f]{6}$", x), "ecl": lambda x: x in {"amb", "blu", "brn", "gry", "grn", "hzl", "oth"}, "pid": lambda x: re.match("^[0-9]{9}$", x) } def validate(passport): for key, valid in RULES.items(): if key not in passport: return False if not valid(passport[key]): return False return True @aoc_timer(1, 4, 2020) def solve_second(passports): return len(list(filter(validate, passports))) if __name__ == '__main__': passports = parse_input(get_input(4, year=2020)) solve_first(passports) solve_second(passports)
def parse_input(input_str): return list(map(int, input_str.split(','))) def solve(numbers, N): mem = {n: i for i, n in enumerate(numbers[:-1], 1)} mem = defaultdict(bool, mem) last = numbers[-1] for turn in range(len(numbers), N): current = mem[last] current = turn - current if current else 0 mem[last] = turn last = current return current @aoc_timer(1, 15, 2020) def solve_first(numbers): return solve(numbers, 2020) @aoc_timer(2, 15, 2020) def solve_second(numbers): return solve(numbers, 30000000) if __name__ == '__main__': numbers = parse_input(get_input(15, year=2020)) solve_first(numbers) solve_second(numbers)
for i, coded_int in enumerate(encrypted_ints[25:]): preamble = encrypted_ints[i:i + 25] for x, y in combinations(preamble, 2): if x + y == coded_int: break else: return coded_int, i @aoc_timer(1, 9, 2020) def solve_first(encrypted_data): return find_error(encrypted_data)[0] @aoc_timer(2, 9, 2020) def solve_second(encrypted_ints): target_int, limit = find_error(encrypted_ints) for i, _ in enumerate(encrypted_ints[:limit]): sum_iterator = accumulate(encrypted_ints[i:]) for j, running_sum in enumerate(sum_iterator): if running_sum == target_int: return i + encrypted_ints[i + j] if running_sum > target_int: break if __name__ == '__main__': encrypted_ints = parse_input(get_input(9, year=2020)) solve_first(encrypted_ints) solve_second(encrypted_ints)
def parse_input(input_str): return input_str.splitlines() def count_trees(forest, right, down): rows, cols = len(forest), len(forest[0]) trees = 0 for row in range(down, rows, down): column = int((row / down) * right % cols) if forest[row][column] == '#': trees += 1 return trees @aoc_timer(1, 3, 2020) def solve_first(forest): return count_trees(forest, 3, 1) @aoc_timer(2, 3, 2020) def solve_second(forest): count = partial(count_trees, forest) return count(1, 1) * count(3, 1) * count(5, 1) * count(7, 1) * count(1, 2) if __name__ == '__main__': forest = parse_input(get_input(3, year=2020)) solve_first(forest) solve_second(forest)
@aoc_timer(2, 21, 2020) def solve_second(args): can_contain, _ = args allergic = {} while len(allergic) != len(can_contain): for allergen, ingredients in can_contain.items(): diff = ingredients - set(allergic) if len(diff) == 1: allergic[diff.pop()] = allergen return ",".join(sorted(allergic, key=lambda ing: allergic[ing])) def parse_line(line, can_contain=dict(), counts=Counter()): ingredients, allergens = line.split(' (contains ') ingredients = set(ingredients.split()) counts += Counter(ingredients) for allergen in allergens.rstrip(')').split(', '): checked = can_contain.get(allergen, ingredients) can_contain[allergen] = checked & ingredients return can_contain, counts def parse_input(input_str): return list(map(parse_line, input_str.splitlines())).pop() if __name__ == '__main__': args = parse_input(get_input(21, year=2020)) solve_first(args) solve_second(args)
def parse_input(input_str): groups = input_str.split('\n\n') groups = map(str.split, groups) return [list(map(set, g)) for g in groups] def count_uniques(answer_sets): unique_answers = set.union(*answer_sets) return len(unique_answers) def count_same(answer_sets): same_answers = set.intersection(*answer_sets) return len(same_answers) @aoc_timer(1, 6, 2020) def solve_first(groups): return sum(map(count_uniques, groups)) @aoc_timer(2, 6, 2020) def solve_second(groups): return sum(map(count_same, groups)) if __name__ == '__main__': answers = parse_input(get_input(6, year=2020)) solve_first(answers) solve_second(answers)
def parse_input(input_str): return list(map(int, input_str.splitlines())) def fuel(mass): return mass // 3 - 2 def rocket_fuel(to_lift): total = delta = fuel(to_lift) while delta := fuel(delta) > 0: total += delta return total @aoc_timer(1, 1, 2019) def solve_first(masses): return sum(map(fuel, masses)) @aoc_timer(2, 1, 2019) def solve_second(masses): return sum(map(rocket_fuel, masses)) if __name__ == '__main__': masses = parse_input(get_input(1, year=2019)) solve_first(masses) solve_second(masses)
from operator import sub from adventofcode.inputs import get_input from adventofcode.utils import aoc_timer def parse_input(input_str): jolts = list(map(int, input_str.splitlines())) jolts.extend([0, max(jolts) + 3]) return sorted(jolts) @aoc_timer(1, 10, 2020) def solve_first(jolts): counter = Counter(starmap(sub, zip(jolts[1:], jolts))) return counter[1] * counter[3] @aoc_timer(2, 10, 2020) def solve_second(jolts): cache = defaultdict(int, {0: 1}) for j in jolts[1:]: cache[j] = sum(cache[i] for i in range(j - 3, j)) return cache[jolts[-1]] if __name__ == '__main__': jolts_lst = parse_input(get_input(10, year=2020)) solve_first(jolts_lst) solve_second(jolts_lst)
addr_template += "1" else: addr_template += "{}" floating_length = mask.count('X') for f in range(2**floating_length): addr = addr_template.format(*bitstring(f, floating_length)) addr = int(addr, 2) mem[addr] = int(val) return sum(mem.values()) def bitstring(x, l): return bin(x)[2:].zfill(l) def parse(line): arg, val = line.split(' = ') if arg == 'mask': return arg, val else: return int(arg[4:-1]), val def parse_input(input_str): return list(map(parse, input_str.splitlines())) if __name__ == '__main__': code = parse_input(get_input(14, year=2020)) solve_first(code) solve_second(code)
elif instr == FORWARD: x, y = move(x, y, arg, facing) else: x, y = move(x, y, arg, instr) return abs(x) + abs(y) @aoc_timer(2, 12, 2020) def solve_second(nav_list): sx, sy = 0, 0 wx, wy = 10, 1 for instr, arg in nav_list: if (instr, arg) in {(LEFT, 90), (RIGHT, 270)}: wx, wy = -wy, wx elif (instr, arg) in {(LEFT, 180), (RIGHT, 180)}: wx, wy = -wx, -wy elif (instr, arg) in {(LEFT, 270), (RIGHT, 90)}: wx, wy = wy, -wx elif instr == FORWARD: sx += wx * arg sy += wy * arg else: wx, wy = move(wx, wy, arg, instr) return abs(sx) + abs(sy) if __name__ == '__main__': nav_list = parse_input(get_input(12, year=2020)) solve_first(nav_list) solve_second(nav_list)
def evaluate(tokens, inner_eval, brackets_regex=re.compile(r'(\([^()]+\))')): inside_brackets = brackets_regex.search(tokens) if not inside_brackets: return inner_eval(tokens) inside_brackets = inside_brackets.group(1) brackets_result = inner_eval(inside_brackets.strip('()')) new_tokens = tokens.replace(inside_brackets, str(brackets_result)) return evaluate(new_tokens, inner_eval) @aoc_timer(1, 18, 2020) def solve_first(lines): return sum(evaluate(line, equal_precedence) for line in lines) @aoc_timer(2, 18, 2020) def solve_second(lines): return sum(evaluate(line, add_before) for line in lines) def parse_input(input_str): return input_str.splitlines() if __name__ == '__main__': lines = parse_input(get_input(18, year=2020)) solve_first(lines) solve_second(lines)
from itertools import combinations, dropwhile from adventofcode.inputs import get_input from adventofcode.utils import aoc_timer def parse_input(input_str): return list(map(int, input_str.split())) def solve(expenses, n): constraint = lambda x: sum(x) != 2020 accepted_values = next(dropwhile(constraint, combinations(expenses, n))) return math.prod(accepted_values) @aoc_timer(1, 1, 2020) def solve_first(expenses): return solve(expenses, 2) @aoc_timer(2, 1, 2020) def solve_second(expenses): return solve(expenses, 3) if __name__ == '__main__': expenses = parse_input(get_input(1, year=2020)) solve_first(expenses) solve_second(expenses)
# [0] is fuel amount, but puzzle input is always 1 reactants = reactions["FUEL"][1] total_ore = 0 for chem, n_current in reactants.items(): total_ore += sum(ore_needed(reactions, chem, n_fuel * n_current)) return total_ore @aoc_timer(1, 14, 2019) def solve_first(reactor_equations): return get_fuel(reactor_equations, 1) @aoc_timer(2, 14, 2019) def solve_second(reactor_equations): trillion = 1000000000000 high, low = trillion, 0 while high - low > 1: fuel = (high + low) // 2 if get_fuel(reactor_equations, fuel) > trillion: high = fuel else: low = fuel return low if __name__ == "__main__": reactor_equations = parse_input(get_input(14, year=2019)) solve_first(reactor_equations) solve_second(reactor_equations)
for color, constraints in rules.items(): if color in in_the_bag: continue if target in constraints: in_the_bag.add(color) search(color, rules) return len(in_the_bag) @aoc_timer(1, 7, 2020) def solve_first(rules_dct): return search('shiny gold', rules_dct) @aoc_timer(2, 7, 2020) def solve_second(rules_dct): final_count = 0 bags_to_check = ['shiny gold'] while bags_to_check: to_check = bags_to_check.pop() for color, count in rules_dct[to_check].items(): final_count += count bags_to_check.extend([color] * count) return final_count if __name__ == '__main__': rules = parse_input(get_input(7, year=2020)) solve_first(rules) solve_second(rules)