213 lines
6.1 KiB
Python
213 lines
6.1 KiB
Python
"""
|
|
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)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|