diff --git a/solver.py b/solver.py old mode 100644 new mode 100755 index 8c3c9e8..a6d76a2 --- a/solver.py +++ b/solver.py @@ -1,5 +1,6 @@ +#!/usr/bin/env python3 + import importlib -import __main__ import os import re import pathlib @@ -8,7 +9,7 @@ import traceback from argparse import ArgumentParser PATH = pathlib.Path(__file__).parent -INPUT_PATH = PATH / "input" +INPUT_PATH = PATH / 'input' class Tests(list): """ @@ -58,22 +59,9 @@ class Solver: self.partI = getattr(mod, 'partI') self.partII = getattr(mod, 'partII') - def format_result(f): - """ - Formatting decorator. Formats and prints a tuple representing - the results of partI and partII. - """ - def aux(*args): - solver = args[0] - ptI, ptII = f(*args) - print("Part One : {}".format(ptI)) - print("Part Two : {}".format(ptII)) - return aux - - @format_result def solve(self, puzzle_input): - """Solves puzzle input and prints the results.""" + """Solves puzzle input and returns pair of solutions""" puzzle_input = puzzle_input.rstrip() if self.preproc != NotImplemented: puzzle_input = self.preproc(puzzle_input) @@ -81,9 +69,8 @@ class Solver: ptII = self.partII(puzzle_input) return ptI, ptII - @format_result def test(self): - """Tests the solver and prints the results.""" + """Tests the solver and returns pair of test results.""" tests = self.tests if self.preproc != NotImplemented: tests = [(self.preproc(str(t)), s1, s2) @@ -94,12 +81,7 @@ class Solver: -def read_input(mod_name): - """Reads input of module with mod_name.""" - name = mod_name + ".txt" - with open(INPUT_PATH / name) as f: - r = f.read() - return r + return r parser = ArgumentParser() @@ -111,60 +93,97 @@ parser.description = \ parser.add_argument('-d', '--day', action='store', type=str, - metavar="DAY[-DAY]", - help="solve puzzle of day DAY or of range DAY-DAY") + metavar='DAY[-DAY]', + help='solve puzzle of day DAY or of range DAY-DAY') + +parser.add_argument('-i', '--input', + action='store', + type=str, + metavar='INPUT', + default=INPUT_PATH, + help='use INPUT as puzzle input') + + parser.add_argument('-t', '--test', action='store_true', help="run tests") -def parse_day_arg(s): +def parse_day_arg(s, mind, maxd): """Parses day argument. Returns a list of days.""" split = s.split('-') if len(split) == 1: return [int(split[0])] elif len(split) == 2: d, D = map(int, split) - return list(range(d, D+1)) + return list(range(max(1, d), min(D+1, 26))) raise ValueError - -if __name__ == '__main__': +def main(): solver_pattern = re.compile("day(\d\d?).py") matches = map(solver_pattern.fullmatch, os.listdir(PATH)) solvers = {int(s.group(1)) : s.group(0) for s in matches if s != None} - - days = list(range(1, 25+1)) + + mind, maxd = min(solvers), max(solvers) + days = sorted(solvers.keys()) args = parser.parse_args() + #Handle day argument if args.day != None: try: - days = parse_day_arg(args.day) + days = parse_day_arg(args.day, mind, maxd) except ValueError: - print("error : invalid format of argument -d/--day") - quit() + return 'invalid format of argument -d/--day' + #Handle input argument + inputs = {} + input_path = pathlib.Path('.') + num_pattern = re.compile(r'\d\d?') + try: + fs = os.listdir(args.input) + input_path /= args.input + for fn in fs: + ns = num_pattern.findall(fn) + if ns == []: + print('warning : ignoring input file {}'.format(fn)) + continue + n = int(ns[0]) + inputs[n] = fn + except FileNotFoundError: + return "input directory or file doesn't exist" + except NotADirectoryError: + if len(days) > 1: + return "input is file" + day = days[0] + inputs[day] = args.input + + #Solve days for d in days: print("=" * 6 + " Day {} ".format(d) + "=" * 6) if d not in solvers: - print("error : no solver for day {}".format(d)) - continue + return "no solver for day {}".format(d) mod_name = solvers[d][:-3] try: mod = importlib.import_module(mod_name) solver = Solver(mod) except: - print("error : bad solver") - print(traceback.format_exc()) - continue + return "bad solver\n\n{}".format(traceback.format_exc()) try: if args.test: - solver.test() + ptI, ptII = solver.test() else: - puzzle_input = read_input(mod_name) - solver.solve(puzzle_input) + if d not in inputs: + return 'no input file' + with open(input_path / inputs[d]) as f: + puzzle_input = f.read() + ptI, ptII = solver.solve(puzzle_input) + print("Part One : {}".format(ptI)) + print("Part Two : {}".format(ptII)) except: - print("error : error in solver") - print(traceback.format_exc()) + return "error in solver\n\n{}".format(traceback.format_exc()) +if __name__ == '__main__': + error = main() + if error != None: + print('error : {}'.format(error))