예제 #1
0
def main(file):
    print("RUNNING", file)
    sections = list(aocutils.readsections(file))
    fields = []
    for line in sections[0]:
        name, a, b, c, d = aocutils.multisplit(line, [": ", "-", " or ", "-"])

        fields.append([
            name,
            (int(a), int(b)),
            (int(c), int(d)),
        ])
    invalid = []
    for line in sections[2][1:]:
        values = [int(x) for x in line.split(",")]
        for v in values:
            valid = False
            for _, (a, b), (c, d) in fields:
                if a <= v <= b or c <= v <= d:
                    valid = True
                    break

            if not valid:
                invalid.append(v)
    print(invalid)
    print(sum(invalid))
예제 #2
0
def main(file):
    print("RUNNING", file)
    on_actions = defaultdict(int)
    off_actions = defaultdict(int)
    total = 0
    for line in aocutils.readlines(file):
        parts = aocutils.multisplit(line,
                                    [' x=', '..', ',y=', '..', ',z=', '..'])
        action_type = parts[0]
        x0, x1, y0, y1, z0, z1 = [int(a) for a in parts[1:]]
        assert x0 <= x1
        assert y0 <= y1
        assert z0 <= z1
        cuboid = Cuboid(x0, x1, y0, y1, z0, z1)
        # Turn off all cubes inside the cuboid by doing
        # the inverse of all actions so far, but only in the
        # intersection with the cuboid
        prev_actions = []
        for k, v in on_actions.items():
            for _ in range(v):
                prev_actions.append(('on', k))
        for k, v in off_actions.items():
            for _ in range(v):
                prev_actions.append(('off', k))
        for prev_action_type, c in prev_actions:
            if prev_action_type == 'on':
                if overlap_cuboid := overlap(c, cuboid):
                    if not try_remove_cuboid(on_actions, overlap_cuboid):
                        off_actions[overlap_cuboid] += 1
                    total -= size(overlap_cuboid)
            elif prev_action_type == 'off':
                if overlap_cuboid := overlap(c, cuboid):
                    if not try_remove_cuboid(off_actions, overlap_cuboid):
                        on_actions[overlap_cuboid] += 1
                    total += size(overlap_cuboid)
예제 #3
0
파일: jigsaw.py 프로젝트: martenbr/aoc
def main(file):
    print("RUNNING", file)
    sections = list(aocutils.readsections(file))
    tile_by_pattern = defaultdict(list)
    for section in sections:
        tile_id = int(aocutils.multisplit(section[0], [" ", ":"])[1])
        top = section[1]
        bot = section[-1]
        left = []
        right = []
        for line in section[1:]:
            left.append(line[0])
            right.append(line[-1])
        top = min(pattern_id(top), pattern_id(reversed(top)))
        bot = min(pattern_id(bot), pattern_id(reversed(bot)))
        left = min(pattern_id(left), pattern_id(reversed(left)))
        right = min(pattern_id(right), pattern_id(reversed(right)))
        tile_by_pattern[top].append(tile_id)
        tile_by_pattern[bot].append(tile_id)
        tile_by_pattern[left].append(tile_id)
        tile_by_pattern[right].append(tile_id)

    counts = defaultdict(int)
    tile_ids_for_unmatched_edges = [
        tiles[0] for tiles in tile_by_pattern.values() if len(tiles) == 1
    ]
    for tile_id in tile_ids_for_unmatched_edges:
        counts[tile_id] = counts[tile_id] + 1
    corners = [tile_id for tile_id, cnt in counts.items() if cnt == 2]
    print(corners)
    print(corners[0] * corners[1] * corners[2] * corners[3])
