Блог пользователя MikeMirzayanov

Автор MikeMirzayanov, 12 лет назад, По-русски

Update: Выпущен новый релиз 0.8.5. Скачать новую версию вы можете с сайта проекта. Новая версия внедрена во все сервисы Codeforces и Polygon. Изначально этот пост содержал информацию о девелопмент-версии, но сейчас он используется для описания версии 0.8.5.

Библиотека testlib — самая популярная и развитая библиотека для написания чекеров, генераторов, валидаторов и теперь интеракторов для задач. Первая версия testlib.h была написана мной в 2005-ом, и представляла по большей степени порт testlib.pas на С++. С тех пор многое было улучшено и расширено. В настоящий момент она активно используется в задачах Codeforces, разных этапах Всероссийской олимпиады школьников, многих петрозаводских контестах, всех саратовских соревнованиях и т.д.

Вот основные изменения/улучшения.

Комментарий программы: stdout -> stderr

Теперь системные сообщения testlib-программ (чекеров, валидаторов, интеракторов) направляются в стандартный поток ошибок (stderr) вместо стандартного потока вывода (stdout). Это сделано для идентичности поведения при написании интеракторов, стандартный вывод которых уходит в программу участника и не может использован для вывода системных сообщений. Это может повлиять на некоторые тестирующие системы, будьте внимательны!

Интеракторы

Появилась поддержка интеракторов. Напомню, что интерактор это программа взаимодействующая с решением участника при тестировании интерактивных задач. Интерактор читает одновременно содержимое теста (первый параметр командной строки, в интеракторе — это inf), вывод программы участника (передается на стандартный ввод интерактора, в интеракторе — это ouf), выводит данные в решение участника (в интеракторе выводите в cout или используйте другой вывод, не забывайте flushes), выводит спец. файл для последующей обработки его чекером (вывод в поток tout, который похож на cout).

Пример интерактора:

#include "testlib.h"
#include <iostream>

using namespace std;

int main(int argc, char* argv[])
{
    setName("Interactor A+B");
    registerInteraction(argc, argv);
    
    // reads number of queries from test file
    int n = inf.readInt();
    for (int i = 0; i < n; i++)
    {
        // reads query from test file
        int a = inf.readInt();
        int b = inf.readInt();

        // writes query to the solution, endl makes flush
        cout << a << " " << b << endl;

        // writes output file to be verified by checker later
        tout << ouf.readInt() << endl;
    }

    // exit with message
    quitf(_ok, "%d queries processed", n);
}

readStrictReal/readStrictDouble

У потоков inf/ouf/ans появились функции readStrictReal/readStrictDouble (это одно и то же). Они очень строго читают вещественные числа, применимы в большей степени в валидаторах. Принимают аргументы:

  • минимальное значение числа,
  • максимальное значение числа,
  • минимальное число цифр после десятичной точки (не обязательный),
  • максимальное число цифр после десятичной точки (не обязательный),
  • имя читаемой переменной (для вывода при ошибке).

Еще раз повторюсь — это нововведение нужно для валидаторов.

Защита от потерянных quit/quitf и readEof

Если вы пишите чекер, то легко забыть в какой-нибудь ветке выполнения сделать правильный quit или quitf. Раньше в этом случае чекер скорее всего завершался с exitcode 0 и для участника это означало вердикт "правильный ответ на тест". Теперь testlib автоматически при выходе проверит что был в самом деле вызван quit/quitf (это работает для чекеров) и аварийно завершит работу, если вызова не было. Аналогично, если валидатор не сделал чтение конца файла (readEof), то произойдет аварийное завершение.

quitif

В чекерах (и не только) очень популярна конструкция вида:

if (answer != output)
    quitf(_wa, "Expected %d, found %d", answer, output);

Теперь ее можно записать чуть короче, используя функцию "выйти если" (quitif): quitif(answer != output, _wa, "Expected %d, found %d", answer, output);

Улучшение производительности

