Инструкция по поиску и установке программистских задач 3

Автор: Дмитрий Петрушенко

Содержание

Что представляет собой задача по информатике на DL.
Условие задачи (файл tasl.htm).
Тесты к задачам и некоторые особенности тестирования.
Инструкция для тестирования (файл task.cfg).
Предназначение и структура файла task.xml.
Постановка задач требующих поясняющие изображения.
Постановка задач требующих checker.
Компоновка и отправка архива.
Проблемы в постановке.

Что представляет собой задача по информатике на сайте дистанционного обучения DLB.

Перечень задач на сайте Дистанционное обучение DLB очень широк. Это задачи по проектированию цифровых устройств, задачи по программированию микроконтроллеров, теория, тесты по английскому языку и, конечно же, задачи по информатике. Как правило, задача по информатике представляет собой следующий набор файлов:

  1. Условие задачи - файл task.htm.
  2. Тесты для данной задачи.
  3. Файл task.cfg.
  4. Файл task.xml.
При необходимости задача может содержать поясняющие изображения и checker (специальная программа, анализирующая неоднозначность решения). Назначение каждого из этих файлов будит, рассмотрено ниже. В зависимости от задачи, она может содержать какие либо другие файлы, не содержать тестов или скорее файлы, перечисленные выше, будут иметь свои особенности, отличающие их от большинства типичных задач. Эти особенности будут обуславливать способ тестирования решения пользователя. В настоящее время разработана система загрузки задач и деревьев задач на сайт при помощи архива. Для этого необходимо иметь права редактора курса или быть одним из авторов задач на специальном курсе по закачке задач. Такая возможность имеется на странице редактора курса (ссылка "установка задач"), или на специальном курсе для установки задач под ссылкой "редактор". Эти возможности позволяют пользователю самому осуществлять постановку задач на сайте. Всё, что требуется от пользователя - это скомпоновать архив в надлежащем виде и отправить архив на загрузку. Каждой задаче, находящейся в архиве, будет присвоен уникальный номер. Этот уникальный номер - имя каталога, в котором будет содержаться данная задача. Тесты вместе с task.cfg файлом, checker-ом и другими файлами хранятся в папке \\NEWIT_server\dldata\Archives\номер_задачи, условие задачи хранится в папке \\NEWIT_server\dldata\Tasks\номер_задачи, рисунки в папке \\NEWIT_server\dldata\Images. При необходимости изменить что-либо в любой задаче, можно без труда найти по уникальному номеру условие, тесты, или другие файлы (кроме task.xml, который прописывается в базе данных и затем уничтожается). Такая структура хранения задач довольно проста и удобна в использовании.


Условие задачи (файл task.htm).

Условие задачи пишется на html-е. В условии содержится непосредственно условие задачи (при необходимости должно содержать поясняющий рисунок), а также информация по тестированию данной задачи. Например: откуда читать входные данные и куда помещать результат, лимит по времени (максимальное количество секунд которое предоставляется решению пользователя на прохождение каждого теста) при выходе за этот лимит тестирование по данному тесту прекращается и происходит переход к другому тесту. Также условие может содержать и другую информацию в зависимости от её контекста. При наличии условия задачи на английском языке оно так же должно предоставляться пользователю.

Пример условия:

ROI_2004 Предварительные: Howmany.

Input file: how.in
Output file: how.out
Time_limit: 3

Howmamy.

Найдите количество целых чисел, лежащих между 1 и N (включительно) и не делящихся ни на a, ни на b.

Ввод:

Вам выдано 5 входных файлов. В каждом входном файле записаны целые положительные числа N, a и b.

Вывод:

В каждый выходной файл выведите искомое количество.

Пример:

how.in
6 2 3
how.out
2
При написании условия на html-е необходимо знать самый минимум информации.
  1. Понятие тега:
    Тег HTML состоит из следующих друг за другом в определенном порядке элементов: Пример: <h4>ТЕГ</h4>
  2. Основные теги:

Пример html файла:

<html>
<h4 align=center>
ROI_2004
Предварительные: Howmany.</h4>
<table align=center> 
<tr>
<td>Input file:
<td>how.in
<tr>
<td>Output file:
<td>how.out
<tr>
<td>Time_limit:
<td>3
</tr>
</table>
<h4>Howmamy.</h4>
Найдите количество целых чисел, лежащих между 1 и N (включительно) и не делящихся ни на a, ни на b. 
<h4>Ввод:</h4>
Вам выдано 5 входных файлов. В каждом входном файле записаны целые положительные числа N, a и b. 
<h4>Вывод:</h4>
В каждый выходной файл выведите искомое количество. 
<h4>Пример:</h4>
<pre>
how.in
6 2 3
how.out
2
</pre>
</html>