예제 #4
0
파일: cuboid1.py 프로젝트: martenbr/aoc
def main(file):
    print("RUNNING", file)
    grid = set()
    for line in aocutils.readlines(file):
        parts = aocutils.multisplit(line, [' x=', '..', ',y=', '..', ',z=', '..'])
        action = parts[0]
        x0, x1, y0, y1, z0, z1 = [int(a) for a in parts[1:]]
        assert x0 <= x1
        assert y0 <= y1
        assert z0 <= z1
        x0 = max(x0, -50)
        y0 = max(y0, -50)
        z0 = max(z0, -50)
        x1 = min(x1, 50)
        y1 = min(y1, 50)
        z1 = min(z1, 50)

        for x in range(x0, x1 + 1):
            for y in range(y0, y1 + 1):
                for z in range(z0, z1 + 1):
                    if action == 'on':
                        grid.add((x, y, z))
                    else:
                        grid.discard((x, y, z))
    print(len(grid))
예제 #5
0
def main(file):
    print("RUNNING", file)
    actions = []
    total = 0
    for line in aocutils.readlines(file):
        parts = aocutils.multisplit(line,
                                    [' x=', '..', ',y=', '..', ',z=', '..'])
        action_type = parts[0]
        x0, x1, y0, y1, z0, z1 = [int(a) for a in parts[1:]]
        assert x0 <= x1
        assert y0 <= y1
        assert z0 <= z1
        cuboid = Cuboid(x0, x1, y0, y1, z0, z1)
        # Turn off all cubes inside the cuboid by doing
        # the inverse of all actions so far, but only in the
        # intersection with the cuboid
        new_actions = []
        for prev_action_type, c in actions:
            if prev_action_type == 'on':
                if overlap_cuboid := overlap(c, cuboid):
                    new_actions.append(('off', overlap_cuboid))
                    total -= size(overlap_cuboid)
            elif prev_action_type == 'off':
                if overlap_cuboid := overlap(c, cuboid):
                    new_actions.append(('on', overlap_cuboid))
                    total += size(overlap_cuboid)
예제 #6
0
파일: docking2.py 프로젝트: martenbr/aoc
def main(file):
    print("RUNNING", file)
    memory = {}
    masks = []
    for line in aocutils.readlines(file):
        if line.startswith("mask"):
            pattern = line.split(" = ")[1]
            masks = [Mask()]
            for c in pattern:
                if c == "X":
                    new_masks = []
                    for mask in masks:
                        new_masks.append(mask.both())
                    masks.extend(new_masks)
                elif c == "1":
                    for mask in masks:
                        mask.push_force1()
                elif c == "0":
                    for mask in masks:
                        mask.push_unchanged()
                else:
                    assert False
        else:
            parts = aocutils.multisplit(line, ["[", "]", " = "])
            address = int(parts[1])
            value = int(parts[-1])
            for mask in masks:
                a = mask.apply(address)
                memory[a] = value
    print(sum(memory.values()))
예제 #7
0
파일: docking.py 프로젝트: martenbr/aoc
def main(file):
    print("RUNNING", file)
    # 10X
    # (0b111 & 0b101) | 0b100 = 0x101
    # (0b000 & 0b101) | 0b100 = 0x100
    memory = {}
    and_mask = 0
    or_mask = 0
    for line in aocutils.readlines(file):

        if line.startswith("mask"):
            pattern = line.split(" = ")[1]
            and_mask = 0
            or_mask = 0
            for c in pattern:
                and_mask = and_mask << 1
                or_mask = or_mask << 1
                if c == "X":
                    and_mask |= 1
                elif c == "1":
                    and_mask |= 1
                    or_mask |= 1
                elif c == "0":
                    pass
                else:
                    assert False
        else:
            parts = aocutils.multisplit(line, ["[", "]", " = "])
            address = int(parts[1])
            value = int(parts[-1])
            write_value = (value & and_mask) | or_mask
            memory[address] = write_value
    print(sum(memory.values()))
