def solve(input): by_num, by_range = parse_fields(input[0]) your_ticket = get_all_nums(input[1][1]) nearby_tickets = [get_all_nums(r) for r in input[2][1:]] # Part 1 acc = 0 valid_tix = [] for t in nearby_tickets: is_valid = True for n in t: if n not in by_num: is_valid = False acc += n if is_valid: valid_tix.append(t) # Part 2 idx_lists = defaultdict(list) for t in valid_tix: for i, n in enumerate(t): idx_lists[i].append(n) idx_potentials = defaultdict(set) for idx, range in idx_lists.items(): for target_range, field_names in by_range.items(): if in_multi_range(target_range, range): idx_potentials[idx].add(field_names) fields = {} removed_idx = set() while len(idx_potentials) > len(removed_idx): singleton = { k: list(v)[0] for k, v in idx_potentials.items() if len(v) == 1 and k not in removed_idx } for sk, sv in singleton.items(): fields[sk] = sv for k, v in idx_potentials.items(): if sv in v: v.remove(sv) if len(v) == 0: removed_idx.add(k) print(fields) acc2 = 1 for k, v in fields.items(): if v.startswith("departure"): acc2 *= your_ticket[k] return acc, acc2
def solve1(input): mem_slots = defaultdict(int) max_idx = 0 mask_map = {} def apply_mask(bin_str, mask_map): acc = "" for idx, b in enumerate(bin_str[::-1]): if idx in mask_map: acc += mask_map[idx] else: acc += b in_bin = acc[::-1] return int(in_bin, 2) for row in input: if row.startswith("mask"): mask_map, max_idx = get_mask(row) continue target_mem, base_num = get_all_nums(row) bin_str = "{0:b}".format(base_num) if len(bin_str) < max_idx: bin_str = "0" * (max_idx - len(bin_str)) + bin_str mem_slots[target_mem] = apply_mask(bin_str, mask_map) return sum(v for v in mem_slots.values())
def solve1(input): et = int(input[0]) ids = get_all_nums(input[1]) multipliers = defaultdict(int) multipliers = {k: ceil(et / k) * k for k in ids} inv_multipliers = {v: k for k, v in multipliers.items()} m = min(multipliers.values()) return (m - et) * inv_multipliers[m]
def parse_fields(rows): by_num = defaultdict(list) by_range = defaultdict(list) for r in rows: field_name = r.split(":")[0] l1, h1, l2, h2 = get_all_nums(r) by_range[((l1, h1 + 1), (l2, h2 + 1))] = field_name for i in range(l1, h1 + 1): by_num[i].append(field_name) for i in range(l2, h2 + 1): by_num[i].append(field_name) return by_num, by_range
def solve2(input): mem_slots = defaultdict(int) max_idx = 0 mask_map = {} def get_poss_bin_str(fluc_bin_str, acc): if len(fluc_bin_str) == 0: return acc char_to_add = fluc_bin_str[0] if char_to_add in "01": new_acc = [acc_elem + char_to_add for acc_elem in acc] return get_poss_bin_str(fluc_bin_str[1:], new_acc) else: with_ones = [acc_elem + "1" for acc_elem in acc] with_zeroes = [acc_elem + "0" for acc_elem in acc] return get_poss_bin_str(fluc_bin_str[1:], with_ones + with_zeroes) def get_mem_addrs(bin_str, mask_map, max_idx): acc = "" # print(bin_str, mask_map) for idx, b in enumerate(bin_str[::-1]): if idx in mask_map and mask_map[idx] in "1X": acc += mask_map[idx] else: acc += b fluc_bin_str = acc[::-1] # print(fluc_bin_str) return [int(s, 2) for s in get_poss_bin_str(fluc_bin_str, [""])] for row in input: if row.startswith("mask"): mask_map, max_idx = get_fluc_mask(row) continue target_mem, base_num = get_all_nums(row) bin_str = "{0:b}".format(target_mem) if len(bin_str) < max_idx: bin_str = "0" * (max_idx - len(bin_str)) + bin_str mem_addrs = get_mem_addrs(bin_str, mask_map, max_idx) for m in mem_addrs: mem_slots[m] = base_num return sum(v for v in mem_slots.values())
def solve(input): mapping = defaultdict(list) inv_mapping = defaultdict(list) inv_mapping_count = defaultdict(dict) base_bags = set() for row in input.split("\n"): if row == "": break left, right = row.split(" contain ") left_color = " ".join(left.split(" ")[:2]) inner_bags = [] for inner_bag in right.split(", "): if "no" in inner_bag: mapping[left_color] = [] base_bags.add(left_color) break n = get_all_nums(inner_bag)[0] color = " ".join(inner_bag.split(" ")[-3:-1]).replace(".", "") inner_bags.append((color, n)) inv_mapping[color].append(left_color) mapping[left_color] = inner_bags encountered = set() queue = list() queue.append("shiny gold") while len(queue) > 0: color = queue.pop() encountered.add(color) for new_color in inv_mapping[color]: if new_color not in encountered: queue.append(new_color) count_memo = {b: 1 for b in base_bags} def recurse(bag): if bag in count_memo: return count_memo[bag] s = 1 for inner_bag, num_bags in mapping[bag]: s += num_bags * recurse(inner_bag) count_memo[bag] = s return s return len(encountered) - 1, recurse("shiny gold") - 1
def solve(input): tiles = {} for tile in input: id, grid_list = int(get_all_nums(tile[0])[0]), tile[1:] new_tile = Tile(id, grid_list) tiles[id] = new_tile by_pattern, by_id = get_matches(tiles) corners = get_corners(by_id) puzzle = build_puzzle(tiles, corners, by_pattern) combined_puzzle = combine_puzzle(puzzle) exhausted_options = False while not exhausted_options: exhausted_options = combined_puzzle.iter_orientation() num_dragons, num_pounds = get_num_dragons(combined_puzzle.grid) if num_dragons > 0: a2 = num_pounds break return reduce(lambda x, y: x * y, corners, 1), a2
import os, sys sys.path.append(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))) from util.helpers import list_of_ints, get_all_nums, grid_to_map assert list_of_ints(["1", "2", "34", "5"]) == [1, 2, 34, 5] assert get_all_nums("12fdsa23-%-45") == [12, 23, 45] test_grid = ["1234", "5678", "9012", "3456"] zero_indexed_map = grid_to_map(test_grid) assert len(zero_indexed_map) == 16 assert (0, 0) in zero_indexed_map assert (4, 4) not in zero_indexed_map one_indexed_map = grid_to_map(test_grid, index_by_one=True) assert len(one_indexed_map) == 16 assert (0, 0) not in one_indexed_map assert (4, 4) in one_indexed_map test_grid_unsplit = """ 1234 5678 9012 3456 """.strip() non_split_map = grid_to_map(test_grid_unsplit, split_input=True) assert len(non_split_map) == 16 assert (3, 3) in non_split_map