#!/usr/bin/env python3 import os import subprocess import re import sys from argparse import ArgumentParser SOLUTIONS = '.solutions.txt' exs = ['py', 'exe'] sol_pattern = re.compile(r'(\d+)_.+\.(?:{})'.format('|'.join(exs))) matches = map(sol_pattern.fullmatch, os.listdir('.')) fs = {int(m.group(1)) : m.group(0) for m in matches if m != None} solved = sorted(fs.keys()) try: with open(SOLUTIONS) as f: lines = (line.split() for line in f.read().rstrip().split('\n')) solutions = {int(line[0]) : ' '.join(line[1:]) for line in lines} except FileNotFoundError: solutions = dict() try: subprocess.run(['pypy', '--version'], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) pypy_installed = True except FileNotFoundError: print('warning : install pypy for faster solving time') pypy_installed = False try: subprocess.run(['pypy3', '--version'], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) pypy3_installed = True except FileNotFoundError: print('warning : install pypy3 for faster solving time') pypy3_installed = False def print_bar(i, count): global print step = 1 while count // step > 80: step += 1 w = count // step j = i // step bar = '[{}{}] {}/{}'.format('#'*(j), '.'*(w - j), i, count) print(bar, end='\r') old_print = print def new_print(x, *args, **kwargs): global print print = old_print print(x + ' '*(len(bar) - len(x)), *args, **kwargs) print = new_print def get_cmd(fn): ext = fn.split('.')[-1] if ext == 'py': with open(fn) as f: fst_line = f.read().lstrip().split('\n')[0] if fst_line[:2] != '#!': return 'python ' shebang = fst_line[2:] if pypy_installed: return shebang.replace('python', 'pypy') + ' ' if pypy3_installed: return shebang.replace('python3', 'pypy3') + ' ' return shebang return './' def run(fn, cmd=None): cmd = get_cmd(fn) if cmd==None else cmd proc = subprocess.run(cmd + fn, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) if len(proc.stderr) > 0: if 'pypy' in cmd: #print('warning : pypy failed. trying cpython', file=sys.stderr) #print(proc.stderr) return run(fn, cmd = cmd.replace('pypy', 'python')) print('error : error while running solution') print(proc.stderr.decode('utf-8'), end='') return proc.stdout.decode('utf-8').rstrip().split('\n')[-1] def solve_all(): print('Num Solution') print('---------------') for i, x in enumerate(solved, start=1): print_bar(i, len(fs)) f = fs[x] r = run(f) if x in solutions.keys() and r != solutions[x]: wrong_err = 'error : wrong solution for {}, expected {}' print(wrong_err.format(x, solutions[x])) print('{:>3d} {}'.format(x, r)) parser = ArgumentParser() parser.description = \ """Solves all Project Euler problems with provided solutions. A solution is an executable or python file in the same directory as this file, with a name of the format XXX_decription.[exe|py], where XXX is the number of the problem. The problems are available at https://projecteuler.net/""" parser.add_argument('--get-solutions', action='store_true', help='downloads solutions for user') def main(): args = parser.parse_args() if args.get_solutions: print('Fetching solutions') else: solve_all() if __name__ == '__main__': main()