Тесты к задачам и некоторые особенности тестирования.

Для проверки любой задачи необходимо некоторое количество тестов, c помощью которых и будет определяться правильность решения той или иной задачи. Как правило, для задач требуются входные и выходные тесты. Пользователь будит читать данные из входных тестов и выводить ответ в свой выходной файл (имена этих файлов всегда оговариваются в условии задачи). После того как пользователь выводит ответ в выходной файл, и его программа отрабатывает, происходит сверка результата его решения с решением находящимся в выходном тесте. Тесты представляют собой текстовые файла, в которых находятся входные или выходные значения для данной задачи. Количество тестов, в различных задачах, может отличаться. Как говорилось выше, набор тестов включает в себя как входные, так и выходные тесты. Но при наличии специальной тестирующей программы входные или выходные (или те и другие) файлы могут отсутствовать. Бывают задачи, у которых существует не одно, а несколько решений при одних и тех же входных данных. Такие задачи требуют checker (специальная программа, предназначенная для проверки неоднозначных решений, понятие checker-а будит подробнее рассмотрено ниже). Тесты на DL должны называться именами 1.in, 2.in, 3.in: (для входных тестов) и 1.out, 2.out, 3.out: (для соответствующих выходных тестов).

Пример тестов:
Входной файл (1.in): 1 2 3
Выходной файл(1.out):    1
Бывают задачи, которые в силу своих особенностей могут требовать файлы с дополнительной информацией. В настоящее время очень модными становятся задачи, когда пользователю предоставляются уже готовые процедуры и функции, с помощью которых он должен организовать решение поставленной перед ним задачи. В таком случае пользователю предоставляются лишь имена функций, их описание, заголовочный файл и уже готовый объектный файл с откомпилированными функциями. Как правило, данный объектный в данном объектном файле фиксируется количество вызовов каждой функции и процедуры, а результаты записываются в специальный файл. Для тестирования такой задачи нельзя обойтись без специальной программы, которая бы учитывала эти особенности при вычислении балов по тесту.


Инструкция для тестирования - файл task.cfg.

По сути, файл task.cfg представляет собой непосредственную инструкцию для тестирования задачи. Так как особенности тестирования бывают различными (наличие checker-а, отправка на тестирование текстовых файлов и др.), поэтому существуют различия и между task.cfg файлами. Следует учитывать, что файл task.cfg должен быть в кодировке Windows. Порядок строк не существенен. Краткий формат файла task.cfg.

Строка (строки) в task.cfg Комментарии
[COUNT_BY = TASK|TEST] Баллы начисляются за задачу или по тестам
[TIME_LIMIT = "время в секундах"] Ограничение работы решения по времени на каждый тест
[INPUT = { FILE(filename) | CON | DIRECTORY }] Имя входного файла, ввод с клавиатуры, или ввод из файлов в каталоге.
[OUTPUT = {FILE(filename) | CON}] Имя выходного файла или вывод на экран
[TESTS_BEGIN "стоимость первого теста" "стоимость второго теста" : "стоимость последнего теста" TESTS_END ] Количество баллов за прохождение каждого теста. Тесты могут группироваться. В этом случае баллы даются, только если пройдены все тесты группы. Все баллы кроме последнего в группе отрицательны (см. пример)
[CHECKER = 'Специальная'] Эта строка указывает на то, что необходимо использовать чекер.
[CHECKFILES = {"маска файла"} CHECKSUBJECT = FILE] Здесь указываются необходимые файлы для чекера.
[TYPE = USERS CHECKER = '"строка запуска проверяющего модуля"' EXTTYPE = 'Пользовательская'] Запуск внешнего модуля для проверки.

Пример task.cfg файла:

count_by=test
input =File(How.in)
output =File(How.out)
time_limit=3
tests_begin
20
20
20
20
20
tests_end
  1. Count_by=test - означает, что количество балов, которые набрал пользователь, будет суммой балов всех пройденных тестов. Вместо count_by=test может стоять count_by=task, что означает, что пользовательская задача может получить лишь только максимальное количество баллов, например 100. Для этого необходимо, что бы задача прошла все тесты.
  2. input=File(How.in) output=File(How.out) - означает, что пользователь должен читать входные данные из файла How.in и выводить результат в файл How.out.
  3. time_limit=3 - означает, что решение пользователя будит тестироваться максимум 3 секунды, при выходе за этот лимит задача будет снята с тестирования. Пользователю выводится сообщение, что задача не прошла по времени.
  4. test_begin
    20
    20
    20
    20
    20
    test_end - этот блок означает, что в задаче пять тестов, стоимость каждого из них 20 баллов. При тестировании, если задача проходит тест соответствующее количество балов будит прибавляться к общей сумме балов за задачу. В нашем случае при каждом пройденном тесте сумма балов будит увеличиваться на 20.


Предназначение и структура файл task.xml.

Файл task.xml требуется для того, что бы соответствующее имя задачи, количество баллов за задачу и т.д., прописались в базе данных. Имя задачи будит отображаться в соответствующем разделе в дереве задач в системе DLB. Файл task.xml должен быть в windows-кодировке и содержать всего один тег:
<taskname="русское имя задачи" ename="english task name" author="Дмитрий"cost="100" type="1"/> Свойство author - необязательное. Все остальные необходимо указать. Если задача имеет только входные тесты, то необходимо добавить свойство tests="in" Если только выходные тесты, то tests="out" По умолчанию задача должна иметь одинаковое количество входных и выходных файлов. Здесь type - тип задачи. 1 - задачи по программированию, HLCCAD, Winter, IEESD 4 - задачи по математике 10 - английский язык


Постановка задач, требующих поясняющие изображения.

При необходимости некоторые задачи могут содержать поясняющие графические изображения к условию (для наиболее точного и корректного понимания поставленной задачи). В таком случае изображение должно быть прикреплено к html-файлу. Для этого необходимо:

  1. Создать каталог с именем images, куда помещается данное изображение (пусть для примера файл называется picture.gif).
  2. Изменить html-файл таким образом, чтобы в месте, где необходимо поместить изображение, находился следующий текст:
    <center>
    <table>
    <tr><td><img src="images/picture.gif"></td></tr>
    <tr><td align=center>Рис.</td></tr>
    </table>
    </center>
    
Здесь тег <img> служит для внедрения графики на страницы.
Атрибут src - обязательный атрибут, указывающий URL рисунка.
leftВыравнивание по левому краю
rightВыравнивание по правому краю
center Выравнивание по центру
bottom Выравнивание по нижнему краю
top Выравнивание по верхнему краю
middle Выравнивание по середине
Аналогичным образом могут подкрепляться к условию другие файлы. Пусть необходимо предоставить пользователю специальный модуль - module.h для задачи. В файле task.htm достаточно прописать строку вида <a href="images\имя_каталога\module.h">module.h</a>. Имя каталога надо указывать такое же как и уникальный номер задачи, что бы можно было быстро найти соответствующий файл и заменить его или исправить при необходимости.


Постановка задач требующих checker.

Часто встречаются задачи, которые при одних и тех же входных данных могут иметь множество решений. В таких случаях задача должна содержать специальную программу checker, которая будит самостоятельно определять правильность или неправильность решения пользователя (при проверки задач, которые не требуют checker, правильность решения возможно лишь при полном соответствии верного решения и решения пользователя). Особенности написание checker-а зависят исключительно от задачи, но все они должны иметь следующие общие для всех checker-ов (здесь говориться о checker- ах предназначенных для DLB) характеристики:

  1. На DL любой checker запускается со следующими параметрами:
  2. После того как checker отработает, он должен выводить в файл $result$.txt информацию по тестированию задачи (вывод и запуск checker-а осуществляется для каждого теста).
  3. Checker требует особый task.cfg файл, который должен содержать строку следующего вида checker='Специальная', эта строка будит говорить тестирующей программе, что задача использует checker.

Пример task.cfg файла:

COUNT_BY=TEST
input =File(programm.in)
output =File(programm.out)
time_limit=15
checker='Специальная'
tests_begin
20
20
20
20
20
tests_end

Пример checker-а.