Вместо слов короткий пример. Запускаем простой чекер сравнения миллиона целых чисел (вывод и ответ ~ 7.5 мегабайт, для C++ использовался g++ 4.6.1, а для pascal — Delphi 7):

  • предыдущий релиз testlib.h — 2.8 секунды,
  • паскалевский testlib от ИТМО — 3 секунды,
  • паскалевский testlib от СПбГУ — 4 секунды,
  • новая версия testlib.h — 0.35 секунды

Таким образом, можно утверждать, что мнение о медленной работе предыдущих версий — просто миф, а новый testlib быстрее предыдущего примерно в 8 раз!

Аналогичные измерения, если использовать текстовые чекеры (сравнения строк или токенов):

  • предыдущий релиз testlib.h — 1.2 секунды,
  • паскалевский testlib от ИТМО — 3.5 секунды,
  • паскалевский testlib от СПбГУ — 2 секунды,
  • новая версия testlib.h — 0.25 секунды.

Миф подтверждается, а время работы сократилось вдвое. Видимо, на больших файлах скорость работы возросла примерно в 3-6 раз.

Функции-помощники

Добавлены несколько простых полезных функций (некоторые уже были):

  • lowerCase(std::string), upperCase(std::string) — перевести строку в нижний или верхний регистр,
  • trim(std::string) — удаляет слева и справа строки пробелы, табы и символы перевода строк,
  • vtos(T) — шаблонная функция, превращает экземпляр T в строку (медленная, использует stringstream),
  • format(шаблон, параметры), например format("n=%d", 5) — возвращает строку по шаблону и параметрам,
  • englishEnding(int) — правильное окончание для числительного, например englishEnding(2)="nd",
  • compress(std::string) — заменяет длинную строку более короткой, оставляя ее префикс и суффикс, а между ними многоточие, очень полезна при выводе в комментарий какого-либо вывода участника,
  • startTest(int) — используется в мультигенераторах, фактически делает freopen(имя-тест, "r", "stdin"), то последующий вывод перенаправляется в файл с именем равным номеру теста.

Мелочи

Макросы I64, U64

Теперь определены макросы:

#ifdef ON_WINDOWS
#define I64 "%I64d"
#define U64 "%I64u"
#else
#define I64 "%lld"
#define U64 "%llu"
#endif

Пример использования: printf("n=" I64 ", m=%d", n, m). Используйте их для ввода-вывода 64-битных знаковых/беззнаковых чисел через scanf/printf. Хотя такое делать почти не надо, так как чтение происходит через inf/ouf/ans, а при выводе лучше сделать vtos(n).

Случайный элемент коллекции (отрезка итераторов).

Теперь можно в генераторе написать так: cout << rnd.any(v) << endl, где v — это вектор. Так же поддерживается вариант с парой итераторов random_t::any(begin, end), т.е. произвольный элемент массива можно получить так rnd.any(a, a + n).

Issue

Исправлен issue с пространством имен около iter_swap, из за чего были проблемы с компиляцией на некоторых GCC g++.

Новый члены-функции у InStream: readWordTo/readTokenTo/readStringTo/readLineTo

Такие функции были добавлены для ускорения чтения в чекерах (валидаторах и т.д.), где приходится очень много читать. Например, вот так может выглядеть основной код чекера, который сравнивает ответы и вывод по словам (токенам):

    string j, p;
    while (!ans.seekEof() && !ouf.seekEof()) 
    {
        n++;
        ans.readWordTo(j);
        ouf.readWordTo(p);
        if (j != p)
            quitf(_wa, "%d%s words differ - expected: '%s', found: '%s'", n, englishEnding(n).c_str(), compress(j).c_str(), compress(p).c_str());
    }

InStream::quitf

Добавлен InStream::quitf, теперь. Помните, что для потоков ans/inf любая причина выхода, отличная от _fail приводит к _fail. Например, следующий участок кода корректен

int readAnswer(InStream& in)
{
    int n = in.readInt();
    if (n % 2 != 0)
        in.quitf(_wa, "n should be even, but %d found", n);
    return n;
}

