Esempio n. 1
0
        # Most complicated part: rotate 'result' backwards and try forward
        # rotation with given letter until we find the matching arrangement.
        match = re.match(r"rotate based on position of letter (\w+)", line)
        if match:
            shift_index = 0
            while True:
                cur = in_deque.copy()
                cur.rotate(-shift_index)
                back_shifted = cur.copy()
                rotate(cur, match.group(1))
                if cur == in_deque:
                    in_deque = back_shifted
                    break
                shift_index += 1
            continue
        # Entirely reversible
        match = re.match(r"reverse positions (\d+) through (\d+)", line)
        if match:
            in_deque = reverse_range(in_deque, int(match.group(1)),
                                               int(match.group(2)))
            continue
        # Swap from/to indices
        match = re.match(r"move position (\d+) to position (\d+)", line)
        if match:
            move_item(in_deque, int(match.group(2)), int(match.group(1)))

    return "".join(in_deque)

print("A: " + str(part_one(lib.get_input(21), collections.deque("abcdefgh"))))
print("B: " + str(part_two(lib.get_input(21), collections.deque("fbgdceah"))))
Esempio n. 2
0
#!/usr/bin/env python3

import re
import lib.common as lib


def calc_checksum(state, disk_len):
    while len(state) < disk_len:
        b = "".join('1' if x == '0' else '0' for x in reversed(state))
        state = "{}0{}".format(state, b)

    checksum = state[:disk_len]
    while len(checksum) % 2 != 1:
        match = re.findall(r"(.)(.)", checksum)
        checksum = "".join('1' if m[0] == m[1] else '0' for m in match)

    return checksum


def part_one(line_gen):
    return calc_checksum(next(line_gen), 272)


def part_two(line_gen):
    return calc_checksum(next(line_gen), 35651584)


print("A: " + str(part_one(lib.get_input(16))))
print("B: " + str(part_two(lib.get_input(16))))
Esempio n. 3
0
                cur_dir_idx = idx
                break

        elif cur_elem.isalpha():
            letters += cur_elem

        nxt = get_next(cur, cur_dir_idx, prev, grid)
        if not nxt:
            if second_part:
                return steps
            else:
                return ''.join(letters)
        prev = cur
        cur = nxt


def read_grid(line_gen):
    return [list(line.rstrip('\n')) for line in line_gen]


def part_one(line_gen):
    return walk(read_grid(line_gen))


def part_two(line_gen):
    return walk(read_grid(line_gen), True)


print("A: " + str(part_one(lib.get_input(19, strip=False))))
print("B: " + str(part_two(lib.get_input(19, strip=False))))
Esempio n. 4
0
    return nodes[name].stack_weight

def part_two():
    # Part one must have already built the graph
    cur_node = root
    sibling_weights = root.weight
    while True:
        succs = [(calc_stack_weight(x), x) for x in cur_node.succs]
        # If all sub-weights are equal, the current node is the culprit and must
        # be adjusted. As its stack weight must match its siblings, we need to
        # calculate the difference between the siblings' stack weights and the
        # sum of all sucessors' weights as the target weight.
        if len(set([x[0] for x in succs])) == 1:
            return sibling_weights - sum(x[0] for x in succs)

        # Dirty hack to find the odd weight and the matching sibling weights
        temp = sorted(succs)
        odd_weight, next_node = temp[0]
        sibling_weights = temp[1][0]
        # If first and second element are equal, they are the sibling weights.
        # In this case, the odd one must be the last weight (it was bigger than
        # the others) and the first one can be used as the sibling weight
        if odd_weight == temp[1][0]:
            odd_weight, next_node = temp[-1]
            sibling_weights = temp[0][0]

        cur_node = nodes[next_node]

print("A: " + str(part_one(lib.get_input(7))))
print("B: " + str(part_two()))
Esempio n. 5
0
#!/usr/bin/env python3

import lib.common as lib


