188 lines
5.1 KiB
Python
188 lines
5.1 KiB
Python
import os
|
|
import re
|
|
import sys
|
|
|
|
from pathlib import Path
|
|
|
|
from solution import process_inputs, solve
|
|
|
|
|
|
USAGE = """\
|
|
usage: python main.py [--tests=DIR] [--output=DIR] <command> [args]
|
|
|
|
commands:
|
|
single path/to/test.in run a single test file
|
|
range START [END] run tests START..END (inclusive)
|
|
|
|
flags:
|
|
--tests=DIR directory containing test inputs (default: tests)
|
|
--output=DIR directory for outputs (default: output)
|
|
"""
|
|
|
|
|
|
config = {
|
|
"input_name": re.compile(r"in_level-[0-9]_([0-9])-(?:small|large)\.txt"),
|
|
"tests_dir": Path("tests"),
|
|
"output_dir": Path("output")
|
|
}
|
|
|
|
class FillingList(list):
|
|
def __init__(self, iterable=(), fill=None):
|
|
super().__init__(iterable)
|
|
self.fill = fill
|
|
|
|
def __setitem__(self, index, value):
|
|
if isinstance(index, int) and index >= len(self):
|
|
self.extend([self.fill] * (index - len(self) + 1))
|
|
super().__setitem__(index, value)
|
|
|
|
|
|
|
|
def run_single_test(input_path: str, output_path: str):
|
|
print(f"Input path: {input_path}")
|
|
print(f"Output path: {output_path}")
|
|
|
|
with open(input_path, 'r') as f:
|
|
data = f.read()
|
|
|
|
testcases = process_inputs(data)
|
|
solution = solve(testcases)
|
|
|
|
with open(output_path, 'w') as f:
|
|
f.write(solution)
|
|
|
|
|
|
|
|
def run_test_range(start_test: int, end_test: int | None = None):
|
|
print(f"Running test range {start_test} {end_test}")
|
|
input_files = FillingList()
|
|
# Find all input files
|
|
for filename in os.listdir(config['tests_dir']):
|
|
path = os.path.join(config['tests_dir'], filename)
|
|
if not os.path.isfile(path):
|
|
continue
|
|
m = config['input_name'].fullmatch(filename)
|
|
if m:
|
|
input_files[int(m.group(1))] = {
|
|
"path": path,
|
|
"filename": filename,
|
|
}
|
|
else:
|
|
print(f"{filename} does not match, skipping")
|
|
|
|
if not end_test:
|
|
end_test = len(input_files)
|
|
|
|
# Run solution for each discovered input file
|
|
for i, input_file in enumerate(input_files[start_test:(end_test + 1)]):
|
|
if not input_file:
|
|
print(f'WARNING: Could not find test #{i}')
|
|
print(f'running test {i} looking at path {input_file['path']}')
|
|
|
|
output_name = input_file['filename'].replace('in', 'out')
|
|
output_path = config['output_dir'] / output_name
|
|
|
|
run_single_test(input_file['path'], output_path)
|
|
|
|
|
|
|
|
def parse_argv(argv):
|
|
"""Split argv into ({flag: value}, [positional]). Supports --k=v and --k v."""
|
|
flags, positional = {}, []
|
|
i = 0
|
|
while i < len(argv):
|
|
arg = argv[i]
|
|
if arg.startswith("--"):
|
|
if "=" in arg:
|
|
key, value = arg[2:].split("=", 1)
|
|
else:
|
|
key = arg[2:]
|
|
i += 1
|
|
if i >= len(argv):
|
|
raise SystemExit(f"error: flag --{key} requires a value\n\n{USAGE}")
|
|
value = argv[i]
|
|
flags[key] = value
|
|
else:
|
|
positional.append(arg)
|
|
i += 1
|
|
return flags, positional
|
|
|
|
|
|
|
|
def main(argv=None):
|
|
argv = sys.argv[1:] if argv is None else argv
|
|
flags, positional = parse_argv(argv)
|
|
|
|
unknown = set(flags) - {"tests", "output"}
|
|
if unknown:
|
|
raise SystemExit(f"error: unknown flag(s): {', '.join(sorted(unknown))}\n\n{USAGE}")
|
|
|
|
config["tests_dir"] = Path(flags.get("tests", config["tests_dir"]))
|
|
config["output_dir"] = Path(flags.get("output", config["output_dir"]))
|
|
os.makedirs(config["output_dir"], exist_ok=True)
|
|
|
|
if not positional:
|
|
raise SystemExit(USAGE)
|
|
|
|
command, *args = positional
|
|
|
|
if command == "single":
|
|
if len(args) != 1:
|
|
raise SystemExit(f"error: 'single' takes exactly one path\n\n{USAGE}")
|
|
input_path = Path(args[0])
|
|
if not input_path.is_file():
|
|
raise SystemExit(f"error: no such file: {input_path}")
|
|
output_path = Path(config["output_dir"]) / input_path.with_suffix(".out").name
|
|
run_single_test(str(input_path), str(output_path))
|
|
|
|
elif command == "range":
|
|
if len(args) not in (1, 2):
|
|
raise SystemExit(f"error: 'range' takes START [END]\n\n{USAGE}")
|
|
try:
|
|
start_test = int(args[0])
|
|
end_test = int(args[1]) if len(args) == 2 else None
|
|
except ValueError:
|
|
raise SystemExit(f"error: range bounds must be integers\n\n{USAGE}")
|
|
run_test_range(start_test, end_test)
|
|
|
|
else:
|
|
raise SystemExit(f"error: unknown command {command!r}\n\n{USAGE}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|
|
|
|
|
|
|
|
|
|
# Path: solution.py
|
|
# def process_inputs(inputs):
|
|
# lines = inputs.split('\n')
|
|
# lines = iter(lines)
|
|
|
|
# testcases_num = int(next(lines))
|
|
# testcases = []
|
|
|
|
# for i in range(testcases_num):
|
|
# line = next(lines)
|
|
|
|
# testcase = {}
|
|
|
|
# return [{'testcase': 'testcase1'}]
|
|
|
|
|
|
|
|
|
|
# def solve(testcases):
|
|
# res = ''
|
|
# for i, testcase in enumerate(testcases):
|
|
# print('Solving testcase #', i + 1)
|
|
# res += process_testcase(**testcase) + '\n'
|
|
|
|
# return res
|
|
|
|
|
|
|
|
# def process_testcase(arg1, args):
|
|
# return 'solution'
|