int main(int argc, char * argv[])
{
    registerTestlibCmd(argc, argv);
    
    int ja = readAnswer(ans);
    int pa = readAnswer(ouf);
    
    quitif(ja > pa,
        _fail, "expected %d, found %d", ja, pa);
    quitif(ja < pa,
        _wa, "expected %d, found %d", ja, pa);
    
    quitf(_ok, "answer is %d", ja);
}

Если выведено нечетное число в файл с ответом, то будет _fail, а если в вывод участника — то _wa.

Стандартные чекеры/валидаторы

В стандартные поставляемые чекеры были добавлены два чекера: caseicmp.cpp и casencmp.cpp, которые работают в случае стандартной для ACM-ICPC Finals разметки multitestcase. Первый из них поможет, если надо проверять одно целое число на testcase, а второй — если последовательность чисел.

Тестирование

Новый код усиленно тестировался, в частности в полуавтоматическом режиме на большом количестве тестов. Сравнивалось, что stdout/stderr и exitcode чекера не изменился после его компиляции с новым testlib.h.

  • Проголосовать: нравится
  • +111
  • Проголосовать: не нравится

»
12 лет назад, # |
  Проголосовать: нравится +25 Проголосовать: не нравится

Раз уж появился I64, то можно за компанию добавить и U64 ("%I64u"/"%llu") для unsigned long long.

»
12 лет назад, # |
Rev. 6   Проголосовать: нравится 0 Проголосовать: не нравится

У меня не компилится. (Видимо из-за 64битности системы size_t = long int)
ncmp.cpp и testlib.h из транка

Ubuntu 12.10 x64

In file included from ncmp.cpp:1:0:
testlib.h: In member function ‘typename Container::value_type random_t::any(const Container&)’:
testlib.h:454:39: error: call of overloaded ‘next(size_t&)’ is ambiguous
testlib.h:454:39: note: candidates are:
testlib.h:354:9: note: int random_t::next(int)
testlib.h:373:9: note: int random_t::next(unsigned int)
testlib.h:381:15: note: long long int random_t::next(long long int)
testlib.h:397:24: note: long long unsigned int random_t::next(long long unsigned int)
testlib.h:429:12: note: double random_t::next(double)
testlib.h: In member function ‘typename Container::value_type random_t::wany(const Container&, int)’:
testlib.h:644:46: error: call of overloaded ‘wnext(size_t&, int&)’ is ambiguous
testlib.h:644:46: note: candidates are:
testlib.h:485:9: note: int random_t::wnext(int, int)
testlib.h:516:9: note: int random_t::wnext(unsigned int, int)
testlib.h:524:15: note: long long int random_t::wnext(long long int, int)
testlib.h:583:12: note: double random_t::wnext(double, int)
ncmp.cpp: In function ‘int main(int, char**)’:
ncmp.cpp:8:87: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘long unsigned int’ [-Wformat]
»
12 лет назад, # |
Rev. 2   Проголосовать: нравится +5 Проголосовать: не нравится

У меня ещё выводит такие предупреждения:

In file included from yesno.cpp:1:0:
../testlib.h: In destructor «InStream::()»:
../testlib.h:1446:16: предупреждение: deleting object of abstract class type «InputStreamReader» which has non-virtual destructor will cause undefined behaviour [-Wdelete-non-virtual-dtor]
In file included from yesno.cpp:1:0:
../testlib.h: В функции-члене «void InStream::close()»:
../testlib.h:2297:16: предупреждение: deleting object of abstract class type «InputStreamReader» which has non-virtual destructor will cause undefined behaviour [-Wdelete-non-virtual-dtor]

Видимо, в класс InputStreamReader надо добавить

virtual ~InputStreamReader() = 0;

. . .

InputStreamReader::~InputStreamReader() { }
»
12 лет назад, # |
  Проголосовать: нравится +17 Проголосовать: не нравится

Вспомнилась еще одна старая проблема тестлиба, которую можно бы попробовать решить.

Он слишком долго компилируется. Видимо решается это так. Из него выделяется собственно .h, в котором все объявления. А все остальное выделяется в .cpp, который можно один раз скомпилировать в библиотеку.

»
12 лет назад, # |
  Проголосовать: нравится +15 Проголосовать: не нравится

