project-euler/main.py

132 lines
3.7 KiB
Python
Executable File

#!/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()