""" Check numbers in range for repeating patterns, add them together. """ import math from curses import start_color # reject odd number of digits in 1 and 2 test_ids = ["11-22", "95-115", "998-1012", "1188511880-1188511890", "222220-222224", " 1698522-1698528", "446443-446449", "38593856-38593862", "565653-565659", "824824821-824824827", "2121212118-2121212124"] def check_and_split(id_range: str) -> tuple[int, int] | None: """ split the range (str, "x-y"), return none if invalid IDs (start and end are odd). Return (start, end), boolean, true if start and end are equal length IDs, false if not. :param id_range: range as string like '1-10' :return: tuple ( tuple(start, end), boolean if equal size or not) """ start, end = id_range.split("-") if len(start)%2 and len(end)%2: return None elif len(start) == len(end): return int(start), int(end) else: return int(start), int(end) def test_check_and_split(): assert check_and_split("11-22") == ((11, 22), True) assert not check_and_split("111-222") assert check_and_split("9-14") == ((9, 14), False) # if second number has more chars than first, do extra step to catch: # 9-14 -> 11 def make_int(l: list): return int("".join(map(str, l))) def make_list(i: int): return [int(n) for n in str(i)] def create_tokens(start: int, end: int): """ Create a list of ids that are in the range """ # keep ids to sum: elf_ids = [] # if start is < 10, round up. No point in checking under 10! if start < 10: start = 10 # set up starts: start_id_length = len(str(start)) start_repeating_length = int(start_id_length/2) start_half_pattern_list = make_list(start)[0:start_repeating_length] start_half_pattern_int = make_int(start_half_pattern_list) # set up ends: end_id_length = int(len(str(end))) end_repeating_length = math.ceil(end_id_length/2) end_half_pattern_list = make_list(end)[0:end_repeating_length] end_half_pattern_int = make_int(end_half_pattern_list) for half_pattern in range(start_half_pattern_int, end_half_pattern_int + 1): new_pattern = int(str(half_pattern) + str(half_pattern)) if start <= new_pattern <= end: elf_ids.append(new_pattern) return elf_ids def test_create_tokens(): assert create_tokens(11, 22) == [11, 22] assert create_tokens(95, 115) == [99] assert create_tokens(998, 1012) == [1010] assert create_tokens(1188511880, 1188511890) == [1188511885] assert create_tokens(222220, 222224) == [222222] assert create_tokens(446443, 446449) == [446446] assert create_tokens(38593856, 38593862) == [38593859] assert create_tokens(9, 14) == [11] def wrap_it_up(ids: list): ids_to_sum = [] for id_range in ids: check = check_and_split(id_range) if check: start, end = check ids_to_sum.extend(create_tokens(start, end)) print(ids_to_sum) return sum(ids_to_sum) def test_wrap_it_up(): actual_sum = wrap_it_up(test_ids) assert actual_sum == 1227775554 def test_real_data(): real_input = open('input_day2.txt').read().split(",") real_output = wrap_it_up(real_input) print(real_output) def get_tokens(start:int, end:int, multiple:int): """ multiple is the small part of the id to be repeated. So in 1000-2000, the multiple of 2 would be 10, 11, 12 etc :param start: :param end: :param multiple: :return: """ ids = [] length = len(make_list(end)) how_many_repeats = int(length/multiple) start_part_pattern_list = make_list(start)[0:multiple] start_part_pattern_int = make_int(start_part_pattern_list) end_part_pattern_list = make_list(end)[0:multiple] end_part_pattern_int = make_int(end_part_pattern_list) pattern_start = min(start_part_pattern_int, end_part_pattern_int) pattern_end = max(start_part_pattern_int, end_part_pattern_int) for subpattern in range(pattern_start, pattern_end+1): for repeats in range(2, how_many_repeats+1): new_pattern = int(str(subpattern) * repeats) if start <= new_pattern <= end: ids.append(new_pattern) set_ids = set(ids) return sorted(list(set_ids)) def test_get_tokens(): assert get_tokens(11, 22, 1) == [11, 22] assert get_tokens(95, 115, 1) == [99, 111] assert get_tokens(998, 1012, 1) == [999] assert get_tokens(998, 1012, 2) == [1010] assert get_tokens(1188511880, 1188511890, 5) == [1188511885] assert get_tokens(222220, 222224, 3) == [222222] assert get_tokens(1698522,1698528, 1) == [] assert get_tokens(446443, 446449, 3) == [446446] assert get_tokens(38593856, 38593862, 4) == [38593859] assert get_tokens(565653,565659, 2) == [565656] assert get_tokens(824824821,824824827, 3) == [824824824] assert get_tokens(2121212118, 2121212124, 2) == [2121212121] def test_actual_input(): factors = get_factors(10) for factor in factors: print(get_tokens(6948, 9419, factor)) def get_factors(number: int): factors = [] for i in range(1, number): if number % i == 0: factors.append(i) return factors def test_get_highest_factor(): assert max(get_factors(10)) == 5 assert max(get_factors(100)) == 50 assert max(get_factors(1428)) == 714 def wrap_it_up_part_two(ids: list): ids_to_sum = [] for id_range in ids: bad_ids_in_range = [] start, end = id_range.strip().split("-") number_of_digits_in_end = len(make_list(end)) for multiple in get_factors(number_of_digits_in_end): bad_ids = get_tokens(int(start), int(end), multiple) bad_ids_in_range.extend(bad_ids) invalid_ids = (list(set(bad_ids_in_range))) ids_to_sum.extend(invalid_ids) final_sum = sum(ids_to_sum) return final_sum def test_wrap_it_up_part_two_test(): final_sum = wrap_it_up_part_two(test_ids) assert final_sum == 4174379265 def test_wrap_it_up_part_two_real(): real_input = open('input_day2.txt').read().split(",") final_sum = wrap_it_up_part_two(real_input) print(final_sum)