예제 #8
0
def main(file):
    print("RUNNING", file)
    sections = list(aocutils.readsections(file))
    fields = []
    for line in sections[0]:
        field_name, a, b, c, d = aocutils.multisplit(line, [": ", "-", " or ", "-"])

        fields.append((
            field_name,
            (int(a), int(b)),
            (int(c), int(d)),
        ))
    valid_tickets = []
    for line in sections[2][1:]:
        values = [int(x) for x in line.split(",")]
        ticket_valid = True
        for v in values:
            if not any(is_valid(f, v) for f in fields):
                ticket_valid = False
                break

        if ticket_valid:
            valid_tickets.append(values)

    possible_fields = []

    for v in valid_tickets[0]:
        possible_fields.append({f[0] for f in fields if is_valid(f, v)})

    for i in range(len(possible_fields)):
        p = possible_fields[i]
        for t in valid_tickets[1:]:
            v = t[i]
            valids = {f[0] for f in fields if is_valid(f, v)}
            p.intersection_update(valids)
    print(possible_fields)

    while True:
        solved = []
        not_solved = []
        for p in possible_fields:
            if len(p) == 1:
                solved.append(list(p)[0])
            else:
                not_solved.append(p)
        if not not_solved:
            break
        for p in not_solved:
            p.difference_update(solved)
    print(possible_fields)

    own_values = [int(x) for x in sections[1][1].split(",")]
    result = 1
    for i in range(len(possible_fields)):
        field_name = list(possible_fields[i])[0]
        if field_name.startswith("departure "):
            result *= own_values[i]

    print(result)
예제 #9
0
파일: jigsaw2.py 프로젝트: martenbr/aoc
def build_tiles_and_find_corners(file):
    sections = list(aocutils.readsections(file))
    tiles_by_id = {}
    tile_by_pattern = defaultdict(list)
    for section in sections:
        tile_id = int(aocutils.multisplit(section[0], [" ", ":"])[1])

        top = section[1]
        bot = section[-1]
        left = []
        right = []
        for line in section[1:]:
            left.append(line[0])
            right.append(line[-1])
        inner = []
        for line in section[2:-1]:
            inner.append(line[1:-1])
        assert len(inner) == len(inner[0])
        # Edges are represents by an int with a bit pattern describing the shape
        # Since the reverse pattern is the same we use the smaller of the two possible representation (when seen as an int)
        #   min(pattern_id("##..#"), pattern_id(reversed("##..#")))
        # = min(pattern_id("##..#"), pattern_id(         "#..##"))
        # = min(         0b_11001,                     0b_10011)
        # = min(25,  19)
        # = 19
        top = min(pattern_id(top), pattern_id(reversed(top)))
        bot = min(pattern_id(bot), pattern_id(reversed(bot)))
        left = min(pattern_id(left), pattern_id(reversed(left)))
        right = min(pattern_id(right), pattern_id(reversed(right)))
        tile = Tile(tile_id, top, bot, left, right, inner)
        tiles_by_id[tile_id] = tile
        tile_by_pattern[top].append(tile)
        tile_by_pattern[bot].append(tile)
        tile_by_pattern[left].append(tile)
        tile_by_pattern[right].append(tile)
    counts = defaultdict(int)
    for tile_id in [tiles[0].tile_id for tiles in tile_by_pattern.values() if len(tiles) == 1]:
        counts[tile_id] = counts[tile_id] + 1
    corners = [tiles_by_id[tile_id] for tile_id, cnt in counts.items() if cnt == 2]
    assert len(corners) == 4
    for pattern, tiles in tile_by_pattern.items():
        if len(tiles) == 2:
            tiles[0].neighbors.append((pattern, tiles[1]))
            tiles[1].neighbors.append((pattern, tiles[0]))
    return corners
예제 #10
0
파일: trick2.py 프로젝트: martenbr/aoc
def main(file):
    print("RUNNING", file)
    line = list(aocutils.readlines(file))[0]
    _, tx0, tx1, ty0, ty1 = aocutils.multisplit(
        line, ['target area: x=', '..', ', y=', '..'])
    tx0 = int(tx0)
    tx1 = int(tx1)
    ty0 = int(ty0)
    ty1 = int(ty1)
    maxy = None
    for y in range(1, 1000):
        if simulate(0, y, tx0, tx1, ty0, ty1, ignore_x=True):
            maxy = y

    success = set()
    while maxy > -1000:
        for x in range(1, tx1 + 1):
            if simulate(x, maxy, tx0, tx1, ty0, ty1):
                success.add((x, maxy))
        maxy -= 1
    print(len(success))
