예제 #1
0
def main(file):
    print("RUNNING", file)
    sections = list(aocutils.readsections(file))
    rules = {}
    for line in sections[0]:
        key, match = line.split(": ")
        key = int(key)

        if '"' in match:
            rules[key] = Literal(match.strip('"'))
        elif "|" in match:
            r1, r2 = match.split(" | ")
            refs1 = [int(r) for r in r1.split(" ")]
            refs2 = [int(r) for r in r2.split(" ")]
            rules[key] = Opt(rules, refs1, refs2)
        else:
            refs = [int(r) for r in match.split(" ")]
            rules[key] = Ref(rules, refs)
    start_rule = rules[0]
    matches = 0
    for line in sections[1]:
        for match_length in start_rule.matches(line, 0):
            if match_length == len(line):
                matches += 1
                break
    print(matches)
예제 #2
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])
예제 #3
0
파일: polymer1.py 프로젝트: martenbr/aoc
def main(file):
    print("RUNNING", file)
    sections = list(aocutils.readsections(file))
    currentp = sections[0][0]
    subs = {}

    for line in sections[1]:
        a, b = line.split(' -> ')
        subs[a] = b

    print(currentp)
    nextp = []
    for step in range(10):
        print(step)
        for i in range(len(currentp) - 1):
            l = currentp[i:i + 2]
            if l in subs:
                nextp.append(l[0])
                nextp.append(subs[l])
            else:
                nextp.append(l[0])
        nextp.append(l[1])
        currentp = ''.join(nextp)
        nextp = []
    counts = defaultdict(int)
    for c in currentp:
        counts[c] += 1
    print(counts)
    values = sorted([(v, k) for k, v in counts.items()])
    print(values)
    print(values[-1][0] - values[0][0])
예제 #4
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))
예제 #5
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)
예제 #6
0
def main(file, rounds):
    print("RUNNING", file)
    sections = list(aocutils.readsections(file))
    algo = ''.join(sections[0])
    image = set()
    image_inverted = False
    minx = 0
    miny = 0
    maxx = 0
    maxy = 0
    for y, line in enumerate(sections[1]):
        for x, char in enumerate(line):
            if char == '#':
                image.add((x, y))
                maxy = max(maxy, y)
                maxx = max(maxx, x)
    invert_mode = False
    if algo[0] == '#':
        assert algo[0b111_111_111] == '.'
        invert_mode = True
    for round in range(rounds):
        new_image = set()
        new_image_inverted = invert_mode and not image_inverted
        outputx = list(range(minx - 1, maxx + 2))
        outputy = list(range(miny - 1, maxy + 2))
        for y in outputy:
            for x in outputx:
                bitstr = []
                for yi in range(y - 1, y + 2):
                    for xi in range(x - 1, x + 2):
                        if (xi, yi) in image:
                            if image_inverted:
                                bitstr.append('0')
                            else:
                                bitstr.append('1')
                        else:
                            if image_inverted:
                                bitstr.append('1')
                            else:
                                bitstr.append('0')
                val = int(''.join(bitstr), 2)

                if new_image_inverted:
                    is_filled = algo[val] == '.'
                else:
                    is_filled = algo[val] == '#'
                if is_filled:
                    new_image.add((x, y))
                    minx = min(minx, x)
                    miny = min(miny, y)

                    maxx = max(maxx, x)
                    maxy = max(maxy, y)
        image = new_image
        image_inverted = new_image_inverted

    print(len(image))
예제 #7
0
def main(file):
    print("RUNNING", file)
    sections = list(aocutils.readsections(file))
    deck1 = deque(int(x) for x in sections[0][1:])
    deck2 = deque(int(x) for x in sections[1][1:])
    _, winning_deck = recursive_combat(deck1, deck2)
    winning_deck = list(winning_deck)

    print(winning_deck)
    print(sum([x * (i + 1) for i, x in enumerate(reversed(winning_deck))]))
예제 #8
0
파일: bingo1.py 프로젝트: martenbr/aoc
def main(file):
    print("RUNNING", file)
    sections = list(aocutils.readsections(file))
    numbers = [int(x) for x in sections[0][0].split(',')]
    boards = []

    for b in sections[1:]:
        rows = []
        for row in b:
            rows.append([int(x) for x in row.split(' ') if x])

        boards.append(rows)

    play_bingo(boards, numbers)
