| | h1. Библиотека fauxtestlib |
| | h1. Библиотека testlib-dl |
| |
| | Многие из российских задач используют для тестирования checker'ы и [player'ы|Интерфейс тестирования задач с интерактивным вводом-выводом], использующие для общих задач тестирования (ввод-вывод, выдача результата) библиотеку {{testlib.h}}. Для использования этих программ на DL можно воспользоваться её модификацией: {{[fauxtestlib.h|http://dl.gsu.by/images/agulenko/fauxtestlib.rar]}}. |
| {info}Данная модификация основана на {{testlib}} версии 0.9.5 |
| | Многие из российских задач используют для тестирования checker'ы и [player'ы|Интерфейс тестирования задач с интерактивным вводом-выводом], использующие для общих задач тестирования (ввод-вывод, выдача результата) библиотеку {{testlib.h}}. Для использования этих программ на DL можно воспользоваться [модификацией этой библиотеки для DL|https://raw.githubusercontent.com/LeXofLeviafan/testlib-dl/master/testlib.h] (из [форка на Github|https://github.com/LeXofLeviafan/testlib-dl]) -- чекер, скомпилированный с этой библиотекой, будет обрабатывать аргументы командной строки и делать вывод в соответствии с протоколом DL. |
| {info}Данная модификация [имеет несколько релизов|https://github.com/LeXofLeviafan/testlib-dl/tags], последний основан на {{testlib}} версии 0.9.40 |
| {info} |
| | {warning}Модификация не гарантирует 100% совместимости с {{testlib}}; после внесения изменений проверялся только основной функционал, необходимый для тестирования задач, установленных до сих пор с её помощью. |
| | {warning}Модификация совместима с {{testlib}}, но поддерживает только функционал чекеров и player'ов. Также может играть роль конкретная версия библиотеки, а в некоторых олимпиадах может использоваться собственная кастомная модификация -- в частности, форк включает версии для [IOI-2021|https://github.com/LeXofLeviafan/testlib-dl/tree/0.9.37_IOI2021_DL-SNAPSHOT] и [IOI-2022|https://github.com/LeXofLeviafan/testlib-dl/tree/0.9.37_IOI2022_DL-SNAPSHOT]. |
| {warning} |
| | Содержание архива: |
| || Имя файла || Содержимое || |
| | {{fauxtestlib.h}} | Модификация {{testlib}} для использования на DL | |
| | {{DL_I.cpp}}, {{DL_I.h}} | Модификация [библиотеки DL_I|Библиотека DL_I и стандартный чекер для интерактивных задач] для использования fauxtestlib | |
| | {{DL_I_player.cpp}} | Версия файла {{DL_I.cpp}} для player'ов (ненулевой код завершения) | |
| | {{checker.pas}} | Код checker'а, совместимого с player'ами fauxtestlib (использует [библиотеку DLChecker|Библиотека для написания checker'ов на DL]) | |
| Инструкция по применению: |
| # Заменить в файле программы подключение {{"testlib.h"}} на {{"fauxtestlib.h"}} |
| # Поместить в папку с исходниками файлы {{fauxtestlib.h}}, {{DL_I.h}} и {{DL_I.cpp}} (или {{DL_I_player.cpp}}) |
| # Скомпилировать программу; в строку компиляции добавить файл {{DL_I.cpp}} и следующие опции: |
| #* {{\-DCHECKER}} (обязательный для компиляции) |
| #* {{\-DINFILE="_имя-файла_"}} (значение по умолчанию: {{"$player$.in"}}) |
| #* {{\-DOUTFILE="_имя-файла_"}} (значение по умолчанию: {{"$player$.out"}}) |
| # Если это программа-player, для обработки вывода использовать предоставленный checker |
| | Для использования достаточно скомпилировать программу ({{checker.cpp}} или {{interact.cpp}}) положив в ту же папку модифицированный {{testlib.h}} вместо оригинального. (Проверялось только на {{g+\+}} версии 7.3+) |
| |
| | |
| Также для интерактивных задач доступны следующие директивы компилятора (добавляются в параметры компиляции): |
| * {{\-DINFILE="_имя-файла_"}} (файл ввода данных для player'а; значение по умолчанию: {{"$player$.in"}}) |
| * {{\-DOUTFILE="_имя-файла_"}} (файл вывода данных для player'а; значение по умолчанию: {{"$player$.out"}}) |
| * {{\-DLOGFILE="_имя-файла_"}} (файл логирования данных для player'а; по умолчанию отсутствует) |
| * {{\-DPLAYER_ADAPT}} (несовместим с {{\-DLOGFILE}}; включает режим совместимости интерактивных задач -- см. ниже) |
| |
| {code:title=примеры строки компиляции} |
| | g++ -O2 -DCHECKER -o checker checker.cpp DL_I.cpp |
| g++ -O2 -DCHECKER -o player DL_I.cpp interactor.cpp |
| g++ -O2 -DCHECKER -o player DL_I.cpp interact_new.cpp -DINFILE="eq.in" -DOUTFILE="eq.out" |
| | g++ -O2 -o checker checker.cpp |
| g++ -O2 -o player interact.cpp |
| g++ -O2 -o player interact_new.cpp -DINFILE="eq.in" -DOUTFILE="eq.out" |
| {code} |
| | {note}{{{}INFILE}} и {{OUTFILE}} должны содержать корректные строки в формате C; в зависимости от особенностей используемого shell'а, может потребоваться взять их дополнительно в одинарные кавычки (например: {{\-DINFILE='"eq.in"'}}) |
| | {note}{{{}INFILE}}, {{OUTFILE}} и {{LOGFILE}} должны содержать корректные строки в формате C; в зависимости от особенностей используемого shell'а, может потребоваться экранировать их, скажем, взяв дополнительно в одинарные кавычки (например: {{\-DINFILE='"eq.in"'}}) |
| {note} |
| | Для интерактивных задач, помимо исполнимых файлов {{checker}} и {{player}}, [обычно нужно изменить {{task.cfg}} и добавить {{stdswp.cfg}}|Интерфейс тестирования задач с интерактивным вводом-выводом]: |
| {code:title=task.cfg (изменения)} |
| TYPE = INTERACTIVE |
| INFILE = FILE($player$.in) |
| OUTFILE = FILE($player$.out) |
| CHECKER = 1 |
| CHECKSUBJECT = FILE |
| CHECKFILES = {stdswp.cfg} |
| {code} |
| {code:title=stdswp.cfg} |
| KillSolution=Yes |
| {code} |
| |
| h2. Режим совместимости интерактивных задач ({{\-DPLAYER_ADAPT}}) |
| |
| Как правило, в интерактивных задачах большая часть проверок производится player'ом ({{interact.cpp}} в исходном архиве); в этом случае чекеру достаточно просто скопировать содержимое {{$player$.out}} в {{$result$.txt}}, умножив выведенное число очков на максимальное за тест. Однако есть и такие задачи, в которых чекеру необходимо читать как файл ответа жюри ({{1.out}} и т.п.) так и вывод чекера; в этом случае {{testlib}}\-задачи как правило используют костыль в виде отправления этих данных в {{LOGFILE}} (т.к. в {{OUTFILE}} отправляется статус самого тестирования) -- ему соответствует глобальная переменная {{tout}}. |
| |
| В {{testlib-dl}} реализован режим совместимости, позволяющий заметно упростить установку подобных задач; это достигается путём совмещения файлов (а именно, при положительном результате тестирования, вместо комментария в {{OUTFILE}} выводится текст, который должен был отправляться в {{LOGFILE}}. Для его применения требуется выполнить следующее: |
| # перенести команду {{quitf(_ok, ...);}} из player'а в чекер (по обстоятельствам -- это комментарий, который пойдёт в протокол при пройденном тесте); |
| # добавить в player на место этой команды вызов {{dl_playerDone();}} -- это выполняет успешное завершение player'а с выводом данных из {{tout}}; |
| # добавить в чекер в начало (сразу после {{registerTestlibCmd(argc, argv);}}) вызов {{dl_playerCheck();}} -- это инициирует проверку статуса завешения player'а и вывод отрицательного статуса; |
| # компилировать и player и чекер с директивой {{\-DPLAYER_ADAPT}} для включения означенного режима совместимости. |
| |
| | {code:title=оригинальный interact.cpp} |
| #include <cstdint> |
| #include <iostream> |
| #include "testlib.h" |
| |
| using namespace std; |
| |
| int const Q_MAX = 42; |
| |
| int main(int argc, char *argv[]) { |
| registerInteraction(argc, argv); |
| |
| int n = inf.readInt(); |
| int c = inf.readInt(); |
| vector<int> a = inf.readInts(n); |
| |
| cout << n << endl << flush; |
| |
| vector<int> qs; |
| int queries = 0; |
| while (true) { |
| string action = ouf.readToken("!|\?"); |
| if (action == "!") { |
| int res = ouf.readInt(0, n - 1, "c"); |
| tout << "answer " << res << "\n"; |
| tout << "queries " << queries << "\n"; |
| break; |
| } |
| |
| if (++queries > Q_MAX) { |
| cout << "-1\n" << flush; |
| quitf(_wa, "too much queries"); |
| } |
| int x = ouf.readInt(1, n); |
| qs.push_back(x); |
| cout << a[(x - 1 + c) % n] << "\n" << flush; |
| } |
| |
| |
| quitf(_ok, "%d queries processed", n); // BEFORE |
| } |
| {code} | {code:title=адаптированный player.cpp (скомпилированный с \-DPLAYER_ADAPT)} |
| #include <cstdint> |
| #include <iostream> |
| #include "testlib.h" |
| |
| using namespace std; |
| |
| int const Q_MAX = 42; |
| |
| int main(int argc, char *argv[]) { |
| registerInteraction(argc, argv); |
| |
| int n = inf.readInt(); |
| int c = inf.readInt(); |
| vector<int> a = inf.readInts(n); |
| |
| cout << n << endl << flush; |
| |
| vector<int> qs; |
| int queries = 0; |
| while (true) { |
| string action = ouf.readToken("!|\?"); |
| if (action == "!") { |
| int res = ouf.readInt(0, n - 1, "c"); |
| tout << "answer " << res << "\n"; |
| tout << "queries " << queries << "\n"; |
| break; |
| } |
| |
| if (++queries > Q_MAX) { |
| cout << "-1\n" << flush; |
| quitf(_pe, "too many queries"); |
| } |
| int x = ouf.readInt(1, n); |
| qs.push_back(x); |
| cout << a[(x - 1 + c) % n] << "\n" << flush; |
| } |
| |
| |
| dl_playerDone(); // AFTER |
| } |
| {code} | |
| | {code:title=оригинальный checker.cpp} |
| #include <cstdint> |
| #include "testlib.h" |
| |
| using namespace std; |
| |
| typedef long long ll; |
| const int MAX_QUERIES = 42; |
| // BEFORE |
| |
| int readAnswer(InStream &inStream, int n, const vector<int> &a, int c) { |
| inStream.readToken("answer", "_"); |
| int answer = inStream.readInt(0, n - 1, "ans"); |
| |
| inStream.readToken("queries", "_"); |
| int queries = inStream.readInt(0, INT_MAX, "queries"); // BEFORE |
| inStream.ensuref(queries < MAX_QUERIES, |
| "too match queries was done (%d)", queries); |
| |
| return answer; |
| } |
| |
| int main(int argc, char *argv[]) { |
| registerTestlibCmd(argc, argv); |
| |
| // BEFORE |
| int n = inf.readInt(); |
| int c = inf.readInt(); |
| vector<int> a = inf.readInts(n); |
| |
| ll juryAnswer = readAnswer(ans, n, a, c); |
| ll pAnswer = readAnswer(ouf, n, a, c); |
| if (juryAnswer != c) { |
| quitf(_fail, "jury's answer is not equal to c"); |
| } |
| if (pAnswer != c) { |
| quitf(_wa, "participant's answer is not equal to c"); |
| } |
| quitf(_ok, "%lld", juryAnswer); // BEFORE |
| } |
| {code} | {code:title=адаптированный checker.cpp (скомпилированный с \-DPLAYER_ADAPT)} |
| #include <cstdint> |
| #include "testlib.h" |
| |
| using namespace std; |
| |
| typedef long long ll; |
| const int MAX_QUERIES = 42; |
| int queries; // AFTER (for printing success message) |
| |
| int readAnswer(InStream &inStream, int n, const vector<int> &a, int c) { |
| inStream.readToken("answer", "_"); |
| int answer = inStream.readInt(0, n - 1, "ans"); |
| |
| inStream.readToken("queries", "_"); |
| queries = inStream.readInt(0, INT_MAX, "queries"); // AFTER |
| inStream.ensuref(queries < MAX_QUERIES, |
| "too many queries were done (%d)", queries); |
| |
| return answer; |
| } |
| |
| int main(int argc, char *argv[]) { |
| registerTestlibCmd(argc, argv); |
| |
| dl_playerCheck(); // AFTER |
| int n = inf.readInt(); |
| int c = inf.readInt(); |
| vector<int> a = inf.readInts(n); |
| |
| ll juryAnswer = readAnswer(ans, n, a, c); |
| ll pAnswer = readAnswer(ouf, n, a, c); |
| if (juryAnswer != c) { |
| quitf(_fail, "jury's answer is not equal to c"); |
| } |
| if (pAnswer != c) { |
| quitf(_wa, "participant's answer is not equal to c"); |
| } |
| quitf(_ok, "%d queries processed", queries); // AFTER |
| } |
| {code} | |