Files
contests/ccc/ccc_42/level4/main.py
T
2026-10-20 01:31:45 +03:00

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'