# 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"))))
#!/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))))
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))))
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()))
#!/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))))
#!/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
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()))
# 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)))
#!/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)))