x), max(xmax, x), min(ymin, y), max(ymax, y) to_flip = set() for x in range(xmin - 1, xmax + 2): for y in range(ymin - 1, ymax + 2): nbr_count = 0 for dx, dy in DIRECTION_VECTORS.values(): if (x + dx, y + dy) in flipped_tiles: nbr_count += 1 if (x, y) in flipped_tiles: if nbr_count == 0 or nbr_count > 2: to_flip.add((x, y)) elif nbr_count == 2: to_flip.add((x, y)) for tile in to_flip: flip_tile(flipped_tiles, tile) return flipped_tiles initial_flipped_tiles = initialise_floor(load_input_list("day24.txt")) print(f"Part 1 => {len(initial_flipped_tiles)}") final_flipped_tiles = evolve_floor(initial_flipped_tiles, 100) print(f"Part 2 => {len(final_flipped_tiles)}")
def count_trees(tree_map, slope): trees = 0 rows = len(tree_map) cols = len(tree_map[0]) x, y = 0, 0 dx, dy = slope while y < rows: if tree_map[y][x] == '#': trees += 1 x = (x + dx) % cols y += dy return trees input_data = load_input_list("day3.txt") def prod_slopes(tree_map, slopes_list): return reduce(mul, (count_trees(tree_map, slope) for slope in slopes_list)) slopes = [[(3, 1)], [(1, 1), (3, 1), (5, 1), (7, 1), (1, 2)]] for i, s in enumerate(slopes): print(f"Part {i + 1} => {prod_slopes(input_data, s)}")
raise ValueError(f"{operand} and {modulus} are not coprime") return inv % modulus # Chinese Remainder Theorem # Any sequence of pairs (c, m) where 0 <= c < m and all m are pairwise coprime defines a set of # simultaneous linear congruences with exactly one solution x satisfying 0 <= x < product(m). def chinese_remainder(congruence_list): prod_m = reduce(mul, (m for c, m in congruence_list)) solution = 0 for c, m in congruence_list: p = prod_m // m solution = (solution + (m - c) * p * mod_inverse(p, m)) % prod_m return solution earliest_dep, bus_schedule = load_input_list("day13.txt") bus_array = { i: int(bus) for i, bus in enumerate(bus_schedule.split(',')) if bus != 'x' } print( f"Part 1 => {reduce(mul, find_first_bus(int(earliest_dep), bus_array.values()))}" ) print(f"Part 2 => {chinese_remainder(bus_array.items())}")
return False def iterate_grid(initial_grid, dimensions, iterations): active_points = set() for y, row in enumerate(initial_grid): for x, cube in enumerate(row): if cube == '#': active_points.add(tuple([x, y] + [0] * (dimensions - 2))) for _ in range(iterations): new_active_points = set() for point in product(*get_new_active_range(active_points, dimensions)): if new_state_is_active(active_points, point): new_active_points.add(point) active_points = new_active_points return len(active_points) starting_grid = [list(row) for row in load_input_list("day17.txt")] print(f"Part 1 => {iterate_grid(starting_grid, 3, 6)}") print(f"Part 1 => {iterate_grid(starting_grid, 4, 6)}")
writemem_pattern = re.compile(r"^mem\[([0-9]+)\] = ([0-9]+)$") bitmask = None mem_map = {} for line in program: match = bitmask_pattern.match(line) if match: bitmask = (BitmaskV2 if chip_ver2 else BitmaskV1)(match.group(1)) continue match = writemem_pattern.match(line) if not match: raise ValueError(f"Invalid instruction: {line}") if chip_ver2: value = int(match.group(2)) for addr in bitmask.apply(int(match.group(1))): mem_map[addr] = value else: mem_map[int(match.group(1))] = bitmask.apply(int(match.group(2))) return sum(mem_map.values()) docking_program = load_input_list("day14.txt") print(f"part 1 => {run_docking_program(docking_program)}") print(f"part 2 => {run_docking_program(docking_program, 2)}")
for instr in instructions: match = pattern.match(instr) if not match: raise ValueError(f"Invalid instruction \"{instr}\"") move = match.group(1) size = int(match.group(2)) if move in (LEFT, RIGHT): heading = rotate_point(heading, move, size) elif move == FORWARD: position = move_point(position, heading, size) elif use_waypoint: heading = move_point(heading, DIRECTION_VECTOR[move], size) else: position = move_point(position, DIRECTION_VECTOR[move], size) return position def manhattan_dist(point): x, y = point return abs(x) + abs(y) navigation_instr = load_input_list("day12.txt") print(f"Part 1 => {manhattan_dist(navigate(navigation_instr))}") print(f"Part 2 => {manhattan_dist(navigate(navigation_instr, True))}")
upper = 2 ** len(bsp_code) - 1 for c in bsp_code: mid = (lower + upper) // 2 if c == high_char: lower = mid + 1 elif c == low_char: upper = mid else: raise ValueError(f"Invalid character '{c}'") return lower def seat_id(bp_code): row = resolve_bsp(bp_code[:7], 'F', 'B') col = resolve_bsp(bp_code[7:], 'L', 'R') return (8 * row) + col taken_seats = sorted(seat_id(s) for s in load_input_list("day5.txt").split('\n')) print(f"Part 1 => {taken_seats[-1]}") prev = taken_seats[0] for s in taken_seats[1:]: if s - prev == 2: print(f"Part 2 => {s - 1}") break prev = s
def safe_ingredients(allergen_map, ingredient_counts): return set(ingredient_counts.keys()).difference( set.union(*allergen_map.values())) def resolve_allergens(allergen_map): resolved = {} while len(allergen_map) > 0: for allerg, ingreds in sorted(allergen_map.items(), key=lambda x: len(x[1])): possibilities = list(ingreds.difference(set(resolved.values()))) if len(possibilities) == 1: resolved[allerg] = possibilities[0] allergen_map.pop(allerg) return resolved allergens, ingredients = parse_ingredients(load_input_list("day21.txt")) print( f"Part 1 => {sum(ingredients[i] for i in safe_ingredients(allergens, ingredients))}" ) allergen_ingredient_map = resolve_allergens(allergens) canonical = ','.join( [allergen_ingredient_map[i] for i in sorted(allergen_ingredient_map)]) print(f"Part 2 => {canonical}")
arg = int(instr_match.group(3)) if sgn == '-': arg *= -1 if swap_instr == current_instr: opr = {"acc": "acc", "jmp": "nop", "nop": "jmp"}[opr] action = { "acc": lambda pos, acc, arg: (pos + 1, acc + arg), "jmp": lambda pos, acc, arg: (pos + arg, acc), "nop": lambda pos, acc, arg: (pos + 1, acc) }[opr] current_instr, accumulator = action(current_instr, accumulator, arg) if current_instr == end_instr: terminated = True return (terminated, accumulator) code = load_input_list("day8.txt") print(f"Part 1 => {run_program(code)[1]}") for swap_line in range(len(code)): terms, accum = run_program(code, swap_line) if terms: print(f"Part 2 => {accum}")
if (char == '*') and add_result: operand = add_result add_result = 0 else: if add_has_precedence: add_result += int(char) else: operand = int(char) if operand: if result is None: result = operand else: result = result + operand if operation == '+' else result * operand if add_result: if result is None: result = add_result else: result *= add_result return result input_expressions = load_input_list("day18.txt") print(f"Part 1 => {sum(eval_expression(expr) for expr in input_expressions)}") print( f"Part 2 => {sum(eval_expression(expr, True) for expr in input_expressions)}" )