Создать интерактивную задачу
В рамках интерактивной задачи участнику нужно реализовать код, который будет взаимодействовать с определенной программой (интерактором), и на основе данных от интерактора решить поставленную задачу.
Примеры таких задач: игра в шахматы или шашки, игра в крестики-нолики, игра больше-меньше
.
Вы можете добавлять готовые наборы задач в соревнование. Подробнее см. в разделе Настройки набора задач.
1. Создайте задачу
- На вкладке Задачи нажмите кнопку Создать задачу.
- Придумайте название. Оно будет отображаться в интерфейсе участника.
- Нажмите Создать. Откроется страница настроек задачи.
- Для более быстрого поиска задачи вы можете указать короткое название — оно не отображается для участников.
- Вы можете добавить перевод полного названия на английском языке.
- В поле Тип задачи выберите
INTERACTIVE_PROBLEM. - Настройте основные параметры таким же образом, как при настройке задачи на программирование.
- В разделе Настройки интерактора выберите Тип интерактора:
TESTLIB_EXITCODEилиEJUDGE_EXITCODE. Эта настройка определяет, какиеexitcodeк какому вердикту посылки приводят. Поведение системы при различныхexitcodeаналогично чекерам.
2. Добавьте интерактор
Воспользуйтесь одним из вариантов:
Когда есть исходный файл интерактора, и его необходимо скомпилировать, нажмите кнопку Скомпилировать интерактор. В открывшемся модальном окне необходимо выполнить следующие шаги:
- Выберите файл исходного кода из файлов задачи или загрузите его с устройства.
- Выберите Компилятор.
- Выберите тип интерактора: TESTLIB_EXITCODE или EJUDGE_EXITCODE.
После выбора всех параметров нажмите кнопку Компилировать. Дождитесь завершения процесса компиляции.
Если компиляция завершилась с ошибкой, то никакие настройки задачи не изменяются.
Если компиляция прошла успешно, то автоматически устанавливаются следующие параметры:
- Тип интерактора — устанавливается выбранный в модальном окне тип.
- Окружение — устанавливается выбранное значение из поля Компилятор.
- В разделе Файлы интерактора появляется скомпилированный исполняемый файл.
Если вместо исходников интерактора есть готовый исполняемый файл, или интерактор не требует компиляции (например, для языка Python), то выполните следующие шаги:
- В поле Тип интерактора выберите соответствующий тип: TESTLIB_EXITCODE или EJUDGE_EXITCODE.
- В поле Окружение выберите подходящий компилятор.
- В разделе Файлы интерактора добавьте необходимые файлы:
- Первым добавьте исполняемый файл интерактора.
- При необходимости добавьте дополнительные файлы, необходимые для работы интерактора.
- Нажмите кнопку Сохранить в правом нижнем углу.
Взаимодействие интерактора с файлом теста
В интерактивной задаче интерактор имеет доступ к файлу теста (например, 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);
});