Создать интерактивную задачу

В рамках интерактивной задачи участнику нужно реализовать код, который будет взаимодействовать с определенной программой (интерактором), и на основе данных от интерактора решить поставленную задачу.

Примеры таких задач: игра в шахматы или шашки, игра в крестики-нолики, игра больше-меньше.

Вы можете добавлять готовые наборы задач в соревнование. Подробнее см. в разделе Настройки набора задач.

1. Создайте задачу

  1. На вкладке Задачи нажмите кнопку Создать задачу.
  2. Придумайте название. Оно будет отображаться в интерфейсе участника.
  3. Нажмите Создать. Откроется страница настроек задачи.
  4. Для более быстрого поиска задачи вы можете указать короткое название — оно не отображается для участников.
  5. Вы можете добавить перевод полного названия на английском языке.
  6. В поле Тип задачи выберите INTERACTIVE_PROBLEM.
  7. Настройте основные параметры таким же образом, как при настройке задачи на программирование.
  8. В разделе Настройки интерактора выберите Тип интерактора: TESTLIB_EXITCODE или EJUDGE_EXITCODE. Эта настройка определяет, какие exitcode к какому вердикту посылки приводят. Поведение системы при различных exitcode аналогично чекерам.

2. Добавьте интерактор

Воспользуйтесь одним из вариантов:

Когда есть исходный файл интерактора, и его необходимо скомпилировать, нажмите кнопку Скомпилировать интерактор. В открывшемся модальном окне необходимо выполнить следующие шаги:

  1. Выберите файл исходного кода из файлов задачи или загрузите его с устройства.
  2. Выберите Компилятор.
  3. Выберите тип интерактора: TESTLIB_EXITCODE или EJUDGE_EXITCODE.

После выбора всех параметров нажмите кнопку Компилировать. Дождитесь завершения процесса компиляции.

Если компиляция завершилась с ошибкой, то никакие настройки задачи не изменяются.

Если компиляция прошла успешно, то автоматически устанавливаются следующие параметры:

  • Тип интерактора — устанавливается выбранный в модальном окне тип.
  • Окружение — устанавливается выбранное значение из поля Компилятор.
  • В разделе Файлы интерактора появляется скомпилированный исполняемый файл.

Если вместо исходников интерактора есть готовый исполняемый файл, или интерактор не требует компиляции (например, для языка Python), то выполните следующие шаги:

  1. В поле Тип интерактора выберите соответствующий тип: TESTLIB_EXITCODE или EJUDGE_EXITCODE.
  2. В поле Окружение выберите подходящий компилятор.
  3. В разделе Файлы интерактора добавьте необходимые файлы:
    • Первым добавьте исполняемый файл интерактора.
    • При необходимости добавьте дополнительные файлы, необходимые для работы интерактора.
  4. Нажмите кнопку Сохранить в правом нижнем углу.

Взаимодействие интерактора с файлом теста

В интерактивной задаче интерактор имеет доступ к файлу теста (например, tests/01). Название файла передается в первом аргументе запуска интерактора.

Взаимодействие интерактора с решением участника

Через потоки stdin и stdout интерактор взаимодействует с решением участника:

  • вывод интерактора в stdout передается в stdin (input.txt) решения участника;
  • вывод решения участника, отправленный в stdout (или output.txt), попадает на stdin интерактора.

Решение участника взаимодействует со стандартными потоками ввода и вывода (и/или с файлами input.txt и output.txt в зависимости от настроек задачи, так же как в задаче на программирование).

Начинать взаимодействие между интерактором и решением участника может как интерактор, так и решение участника.

Завершение работы интерактора и решения участника должно происходить синхронизированно. Обе программы должны ожидать данные на потоке ввода до выполнения определенных условий и затем завершать выполнение по управляющему сигналу от одной из программ. Например, возможны такие варианты:

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

Взаимодействие интерактора с чекером

