Система невидимой автоматической проверки заданий LightPT. Часть 1
В PascalABC.NET встроена система автоматической проверки LightPT, которая позволяет легко составлять автоматически проверяемые задания.
Рассмотрим данный процесс на примере.
Начальные действия
Чтобы задания проверялись автоматически, необходимо создать Урок с заданиями. Урок представляет собой папку, в которой находятся .pas-файлы - заготовки с формулировками заданий, а также специальный файл lightpt.dat. Этот файл может быть пустым или содержать название урока. Именно этот файл является маркером того, что все задания в этой папки будут проходить через невидимую проверяющую систем
Итак, создадим папку Lesson1 и в ней файл lightpt.dat, в котором напишем одну строчку в кодировке Windows 1251: Урок-1. Задания на массивы
Создание задания
Теперь создадим в этой папке первый файл с заданием ArrTask1.pas со следующим содержимым:
Обязательно сохраним указанный файл в папку с уроком.
Создание модуля проверки заданий
Теперь создадим модуль, который будет проверять все выполненные задания в уроке (в олимпиадном программировании такие подпрограммы называются чекерами). Для этого в той же папке создадим файл Tasks.pas со следующим содержимым (важно использовать именно это имя файла):
Вот полный текст проверяющего модуля Tasks:
unit Tasks; uses LightPT; procedure CheckTaskT(name: string); begin case name of 'ArrTask1': begin end; end; end; initialization CheckTask := CheckTaskT; end.
Код проверки задания
Далее напишем самую главную часть - код проверки:
unit Tasks; uses LightPT; procedure CheckTaskT(name: string); begin case name of 'ArrTask1': begin var N := Int; CheckData(Input := |cInt| + |cRe| * N); var a := ReArr(N); var cnt := a.Count(x -> x > 5); CheckOutput(cnt); end; end; end; initialization CheckTask := CheckTaskT; end.
1. Введенное учеником первое целоезначение, характеризующее размер массива, запоминается в переменной N
var N := Int;
2. В процедуре CheckData указывается, что входные данные Input должны состоять из целого числа (константа cInt) и N вещественных чисел (константа cRe). Все данные объединяются в массив входных данных с помощью конструктора массива |cInt| + |cRe| * N.
CheckData(Input := |cInt| + |cRe| * N);
Константы cInt, cRe, cStr, cBool, cChar хранят в себе элементарные типы значений - именно из них конструируются типы входных данных и соответствие именно этим типам проверяются чекером у входных данных.
Если мы введем неверное количество входных данных или неверно укажем их типы, система проверки выведет соответствующее сообщение об ошибке.
3. С помощью функции ReArr введенные учеником N вещественных значений заносятся в массив a
var a := ReArr(N);
4. Количество элементов, больших 5, вычисляется с помощью стандартного метода массива a.Count и заносится в переменную cnt.
var cnt := a.Count(x -> x > 5);
5. Проверка правильности вывода осуществляется с помощью процедуры CheckOutput:
CheckOutput(cnt);
Решение задания учеником
Теперь всё готово к выполнению задания под управлением системы невидимой автоматической проверки.
Закроем среду PascalABC.NET и промоделируем действия ученика на уроке.
Ученик обязательно должен запустить PascalABC.NET из файла урока щелчком мыши на файле с заданием:
Кнопка белого человечка на тулбаре является признаком того, что задание находится под управлением системы невидимой проверки.
Наберем часть решения и запустим:
Мы видим, что система автоматической проверки начала свою работу и показала, что необходимо ввести дополнительные данные.
Введем массив N вещественных любым доступным способом:
Здесь мы ошиблись - надо ввести вещественный массив:
Это сообщение системы невидимой проверки выводится серым, что означает, что ошибки нет, и мы на верном пути.
Попытаемся обмануть систему и выведем неверное значение:
Система невидимой проверки показала, что результат неверен.
И наконец правильно решим задачу:
Система невидимой проверки зеленым вывела, что задание выполнено.
Поздравляем! Вы составили и выполнили первое задание под управлением системы невидимой автоматической проверки!
Составление нескольких тестов
Ученик может обмануть данный алгоритм проверки. Например, он может ввести три единицы и не записывая алгоритм, вывести 0 в качестве результата:
Это означает, что проверка задания составлена некачественно.
Вернемся к заданию и добавим к проверке дополнительные тесты. Сделать это просто:
GenerateTests(10,tInt(N,N) + tRe(1,10) * N);
означает "сгенерировать 10 автоматических тестов, каждый тест в качестве входных данных будет содержать одно целое число в диапазоне от N до N (то есть, само число N) и затем N вещественных чисел в диапазоне от 1 до 10".
Здесь tInt, tRe, tChr, tBoo - это функции, которые вызываются только при генерации тестов для задания алгоритма генерации случайного тестового входного значения нужного типа в указанном диапазоне.
После этого запуск предыдущего неправильного решения ученика приведет к следующему выводу:
- Ученик попытался обмануть систему, ввел определённые данные, не написал алгоритм и вывел результат для этих данных.
- Система невидимой проверки проверила его решение и посчитала его верным.
- Система невидимой проверки не поверила ученику и предложила 10 своих тестов, где в качестве входных данных сгенерировала случайные значения по спецификации tInt(N,N) + tRe(1,10) * N
- На одном из таких тестов 3 7 8 5 (сгенерировано автоматически 3 вещественных числа 7 8 5) система "поймала" ученика, вывела данные теста, вывела неправильный ответ ученика и правильный результат, который необходимо было вывести если бы эти данные были бы введены.
То есть, систему проверки обмануть не удалось. Теперь только правильный алгоритм будет оценен чекером как выполненное задание:
Протокол выполнения заданий учеником
Протокол выполнения заданий учеником хранится в файле db.txt в папке урока. Он имеет вид:
Урок-1. ArrTask1 2023-11-01 11:36:05Z IOError InputCount(1,4) Урок-1. ArrTask1 2023-11-01 11:36:59Z IOError InputCount(1,4) Урок-1. ArrTask1 2023-11-01 11:38:05Z IOError InputCount(1,4) Урок-1. ArrTask1 2023-11-01 11:56:53Z IOError InputCount(1,4) Урок-1. ArrTask1 2023-11-01 11:59:13Z IOError InputType(2,real,integer) Урок-1. ArrTask1 2023-11-01 12:00:05Z IOError OutputCount(0,2) Урок-1. ArrTask1 2023-11-01 12:46:46Z BadSolution NoInfo Урок-1. ArrTask1 2023-11-01 12:48:19Z Solved NoInfo
При каждом запуске в конец этого файла добавляется строка, характеризующая текущий запуск. Она содержит имя урока, имя задания, время запуска и результат запуска - степень выполнения и дополнительные параметры. По данному содержимому видно, что ученик 4 раза запустил программу, в которой было введено всего одно число, после этого он ввел неверный тип при вводе массива (ошибка InputType(2,real,integer) во втором элементе), затем он выводил неверное количество данных (ошибка OutputCount(0,2) - выведено 0, а надо вывести 2 элемента), после этого неправильно решил задание (BadSolution) и наконец решил правильно (Solved).
Разработка следующих заданий урока
Следующие задания разрабатываются существенно проще.
Скажем, мы добавляем в папку урока новое задание ArrTask2.pas с формулировкой задания в комментарии. Тогда чтобы оно стало проверяемым, мы также должны добавить в модуль Tasks.pas строки
Мы также должны добавить в модуль Tasks.pas строки
'ArrTask2': begin // Здесь - текст чекера end;
Заключение
В данной статье показано использование системы невидимой автоматической проверки, имеющей существенные отличия от всех известных систем автоматической проверки:
1. Разработка заданий осуществляется в той же среде, что и решение заданий учеником
2. Разработка заданий проста и для последующих задач по данной теме занимает 2-3 минуты на задание.
3. Задания проверяют типы при вводе-выводе (в системах олимпиадного тестирования из файла считываются лишь текстовые данные, что крайне бедно)
4. Решение задания учеником выполняется непосредственно в среде PascalABC.NET без каких-то дополнительных действий. Текст программы не надо копировать на интернет-страницу сетевой тестирующей системы.
5. Задание проверяется в момент запуска программы ученика - нет ожидания ответа от сервера.
В следующих статьях о системе LightPT мы рассмотрим более сложные случаи составления заданий.