| | h1. Альтернативная установка задач с интерактивным вводом-выводом |
| | |
| | {note:title=Данная инструкция описывает усложнённый процесс установки} |
| | Здесь описан минимальный процесс конверсии задачи, установленной под *StdSwp*, для запуска *tester*'ом. |
| | Это следует делать в случае если требуется использовать групповое тестирование, или для обхода проблем запуска глобально установленного *StdSwp* на новых DelTA'х. |
| | {note} |
| |  | |
| | *Tester* (программа, изначально предназначенная для тестирования задач IOI) с некоторых пор поддерживает тестирование задач с интерактивным вводом-выводом, запускаемых через *StdSwp*. |
| | По умолчанию под Windows используется путь {{D:\DelTA\stdswp}} (под Linux/Mac - локальный файл {{./stdswp}}); однако в конфигурации можно указать путь к альтернативному исполнимому файлу. |
| | Также (в отличие от DelTA) у *tester*'а нет проблем с использованием группового тестирования для интерактивных задач. |
| | |
| | Более подробная инструкция по использованию *tester*'а находится [тут|Установка задач IOI]; |
| | с общей инструкцией по установке задач с интерактивным вводом-выводом (*StdSwp*) можно ознакомиться [здесь|Интерфейс тестирования задач с интерактивным вводом-выводом]. |
| | |
 |  | {warning:title=При несоблюдении данной инструкции тестирование работать не будет!} |
