def initialize(self, change=None): """ The Builder's main method. It stores all the changes that needs to be made in `self.details` for a file. Which would then be used to add Docstrings to. """ result = dict() patches = [] if change: patches = change.get('additions') for line in fileinput.input(self.filename): filename = fileinput.filename() lineno = fileinput.lineno() keywords = self.config.get('keywords') found = len(filter(lambda word: word.lstrip() in keywords, line.split(' '))) > 0 if change and found: found = self._is_line_part_of_patches(lineno, line, patches) if not self.details.get(filename): self.details[filename] = dict() if found: length = get_file_lines(filename) result = self.extract_and_set_information(filename, lineno, line, length) if self.validate(result): self.details[filename][result.name] = result
def get_layout(self, name): """ Returns the layout matching the name. """ layout = None if name in self.layouts: # Load the layout if it hasnt been yet if not self.layouts[name]: self.layouts[name] = utils.get_file_lines(self.layouts_dir + name) layout = self.layouts[name] return layout
def parse_templates(self, path): """ Looks for template syntax on each line and replaces it with the corresponding layout. """ new_lines = [] lines = utils.get_file_lines(path) for line in lines: # check each line for the template syntax template, num_tabs = self.extract_template(line) if not template: new_lines.append(line) continue # concat the new lines added new_lines += self.eval_template(template, num_tabs) return new_lines
from utils import get_file_lines def parse_ticket(raw_ticket: str) -> int: table = str.maketrans('FBLR', '0101') binary = raw_ticket.translate(table) return int(binary, 2) def part1(tickets: Set[int]) -> int: return max(tickets) def part2(tickets: Set[int]) -> Optional[int]: def is_gap(x: int) -> bool: return x not in tickets and \ x-1 in tickets and \ x+1 in tickets for x in range(min(tickets)+1, max(tickets)): if is_gap(x): return x return None if __name__ == '__main__': data = set(parse_ticket(t) for t in get_file_lines()) print(part1(data)) # 911 print(part2(data)) # 629
def part1(grid: list[list[int]], steps: int) -> int: flashes = 0 for i in range(steps): _increase_grid(grid) _prepare_all_to_flash(grid) flashes += _flash_all(grid) # print('After step', i+1) # print_grid(grid) # print() return flashes def part2(grid: list[list[int]]) -> int: octopus_count = len(grid) * len(grid[0]) step = 0 while True: step += 1 _increase_grid(grid) _prepare_all_to_flash(grid) if _flash_all(grid) == octopus_count: return step if __name__ == '__main__': grid = get_file_lines(transform=lambda line: [int(c) for c in line]) X, Y = len(grid[0]), len(grid) STEPS = 100 print(part1(grid, STEPS)) # 1719 print(part2(grid) + STEPS) # 232
elif floor_map[y][x] == '#' and _too_many_neighbours(x, y): new_row += 'L' else: new_row += floor_map[y][x] result.append(new_row) return result def part1(floor_map: List[str]) -> int: neighbour_depth = 1 neighbour_threshold = 4 old_map = floor_map while (new_map := generate_next(old_map, neighbour_depth, neighbour_threshold)) != old_map: old_map = new_map return sum(x=='#' for x in chain.from_iterable(old_map)) def part2(floor_map: List[str]) -> int: neighbour_depth = max(len(floor_map), len(floor_map[0])) neighbour_threshold = 5 old_map = floor_map while (new_map := generate_next(old_map, neighbour_depth, neighbour_threshold)) != old_map: old_map = new_map return sum(x=='#' for x in chain.from_iterable(old_map)) if __name__ == '__main__': raw_map = get_file_lines() print(part1(raw_map)) # 2481 print(part2(raw_map)) # 2227
def part1(all_food: List[Food]) -> int: food = copy.deepcopy(all_food) while True: definite_allergens = get_definite_allergens(food) if not definite_allergens: break remove_ingredient_allergens(food, definite_allergens) return sum(len(f.ingredients) for f in food) def part2(all_food: List[Food]) -> str: food = copy.deepcopy(all_food) all_allergens: List[Tuple[str, str]] = [] while True: definite_allergens = get_definite_allergens(food) if not definite_allergens: break remove_ingredient_allergens(food, definite_allergens) all_allergens.extend(definite_allergens) ingredients = ','.join(x[0] for x in sorted(all_allergens, key=lambda x: x[1])) return ingredients if __name__ == '__main__': raw_food = [Food(line) for line in get_file_lines()] print(part1(raw_food)) # 2020 print(part2( raw_food)) # bcdgf,xhrdsl,vndrb,dhbxtb,lbnmsr,scxxn,bvcrrfbr,xcgtv
def part1(now: int, buses: List[int]) -> int: wait_to_bus = {wait_time(now, bus): bus for bus in buses} shortest_wait = min(wait_to_bus.keys()) return shortest_wait * wait_to_bus[shortest_wait] def part2(buses: List[RankedBus]) -> int: timestamp = 0 period = buses[0][1] for bus in buses[1:]: offset = bus[0] % bus[1] while wait_time(timestamp, bus[1]) != offset: timestamp += period period *= bus[1] return timestamp if __name__ == '__main__': all_lines = get_file_lines() start_time = int(all_lines[0]) active_buses = [int(t) for t in all_lines[1].split(',') if t != 'x'] print(part1(start_time, active_buses)) # 3997 ranked_buses = [ RankedBus(i, int(b)) for i, b in enumerate(all_lines[1].split(',')) if b != 'x' ] print(part2(ranked_buses)) # 500033211739354
def expand_addresses(address: int, mask: str) -> Iterable: ''' Generator to generate all combinations in memory efficient way ''' float_count = mask.count('X') original_address = to_bin(address) for combination in range(2**float_count): subs = to_bin(combination, float_count) new_address = [] combi_i = 0 for i in range(len(mask)): if mask[i] == '0': new_address.append(original_address[i]) elif mask[i] == '1': new_address.append('1') else: new_address.append(subs[combi_i]) combi_i += 1 yield int(''.join(new_address), 2) memory: Dict[int, int] = dict() # {addr: value} for instruction in instructions: for setting in instruction.settings: for address in expand_addresses(setting.address, instruction.mask): memory[address] = setting.value return sum(memory.values()) if __name__ == '__main__': raw_instructions = parse_instructions(get_file_lines()) print(part1(raw_instructions)) # 10885823581193 print(part2(raw_instructions)) # 3816594901962
default_debug_mode_setting = False elif default_debug_mode_setting not in [ "CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG" ]: raise RuntimeError("default_debug_mode setting invalid") logger = logging.getLogger("chat_app") if default_debug_mode_setting is not False: logger.setLevel(getattr(logging, default_debug_mode_setting)) if log_enabled_setting and log_file_name_setting: logger.addHandler(logging.FileHandler(log_file_name_setting)) else: logger.addHandler(logging.NullHandler()) root = tk.Tk() chatGUI = ChatGUI(root) chatGUI.clientSocket.connect(hostname_setting, port_setting, username_setting) if chatGUI.clientSocket.is_client_connected: SocketThreadedTask(chatGUI.clientSocket, chatGUI.ChatWindow.update_chat_window).start() if test_file_setting is not None: commands = utils.get_file_lines(test_file_setting) commands_fixed = \ filter(lambda command_line: not command_line.startswith("#"), map(lambda command_line: command_line.strip(), commands)) for command in commands_fixed: chatGUI.clientSocket.send(command) time.sleep(0.1) root.mainloop()
left_id = puzzle[row][0] for _ in range(PUZZLE_WIDTH - 1): for right in connections[left_id]: if tiles[right].orientate_and_connect(Tile.LEFT, tiles[left_id].right): puzzle[row].append(right) left_id = right full_map = build_map(tiles, puzzle) mask = [ ' # ', '# ## ## ###', ' # # # # # # ' ] map_orientations = dict() for new_map in get_all_map_orientations(full_map): monster_count = get_mask_count(new_map, mask) map_orientations[monster_count] = new_map.copy() monster_count = max(map_orientations.keys()) full_map = map_orientations[monster_count] mark_mask(full_map, mask) return sum(c == '#' for row in full_map for c in row) if __name__ == '__main__': all_pieces = {piece.id: piece for piece in parse_pieces(get_file_lines())} print(part1(all_pieces)) # 18449208814679 print(part2(all_pieces)) # 1559
vector = self.waypoint - self.position self.waypoint = self.position + complex( vector.real * matrix[0][0] + vector.imag * matrix[0][1], vector.real * matrix[1][0] + vector.imag * matrix[1][1]) def parse_instruction(raw_instruction: str) -> Instruction: return Instruction(raw_instruction[0], int(raw_instruction[1:])) def part1(instructions: List[Instruction]) -> int: navigation = Navigation(DIRECTION['E'], loose_waypoint=False) for instruction in instructions: navigation.apply(instruction) return navigation.distance() def part2(instructions: List[Instruction]) -> int: navigation = Navigation(10 + 1j, loose_waypoint=True) for instruction in instructions: navigation.apply(instruction) return navigation.distance() if __name__ == '__main__': all_instructions = [ parse_instruction(instruction) for instruction in get_file_lines() ] print(part1(all_instructions)) # 445 print(part2(all_instructions)) # 42495
def refresh_from_files(self): """ Loads the DB data with data from the appropriate files self.banner from the file at BANNER_FILE path self.users from the file at USERS_FILE path self.banned_users from the file at BANNED_USERS_FILE path self.channels from the file at CHANNELS_FILE path :return: """ # Load banner message from file try: with open(self.BANNER_FILE) as banner_file: self.banner = banner_file.read() except IOError: pass # Load users from file for user_line in utils.get_file_lines(self.USERS_FILE): try: user_line_splitted = user_line.split(None, 3) username = user_line_splitted[0] user_password = user_line_splitted[1] if user_password == '@': user_password = '' user_level = user_line_splitted[2] if user_level not in ["user", "channelop", "sysop", "admin"]: user_level = "user" user_is_banned = user_line_splitted[3] if user_is_banned == "false": user_is_banned = False elif user_is_banned == "true": user_is_banned = True else: user_is_banned = bool(user_is_banned) self.users[username] = { 'username': username, 'password': user_password, 'level': user_level, 'banned': user_is_banned } except IndexError: continue # Load banned users from file self.banned_users = utils.get_file_lines(self.BANNED_USERS_FILE) # Load channels from file for channel_line in utils.get_file_lines(self.CHANNELS_FILE): try: channel_line_splitted = channel_line.split(None, 3) channel_name = channel_line_splitted[0] channel_password = channel_line_splitted[2] if channel_password == '@': channel_password = '' channel_ops = channel_line_splitted[3] self.channels[channel_name] = { 'name': channel_name, 'description': channel_line_splitted[1], 'password': channel_password, 'channelops': [channel_op.strip() for channel_op in channel_ops.split(",") for channel_op in channel_op.split(None)] } except IndexError: pass
current = original[0] removed = [0] * 3 for _ in range(10_000_000): # remove removed[0] = ring[current] removed[1] = ring[removed[0]] removed[2] = ring[removed[1]] ring[current] = ring[removed[2]] # find destination destination = size if current == 1 else current - 1 while destination in removed: destination = size if destination == 1 else destination - 1 # insert ring[removed[2]] = ring[destination] ring[destination] = removed[0] # next current = ring[current] return ring[1] * ring[ring[1]] if __name__ == '__main__': raw_data = [int(number) for number in list(get_file_lines()[0])] start_node = build_ring(raw_data) print(part1(start_node)) # 74698532 print(part2(tuple(raw_data))) # 286194102744
sub_hand1 = get_sub_hand(hand1) sub_hand2 = get_sub_hand(hand2) winner = play_recursive(sub_hand1, sub_hand2) move_cards_to_winner(hand1, hand2, winner) return 1 if hand1 else 2 def calc_score(hand: Hand) -> int: return sum((i + 1) * card for i, card in enumerate(reversed(hand))) def part1(hand1: Hand, hand2: Hand) -> int: hand1, hand2 = hand1.copy(), hand2.copy() while hand1 and hand2: play_highest_card_wins(hand1, hand2) return calc_score(hand1 or hand2) def part2(hand1: Hand, hand2: Hand) -> int: if play_recursive(hand1, hand2) == 1: return calc_score(hand1) return calc_score(hand2) if __name__ == '__main__': raw_hand1, raw_hand2 = parse_input(get_file_lines()) print(part1(raw_hand1, raw_hand2)) # 30138 print(part2(raw_hand1, raw_hand2)) # 31587
computer.step() return computer.ip < len(computer.instructions) def part1(computer: Computer) -> int: assert run_to_loop_start(computer) return computer.accumulator def part2(computer: Computer) -> Optional[int]: def make_new_instruction(old: Instruction) -> Instruction: new_operation = 'jmp' if old.operation == 'nop' else 'nop' return Instruction(new_operation, old.param) for i in range(len(computer.instructions)): computer.reset() old_instruction = computer.instructions[i] if old_instruction.operation in ('jmp', 'nop'): computer.instructions[i] = make_new_instruction(old_instruction) if not run_to_loop_start(computer): return computer.accumulator computer.instructions[i] = old_instruction return None if __name__ == '__main__': raw_instructions = get_file_lines() main_computer = Computer(raw_instructions) print(part1(main_computer)) # 2051 print(part2(main_computer)) # 2304
def can_bag_contain_colour(rules: Dict[str, List[Capacity]], source_colour: str, target_colour: str) -> bool: return any( child.colour == target_colour or can_bag_contain_colour(rules, child.colour, target_colour) for child in rules[source_colour] ) def count_contained(rules: Dict[str, List[Capacity]], colour: str) -> int: return sum( (child.total * count_contained(rules, child.colour) for child in rules[colour]), 1 ) def part1(rules: Dict[str, List[Capacity]]) -> int: return sum(can_bag_contain_colour(rules, b, 'shiny gold') for b in rules.keys()) def part2(rules: Dict[str, List[Capacity]]) -> int: return count_contained(rules, 'shiny gold') - 1 # exclude the bag itself if __name__ == '__main__': bag_rules = dict(parse_rule(line) for line in get_file_lines()) print(part1(bag_rules)) # 142 print(part2(bag_rules)) # 10219
def parse_hosts_file(cls, path): "Parse a hosts file ``path`` and return a list of lines" return [HostLine(line) for line in get_file_lines(path)]
for next_number in numbers[25:]: if not is_valid(preamble, next_number): return next_number preamble.popleft() preamble.append(next_number) return 0 def part2(numbers: List[int], magic_number: int) -> int: def apply_range( fn: Callable[[Iterable], int], first_index: int, last_index: int): return fn(numbers[i] for i in range(first_index, last_index+1)) start, end = 0, 1 while True: total = apply_range(sum, start, end) if total == magic_number: return apply_range(min, start, end) + apply_range(max, start, end) if total < magic_number: end += 1 else: start += 1 if __name__ == '__main__': raw_numbers = [int(i) for i in get_file_lines()] print(magic := part1(raw_numbers)) # 1639024365 print(part2(raw_numbers, magic)) # 219202240
from utils import get_file_lines def calc_population(timers: dict, days: int) -> int: for _ in range(days): next_gen = defaultdict(int) for timer, count in timers.items(): if timer == 0: next_gen[8] = count next_gen[6] += count else: next_gen[timer - 1] += count timers = next_gen return sum(timers.values()) def part1(timers: dict) -> int: return calc_population(timers, 80) def part2(timers: list[int]) -> int: return calc_population(timers, 256) if __name__ == '__main__': line = get_file_lines()[0] timers = Counter([int(i) for i in line.split(',')]) print(part1(timers)) # 358214 print(part2(timers)) # 1622533344325
for coord in get_all_coordinates(min_coord, max_coord, dimensions): neighbour_count = 0 for neighbour in get_neighbours(coord, dimensions): if cube[neighbour]: neighbour_count += 1 if should_activate(cube[coord], neighbour_count): next_cube[coord] = True return next_cube def part1(cube: Cube) -> int: for _ in range(6): cube = next_gen(cube, 3) return sum(state for state in cube.values()) def part2(cube: Cube) -> int: for _ in range(6): cube = next_gen(cube, 4) return sum(state for state in cube.values()) if __name__ == '__main__': raw_data = get_file_lines() initial_map_3d = parse_raw_data(raw_data, 3) print(part1(initial_map_3d)) # 240 initial_map_4d = parse_raw_data(raw_data, 4) print(part2(initial_map_4d)) # 1180
for pair in line.split()) # type: ignore passport.update(new_fields) if passport: yield passport def contains_required_fields(entry: Dict) -> bool: return set(entry).issuperset(REQUIRED_FIELDS.keys()) def are_fields_valid(entry: Dict) -> bool: return all( validate(entry[key]) for key, validate in REQUIRED_FIELDS.items()) def part1(data: List[Dict]) -> int: return sum(contains_required_fields(entry) for entry in data) def part2(data: List[Dict]) -> int: return sum( contains_required_fields(entry) and are_fields_valid(entry) for entry in data) if __name__ == '__main__': parsed_data = list(parse_passports(get_file_lines())) print(part1(parsed_data)) # 228 print(part2(parsed_data)) # 175
return PasswordInfo(int1, int2, char, password) def part1(password_info: List[PasswordInfo]) -> int: result: int = 0 for info in password_info: counter = Counter(info.password) if info.char in counter and info.int1 <= counter[ info.char] <= info.int2: result += 1 return result def part2(password_info: List[PasswordInfo]) -> int: result: int = 0 for info in password_info: password_len = len(info.password) match1 = info.int1 <= password_len and info.password[info.int1 - 1] == info.char match2 = info.int2 <= password_len and info.password[info.int2 - 1] == info.char if match1 ^ match2: result += 1 return result if __name__ == '__main__': data = [parse_password_info(line) for line in get_file_lines()] print(part1(data)) # 474 print(part2(data)) # 745
Number of combinations is determined by considering each middle number as a bit which can be present (one) or not (zero): s**nrOfBits. Then subtract the number of groups of 3 consecutive bits: nrBits-2''' def are_consecutive(first: int, second: int) -> bool: return second - first == 1 def combinations(nr_middle_bits: int) -> int: return 2**nr_middle_bits - max(nr_middle_bits - 2, 0) last_number = 0 group_combinations: List[int] = [ ] # nr combinations for each consecutive group length = 0 for next_number in numbers: if are_consecutive(last_number, next_number): length += 1 elif length > 0: if length >= 2: group_combinations.append(combinations(length - 1)) length = 0 last_number = next_number if length >= 2: group_combinations.append(combinations(length)) return math.prod(group_combinations) if __name__ == '__main__': raw_numbers = sorted([int(i) for i in get_file_lines()]) print(part1(raw_numbers)) # 2030 print(part2(raw_numbers)) # 42313823813632
#! /usr/bin/env python3.10 from utils import get_file_lines def count_increase(depths: list[int], lookback: int) -> int: count = 0 for i in range(lookback, len(depths)): if depths[i] > depths[i - lookback]: count += 1 return count def part1(depths: list[int]) -> int: return count_increase(depths, 1) def part2(depths: list[int]) -> int: return count_increase(depths, 3) if __name__ == '__main__': depths = get_file_lines(transform=int) print(part1(depths)) # 1791 print(part2(depths)) # 1822
floors = [floor] for _ in range(20): floor = day24.next_floor(floor) floors.append(floor) col_count, row_count = get_grid_size(floors) x_offset = col_count // 2 y_offset = row_count // 2 center = complex(x_offset, y_offset) length = 10 row_height = length * 1.7320508075688772935274463415059 print('cols', col_count, 'width', 2 * length * col_count + 10) win = graphics.GraphWin('Part 2', 1.5 * length * col_count + 20, row_count * row_height + 20) grid = HexagonGrid(5, 5, col_count, row_count, length) grid.draw(win) for floor in floors: print(win.getMouse()) grid.reset_cells(set([center + pos for pos in floor.keys()])) print(win.getMouse()) return sum(floor.values()) if __name__ == '__main__': raw_data = get_file_lines('input/day24.txt') raw_floor = day24.get_initial_state(raw_data) part1(raw_floor) part2(raw_floor)