Для более наглядного, представления работы checker-а рассмотрим, например такую задачу, когда ответом является дробное число и допускается отклонение от истинного значения максимум на 0.5.
Текст программы.          
#include 
#include 
int main(int argc,char **argv)
{
  FILE *sol,*user,*res;
  float a,b;
  sol=fopen(argv[2],"r");                //открытие родного решения
  user=fopen(argv[3],"r");               //открытие решения пользователя
  res=fopen("$result$.txt","w");         //создаем файл $result$.txt
  fscanf(sol,"%f",&a);
  fscanf(user,"%f",&b);
  if (fabs(a-b)>0.5)
    {
     fprintf(res,"%d\n",0);              //записываем в $result$.txt 0
     fputs("Wrong answer!!!",res);       //записываем сообщение
     fclose(res);
     return 0;
    }
  fprintf(res,"%s",argv[4]);             //записываем в$result$.txt кол.
  fclose(res);                           //балов за тест
  return 0;
}
После того как checker написан, должен быть создан файл checker.exe, который также помещается в архив вместе с тестами, условием и т.д.


Компоновка и отправка архива.

Структура архива.
Архив содержит дерево каталогов и задачи, вместе с директориями, содержащими тесты и при необходимости рисунки. Примечание: Здесь (...) - необязательный элемент <...> - обязательный

<русское_имя_узла(english_node_name)>        - директория (корень дерева)
   <русское_имя_узла(english_node_name)>     - директория (ответвление)
   ...
   <русское_имя_узла(english_node_name)>     - директория (ответвление)
      <индекс>                               - директория (индекс задачи)
      ...
      <индекс>                               - директория (индекс задачи)
     images                              - директория для рисунков(не обязательная)
        <любой файл>                     - рисунок
        <любой файл>                     - рисунок
        ...
        <любой файл>                     - рисунок
     taskrus.htm                         - русское условие задачи
     taskeng.htm                         - английское условие
     task.xml                            - файл описания задачи
         task.cfg                            - обязательный файл (конфигурация тестирования)
         1.in                                - 1-й входной файл тестов
         1.out                               - 1-й выходной файл тестов
         ...
...
<русское_имя_узла(english_node_name)>        - директория (корень дерева)
Возможное изменение структуры.
Также можно заменить файлы taskrus.htm и taskeng.htm на один файл task.htm с условием (будет вместо двух).
Если русское имя задачи совпадает с английским, то можно просто заменить '<русское_имя_узла(english_node_name)>'
на '<русское_имя_узла>#'.
Если не предполагается использовать английского имени, то можно заменить '<русское_имя_узла(english_node_name)>'
на '<русское_имя_узла>'
Если Вы устанавливаете задания для английского языка, то файлы условий могут отсутствовать. <индекс> - номер задачи, которая будет заменена или номер, под которым задача будет установлена. Архив обрабатывается так, что дополнительные узлы (поддеревья) вставляются в лексикографическом(для строковых имен) или числовом (для числовых имен) порядке в текущее дерево. Аналогично, если создавать дерево в архиве, то внутри этого дерева названия узлов будут отсортированы: в лексикографическом порядке названия, а цифры в числовом порядке. Дерево может и не существовать, тогда в архиве будет только:
<индекс>
   images
      <любой файл>
      ...
   task.htm
   task.xml
   task.cfg
   1.in
   2.out
   ...
<индекс>
...
И задачи будут загружены списком в текущий раздел. По аналогии, в архиве может быть только дерево каталогов без задач.