| | Креативная замена важных файлов (из описания ниже) на какие попало (особенно *{{checker.exe}}*, который должен быть скомпилирован из *{{checker.pas}}*) помешает работе системы тестирования. |
| | Также, нижеописанные операции _не рассчитаны_ на [интерактивные задачи NEERC|Установка интерактивных задач NEERC (Питер)]; их можно опознать по файлам *{{coact.exe}}*, *{{coact.bat}}*, *{{Check.jar}}*, *{{Interact.jar}}*, *{{InteractChecker.jar}}* и т.п. |
| | {warning} |
| | |
| | h2. Конверсия интерактивной задачи под Tester |
| | |
| | * файл чекера ({{checker.exe}}) следует переименовать в {{check.exe}} (из-за особенностей реализации tester'а) |
| | * программа взаимодействующая с решением всё так же зовётся player'ом |
| | * файл {{stdswp.cfg}} работает так же как описано в инструкции по StdSwp |
| | * также нужны файлы конфигурации и исходники для tester'а (помимо {{src/CheckLib.pp}} и {{src/TesterLib.pp}}) нижеследующего содержания |
| | |
| | {code:title=src/checker.pas (выполняет запуск отдельного теста)} |
| | Uses |
| | CheckLib; |
| | |
| | BEGIN |
| | Run(ProgName, OutFile); |
| | Prepend(OutFile, 'OK'); |
| | END. |
| | {code} |
| | {code:title=src/tester.pas (выполняет процесс тестирования)} |
| | Uses |
| | TesterLib; |
| | |
| | BEGIN |
| | Body(); |
| | POut(); |
| | END. |
| | {code} |
| | {code:title=task.cfg (передаёт контроль над тестированием задач Tester'у)} |
| | TYPE = USERS |
| | CHECKSUBJECT = FILE |
| | CHECKFILES = {*.*} |
| | CHECKER = 'tester.exe $SOLUTION$' |
| | {code} |
| | {code:title=tester.cfg (управляет поведением Tester'а)} |
| | PreRun = prepare.bat # скрипт компиляции решения! |
| | Program = yes # решение - не библиотека а программа |
| | Interactive = yes # тестировать с интерактивным вводом-выводом |
| | InFile = input.txt # название input-файла |
| | OutFile = output.txt # название output-файла |
| | ExtChecker = check # название оригинального чекера (без расширения) |
| | < |
| | # сюда внести описание групп тестов, по одной на строку |
| | # (для раздельного тестирования достаточно указать число баллов за соответствующий тест) |
| | > |
| | {code} |
| | {code:title=prepare.bat (отвечает за компиляцию файла решения на Pascal, C/C++, Java или Python3)} |
| | @echo off |
| | for %%f in ("%~n1") do ( |
| | if /i %%~xf==.java goto rename |
| | ) |
| | set sol=%1 |
| | set solext=%~x1 |
| | set runnerfile=solution.bat |
| | set runner=%~n1.exe |
| | if not exist 2.in cmd /C unrar -o- x tests |
| | if /i %solext%==.pas goto pascal |
| | if /i %solext%==.ppw24 goto pascal |
| | if /i %solext%==.c goto c |
| | if /i %solext%==.cpp goto cpp |
| | if /i %solext%==.g54 goto cpp |
| | if /i %solext%==.g73 goto cpp |
| | if /i %solext%==.java goto java |
| | if /i %solext%==.py goto py3 |
| | |
| | echo not found |
| | @exit /B 1 |
| | |
| | :pascal |
| | echo %runner%> %runnerfile% |
| | cmd /C D:\DelTA\Lngs\compile_ppw302 %sol% . |
| | @exit /B %errorlevel% |
| | |
| | :c |
| | echo %runner%> %runnerfile% |
| | cmd /C D:\DelTA\Lngs\compile_c73 %sol% . |
| | @exit /B %errorlevel% |
| | |
| | :cpp |
| | echo %runner%> %runnerfile% |
| | cmd /C D:\DelTA\Lngs\compile_g73_old %sol% . |
| | @exit /B %errorlevel% |
| | |
| | :java |
| | echo %runner%> %runnerfile% |
| | cmd /C D:\DelTA\Lngs\compile_java8 %sol% . |
| | @exit /B %errorlevel% |
| | |
| | :py3 |
| | echo %runner%> %runnerfile% |
| | cmd /C D:\DelTA\Lngs\compile_py %sol% . |
| | @exit /B %errorlevel% |
| | |
| | :rename |
| | copy %1 %~n1 |
| | prepare %~n1 |
| | {code} |
| | {code:title=limiter.bat (обёртка вокруг системного Limiter'а)} |
| | @echo off |
| | if "%~4" == "" goto 5 |
| | if "%~5" == "" goto 4 |
| | D:\DelTA\DelTA3DL\limiter %1 %2 "%3 < %4 > %5" %6 > lim.log 2> lim.err |
| | goto :eof |
| | :4 |
| | D:\DelTA\DelTA3DL\limiter %1 %2 "%3 < %4" %6 > lim.log 2> lim.err |
| | goto :eof |
| | :5 |
| | @if "%~5" == "" goto 0 |
| | D:\DelTA\DelTA3DL\limiter %1 %2 "%3 > %5" %6 > lim.log 2> lim.err |
| | goto :eof |
| | :0 |
| | D:\DelTA\DelTA3DL\limiter %1 %2 "%~3" %6 > lim.log 2> lim.err |
| | {code} |
| | |
| | h2. Альтернативный StdSwp |
| | |
| | При наличии проблем с версией StdSwp используемой по умолчанию, можно использовать какую-нибудь альтернативную версию (лично я предлагаю использовать скрипт на Python). |
| | Пример такой конфигурации: |
 | | |
| | {code:title=tester.cfg (добавить перед описанием тестов)} |
| | StdSwp = stdswp-py.cmd |
| | {code} |
| | {code:title=stdswp-py.cmd (обёртка для запуска Python)} |
| | D:\DelTA\Lngs\Python-3.11.3\python stdswp.py %* |
| | {code} |
| | {code:title=stdswp.py (простая реализация, игнорирует stdswp.cfg и подразумевает KillSolution=yes)} |
| | #!/usr/bin/env python |
| | from concurrent.futures import wait, ThreadPoolExecutor, FIRST_COMPLETED |
| | from subprocess import Popen, PIPE |
| | from sys import argv |
| | |
| | def interact (player, solution, kill_player=False, kill_solution=True): |
| | player = Popen(player, stdin=PIPE, stdout=PIPE) |
| | solution = Popen(solution, stdin=player.stdout, stdout=player.stdin) |
| | try: |
| | executor = ThreadPoolExecutor(max_workers=2) |
| | futures = [executor.submit(x.wait) for x in (player, solution)] |
| | wait(futures, return_when=FIRST_COMPLETED) |
| | if kill_player and solution.returncode is not None: |
| | player.terminate() |
| | assert {solution.returncode} <= {0, None} |
| | elif kill_solution and player.returncode is not None: |
| | solution.terminate() |
| | assert {player.returncode} <= {0, None} |
| | else: |
| | assert {player.returncode, solution.returncode} <= {0, None} |
| | wait(futures) |
| | assert {player.returncode, solution.returncode} <= {0, None} |
| | finally: |
| | player.kill() |
| | solution.kill() |
| | |
| | if __name__ == '__main__': |
| | interact(argv[1], argv[2]) |
| | {code} |