advent-of-code/2024/11/two.py
2024-12-25 12:59:49 +01:00

122 lines
3.1 KiB
Python

#!/usr/bin/env python3
import bisect
import sys
import time
import functools
input_file = sys.argv[1]
with open(input_file) as fd:
lines = [line.rstrip() for line in fd.readlines()]
start = time.time()
stones = [int(stone) for stone in lines[0].split()]
# for i in range(75):
# print(i, time.time() - start, len(stones))
# # for s, stone in enumerate(stones):
# # if stone == 0:
# # stones[s] = 1
# # continue
# # stone_str = str(stone)
# # if len(stone_str) % 2 == 0:
# # mid = int(len(stone_str) / 2)
# # stones[s] = int(stone_str[:mid])
# # stones.insert(s, int(stone_str[mid:]))
# # else:
# # stones[s] *= 2024
# new_stones = []
# for stone in stones:
# stone_str = str(stone)
# if stone == 0:
# new_stones.append(1)
# elif len(stone_str) % 2 == 0:
# mid = int(len(stone_str) / 2)
# new_stones.append(int(stone_str[:mid]))
# new_stones.append(int(stone_str[mid:]))
# else:
# new_stones.append(stone * 2024)
# stones = new_stones
target = int(sys.argv[2])
its = [0] * len(stones)
start_stones = stones.copy()
pow10 = list()
for i in range(25):
pow10.append(10**i)
def num_digits(a: int) -> int:
# for i, p in enumerate(pow10):
# if a < p:
# # assert len(str(a)) == i
# return i
# raise NotImplementedError
# return bisect.bisect(pow10, a)
# # nb = bisect.bisect(pow10, a)
num = 0
while a > 0:
num += 1
a //= 10
# assert nb == num
return num
# lstones = 0
# for e, sstone in enumerate(start_stones):
# print(f"47 {e}/{len(start_stones)} {time.time() - start}")
# stones = [sstone]
# while stones:
# stone = stones.pop(0)
# it = its.pop(0)
# lstones += 1
# if stone == 0:
# stone = 1
# it += 1
# nd = num_digits(stone)
# for i in range(it, target):
# print(stone)
# if nd % 2 == 0:
# mid = nd // 2
# left, right = divmod(stone, pow10[mid])
# # left, right = divmod(stone, 10**mid)
# stone = left
# stones.insert(0, right)
# its.insert(0, i + 1)
# nd = mid
# else:
# stone *= 2024
# nd = num_digits(stone)
# # print(f"64 {stone}")
# @functools.lru_cache(maxsize=1024)
@functools.cache
def proc(stone: int, target: int) -> int:
if target == 0:
return 1
target -= 1
if stone == 0:
return proc(1, target)
nd = num_digits(stone)
if nd % 2 == 0:
mid = nd // 2
left, right = divmod(stone, pow10[mid])
return proc(left, target) + proc(right, target)
else:
return proc(stone * 2024, target)
lstones = 0
for e, stone in enumerate(stones):
print(f"47 {e}/{len(stones)} {time.time() - start}")
lstones += proc(stone, target)
print(f"{target=}")
print(lstones)