AoC_2025/day_2.py
2025-12-04 23:37:40 +00:00

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)