--- /dev/null
+#!/usr/bin/env pypy3.10
+
+import sys
+import unittest
+import argparse
+
+
+def race_generator(duration, record):
+ for hold in range(0, duration):
+ runtime = duration - hold
+ speed = 1 * hold
+ travel = runtime * speed
+ if travel > record:
+ yield hold, travel
+
+
+class TestRaceGenerator(unittest.TestCase):
+ def test_part1_calculation(self):
+ one = len(list(race_generator(7, 9)))
+ two = len(list(race_generator(15, 40)))
+ three = len(list(race_generator(30, 200)))
+ self.assertSequenceEqual([4, 8, 9], [one, two, three])
+ self.assertEqual(288, one * two * three)
+
+ def test_part2_calculation(self):
+ test_race = list(race_generator(71530, 940200))
+ self.assertEqual(71503, len(test_race))
+
+
+def part1(filename):
+ with open(filename) as input:
+ races = zip(
+ [int(x) for x in input.readline().split(":")[1].split()],
+ [int(x) for x in input.readline().split(":")[1].split()])
+
+ final = 1
+ for race in races: # ((59, 597), (79, 1234), (65, 1032), (75, 1328)):
+ result = len(list(race_generator(*race)))
+ final *= result
+ return final
+
+
+def part2(filename):
+ with open(filename) as input:
+ duration = int("".join(input.readline().split(":")[1].split()))
+ distance = int("".join(input.readline().split(":")[1].split()))
+ return len(list(race_generator(duration, distance)))
+
+
+def main(args=None):
+ parser = argparse.ArgumentParser(description="advent of code 2023 day 6")
+ parser.add_argument('filename')
+ parser.add_argument('-t', '--test', action='store_true')
+ options = parser.parse_args(args)
+
+ if options.test:
+ return unittest.main()
+
+ print(f"part 1: {part1(options.filename)}")
+ print(f"part 2: {part2(options.filename)}")
+
+
+if __name__ == '__main__':
+ sys.exit(main(sys.argv[1:]))