Спасибо за новую версию. Особенно за "в 5 раз быстрее " :-)

На всякий случай дам альтернативную статистику на тему "мнение о медленной работе предыдущих версий — просто миф". У меня под рукой был kitten-testlib (СПБГУ, pas). Вспоминаем, что под fpc скорость работы testlib выше, чем под dcc. Далее статистика:

KITTEN (dcc 6, dcc 7)
  0.03 Compile checker
  5.50 Run checker

KITTEN (fpc 2.2)
  0.07 Compile checker
  1.72 Run checker

VERSION 0.7.4
  2.73 Compile checker
  5.50 Run checker
  2.73 Compile validator
  2.66 Run validator

VERSION 0.8.3
  3.00 Compile checker
  1.30 Run checker
  3.13 Compile validator
  0.80 Run validator

Видно, что старый testlib.h медленней в 3 раза и в infinity раз дольше компилится. Новый testlib.h быстрее в 1.3 раз. И это круто :-)

Тем не менее, это не предел скорости. В качестве эксперимента, возвращаясь со школьных сборов, где почти каждый день новые задачи на 50-100 больших тестов и часто хочется б**о**льшей скорости от валидатора и чекера... Так вот, в качестве эксперимента я написал быстрый аналог testlib.h, совместимый со старым. Далее статистика:

VERSION BURUNDUK1
  0.50 Compile checker
  0.67 Run checker
  0.49 Compile validator
  0.24 Run validator

Принципиальное отличие "быстрого my_testlib.h" в том, что он не использует нигде STL (включая string). Посмотреть код можно здесь my_testlib (readme)

Вся статистика приведена для теста "106 целых чисел по модулю не более 109". Способ запуска: validate < a.in и check emptyinput a.in a.in

Кстати, раньше на сборах для повышение скорости я иногда пользовался вот такой заплаткой: patch

P.S. Для "testlib.h" есть более жесткий тест — это валидация 107 слов, каждое из одной буквы. Версия 0.8.3 работает 5.22 секунды, my_testlib работает 0.87 секунд. Файл весит 20M.

  • »
    »
    12 лет назад, # ^ |
      Проголосовать: нравится +8 Проголосовать: не нравится

    Про FPC не знал, но первый попавшийся чекер после компиляции на FPC стал работать неправильно :-( У FPC есть ряд несовместимостей с Delphi вокруг ввода-вывода и в чекерах это бывает заметно. Мы неоднократно на это напарывались в чекерах для тренировок.

    Добавил в testlib.h функции вида readWordTo/readTokenTo/readStringTo/readLineTo, ncmp стал работать 0.35 сек (предыдущий релиз 2.8 секунды, версия на момент написания поста 0.55 сек), а wcmp стал работать 0.23 сек (предыдущий релиз 1.2 секунды, версия на момент написания поста 0.65 сек).

    Кстати, my_testlib не могу проверить на больших файлах (как в комменте, 20М), так как его буфер переполняется. Попробовал адаптировать ncmp к использованию my_testlib, получилось 0.6 сек.

    Попробовал wcmp на 107 строках с буквой a, он сейчас работает 1.4 сек против 10 секунд для версии 0.7.4.

    Сергей, можно подробнее что такое валидация такого файла и что именно написано в твоем валидаторе?

    • »
      »
      »
      12 лет назад, # ^ |
        Проголосовать: нравится +8 Проголосовать: не нравится

      readWordTo/readTokenTo/readStringTo/readLineTo

      Я правильно понял, что последнее ускорение получено благодаря ним? Если так, это круто, спасибо =)

      Только почему они все вида void readWordTo(std::string& result); ?

      Мне казалось, кучу тормозов создают как раз string-и...

      my_testlib не могу проверить на больших файлах

      Да... там буффер всего 107. Можешь его руками увеличить :-) Я так некрасиво сделал потому что это таки самый быстрый способ "выделить" себе много памяти. Завести глобальный массив. Именно глобальный не static массив.

      Видимо, правильней делать readWordTo(char *s, size_t maxLen), тогда сколько нужно памяти и как ее выделять решит юзер.

      подробнее

      Да, конечно. Вот код валидатора.

      Статистика на моем компе такая: N = 107, testlib.0.8.3 = 5.22 sec, my_teslib = 0.87 sec

      P.S. Меня еще всегда удивляло, что есть quit, quitf, InStream::quit, но нет InStream::quitf. Было неудобно. Отдельное спасибо, что в 0.8.* оно появилось :)

      • »
        »
        »
        »
        12 лет назад, # ^ |
          Проголосовать: нравится +8 Проголосовать: не нравится

        Да, многое ускорилось, когда строки стали поменьше создаваться/копироваться.

        Можно, конечно, еще char*-варианты сделать, но ускорят они уже не сильно.

        Статистика на твоем компе непонятна. Я воспроизвел у себя твой кейс с валидацией. Результат такой (win7, g++ 4.6.1, ssd):

        • my_testlib: 0.75 сек,
        • testlib.h: 1.05 сек,
        • testlib.h: (после замены в валидаторе inf.readWord() на inf.readWordTo(s)) 0.85 сек.

        Компилировал так: g++ -Wall -O2 -Wl,--stack=256000000 -static -o v v.cpp

        Конечно, практически plain C вариант чуток шустрей, но разница не принципиальна.

        • »
          »
          »
          »
          »
          12 лет назад, # ^ |
            Проголосовать: нравится 0 Проголосовать: не нравится

          Разница порядка 10% таки может значить разницу между "judge всё успевает" и "накапливается получасовая очередь". Особенно если учесть психологический эффект: "что-то у меня долго не проверяют — перепошлю, мало ли что".

