80 lines
1.7 KiB
Python
80 lines
1.7 KiB
Python
import math
|
|
from typing import Any
|
|
|
|
|
|
def _cut_right_n_digits(s: int, n: int) -> tuple[int, int]:
|
|
left = s // 10**n
|
|
right = s - left * 10**n
|
|
return left, right
|
|
|
|
|
|
def is_invalid(n: int) -> bool:
|
|
size = int(math.log10(n)) + 1
|
|
left, right = _cut_right_n_digits(n, size // 2)
|
|
return left == right
|
|
|
|
|
|
def is_invalid_any(n: int) -> bool:
|
|
size = int(math.log10(n)) + 1
|
|
|
|
for cut in range(1, size):
|
|
if size % cut != 0:
|
|
continue
|
|
|
|
left, right = _cut_right_n_digits(n, cut)
|
|
while left != 0:
|
|
nleft, nright = _cut_right_n_digits(left, cut)
|
|
if nright != right:
|
|
break
|
|
left = nleft
|
|
|
|
if left == 0:
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
def part_1(input_data: str) -> Any:
|
|
s = 0
|
|
for rng in input_data.split(","):
|
|
a, b = (int(s) for s in rng.split("-"))
|
|
s += sum([n for n in range(a, b + 1) if is_invalid(n)])
|
|
|
|
return s
|
|
|
|
|
|
def part_2(input_data: str) -> Any:
|
|
s = 0
|
|
for rng in input_data.split(","):
|
|
a, b = (int(s) for s in rng.split("-"))
|
|
s += sum([n for n in range(a, b + 1) if is_invalid_any(n)])
|
|
|
|
return s
|
|
|
|
|
|
def test_is_invalid():
|
|
assert is_invalid(55)
|
|
assert is_invalid(6464)
|
|
assert is_invalid(123123)
|
|
|
|
assert not is_invalid(123124)
|
|
assert not is_invalid(22222)
|
|
|
|
|
|
def test_is_invalid_any():
|
|
assert is_invalid_any(12341234)
|
|
assert is_invalid_any(123123123)
|
|
assert is_invalid_any(12121212)
|
|
assert is_invalid_any(1111111)
|
|
|
|
assert not is_invalid_any(123124)
|
|
assert not is_invalid_any(12312)
|
|
|
|
|
|
def test_part_1(example_data):
|
|
assert part_1(example_data) == 1227775554
|
|
|
|
|
|
def test_part_2(example_data):
|
|
assert part_2(example_data) == 4174379265
|