My Advent of Code solutions in Python. kevinyap.ca/2019/12/going-fast-in-advent-of-code/
advent-of-code python
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Update puzzle runner

- Use argparse to parse command line options.
- Pass `--pypy` flag to run puzzles using PyPy.
- Pass `--benchmark` flag to compare CPython and PyPy performance.

+51 -21
+51 -21
advent.py
··· 5 5 import re 6 6 import sys 7 7 import glob 8 + import argparse 8 9 import resource 9 10 import subprocess 10 11 ··· 56 57 return color_time_str(time_str, timespan) 57 58 58 59 59 - def check_solution(program, day, input_file, output_file): 60 + def check_solution(program, day, input_file, output_file, pypy=False): 60 61 with Halo(text='Day {:02}'.format(day)): 61 - cmd = ['python', program, input_file] 62 + cmd = ['pypy' if pypy else 'python', program, input_file] 62 63 start = clock() 63 64 proc = subprocess.Popen(cmd, stdout=subprocess.PIPE) 64 65 stdout = proc.communicate()[0] ··· 77 78 78 79 79 80 if __name__ == '__main__': 80 - exit_code = 0 81 + parser = argparse.ArgumentParser(description="Advent of Code puzzle runner.") 82 + parser.add_argument('year', type=int) 83 + parser.add_argument('puzzle', type=int, nargs='?') 84 + parser.add_argument('--pypy', const=True, action='store_const', 85 + help="use PyPy instead of CPython") 86 + parser.add_argument('--benchmark', const=True, action='store_const', 87 + help="compare PyPy against CPython") 81 88 82 - if len(sys.argv) == 1: 83 - print "Usage: ./test.py <year> [problem]" 84 - sys.exit() 89 + args = parser.parse_args() 85 90 86 - year = sys.argv[1] 91 + year = args.year 92 + puzzle = args.puzzle 93 + pypy = args.pypy 87 94 88 - if len(sys.argv) > 2: 89 - programs = glob.glob('%s/day%02i.py' % (year, int(sys.argv[2]))) 95 + if puzzle is not None: 96 + programs = glob.glob('%s/day%02i.py' % (year, puzzle)) 90 97 else: 91 98 programs = glob.glob('%s/day*.py' % year) 92 99 93 - runtimes = [] 100 + to_run = [] 94 101 95 102 for program in programs: 96 103 day = int(re.findall(r'(\d+).py', program)[0]) ··· 98 105 output_file = '%s/outputs/%02i.txt' % (year, day) 99 106 100 107 if os.path.exists(output_file): 101 - valid, stdout, cpu_usr = check_solution(program, day, input_file, output_file) 102 - runtimes.append(cpu_usr) 108 + to_run.append((program, day, input_file, output_file)) 103 109 104 - print '{}{}{} Day {:02} ({})'.format( 105 - bcolors.OKGREEN if valid else bcolors.FAIL, 106 - '✓' if valid else '✗', 107 - bcolors.ENDC, 110 + if args.benchmark: 111 + print "Day CPython PyPy Speedup" 112 + print '-' * 34 113 + 114 + for program, day, input_file, output_file in to_run: 115 + cpy_time = check_solution(program, day, input_file, output_file, pypy=False)[2] 116 + pypy_time = check_solution(program, day, input_file, output_file, pypy=True)[2] 117 + 118 + print "{:02} {} {} {:0.1f}".format( 108 119 day, 109 - format_time(cpu_usr), 120 + format_time(cpy_time, padding=7), 121 + format_time(pypy_time, padding=7), 122 + cpy_time / pypy_time 110 123 ) 111 - print stdout 112 124 113 - if not valid: 114 - exit_code = 1 125 + sys.exit(0) 115 126 116 - if len(sys.argv) <= 2: 127 + exit_code = 0 128 + runtimes = [] 129 + 130 + for program, day, input_file, output_file in to_run: 131 + valid, stdout, cpu_usr = check_solution(program, day, input_file, output_file, pypy) 132 + runtimes.append(cpu_usr) 133 + 134 + print '{}{}{} Day {:02} ({})'.format( 135 + bcolors.OKGREEN if valid else bcolors.FAIL, 136 + '✓' if valid else '✗', 137 + bcolors.ENDC, 138 + day, 139 + format_time(cpu_usr), 140 + ) 141 + print stdout 142 + 143 + if not valid: 144 + exit_code = 1 145 + 146 + if puzzle is None: 117 147 print "Total runtime:", format_time(sum(runtimes)) 118 148 119 149 cutoffs = [