»
12 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

А за счет чего увеличилась скорость работы в новой версии?

»
12 лет назад, # |
  Проголосовать: нравится -11 Проголосовать: не нравится

Итмо так-то на java чекеры/валидаторы давно переходит

»
12 лет назад, # |
  Проголосовать: нравится +5 Проголосовать: не нравится

Can you try to translate it to English? I can only read the sample code...

»
12 лет назад, # |
  Проголосовать: нравится +5 Проголосовать: не нравится

Встроена ли поддержка нового testlib'а в Contest Wizard? Можно ли уже включать интерактивные задачи в контест из Визарда? Последний раз 2 недели назад, когда я это пробовал, у меня не получилось. Если нельзя, то как все-таки добавлять интерактивные задачи?

  • »
    »
    12 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится

    Да, сейчас все встроено. Обратите внимание, что интерактор читает в качестве теста argv[1], а пишет в argv[2]. Например, в задачах ITMO это не всегда так. Кроме того, если он выводит не exitcode=0, то он трактуется как и exitcode чекера (например, exitcode=1 это wrong answer).

»
12 лет назад, # |
  Проголосовать: нравится +5 Проголосовать: не нравится

А можно где-нибудь почитать, как устроены интерактивные задачи в полигоне? А то я всё никак не пойму, почему решение http://pastebin.com/YkUtyLZt получает WA, а http://pastebin.com/rjHebe82 — TL.

»
12 лет назад, # |
  Проголосовать: нравится +3 Проголосовать: не нравится

В новой версии падают чекеры, которые передают InStream в функцию.
Лечится передаванием InStream& вместо него.
В общем-то это логично, я и раньше не понимал, как оно работало.

  • »
    »
    12 лет назад, # ^ |
      Проголосовать: нравится +3 Проголосовать: не нравится

    Видимо, лучше вообще запретить у него конструктор копирования и оператор присваивания. Чтобы такие чекеры даже не компилировались.

»
12 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

А разъясните, пожалуйста: то, что под Visual C++ 2008 Express Edition не компилируются проверялки/генераторы/... с использованием testlib.h — это проблема настроек студии, проблема конкретной версии студии, или добиться работы таковых генераторов из-под студии вообще сложно и так и задумано?

Конкретные ошибки:

d:\user\.......\testlib.h(2882) : warning C4273: 'rand' : inconsistent dll linkage
        c:\program files\microsoft visual studio 9.0\vc\include\stdlib.h(505) : see previous definition of 'rand'
