77
88
99@functools .cache
10- def get_points (rows , token , start ):
10+ def get_points (rows : tuple [str , ...], token : str , start : int ) -> int :
11+ """Return how many points are won for a given configuration."""
1112 pos = start * 2
1213 bounces = iter (token )
1314 for row in rows :
@@ -29,45 +30,48 @@ def get_points(rows, token, start):
2930 return points
3031
3132
32- def min_max_points (rows , tokens , slots ):
33+ def min_max_points (rows : tuple [str , ...], tokens : tuple [str , ...], slots : frozenset [int ]) -> tuple [int , int ]:
34+ """Return the min and max possible points."""
3335
3436 @functools .cache
35- def cached (tokens , slots ) :
37+ def cached (tokens : tuple [ str , ...], slots : frozenset [ int ]) -> tuple [ int , int ] :
3638 assert len (tokens ) < len (slots )
3739 if len (tokens ) == 1 :
3840 points = sorted (get_points (rows , tokens [0 ], i ) for i in slots )
3941 return points [0 ], points [- 1 ]
4042
41- token , * tokens = tokens
43+ token , * rest = tokens
44+ tokens = tuple (rest )
4245 return min (
43- get_points (rows , token , slot ) + cached (tuple ( tokens ) , frozenset (slots - {slot }))[0 ]
46+ get_points (rows , token , slot ) + cached (tokens , frozenset (slots - {slot }))[0 ]
4447 for slot in slots
4548 ), max (
46- get_points (rows , token , slot ) + cached (tuple ( tokens ) , frozenset (slots - {slot }))[1 ]
49+ get_points (rows , token , slot ) + cached (tokens , frozenset (slots - {slot }))[1 ]
4750 for slot in slots
4851 )
4952
5053 return cached (tokens , slots )
5154
5255
53- def solve (part : int , data : str ) -> int :
56+ def solve (part : int , data : str ) -> int | str :
5457 """Solve the parts."""
5558 nails , tokens = data .split ("\n \n " )
56- rows = nails .splitlines ()
59+ rows = tuple ( nails .splitlines () )
5760 assert len (rows [0 ]) % 2 == 1
5861 positions = (len (rows [0 ]) + 1 ) // 2
5962
60- if part in [1 , 2 ]:
61- score = 0
62- for start , token in enumerate (tokens .splitlines ()):
63- if part == 1 :
64- score += get_points (rows , token , start )
65- if part == 2 :
66- score += max (get_points (rows , token , i ) for i in range (positions ))
67- return score
68-
69- slots = frozenset (range (positions ))
70- return min_max_points (tuple (rows ), tuple (tokens .splitlines ()), slots )
63+ if part == 3 :
64+ slots = frozenset (range (positions ))
65+ a , b = min_max_points (tuple (rows ), tuple (tokens .splitlines ()), slots )
66+ return f"{ a } { b } "
67+
68+ score = 0
69+ for start , token in enumerate (tokens .splitlines ()):
70+ if part == 1 :
71+ score += get_points (rows , token , start )
72+ if part == 2 :
73+ score += max (get_points (rows , token , i ) for i in range (positions ))
74+ return score
7175
7276
7377TEST_DATA = [
0 commit comments