Проблемы в постановке.

  1. Проблема с кодировкой текста в html-е.
    При возникновении такой проблемы необходимо поменять кодировку с Dos на Windows. Для этого надо:
  2. Ошибка при отправке архива 1.
    При отправке архива может возникнуть следующая ошибка java.lang.RuntimeException: java.io.FileNotFoundException: C:\Inetpub\upload\ArchProcessorTemp\1\1.in (Access is denied), она возникает при неправильных атрибутах отправляемых файлов (должен быть один атрибут "Архивный"). Чтобы поменять атрибуты у всех файлов необходимо (в Far-e) поставить курсор на корневой каталог, нажать ctrl+A (высветится меню атрибутов файлов), поставить метку в пункте "обрабатывать вложенные папки", затем убрать метки там, где это необходимо, поставить метку "архивный", нажать enter. Для просмотра атрибутов файлов так же необходимо нажимать ctrl+A.
  3. Ошибка при отправке архива 2.
    Иногда архив с задачей может не отправляться по причине больших размеров. При такой проблеме надо попробовать поставить каждую задачу в отдельности, но если размеры отдельных задач также не позволяют это сделать необходимо, поступать следующим образом:
  4. Задачи, требующие от участников отправлять на тестирование текстовые файлы с решениями.
    Встречаются задачи, в которых на тестирование надо отправлять не саму программу, а уже готовые текстовые файлы с результатами. Задачи такого вида требуют специальный task.cfg файл и специальный checker для данной программы.

    Пример task.cfg файла.

    TYPE = USERS
    CHECKER = 'D:\DelTA\CHECKERS\12973.exe'
    CHECKFILES = {*.*}
    CHECKSUBJECT = FILE
    EXTTYPE = 'Пользовательская'
    
    Во второй строке записывается путь к checker-у для данной задачи. Для порядка checker-ы такого вида должны носить имя, такое же, как номер соответствующей задачи (в нашем случае задача имеет номер 12973).

    Написание checker-а.

    Ваш checker должен проверить каждый из файлов, которые прислал пользователь и в конечном итоге вывести ему минимальную информацию по каждому из тестов в отдельности.
    Пример:
    Допустим, что пользователю надо прислать архив с десятью тестами, в которых должен располагаться ответ в виде одного числа. Вам придется оповестить пользователя как ему называть файлы. В нашем случае пусть это будут имена result1.out, result2.out, : ,result10.out. Наш checker должен прочитать данные из этих файлов и сравнить их с данными выходных файлов для данной задачи (1.out, 2.out, : ,10.out) соответственно.
    Текст программы на С:
    #include 
    #include 
    FILE *res;
    void final(int point,char *mes="")
    {
      res=fopen("$result$.txt","w");
      fprintf(res,"%d\n",point);
      fputs(mes,res);
      fclose(res);
    }
    int read_res()
    {
      int a;
      res=fopen("$result$.txt","r");
      fscanf(res,"%d",&a);
      fclose(res);
      return a;
    }
    int check(char *user_name,char *sol_name)
    {
      FILE *user,*sol;
      int a,b;
      user=fopen(user_name,"r");
      if (user==NULL) return 0;
      sol=fopen(sol_name,"r");
      fscanf(user,"%d",&a);
      fscanf(sol,"%d",&b);
      if (a!=b) final(0,"Wrong answer!!!");
      else final(10);
      fclose(user);
      fclose(sol);
      return 1;
    }
    void main()
    {
      FILE *user,*sol,*res;
      char str_res[20]="",us_str[20],sl_str[20];
      int i,ALL=0,X;
      for (i=1;i<11;i++)
        {
         sprintf(us_str,"result%d.out",i);
         sprintf(sl_str,"%d.out",i);
         if (check(us_str,sl_str)==0)
           {
    	strcat(str_res,".");
    	continue;
           }
         X=read_res();
         if (X==0) strcat(str_res,"-");
         else
           {
    	strcat(str_res,"+");
    	ALL+=10;
           }
        }
      final(ALL,str_res);
    }  
    
    Пояснение:
    Главная функция программы int check(char *user_name,char *sol_name) в качестве своих параметров получает имена файлов (char *user_name - имя файла пользователя, char *sol_name - имя соответствующего выходного файла для данного теста). Затем осуществляется сравнение ответа пользователя и правильного ответа, если пользователь дал правильный ответ по данному тесту, то в файл $result$.txt записывается количество балов по данному тесту (в нашем случае количество балов по каждому из тестов 10), если пользователь ответил неправильно, то в файл записывается 0, если данного файла нет, то функция возвращает 0. После того как проверка завершена, в функции main осуществляется анализ результатов. Если количество балов в $result$.txt равно 10, то к числу всех балов (ALL) прибавляется это значение (в нашем случае 10) и в результирующую строку str_res добавляется символ "+", при неправильности ответы в str_res добавляется символ "-", если пользователь не вложил какой-то из файлов в архив, то в ту же строку выводится просто точка ".". При завершении цикла в тот же файл $result$.txt выводится количество баллов, которые набрал пользователь в сумме (ALL) и результирующая строка (её назначение показать пользователю, какие из его тестов прошли, а какие нет. В случае если пользователь набирает не максимальное количество балов по данному тесту можно выводить в str_res знак "<". Но не обязательно, символы разработчик checker-а может выбирать по желанию). В конечном итоге пользователю будит предоставляться минимальная информация по каждому из тестов и общее количество балов за задачу.

  5. Некоторые из причин, почему задача может не проходить тестирование