d:\user\.......\testlib.h(2893) : warning C4273: 'srand' : inconsistent dll linkage
        c:\program files\microsoft visual studio 9.0\vc\include\stdlib.h(512) : see previous definition of 'srand'
d:\user\.......\testlib.h(2884) : error C4716: 'rand' : must return a value
  • »
    »
    12 лет назад, # ^ |
    Rev. 2   Проголосовать: нравится +5 Проголосовать: не нравится

    Quick fix: вставить throw в конец этой функции rand().

    • »
      »
      »
      12 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится

      извините, не понял. можно чуть подробнее?

      • »
        »
        »
        »
        12 лет назад, # ^ |
          Проголосовать: нравится +5 Проголосовать: не нравится

        Дописать строку "throw" в функцию rand() в testlib.h. Студия ругается на то, что функция не содержит return, хотя должна возвращать int.

        • »
          »
          »
          »
          »
          12 лет назад, # ^ |
            Проголосовать: нравится +4 Проголосовать: не нравится

          Ругается она на несоответствие заявленных exception с предыдущим определением функции. Что вроде пофиксили в послдней версии тестлиба. Попробуйте поставить его первым include.

          • »
            »
            »
            »
            »
            »
            12 лет назад, # ^ |
              Проголосовать: нравится 0 Проголосовать: не нравится

            Нет, то был warning, он всегда был и остался. Сейчас же к нему добавилась фатальная ошибка компиляции.

            • »
              »
              »
              »
              »
              »
              »
              12 лет назад, # ^ |
                Проголосовать: нравится 0 Проголосовать: не нравится

              Упс. Незаметил последнюю строку.. Ну под g++ эта проблема полностью полечена сейчас. С MSVS хуже. А о чем первые две ошибки кстати?

  • »
    »
    12 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится

    Вы уверены, что речь о последней версии testlib? Специально установил все версии Visual Studio от 2005 до 2012. Примеры из архива компилируются на всех.

    • »
      »
      »
      12 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится

      У меня не компилируется даже просто "#include "testlib.h"", testlib взял 0.8.5 из свежесозданной в полигоне задачи, компилятор Visual Studio 2012 + November CTP. Может, в полигоне не самая последняя версия?

      • »
        »
        »
        »
        12 лет назад, # ^ |
          Проголосовать: нравится 0 Проголосовать: не нравится

        А как из Полигона взял? Лучше прям из пакета взять, а не копи-пейстнуть из textarea (так могут быть проблемы с кавычками или что-то такое). Кинь мне лог компиляции.

»
12 лет назад, # |
Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится

Мне кажется, было бы удобно в полигоне видеть коммент интерактора, не только коммент чекера. (в Invocations, в т.ч при ОКе)

»
12 лет назад, # |
  Проголосовать: нравится +11 Проголосовать: не нравится

Баг-репорт.
Строчка 321:
return ((nextBits(31) << 32) ^ nextBits(31));
32-й бит всегда получается нулевой.
Должно быть хотя бы:
return ((nextBits(31) << 32) ^ nextBits(32));
Из-за этого при генерации
rnd.next(-(1LL<<31),(1LL<<31)-1);
всегда получаются отрицательные числа.

  • »
    »
    12 лет назад, # ^ |
    Rev. 3   Проголосовать: нравится 0 Проголосовать: не нравится

    Может тогда правильно так: return ((nextBits(32) << 32) ^ nextBits(32));? Ну и проверку снизу ослабить до 64.

    • »
      »
      »
      12 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится

      nextBits(63) используется в next(long long).
      Ваш вариант может возвращать отрицательное число.
      Но там стоит
      do { bits = nextBits(63); } while (bits >= limit);
      так что без разницы.
      Вообще, по идее надо обрезать первые bits битов, чтобы оно соотвествовало названию, но так как она private и используется только c bits = 26, 31, 63, то, опять же, это не так важно.

      • »
        »
        »
        »
        12 лет назад, # ^ |
          Проголосовать: нравится 0 Проголосовать: не нравится

        Исправил на предложенный первоначальный вариант. В ближайшем релизе появится.

        • »
          »
          »
          »
          »
          12 лет назад, # ^ |
            Проголосовать: нравится 0 Проголосовать: не нравится

          А это не плохо, что меняется поведение рандома?

          • »
            »
            »
            »
            »
            »
            12 лет назад, # ^ |
              Проголосовать: нравится 0 Проголосовать: не нравится

            В данном случае это конкретный баг. Видимо, лучше поменять. Понятно, что влияет это на поведение в довольно экзотических случаях вроде того, что указал Anton_Lunyov