예제 #11
0
파일: allergen.py 프로젝트: martenbr/aoc
def main(file):
    print("RUNNING", file)
    possible_allergen = defaultdict(set)
    recipies = []
    ingredients_by_allergen = dict()
    for line in aocutils.readlines(file):
        parts = aocutils.multisplit(line, [" (contains ", ")"])
        ingredients = parts[0].split(" ")
        recipies.append(ingredients)
        allergen = parts[1].split(", ")
        for allergen in allergen:
            if allergen not in ingredients_by_allergen:
                ingredients_by_allergen[allergen] = set(ingredients)
            else:
                ingredients_by_allergen[allergen].intersection_update(ingredients)
        for i in ingredients:
            possible_allergen[i].add(i)

    ingredients_with_known_allergen = set()
    for _ in range(10):  # arbitrary limit which was enough
        for ingredient_set in ingredients_by_allergen.values():
            if len(ingredient_set) == 1:
                ingredients_with_known_allergen.update(ingredient_set)
            else:
                ingredient_set.difference_update(ingredients_with_known_allergen)

    safe = 0
    for recipe in recipies:
        for i in recipe:
            if i not in ingredients_with_known_allergen:
                safe += 1
    print("part1", safe)

    d = []
    for allergen, ingredient_set in ingredients_by_allergen.items():
        assert len(ingredient_set) == 1
        i = list(ingredient_set)[0]
        d.append((i, allergen))
    d.sort(key=lambda x: x[1])
    print("part2", ",".join(x[0] for x in d))
예제 #12
0
def main(file):
    print("RUNNING", file)
    counts = defaultdict(int)
    for line in aocutils.readlines(file):
        x0, y0, x1, y1 = [int(i) for i in aocutils.multisplit(line, [',', ' -> ', ','])]

        if x0 == x1:
            for i in range(min(y0, y1), max(y0, y1) + 1):
                counts[(x0, i)] += 1
        elif y0 == y1:
            for i in range(min(x0, x1), max(x0, x1) + 1):
                counts[(i, y0)] += 1
        else:
            xdir = -1 if x0 > x1 else 1
            ydir = -1 if y0 > y1 else 1
            for i in range(0, max(x0, x1) - min(x0, x1) + 1):
                counts[(x0 + (i * xdir), y0 + (i * ydir))] += 1

    n = 0
    for x in counts.values():
        if x >= 2:
            n += 1
    print(n)
예제 #13
0
def main(file):
    print("RUNNING", file)
    line = list(aocutils.readlines(file))[0]
    _, tx0, tx1, ty0, ty1 = aocutils.multisplit(
        line, ['target area: x=', '..', ', y=', '..'])
    tx0 = int(tx0)
    tx1 = int(tx1)
    ty0 = int(ty0)
    ty1 = int(ty1)
    maxy = None
    for y in range(1, 1000):
        ok, reached = simulate(0, y, tx0, tx1, ty0, ty1, ignore_x=True)
        if ok:
            maxy = y

    while maxy > 0:
        for x in range(1, tx1 + 1):
            ok, reached = simulate(x, maxy, tx0, tx1, ty0, ty1)
            if ok:
                print(x, maxy)
                print(reached)
                return
        maxy -= 1
예제 #14
0
def main(file):
    print("RUNNING", file)
    counts = defaultdict(int)
    for line in aocutils.readlines(file):
        x0, y0, x1, y1 = [
            int(i) for i in aocutils.multisplit(line, [',', ' -> ', ','])
        ]

        if x0 != x1 and y0 != y1:
            continue
        if x0 == x1:
            for i in range(min(y0, y1), max(y0, y1) + 1):
                counts[(x0, i)] += 1
        elif y0 == y1:
            for i in range(min(x0, x1), max(x0, x1) + 1):
                counts[(i, y0)] += 1
        else:
            assert False

    n = 0
    for x in counts.values():
        if x >= 2:
            n += 1
    print(n)
예제 #15
0
def test_multisplit():
    assert aocutils.multisplit("1-3 b: cdefg",
                               ["-", " ", ": "]) == ["1", "3", "b", "cdefg"]