Beispiel #1
0
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
Beispiel #2
0
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())
Beispiel #3
0
 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]
Beispiel #4
0
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
Beispiel #5
0
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())
Beispiel #6
0
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
Beispiel #7
0
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