1+ #!/usr/bin/env python
2+ # -*- coding: utf-8 -*-
3+
4+ from typing import List
5+ from functools import lru_cache
6+ from collections import Counter
7+
8+ split_data = ' '
9+ completed = True
10+ raw_data = None # Not To be touched
11+
12+ def part1 (data :List [str ]):
13+ stones = data
14+
15+ for _ in range (25 ):
16+ newStones = []
17+
18+ for stone in stones :
19+ if stone == '0' :
20+ newStones .append ('1' )
21+ elif len (stone ) % 2 == 0 :
22+ mid = len (stone ) // 2
23+ left , right = stone [:mid ], stone [mid :]
24+ # str -> int -> str to remove trailing 0
25+ newStones .append (str (int (left )))
26+ newStones .append (str (int (right )))
27+ else :
28+ newStones .append (str (int (stone )* 2024 ))
29+
30+ stones = newStones
31+
32+ return len (stones )
33+
34+ def part2 (data :List [str ]):
35+ # We can speed up the entire thing by grouping the same stones together
36+
37+ @lru_cache (None , typed = False )
38+ def resolve (stone :str ) -> List [str ]:
39+ if stone == '0' :
40+ return ['1' ]
41+ elif len (stone ) % 2 == 0 :
42+ mid = len (stone ) // 2
43+ left , right = stone [:mid ], stone [mid :]
44+ # str -> int -> str to remove trailing 0
45+ return [str (int (left )), str (int (right ))]
46+ else :
47+ return [str (int (stone )* 2024 )]
48+
49+ stones = Counter (data )
50+
51+ for _ in range (75 ):
52+ newStones = Counter ()
53+ for stone , value in stones .items ():
54+ resolved = {s :v * value for s , v in Counter (resolve (stone )).items ()}
55+ newStones .update (resolved )
56+
57+ stones = newStones
58+
59+ print (resolve .cache_info ())
60+
61+ return stones .total ()
0 commit comments