»
12 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

Улучшенная защита от случайных выходов в чекере (действительно уменьшающая вероятность случайного, помимо воли автора чекера, вердикта OK) становится головной болью при попытке написать оценивающий чекер, то есть ставящий отдельному запуску решения на отдельном тесте целочисленную оценку от 0 до максЗаТест.

  • »
    »
    12 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится

    Используйте quitp, передавая в него целочисленный балл.

    • »
      »
      »
      12 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится

      Он выходит не с тем кодом возврата. Для этого было бы удобно, если бы можно было переопределять коды. Я что-то тебе писал про это, но ответа не получил.

      • »
        »
        »
        »
        12 лет назад, # ^ |
          Проголосовать: нравится 0 Проголосовать: не нравится

        Я не очень понял, что ты имел ввиду. Давай попробуем еще раз :)

        • »
          »
          »
          »
          »
          12 лет назад, # ^ |
            Проголосовать: нравится 0 Проголосовать: не нравится

          У тебя опредляются константы вроде OK_EXIT_CODE. Я предлагаю их не определять если они уже определены, например из строки компиляции, или как костыль из кода чекера. Это позволит решить большинство таких проблем.

          • »
            »
            »
            »
            »
            »
            12 лет назад, # ^ |
            Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится

            Вроде того, что протаскивать значения из defines вида -DOK_CODE=0 -DWA_CODE=1 в константы, если такие defines определены?

            • »
              »
              »
              »
              »
              »
              »
              12 лет назад, # ^ |
                Проголосовать: нравится 0 Проголосовать: не нравится

              Ну например так. Хотя я имел ввиду чтото вроде

              #ifndef OK_EXIT_CODE
              #define OK_EXIT_CODE 0
              #endif
              
»
10 лет назад, # |
Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится

Есть вопрос по интерактору. Взял из примера интерактор, написал такое авторское решение:

#include <iostream>
using namespace std;

int main(int /* argc */, char** /* argv */)
{
    int a, b;
    while (cin >> a >> b) {
        cout << a + b << endl;
    }
    return 0;
}

При его тестировании получаю FL:

Verdict FL (verdict FL violates solution's tag MAIN) Comment Interactor 'i.cpp' returns exit code 3 [FAIL Answer file not found: "C:\Contest..."]

Что я делаю не так?

UPD. Checker: std::ncmp.cpp

  • »
    »
    10 лет назад, # ^ |
      Проголосовать: нравится +16 Проголосовать: не нравится

    Могу расшарить работающую интерактивку

  • »
    »
    10 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится

    registerInteraction ?

  • »
    »
    10 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится

    Если еще не разобрался, то пошарь на меня эту задачу, я разберусь.

    • »
      »
      »
      10 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится

      А на какой ник?

    • »
      »
      »
      10 лет назад, # ^ |
        Проголосовать: нравится +8 Проголосовать: не нравится

      Там с тестлибом что-то. На 0.9.5 работает, на последней не работает

    • »
      »
      »
      10 лет назад, # ^ |
      Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится

      Я расшарил dalex, он глянул и обновил testlib.h из своей задачки с интерактором и все заработало. С testlib.h все хорошо сейчас?

  • »
    »
    10 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится

    Я хочу разобраться с проблемной, пока не смог воспроизвести. Я пошарил на тебя задачу interactive-a-plus-b, которую только что с нуля создал. В ней всё работает. Как добиться, чтобы сломалось?

»
10 лет назад, # |
  Проголосовать: нравится +16 Проголосовать: не нравится

Когда планируется переезд testlib на github?