from collections import Counter from copy import copy from typing import List from aoc import BaseAssignment class Assignment(BaseAssignment): def read_input(self, example = False) -> List[str]: return list(super().read_input(example)) @staticmethod def flip(bits: str) -> str: return bin(~int(bits, 2) + (1 << len(bits))).strip('0b') class AssignmentOne(Assignment): example_result = 198 @staticmethod def convert(input: List[str]) -> List[List[str]]: items = [] for item in input: for index, char in enumerate([char for char in item]): try: items[index].append(char) except IndexError: items.append([char]) return items @staticmethod def gamma_rate(input: List[str]) -> str: converted = AssignmentOne.convert(input) return ''.join([ Counter(i).most_common(1)[0][0] for i in converted ]) @staticmethod def epsilon_rate(input: List[str]) -> str: return Assignment.flip(AssignmentOne.gamma_rate(input)) def run(self, input: List[str]) -> int: return int(self.gamma_rate(input), 2) * int(self.epsilon_rate(input), 2) class AssignmentTwo(Assignment): example_result = 230 @staticmethod def oxygen_generator_rating(input: List[str]): bit_length = len(input[0]) modified_input = copy(input) bits = '' for i in range(bit_length): count = Counter([_[i] for _ in modified_input]).most_common(2) most_used = count[0] most_used_count = most_used[1] least_used = count[-1] least_used_count = least_used[1] bit = '1' if most_used_count == least_used_count else most_used[0] bits += bit modified_input = list(filter(lambda _: _[i] == bit, modified_input)) return bits @staticmethod def co2_scrubbing_rating(input: List[str]): bit_length = len(input[0]) modified_input = copy(input) for i in range(bit_length): if len(modified_input) == 1: return modified_input[0] count = Counter([_[i] for _ in modified_input]).most_common(2) most_used = count[0] most_used_count = most_used[1] least_used = count[-1] least_used_count = least_used[1] bit = '0' if most_used_count == least_used_count else least_used[0] modified_input = list(filter(lambda _: _[i] == bit, modified_input)) def run(self, input: List[str]) -> int: return int(AssignmentTwo.oxygen_generator_rating(input), 2) \ * int(AssignmentTwo.co2_scrubbing_rating(input), 2)