def part_one(line_gen):
    # line = next(line_gen) # one line input
    # for line in line_gen: # multi line input
    pass


def part_two(line_gen):
    # line = next(line_gen) # one line input
    # for line in line_gen: # multi line input
    pass


print("A: " + str(part_one(lib.get_input(CURRENT_DAY))))
print("B: " + str(part_two(lib.get_input(CURRENT_DAY))))
Esempio n. 6
0
#!/usr/bin/env python3

import re
import lib.common as lib

for line in lib.get_input(1):
    instrs = re.split(", ", line)
    # X, Y -> positive means up/north and right/east
    loc = [0, 0]
    directions = ['north', 'east', 'south', 'west']
    current_direction_idx = 0

    # Location tracking for part B
    visited = set()
    visited.add((0, 0))
    first_twice = None

    # Go the path
    for instr in instrs:
        match = re.match("([LR])([0-9]+)", instr)
        turn_dir = match.group(1)
        steps = int(match.group(2))
        if turn_dir == 'L':
            current_direction_idx = (current_direction_idx -
                                     1) % len(directions)
        else:
            current_direction_idx = (current_direction_idx +
                                     1) % len(directions)

        for _ in range(0, steps):
            # north
Esempio n. 7
0
                for x in range(0, rect_x):
                    field[y][x] = "#"
            continue
        # Buffer old field for rotations
        field_old = [x[:] for x in field]
        # Check for rotations
        match = re.match(r"rotate (row y|column x)=(\d+) by (\d+)", line)
        if match:
            shift = int(match.group(3))
            if match.group(1) == "column x":
                col = int(match.group(2))
                for y in range(0, size_y):
                    new_y = (y + shift) % size_y
                    field[new_y][col] = field_old[y][col]
            else:
                row = int(match.group(2))
                for x in range(0, size_x):
                    new_x = (x + shift) % size_x
                    field[row][new_x] = field_old[row][x]

    return collections.Counter(entry for row in field for entry in row)["#"]


def part_two():
    print_field()
    return "See image above in a wide enough terminal"


print("A: " + str(part_one(lib.get_input(8), 50, 6)))
print("B: " + str(part_two()))
Esempio n. 8
0
        # Merge overlapping and adjacent, only keep merged pair
        # overlapping:  end_a >= start_b
        # adjacent: end_a + 1 == start_b
        if end_a + 1 >= start_b:
            merged_range = (start_a, max(end_a, end_b))
            merged_ranges.pop()
            merged_ranges.append(merged_range)
        # No merge possible, add this pair
        else:
            merged_ranges.append(ranges[cur_ind])

    return merged_ranges

def part_one(line_gen):
    merged_ranges = merge_ranges(line_gen)
    return merged_ranges[0][1] + 1

def part_two(line_gen, max_ip):
    merged_ranges = merge_ranges(line_gen)
    # Add fake range which blocks ports > max_ip
    merged_ranges.append((max_ip + 1, None))

    allowed = 0
    for cur_ind in range(len(merged_ranges) - 1):
        allowed += merged_ranges[cur_ind + 1][0] - merged_ranges[cur_ind][1] - 1

    return allowed

print("A: " + str(part_one(lib.get_input(20))))
print("B: " + str(part_two(lib.get_input(20), 4294967295)))
Esempio n. 9
0
#!/usr/bin/env python3

import lib.common as lib

def read_program(line_gen):
    return [int(x) for x in line_gen]

def simulate(line_gen, part_two=False):
    program = read_program(line_gen)
    pc = 0
    count = 0
    while pc < len(program):
        count += 1
        old_pc = pc
        pc += program[pc]
        if part_two and program[old_pc] >= 3:
            program[old_pc] -= 1
        else:
            program[old_pc] += 1

    return count

print("A: " + str(simulate(lib.get_input(5))))
print("B: " + str(simulate(lib.get_input(5), True)))