Интерактор взаимодействует с чекером посредством файла, передаваемого во втором аргументе при запуске интерактора. После завершения работы интерактора и решения участника чекер будет читать значение, записанное в этот файл, и проверять его на соответствие файлу ответа (например, tests/01.a).

Подробнее о работе чекера.

Пример. Задача Угадайка

Задача: определить загаданное число в ограниченном числовом интервале, используя количество попыток меньше определенного.

Решение участника должно предлагать число интерактору и получать от него ответ (less/more/success в зависимости от того, угадала программа загаданное число или предложила большее или меньшее значение). Интерактор будет считать количество попыток и передавать его чекеру перед завершением работы.

Интерактор реализован для exitcode типа TESTLIB_EXITCODE.

Тестовые данные для примера:

  • tests/01 содержит загаданное число — 15;
  • tests/01.a содержит максимально допустимое количество попыток — 50.

Важно

Файл чекера должен содержать переносы строк только вида \n (Unix-переносы). Если переносы будут другого вида (например, \r\n — Windows-переносы), система не сможет запустить файл.

Пример кода интерактора
#!/usr/local/bin/python3.7
import sys

class Verdict:
    OK = 0
    WA = 1
    PE = 2
    FAIL = 10

def calculate(attempt, answer):
    if attempt < answer:
        result = 'more'
    elif attempt > answer:
        result = 'less'
    else:
        result = 'success'

    return result

try:
    with open(sys.argv[1], "r") as input_file:
        answer = input_file.readline().strip()

    with open(sys.argv[2], "w") as output_file:
        tries = 0

        while True:
            tries += 1

            try:
                attempt = input().strip()
            except EOFError:
                print("EOF from participant", file=sys.stderr)
                sys.exit(Verdict.PE)

            if not attempt.isdigit():
                print("Invalid attempt: %s" % attempt, file=sys.stderr)
                sys.exit(Verdict.PE)

            result = calculate(attempt, answer)

            print(result, flush=True)
        
            if result == 'success':
                print(tries, file=output_file)

                print("Found number: %s" % attempt, file=sys.stderr)
                sys.exit(Verdict.OK)
except Exception:
    sys.exit(Verdict.FAIL)
Код чекера
#!/usr/local/bin/python3.7
import sys

class Verdict:
    OK = 0
    WA = 1
    PE = 2
    FAIL = 10

try:
    with open(sys.argv[2], "r") as output_file:
        tries = int(output_file.read())

    with open(sys.argv[3], "r") as answer_file:
        max_tries = int(answer_file.read())

    if tries > max_tries:
        print("Limit exceeded: used %s attempts, max = %s" % (tries, max_tries), file=sys.stderr)
        sys.exit(Verdict.WA)

    print("Used %s attempts of %s" % (tries, max_tries), file=sys.stderr)
    sys.exit(Verdict.OK)
except Exception:
    sys.exit(Verdict.FAIL)
Пример решения участника
import random
import sys

max = 100
min = 0

while True:
    attemptNumber = int((max - min) / 2) + min

    print(attemptNumber, flush=True)

    readInput = input()

    if readInput == 'less':
        max = attemptNumber
    elif readInput == 'more':
        min = attemptNumber
    else:
        sys.exit(0)
Пример решения участника на JavaScript
let max = 100;
let min = 0;

let attemptNumber = parseInt((max - min) / 2);

console.log(attemptNumber);

nextInt = (response) => {
    if (response.indexOf('less') > -1) {
        max = attemptNumber     
    } else if (response.indexOf('more') > -1) {
        min = attemptNumber;
    } else {
        process.exit(0);
    }
    attemptNumber = parseInt((max - min) / 2 + min);

    return attemptNumber;
};

process.stdin.on('data', response => {
    attemptResponse = response.toString();
    attempt = nextInt(attemptResponse);
    console.log(attempt);
});
Написать в службу поддержки