1
+ import re
2
+ from sys import argv , stdin
3
+ from math import prod
4
+
5
+ def win_races (time :int , record :int ) -> int :
6
+ # charge = time spent charging = speed of the boat
7
+ # charge - time = remaining time
8
+ distances = [ (time - charge ) * charge for charge in range (0 , time ) ]
9
+
10
+ # collect elements that pass the record and return the number
11
+ return sum (x > record for x in distances )
12
+
13
+ def parse_config (source ) -> list [tuple [int , int ]]:
14
+ re_time = re .compile (r"^Time:\s+((?:\d+\s*)+)" , re .MULTILINE )
15
+ re_distance = re .compile (r"^Distance:\s+((?:\d+\s*)+)" , re .MULTILINE )
16
+ re_int = re .compile (r"(\d+)" )
17
+
18
+ times = re .findall (re_int , ' ' .join (re .findall (re_time , source )))
19
+ distances = re .findall (re_int , ' ' .join (re .findall (re_distance , source )))
20
+
21
+ races = zip (times , distances )
22
+ return list (races )
23
+
24
+ def part_one (races : list [tuple [int , int ]]) -> int :
25
+ return prod (win_races (int (time ), int (record )) for time , record in races )
26
+
27
+ def part_two (races : list [tuple [int , int ]]) -> int :
28
+ # Unpack tuples in the list, assign them to variables,
29
+ # concatenate into a single string, then convert to an int
30
+ time , record = zip (* races )
31
+ time = int ('' .join (time ))
32
+ record = int ('' .join (record ))
33
+
34
+ return win_races (time , record )
35
+
36
+ if __name__ == "__main__" :
37
+ if len (argv ) < 2 or argv [1 ] == '-' :
38
+ print (f"Reading from stdin" )
39
+ text = stdin .read ()
40
+ else :
41
+ try :
42
+ with open (argv [1 ]) as f :
43
+ print (f"Reading from { argv [1 ]} " )
44
+ text = f .read ()
45
+ except FileNotFoundError :
46
+ print (f"Unable to find file: { argv [1 ]} " )
47
+ exit (1 )
48
+
49
+ races = parse_config (text )
50
+
51
+ print (f"Part 1: { part_one (races )} " )
52
+ print (f"Part 2: { part_two (races )} " )
0 commit comments