예제 #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
def main(file):
    check_rotations()
    print("RUNNING", file)
    scanners = []
    for sec_lines in aocutils.readsections(file):
        scanner = []
        for line in sec_lines[1:]:
            scanner.append(tuple(int(x) for x in line.split(',')))
        scanners.append(scanner)
    # Scanner ID is their index in 'scanners'

    searched = set()
    offsets = {
        0: (0, 0, 0)
    }
    to_search = [0]
    while to_search:
        progress = (len(searched) + len(offsets)) * 50 / len(scanners)
        print(f'{round(progress)}%')
        if len(offsets) == len(scanners):
            break
        s1_id = to_search.pop()
        assert s1_id not in searched
        searched.add(s1_id)

        s1 = scanners[s1_id]
        s1_set = set(s1)
        for s2_id, s2 in enumerate(scanners):
            if s1_id == s2_id:
                continue
            if s2_id in offsets:
                continue
            for rotate in rotations:
                rotated_s2 = [rotate(x) for x in s2]
                if offset := scanners_overlaps(s1_set, rotated_s2):
                    scanners[s2_id] = rotated_s2
                    offsets[s2_id] = (
                        offsets[s1_id][0] + offset[0],
                        offsets[s1_id][1] + offset[1],
                        offsets[s1_id][2] + offset[2],
                    )
                    to_search.append(s2_id)
                    break
예제 #11
0
def main(file):
    print("RUNNING", file)
    sections = list(aocutils.readsections(file))
    deck1 = deque(int(x) for x in sections[0][1:])
    deck2 = deque(int(x) for x in sections[1][1:])
    while deck1 and deck2:
        c1 = deck1.popleft()
        c2 = deck2.popleft()
        if c1 > c2:
            deck1.append(c1)
            deck1.append(c2)
        elif c1 < c2:
            deck2.append(c2)
            deck2.append(c1)
        else:
            assert False

    winning_deck = list(deck1 or deck2)
    print(winning_deck)
    print(sum([x * (i + 1) for i, x in enumerate(reversed(winning_deck))]))
예제 #12
0
def main(file):
    print("RUNNING", file)
    sections = list(aocutils.readsections(file))
    poly = sections[0][0]
    subs = {}

    for line in sections[1]:
        a, b = line.split(' -> ')
        subs[a] = b

    cache = dict()

    def expand_and_count(pair, num_expands):
        if num_expands == 0:
            result = defaultdict(int)
            result[pair[0]] += 1
            result[pair[1]] += 1
            return result
        elif (pair, num_expands) in cache:
            return cache[(pair, num_expands)]
        else:
            new_char = subs[pair]
            r1 = expand_and_count(pair[0] + new_char, num_expands - 1)
            r2 = expand_and_count(new_char + pair[1], num_expands - 1)
            result = r1.copy()
            for k, v in r2.items():
                result[k] += v
            result[new_char] -= 1
            cache[(pair, num_expands)] = result
            return result

    total_counts = defaultdict(int)
    for i in range(len(poly) - 1):
        for k, v in expand_and_count(poly[i:i + 2], 40).items():
            total_counts[k] += v
    for i in range(1, len(poly) - 1):
        total_counts[poly[i]] -= 1
    values = sorted([(v, k) for k, v in total_counts.items()])
    print(len(cache))
    print(values)
    print(values[-1][0] - values[0][0])
예제 #13
0
def main(file):
    print("RUNNING", file)
    sections = list(aocutils.readsections(file))
    currentp = sections[0][0]
    subs = {}
    subs20 = {}

    for line in sections[1]:
        a, b = line.split(' -> ')
        subs[a] = b

    # Pre calculate result of doing 20 expansion for all pairs
    for a in subs.keys():
        print(a)
        subs20[a] = expand20x(a, subs)

    # Expand x20
    nextp = []
    for i in range(len(currentp)-1):
        pair = currentp[i:i + 2]
        nextp.append(subs20[pair][:-1])

    nextp.append(pair[1])
    currentp = ''.join(nextp)

    # Expand x20 again, but only count characters this time
    counts20 = {}
    total_count = defaultdict(int)
    for i in range(len(currentp) - 1):
        pair = currentp[i:i + 2]
        if pair not in counts20:
            counts20[pair] = count_chars(subs20[pair])

        for k, v in counts20[pair].items():
            total_count[k] += v
    total_count[pair[-1]] += 1

    values = sorted([(v, k) for k, v in total_count.items()])
    print(values)
    print(values[-1][0]-values[0][0])
예제 #14
0
파일: origami2.py 프로젝트: martenbr/aoc
def main(file):
    print("RUNNING", file)
    sections = list(aocutils.readsections(file))
    maxx = 0
    maxy = 0
    for line in sections[0]:
        x, y = [int(a) for a in line.split(',')]
        maxx = max(maxx, x)
        maxy = max(maxy, y)
    grid = []
    for _ in range(maxy + 1):
        grid.append([False for _ in range(maxx + 1)])
    for line in sections[0]:
        x, y = [int(x) for x in line.split(',')]
        grid[y][x] = True

    folds = sections[1]

    for fold in folds:
        instr, v = fold.split('=')
        v = int(v)
        if instr == "fold along x":
            part1 = [r[:v] for r in grid]
            part2 = [r[v + 1:] for r in grid]
            part1 = vflip(part1)
            result = merge(part1, part2)
            result = vflip(result)
            grid = result
        elif instr == "fold along y":
            part1 = grid[:v]
            part2 = grid[v + 1:]
            part1 = hflip(part1)
            result = merge(part1, part2)
            result = hflip(result)
            grid = result

    print_grid(grid)