22
33import collections
44import functools
5+ import typing
56from lib import parsers
67
78
8- def solve (part : int , data : str ) -> int :
9+ def solve (part : int , data : list [ list [ str | list [ str ]]] ) -> int | str :
910 """Solve the parts."""
10- rev_pairs = collections .defaultdict (set )
11- pairs = collections .defaultdict (set )
12- for line in data .split ("\n \n " )[1 ].splitlines ():
13- a , b = line .split (" > " )
11+ names , rules = typing .cast (tuple [list [str ], list [list [str ]]], data )
12+
13+ # Parse the rules into maps.
14+ rule_prior = collections .defaultdict (set )
15+ rule_next = collections .defaultdict (set )
16+ for a , b in rules :
1417 for c in b .split ("," ):
15- pairs [a ].add (c )
16- rev_pairs [c ].add (a )
18+ rule_next [a ].add (c )
19+ rule_prior [c ].add (a )
1720
1821 @functools .cache
1922 def possibilities (size : int , letter : str ) -> int :
23+ """Count the number of possible names that can be formed."""
2024 if size == 11 :
2125 return 1
2226 count = 0 if size < 7 else 1
2327 size += 1
24- return count + sum (possibilities (size , i ) for i in pairs [letter ])
28+ return count + sum (possibilities (size , i ) for i in rule_next [letter ])
2529
26- total = 0
27- names = data .split ("\n \n " )[0 ].split ("," )
30+ # Dedupe names which have a prefix also included.
2831 if part == 3 :
29- names = set (names )
30- names = {n for n in names if not any (n != m and n .startswith (m ) for m in names )}
32+ filtered = set (names )
33+ filtered = {n for n in names if not any (n != m and n .startswith (m ) for m in names )}
34+ names = list (filtered )
3135
36+ total = 0
3237 for idx , name in enumerate (names , start = 1 ):
3338 for a , b in zip (name , name [1 :]):
34- if a not in rev_pairs [b ]:
39+ if a not in rule_prior [b ]:
3540 break
3641 else :
3742 if part == 1 :
@@ -43,6 +48,10 @@ def possibilities(size: int, letter: str) -> int:
4348 return total
4449
4550
51+ PARSER = parsers .ParseBlocks ([
52+ parsers .ParseMultiWords (str , separator = "," ),
53+ parsers .BaseParseMultiPerLine (word_separator = " > " ),
54+ ])
4655TEST_DATA = [
4756 """\
4857 Oronris,Urakris,Oroneth,Uraketh
0 commit comments