2018-08-02 22:04:49 +03:00
|
|
|
|
<html>
|
|
|
|
|
|
|
|
|
|
|
|
<head>
|
|
|
|
|
|
<object type="application/x-oleobject" classid="clsid:1e2a7bd0-dab9-11d0-b93a-00c04fc99f9e">
|
|
|
|
|
|
<param name="Keyword" value="">
|
|
|
|
|
|
</object>
|
|
|
|
|
|
<meta http-equiv="Content-Type" content="text/html; charset=windows-1251">
|
|
|
|
|
|
<title></title>
|
|
|
|
|
|
<link rel="StyleSheet" href="../../default.css">
|
|
|
|
|
|
</head>
|
|
|
|
|
|
|
|
|
|
|
|
<body>
|
2025-11-07 16:12:31 +03:00
|
|
|
|
<H1>Модуль PT4TaskMakerNET: примеры разработки учебных заданий</H1>
|
2018-08-02 22:04:49 +03:00
|
|
|
|
<hr>
|
|
|
|
|
|
|
2025-11-07 16:12:31 +03:00
|
|
|
|
<h2>Создание простейшей сводной группы</h2>
|
|
|
|
|
|
<p>Вначале опишем действия по созданию наиболее простого варианта группы заданий — <a href="tmaker_main.html#Libr"><i>сводной группы</i></a>,
|
|
|
|
|
|
в которой не разрабатываются новые задания, а лишь производится перекомпоновка заданий из имеющихся групп.
|
2018-08-02 22:04:49 +03:00
|
|
|
|
</p>
|
|
|
|
|
|
|
2025-11-07 16:12:31 +03:00
|
|
|
|
<p>Создадим группу
|
|
|
|
|
|
заданий MakerDemo, в которую импортируем два первых задания из базовой группы Begin. Следуя правилам об именовании
|
|
|
|
|
|
dll-файлов с группами заданий, дадим нашей библиотеке имя PT4MakerDemo.
|
2018-08-02 22:04:49 +03:00
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-11-07 16:12:31 +03:00
|
|
|
|
<p>Файл PT4MakerDemo.pas, содержащий сводную группу заданий, является кратким и имеет стандартную структуру:
|
2018-08-02 22:04:49 +03:00
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
|
|
<pre>library PT4MakerDemo;
|
|
|
|
|
|
|
|
|
|
|
|
uses PT4TaskMakerNET;
|
|
|
|
|
|
|
|
|
|
|
|
procedure InitTask(num: integer);
|
|
|
|
|
|
begin
|
|
|
|
|
|
case num of
|
|
|
|
|
|
1..2: UseTask('Begin', num);
|
|
|
|
|
|
end;
|
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
procedure inittaskgroup;
|
|
|
|
|
|
begin
|
2025-11-07 16:12:31 +03:00
|
|
|
|
CreateGroup('MakerDemo', 'Примеры различных задач',
|
|
|
|
|
|
'М. Э. Абрамян, 2013', 'qwqfsdf13dfttd', 2, InitTask);
|
2018-08-02 22:04:49 +03:00
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
procedure activate(S: string);
|
|
|
|
|
|
begin
|
|
|
|
|
|
ActivateNET(S);
|
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
begin
|
|
|
|
|
|
end.
|
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
2025-11-07 16:12:31 +03:00
|
|
|
|
<p>К библиотеке подключается модуль PT4TaskMakerNET, после чего в ней описывается основная процедура группы заданий
|
|
|
|
|
|
<a href="tmaker_proc1.html#TInitTaskProc">InitTask</a>, определяющая задание по его номеру.
|
|
|
|
|
|
Поскольку мы не создавали своих заданий, в данной процедуре
|
|
|
|
|
|
используется только стандартная процедура <a href="tmaker_proc1.html#UseTask">UseTask</a>, позволяющая импортировать задания из имеющихся групп.
|
|
|
|
|
|
В нашем случае импортируются задания с номерами 1 и 2 из группы Begin.
|
2018-08-02 22:04:49 +03:00
|
|
|
|
</p>
|
2025-11-07 16:12:31 +03:00
|
|
|
|
<p>Затем описывается процедура инициализации данной группы заданий. Она должна иметь стандартное имя inittaskgroup
|
|
|
|
|
|
(<i><b>набранное строчными, т. е. маленькими буквами</b></i>). В этой процедуре
|
|
|
|
|
|
вызывается процедура <a href="tmaker_proc1.html#CreateGroup">CreateGroup</a>, в которой задаются настройки создаваемой группы:
|
|
|
|
|
|
имя (<code>'MakerDemo'</code>), описание (<code>'Примеры различных задач'</code>), сведения об авторе,
|
|
|
|
|
|
строковый ключ, число заданий (<code>2</code>) и основная процедура группы (<code>InitTask</code>).
|
2018-08-02 22:04:49 +03:00
|
|
|
|
</p>
|
2025-11-07 16:12:31 +03:00
|
|
|
|
<p>После процедуры inittaskgroup описывается вспомогательная процедура activate
|
|
|
|
|
|
(ее имя также должно быть набрано строчными буквами), в которой необходимо вызвать
|
|
|
|
|
|
процедуру ActivateNET, описанную в модуле PT4TaskMakerNET.
|
2018-08-02 22:04:49 +03:00
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
|
|
<a name="debug"></a>
|
2025-11-07 16:12:31 +03:00
|
|
|
|
<h2>Тестирование созданной группы</h2>
|
|
|
|
|
|
|
|
|
|
|
|
<p>Для успешной компиляции программы с созданной группой необходимо, чтобы ей был доступен
|
|
|
|
|
|
модуль PT4TaskMakerNET. Этот модуль входит в число стандартных модулей библиотеки системы PascalABC.NET
|
|
|
|
|
|
и размещается в подкаталоге LIB системного каталога PascalABC.NET, поэтому копировать его в рабочий каталог
|
|
|
|
|
|
не требуется.
|
|
|
|
|
|
Однако даже при успешной компиляции программы просмотреть задания группы не удастся, так как
|
|
|
|
|
|
созданную библиотеку (dll-файл) нельзя запускать на выполнение (при успешной компиляции будет выведено
|
|
|
|
|
|
сообщение «Невозможно запустить динамическую библиотеку».
|
|
|
|
|
|
</p>
|
|
|
|
|
|
<p>Для тестирования полученной библиотеки
|
|
|
|
|
|
необходимо создать вспомогательную программу, являющуюся заготовкой для выполнения заданий из созданной группы.
|
|
|
|
|
|
Так как после успешной компиляции библиотеки в рабочем каталоге уже содержится файл PT4MakerDemo.dll,
|
|
|
|
|
|
для создания программы-заготовки можно использовать программный модуль PT4Load.
|
|
|
|
|
|
Вызвав его окно на экран (для этого достаточно использовать клавиатурную комбинацию [Shift]+[Ctrl]+[L])
|
|
|
|
|
|
и удалив, при необходимости, имя ранее введенного задания,
|
|
|
|
|
|
мы должны увидеть в списке доступных групп заданий созданную нами группу MakerDemo.
|
|
|
|
|
|
Если имя группы MakerDemo не отображается, значит, задачник не смог успешно загрузить эту группу
|
|
|
|
|
|
из библиотеки PT4MakerDemo.dll. В этом случае необходимо проверить имя созданной библиотеки (в частности,
|
|
|
|
|
|
наличие в нем префикса PT4) и наличие в файле библиотеки процедур inittaskgroup и activate,
|
|
|
|
|
|
определенных по описанным выше правилам.
|
|
|
|
|
|
</p>
|
|
|
|
|
|
<p>Если имя группы появилось в списке, то надо ввести в поле «Задание» имя «MakerDemo1»
|
|
|
|
|
|
и нажать клавишу [Enter] (или кнопку «Загрузка»); в результате будет создан файл MakerDemo1.pas,
|
|
|
|
|
|
который сразу загрузится в редактор среды PascalABC.NET. Приведем содержимое этого файла:
|
2018-08-02 22:04:49 +03:00
|
|
|
|
</p>
|
|
|
|
|
|
<pre>
|
|
|
|
|
|
uses PT4;
|
|
|
|
|
|
|
|
|
|
|
|
begin
|
|
|
|
|
|
Task('MakerDemo1');
|
|
|
|
|
|
|
|
|
|
|
|
end.
|
|
|
|
|
|
</pre>
|
2025-11-07 16:12:31 +03:00
|
|
|
|
<p>Поскольку мы собираемся просматривать задания группы в демо-режиме,
|
|
|
|
|
|
добавим в конец строки с именем
|
|
|
|
|
|
задания символ «?»:
|
2018-08-02 22:04:49 +03:00
|
|
|
|
</p>
|
|
|
|
|
|
<pre> Task('MakerDemo1?');
|
|
|
|
|
|
</pre>
|
2025-11-07 16:12:31 +03:00
|
|
|
|
<p>После компиляции и запуска полученной программы на экране отобразится окно задачника
|
|
|
|
|
|
с указанным заданием данной группы:
|
2018-08-02 22:04:49 +03:00
|
|
|
|
</p>
|
|
|
|
|
|
<p class="ris"><img border="0" src="images\pt4make6.png">
|
|
|
|
|
|
</p>
|
2025-11-07 16:12:31 +03:00
|
|
|
|
<p>По умолчанию окно задачника отображается в режиме с динамической компоновкой, который появился
|
|
|
|
|
|
в версии 4.11 и является более наглядным, чем режим с фиксированной компоновкой. Однако
|
|
|
|
|
|
при разработке заданий желательно применять режим с фиксированной компоновкой, поскольку
|
|
|
|
|
|
он позволит выявить недостатки форматирования (в частности, вертикального выравнивания данных),
|
|
|
|
|
|
присущие только этому режиму. Для переключения между режимами отображения данных достаточно нажать клавишу
|
|
|
|
|
|
[F4]. После выполнения этого действия окно задачника изменится следующим образом:
|
2018-08-02 22:04:49 +03:00
|
|
|
|
</p>
|
|
|
|
|
|
<p class="ris"><img border="0" src="images\pt4make6a.png">
|
|
|
|
|
|
</p>
|
|
|
|
|
|
|
2025-11-07 16:12:31 +03:00
|
|
|
|
<p>В окне задачника можно просматривать все имеющиеся задания данной группы
|
|
|
|
|
|
(нажимая клавиши [Enter] и [Backspace], а также генерировать различные варианты исходных данных
|
|
|
|
|
|
и связанных с ними контрольных (т. е. «правильных») результатов. При закрытии окна
|
|
|
|
|
|
программа немедленно завершит работу, и мы вернемся в редактор среды PascalABC.NET.
|
|
|
|
|
|
Заметим, что при последующих запусках программы будет автоматически выбираться тот режим окна
|
|
|
|
|
|
задачника, в котором оно находилось в момент его предшествующего закрытия.
|
2018-08-02 22:04:49 +03:00
|
|
|
|
</p>
|
|
|
|
|
|
<p>
|
|
|
|
|
|
</p>
|
2025-11-07 16:12:31 +03:00
|
|
|
|
<p><b>Примечание</b>. После добавления в группу нового задания было бы желательно, чтобы
|
|
|
|
|
|
при звпуске тестирующей программы на экране сразу отображались данные, связанные с последним
|
|
|
|
|
|
добавленным заданием. Чтобы не приходилось каждый раз изменять номер задания в процедуре Task,
|
|
|
|
|
|
можно удалить этот номер, указав символ «?» сразу после имени группы:
|
2018-08-02 22:04:49 +03:00
|
|
|
|
<code>Task('MakerDemo?')</code>.
|
2025-11-07 16:12:31 +03:00
|
|
|
|
В этом случае при запуске программы на экране будет отображаться
|
|
|
|
|
|
<i>последнее</i> задание данной группы.
|
2018-08-02 22:04:49 +03:00
|
|
|
|
</p>
|
|
|
|
|
|
|
2025-11-07 16:12:31 +03:00
|
|
|
|
<a name="comments"></a><h2>Добавление описания группы и ее подгрупп</h2>
|
2018-08-02 22:04:49 +03:00
|
|
|
|
|
2025-11-07 16:12:31 +03:00
|
|
|
|
<p>По тексту, расположенному выше названия задания MakerDemo1 (см. приведенные выше рисунки),
|
|
|
|
|
|
мы видим, что импортированные из группы Begin задания
|
|
|
|
|
|
входят в подгруппу с заголовком «Ввод и вывод данных, оператор присваивания».
|
|
|
|
|
|
В сводной группе MakerDemo мы можем добавить комментарий (<i>преамбулу</i>) как к самой группе, так и к любой имеющейся в ней
|
|
|
|
|
|
подгруппе. Кроме того, мы можем <i>импортировать</i>
|
|
|
|
|
|
преамбулу любой имеющейся группы или подгруппы. Для иллюстрации этих возможностей добавим в процедуру inittaskgroup
|
|
|
|
|
|
новые операторы (их надо указать после вызова процедуры CreateGroup):
|
2018-08-02 22:04:49 +03:00
|
|
|
|
</p>
|
|
|
|
|
|
|
2025-11-07 16:12:31 +03:00
|
|
|
|
<pre>CommentText('Данная группа демонстрирует различные возможности');
|
|
|
|
|
|
CommentText('\Iконструктора учебных заданий\i \MPT4TaskMaker\m.');
|
2018-08-02 22:04:49 +03:00
|
|
|
|
|
2025-11-07 16:12:31 +03:00
|
|
|
|
Subgroup('Ввод и вывод данных, оператор присваивания');
|
|
|
|
|
|
CommentText('В этой подгруппе содержатся задания, импортированные');
|
|
|
|
|
|
CommentText('из группы Begin.\PПриводимый ниже абзац преамбулы');
|
|
|
|
|
|
CommentText('также импортирован из данной группы.\P');
|
2018-08-02 22:04:49 +03:00
|
|
|
|
UseComment('Begin');
|
|
|
|
|
|
</pre>
|
2025-11-07 16:12:31 +03:00
|
|
|
|
<p>Два первых вызова процедуры <a href="tmaker_proc1.html#CommentText">CommentText</a>
|
|
|
|
|
|
определяют текст преамбулы для группы MakerDemo. Обратите внимание на
|
|
|
|
|
|
<a href="tmaker_format.html"><i>управляющие последовательности</i></a>: пара последовательностей <code>\I</code>
|
|
|
|
|
|
и <code>\i</code> выделяет <i>курсивный</i> фрагмент,
|
|
|
|
|
|
а пара <code>\M</code> и <code>\m</code> выделяет фрагмент, в которым используется <code>моноширинный</code> шрифт.
|
|
|
|
|
|
Последующий вызов процедуры Subgroup устанавливает режим определения преамбулы для подгруппы с указанным именем.
|
|
|
|
|
|
В тексте этой преамбулы, который, как и текст преамбулы группы, определяется с помощью процедуры CommentText,
|
|
|
|
|
|
используется управляющая последовательность <code>\P</code>, обеспечивающая переход к новому абзацу.
|
|
|
|
|
|
</p>
|
|
|
|
|
|
<p>Наконец, последняя процедура (<a href="tmaker_proc1.html#UseComment">UseComment</a>) импортирует преамбулу группы
|
|
|
|
|
|
Begin в преамбулу нашей подгруппы «Ввод и вывод данных, оператор присваивания». Имеется также вариант процедуры
|
|
|
|
|
|
UseComment, позволяющий импортировать преамбулу подгруппы; в этом варианте следует указать два параметра: имя группы и
|
|
|
|
|
|
заголовок требуемой подгруппы, входящей в эту группу. Импортировать преамбулы подгрупп можно только для тех групп заданий, в которых
|
|
|
|
|
|
имеется разделение на подгруппы (обычно это группы, содержащие большое количество заданий). В группе Begin деления на подгруппы нет, поэтому
|
|
|
|
|
|
из нее можно импортировать только преамбулу самой группы.
|
|
|
|
|
|
</p>
|
|
|
|
|
|
<p>Для того чтобы ознакомиться с результатом сделанных изменений, следует сгенерировать html-страницу с текстом группы MakerDemo.
|
|
|
|
|
|
Для этого достаточно внести небольшое изменение в тестирующую программу, а именно, следует
|
|
|
|
|
|
заменить символ «?» в параметре процедуры Task на «#»: <code>Task('MakerDemo?')</code>.
|
|
|
|
|
|
Теперь при запуске данной программы на экране вместо окна задачника появится html-браузер с описанием созданной группы:
|
2018-08-02 22:04:49 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<p class="ris"><img border="1" src="images\pt4make7.png">
|
|
|
|
|
|
</p>
|
2025-11-07 16:12:31 +03:00
|
|
|
|
<p>Обратите внимание на последний абзац в описании подгруппы («Все входные и выходные данные в заданиях этой группы являются
|
|
|
|
|
|
вещественными числами»), который был импортирован из группы Begin.
|
2018-08-02 22:04:49 +03:00
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-11-07 16:12:31 +03:00
|
|
|
|
<p><b>Примечание</b>. Если указать в параметре процедуры Task символ «#»,
|
|
|
|
|
|
не удаляя номер задания (например, <code>Task('MakerDemo2#')</code>), то в html-описание
|
|
|
|
|
|
будет включено только задание с указанным номером. При этом будут также выведены комментарии ко всей группе и к той подгруппе, к
|
|
|
|
|
|
которой относится выбранное задание. Для включения в html-страницу нескольких заданий (или групп заданий) достаточно для каждого из них
|
|
|
|
|
|
вызвать процедуру Task с параметром, оканчивающимся символом «#».
|
2018-08-02 22:04:49 +03:00
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-11-07 16:12:31 +03:00
|
|
|
|
<h2>Добавление нового задания</h2>
|
|
|
|
|
|
<p>Добавим к нашей группе новое задание. Фактически это задание будет дублировать задание Begin3,
|
|
|
|
|
|
однако вместо импортирования этого задания мы разработаем его самостоятельно. Все действия по созданию
|
|
|
|
|
|
нового задания удобно реализовать во вспомогательной процедуре, которую можно назвать MakerDemo3
|
|
|
|
|
|
(таким образом, название процедуры будет соответствовать имени создаваемого задания, хотя это и не является обязательным):
|
2018-08-02 22:04:49 +03:00
|
|
|
|
</p>
|
|
|
|
|
|
<pre>procedure MakerDemo3;
|
|
|
|
|
|
var
|
|
|
|
|
|
a, b: real;
|
|
|
|
|
|
begin
|
2025-11-07 16:12:31 +03:00
|
|
|
|
CreateTask('Ввод и вывод данных, оператор присваивания');
|
|
|
|
|
|
TaskText('Даны стороны прямоугольника~{a} и~{b}.', 0, 2);
|
|
|
|
|
|
TaskText('Найти его площадь {S}~=~{a}\*{b} и периметр {P}~=~2\*({a}\;+\;{b}).',
|
2018-08-02 22:04:49 +03:00
|
|
|
|
0, 4);
|
|
|
|
|
|
a := RandomN(1, 99) / 10;
|
|
|
|
|
|
b := RandomN(1, 99) / 10;
|
|
|
|
|
|
DataR('a = ', a, xLeft, 3, 4);
|
|
|
|
|
|
DataR('b = ', b, xRight, 3, 4);
|
|
|
|
|
|
ResultR('S = ', a * b, 0, 2, 4);
|
|
|
|
|
|
ResultR('P = ', 2 * (a + b), 0, 4, 4);
|
|
|
|
|
|
SetTestCount(3);
|
|
|
|
|
|
end;
|
|
|
|
|
|
</pre>
|
2025-11-07 16:12:31 +03:00
|
|
|
|
<p>Описание процедуры MakerDemo3 (как и описания всех других процедур, обеспечивающих формирование новых заданий)
|
|
|
|
|
|
следует разместить перед описанием процедуры InitTask.
|
|
|
|
|
|
</p>
|
|
|
|
|
|
<p>Процедура MakerDemo3 включает все основные действия, используемые при формировании нового задания:
|
|
|
|
|
|
</p>
|
|
|
|
|
|
<ul><li><i>инициализацию</i> нового задания (процедура <a href="tmaker_proc1.html#CreateTask">CreateTask</a>;
|
|
|
|
|
|
мы указали в этой процедуре, что данное задание должно входить
|
|
|
|
|
|
в подгруппу «Ввод и вывод данных, оператор присваивания», т. е. в ту же подгруппу, что и два
|
|
|
|
|
|
предыдущих задания);
|
|
|
|
|
|
<li>определение его <i>формулировки</i> (процедуры <a href="tmaker_proc1.html#TaskText">TaskText</a>; обратите внимание на используемые в
|
|
|
|
|
|
этих процедурах <a href="tmaker_format.html">управляющие последовательности</a>);
|
|
|
|
|
|
<li>определение исходных (процедуры <a href="tmaker_proc1.html#DataN">DataR</a>) и результирующих данных
|
|
|
|
|
|
(процедуры <a href="tmaker_proc1.html#ResultN">ResultR</a>); при этом исходные данные генерируются с помощью
|
|
|
|
|
|
датчика случайных чисел (процедура <a href="tmaker_proc1.html#Random">RandomN</a>);
|
|
|
|
|
|
<li>указание количества успешных тестовых запусков программы учащегося, достаточных для регистрации задания как выполненного
|
|
|
|
|
|
(процедура <a href="tmaker_proc1.html#SetTestCount">SetTestCount</a>;
|
|
|
|
|
|
для нашего простого задания достаточно трех <i>проведенных подряд</i> успешных тестовых запусков).
|
2018-08-02 22:04:49 +03:00
|
|
|
|
</ul>
|
2025-11-07 16:12:31 +03:00
|
|
|
|
<p>Необходимо также включить вызов созданной процедуры в основную процедуру группы MakerDemo, связав его с номером 3:
|
2018-08-02 22:04:49 +03:00
|
|
|
|
</p>
|
|
|
|
|
|
<pre>procedure InitTask(num: integer);
|
|
|
|
|
|
begin
|
|
|
|
|
|
case num of
|
|
|
|
|
|
1..2: UseTask('Begin', num);
|
|
|
|
|
|
3: MakerDemo3;
|
|
|
|
|
|
end;
|
|
|
|
|
|
end;
|
|
|
|
|
|
</pre>
|
2025-11-07 16:12:31 +03:00
|
|
|
|
<p>Наконец, следует откорректировать число заданий в вызове процедуры CreateGroup, изменив его на 3.
|
2018-08-02 22:04:49 +03:00
|
|
|
|
</p>
|
2025-11-07 16:12:31 +03:00
|
|
|
|
<p>Запустив тестирующую программу, мы увидим в html-описании группы MakerDemo формулировки трех заданий,
|
|
|
|
|
|
а выполнив обратную замену в этой программе символа «#» на «?» (в результате
|
|
|
|
|
|
вызов процедуры Task опять примет вид <code>Task('MakerDemo?')</code>) и повторно запустив программу
|
|
|
|
|
|
на выполнение, мы увидим окно задачника
|
|
|
|
|
|
с загруженным заданием MakerDemo3. Заметим, что при последующих запусках проекта мы будем получать
|
|
|
|
|
|
в окне задачника различные исходные данные; это связано с тем, что при генерации исходных данных
|
|
|
|
|
|
используется датчик случайных чисел.
|
2018-08-02 22:04:49 +03:00
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-11-07 16:12:31 +03:00
|
|
|
|
<h2>Добавление заданий на обработку двумерных массивов и символьных строк</h2>
|
|
|
|
|
|
<p>Добавим к группе MakerDemo еще два задания: первое из них дублирует задание Matrix7
|
|
|
|
|
|
(подгруппа «Двумерные массивы (матрицы): вывод элементов»), а второе
|
|
|
|
|
|
не имеет полного аналога в группе String, однако может быть отнесено к ее первой
|
|
|
|
|
|
подгруппе: «Символы и строки: основные операции». Реализуем эти задания
|
|
|
|
|
|
в процедурах MakerDemo4 и MakerDemo5:
|
2018-08-02 22:04:49 +03:00
|
|
|
|
</p>
|
|
|
|
|
|
<pre>procedure MakerDemo4;
|
|
|
|
|
|
var
|
|
|
|
|
|
m, n, i, j, k: integer;
|
|
|
|
|
|
a: array [1..5, 1..8] of real;
|
|
|
|
|
|
begin
|
2025-11-07 16:12:31 +03:00
|
|
|
|
CreateTask('Двумерные массивы (матрицы): вывод элементов');
|
|
|
|
|
|
TaskText('Дана матрица размера~{M}\;\x\;{N} и целое число~{K} (1~\l~{K}~\l~{M}).',
|
2018-08-02 22:04:49 +03:00
|
|
|
|
0, 2);
|
2025-11-07 16:12:31 +03:00
|
|
|
|
TaskText('Вывести элементы {K}-й строки данной матрицы.', 0, 4);
|
2018-08-02 22:04:49 +03:00
|
|
|
|
m := RandomN(2, 5);
|
|
|
|
|
|
n := RandomN(4, 8);
|
|
|
|
|
|
k := 1;
|
|
|
|
|
|
if m = 5 then k := 0;
|
|
|
|
|
|
DataN('M = ', m, 3, 1, 1);
|
|
|
|
|
|
DataN('N = ', n, 10, 1, 1);
|
|
|
|
|
|
for i := 1 to m do
|
|
|
|
|
|
for j := 1 to n do
|
|
|
|
|
|
begin
|
|
|
|
|
|
a[i, j] := RandomR(-9.99, 9.99);
|
|
|
|
|
|
DataR(a[i,j], Center(j, n, 5, 1), i + k, 5);
|
|
|
|
|
|
end;
|
|
|
|
|
|
k := RandomN(1, m);
|
|
|
|
|
|
DataN('K = ', k, 68, 5, 1);
|
|
|
|
|
|
for j := 1 to n do
|
|
|
|
|
|
ResultR(a[k, j], Center(j, n, 5, 1), 3, 5);
|
|
|
|
|
|
SetTestCount(5);
|
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
procedure MakerDemo5;
|
|
|
|
|
|
var
|
|
|
|
|
|
s: string;
|
|
|
|
|
|
begin
|
2025-11-07 16:12:31 +03:00
|
|
|
|
CreateTask('Символы и строки: основные операции');
|
|
|
|
|
|
TaskText('Дана непустая строка~{S}.', 0, 2);
|
|
|
|
|
|
TaskText('Вывести ее первый и последний символ.', 0, 4);
|
2018-08-02 22:04:49 +03:00
|
|
|
|
s := WordSample(RandomN(0, WordCount-1));
|
|
|
|
|
|
if CurrentTest = 3 then
|
|
|
|
|
|
while s[1] = s[Length(s)] do
|
|
|
|
|
|
s := WordSample(RandomN(0, WordCount-1));
|
|
|
|
|
|
DataS('S = ', s, 0, 3);
|
2025-11-07 16:12:31 +03:00
|
|
|
|
ResultC('Первый символ: ', s[1], xLeft, 3);
|
|
|
|
|
|
ResultC('Последний символ: ', s[Length(s)], xRight, 3);
|
2018-08-02 22:04:49 +03:00
|
|
|
|
SetTestCount(4);
|
|
|
|
|
|
end;
|
|
|
|
|
|
</pre>
|
2025-11-07 16:12:31 +03:00
|
|
|
|
<p>Обратите внимание на использование вспомогательной функции <a href="tmaker_proc1.html#Center">Center</a>
|
|
|
|
|
|
для центрирования строк матрицы в области
|
|
|
|
|
|
исходных и результирующих данных: каждый элемент матрицы занимает 5 экранных позиций, а между
|
|
|
|
|
|
элементами размещается по одному пробелу. В процедуре MakerDemo4 не вызывается процедура SetTestCount; в этом случае
|
|
|
|
|
|
число успешных тестов, необходимых для регистрации задания как выполненного, по умолчанию полагается равным 5.
|
|
|
|
|
|
</p>
|
|
|
|
|
|
<p>При выводе элементов исходной матрицы и результирующей матричной строки дополнительные комментарии
|
|
|
|
|
|
указывать не требуется, поэтому используется вариант процедур DataR и ResultR, в котором комментарий
|
|
|
|
|
|
отсутствует (этот вариант процедур групп Data и Result добавлен в версию 4.11 конструктора учебных заданий).
|
|
|
|
|
|
</p>
|
|
|
|
|
|
<p>В процедуре MakerDemo5 для получения исходных символьных строк используются
|
|
|
|
|
|
функции <a href="tmaker_proc1.html#Sample">WordCount и WordSample</a>. С помощью этих функций можно получать
|
|
|
|
|
|
различные варианты русских слов. Заметим, что в конструкторе PT4TaskMaker имеются также функции
|
|
|
|
|
|
EnWordCount и EnWordSample, с помощью которых можно получать варианты английских слов.
|
|
|
|
|
|
</p>
|
|
|
|
|
|
<p>В процедуре MakerDemo5 использована еще одна возможность, появившаяся в версии 4.11 конструктора:
|
|
|
|
|
|
функция <a href="tmaker_proc1.html#CurrentTest">CurrentTest</a>,
|
|
|
|
|
|
возвращающая порядковый номер текущего тестового запуска. Использование этой функции позволяет
|
|
|
|
|
|
связать какой-либо особый вариант теста с некоторым номером тестового испытания, и тем самым гарантировать,
|
|
|
|
|
|
что программа с решением задачи обязательно будет проверена на этом особом варианте теста.
|
|
|
|
|
|
В нашем случае строка S выбирается из набора слов-образцов, среди которых имеется
|
|
|
|
|
|
сравнительно большое число слов, начинающихся и оканчивающихся одной и той же буквой.
|
|
|
|
|
|
Для более надежного тестирования решения желательно гарантировать, что в наборе тестов
|
|
|
|
|
|
будет <i>хотя бы один тест</i>, в котором начальный и конечный символ исходной строки различаются.
|
|
|
|
|
|
Разумеется, можно было бы <i>всегда</i> выбирать подобные строки, используя соответствующий
|
|
|
|
|
|
цикл while. Однако при наличии функции CurrentTest
|
|
|
|
|
|
в этом нет необходимости: достаточно выполнять подобный цикл для единственного теста, например,
|
|
|
|
|
|
с номером 3, как это сделано в приведенной реализации задания.
|
|
|
|
|
|
В дальнейшем мы рассмотрим более содержательный пример использования функции CurrentTest.
|
|
|
|
|
|
</p>
|
|
|
|
|
|
<p>Осталось изменить количество заданий в вызове процедуры CreateGroup на 5 и
|
|
|
|
|
|
включить вызовы новых процедур в основную процедуру группы InitTask:
|
2018-08-02 22:04:49 +03:00
|
|
|
|
</p>
|
|
|
|
|
|
<pre>procedure InitTask(num: integer);
|
|
|
|
|
|
begin
|
|
|
|
|
|
case num of
|
|
|
|
|
|
1..2: UseTask('Begin', num);
|
|
|
|
|
|
3: MakerDemo3;
|
|
|
|
|
|
4: MakerDemo4;
|
|
|
|
|
|
5: MakerDemo5;
|
|
|
|
|
|
end;
|
|
|
|
|
|
end;
|
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
2025-11-07 16:12:31 +03:00
|
|
|
|
<p>Приведем вид окна задачника для новых заданий:
|
2018-08-02 22:04:49 +03:00
|
|
|
|
</p>
|
|
|
|
|
|
<p class="ris"><img border="0" src="images\pt4make8.png">
|
|
|
|
|
|
</p>
|
|
|
|
|
|
<p class="ris"><img border="0" src="images\pt4make9.png">
|
|
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-11-07 16:12:31 +03:00
|
|
|
|
<h2>Добавление заданий на обработку файлов</h2>
|
|
|
|
|
|
<p>Добавим к группе MakerDemo еще два задания: первое из них дублирует задание File63
|
|
|
|
|
|
(подгруппа «Символьные и строковые файлы»), а второе
|
|
|
|
|
|
— задание Text16 (подгруппа «Текстовые файлы: основные операции»). Реализуем эти задания
|
|
|
|
|
|
в процедурах MakerDemo6 и MakerDemo7:
|
2018-08-02 22:04:49 +03:00
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
|
|
<pre>function FileName(Len: integer): string;
|
|
|
|
|
|
const
|
|
|
|
|
|
c = '0123456789abcdefghijklmnopqrstuvwxyz';
|
|
|
|
|
|
var
|
|
|
|
|
|
i: integer;
|
|
|
|
|
|
begin
|
|
|
|
|
|
result := '';
|
|
|
|
|
|
for i := 1 to Len do
|
|
|
|
|
|
result := result + c[RandomN(1, Length(c))];
|
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
procedure MakerDemo6;
|
|
|
|
|
|
var
|
|
|
|
|
|
k, i, j, jmax: integer;
|
|
|
|
|
|
s1, s2, s3: string;
|
|
|
|
|
|
fs1: file of ShortString;
|
|
|
|
|
|
fs2: file of ShortString;
|
|
|
|
|
|
fc3: file of char;
|
|
|
|
|
|
s: ShortString;
|
|
|
|
|
|
c: char;
|
|
|
|
|
|
begin
|
2025-11-07 16:12:31 +03:00
|
|
|
|
CreateTask('Символьные и строковые файлы');
|
2018-08-02 22:04:49 +03:00
|
|
|
|
TaskText(
|
2025-11-07 16:12:31 +03:00
|
|
|
|
'Дано целое число~{K} (>\,0) и строковый файл.'#13 +
|
|
|
|
|
|
'Создать два новых файла: строковый, содержащий первые {K}~символов'#13 +
|
|
|
|
|
|
'каждой строки исходного файла, и символьный, содержащий {K}-й символ'#13 +
|
|
|
|
|
|
'каждой строки (если длина строки меньше~{K}, то в строковый файл'#13 +
|
|
|
|
|
|
'записывается вся строка, а в символьный файл записывается пробел).'
|
2018-08-02 22:04:49 +03:00
|
|
|
|
);
|
|
|
|
|
|
s1 := '1' + FileName(5) + '.tst';
|
|
|
|
|
|
s2 := '2' + FileName(5) + '.tst';
|
|
|
|
|
|
s3 := '3' + FileName(5) + '.tst';
|
|
|
|
|
|
Assign(fs1, s1);
|
|
|
|
|
|
Rewrite(fs1);
|
|
|
|
|
|
Assign(fs2, s2);
|
|
|
|
|
|
Rewrite(fs2);
|
|
|
|
|
|
Assign(fc3, s3);
|
|
|
|
|
|
Rewrite(fc3);
|
|
|
|
|
|
k := RandomN(2, 11);
|
|
|
|
|
|
jmax := 0;
|
|
|
|
|
|
for i := 1 to RandomN(10, 20) do
|
|
|
|
|
|
begin
|
|
|
|
|
|
j := RandomN(2, 16);
|
|
|
|
|
|
if jmax < j then
|
|
|
|
|
|
jmax := j;
|
|
|
|
|
|
s := FileName(j);
|
|
|
|
|
|
write(fs1, s);
|
|
|
|
|
|
if j >= k then
|
|
|
|
|
|
c := s[k]
|
|
|
|
|
|
else
|
|
|
|
|
|
c := ' ';
|
|
|
|
|
|
write(fc3, c);
|
|
|
|
|
|
s := copy(s, 1, k);
|
|
|
|
|
|
write(fs2,s);
|
|
|
|
|
|
end;
|
|
|
|
|
|
Close(fs1);
|
|
|
|
|
|
Close(fs2);
|
|
|
|
|
|
Close(fc3);
|
|
|
|
|
|
DataN('K = ', k, 0, 1, 1);
|
2025-11-07 16:12:31 +03:00
|
|
|
|
DataS('Имя исходного файла: ', s1, 3, 2);
|
|
|
|
|
|
DataS('Имя результирующего строкового файла: ', s2, 3, 4);
|
|
|
|
|
|
DataS('Имя результирующего символьного файла: ', s3, 3, 5);
|
|
|
|
|
|
DataComment('Содержимое исходного файла:', xRight, 2);
|
2018-08-02 22:04:49 +03:00
|
|
|
|
DataFileS(s1, 3, jmax + 3);
|
2025-11-07 16:12:31 +03:00
|
|
|
|
ResultComment('Содержимое результирующего строкового файла:',
|
2018-08-02 22:04:49 +03:00
|
|
|
|
0, 2);
|
2025-11-07 16:12:31 +03:00
|
|
|
|
ResultComment('Содержимое результирующего символьного файла:',
|
2018-08-02 22:04:49 +03:00
|
|
|
|
0, 4);
|
|
|
|
|
|
ResultFileS(s2, 3, k + 3);
|
|
|
|
|
|
ResultFileC(s3, 5, 4);
|
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
procedure MakerDemo7;
|
|
|
|
|
|
var
|
|
|
|
|
|
p: integer;
|
|
|
|
|
|
s, s1, s2, s0: string;
|
|
|
|
|
|
t1, t2: text;
|
|
|
|
|
|
begin
|
2025-11-07 16:12:31 +03:00
|
|
|
|
CreateTask('Текстовые файлы: основные операции');
|
|
|
|
|
|
TaskText('Дан текстовый файл.', 0, 2);
|
|
|
|
|
|
TaskText('Удалить из него все пустые строки.', 0, 4);
|
2018-08-02 22:04:49 +03:00
|
|
|
|
s1 := FileName(6) + '.tst';
|
|
|
|
|
|
s2 := '#' + FileName(6) + '.tst';
|
|
|
|
|
|
s := TextSample(RandomN(0, TextCount-1));
|
|
|
|
|
|
Assign(t2, s2);
|
|
|
|
|
|
Rewrite(t2);
|
|
|
|
|
|
Assign(t1, s1);
|
|
|
|
|
|
Rewrite(t1);
|
|
|
|
|
|
writeln(t2, s);
|
|
|
|
|
|
Close(t2);
|
|
|
|
|
|
s0 := #13#10#13#10;
|
|
|
|
|
|
p := Pos(s0, s);
|
|
|
|
|
|
while p <> 0 do
|
|
|
|
|
|
begin
|
|
|
|
|
|
Delete(s, p, 2);
|
|
|
|
|
|
p := Pos(s0, s);
|
|
|
|
|
|
end;
|
|
|
|
|
|
writeln(t1, s);
|
|
|
|
|
|
Close(t1);
|
|
|
|
|
|
ResultFileT(s1, 1, 5);
|
|
|
|
|
|
Rename(t2, s1);
|
|
|
|
|
|
DataFileT(s1, 2, 5);
|
2025-11-07 16:12:31 +03:00
|
|
|
|
DataS('Имя файла: ', s1, 0, 1);
|
2018-08-02 22:04:49 +03:00
|
|
|
|
SetTestCount(3);
|
|
|
|
|
|
end;
|
|
|
|
|
|
</pre>
|
2025-11-07 16:12:31 +03:00
|
|
|
|
<p>При реализации этих заданий используется вспомогательная функция FileName(Len), позволяющая
|
|
|
|
|
|
создать случайное имя файла длины Len (без расширения).
|
|
|
|
|
|
Имя файла при этом будет содержать только цифры и строчные (маленькие) латинские буквы.
|
|
|
|
|
|
</p>
|
|
|
|
|
|
<p>Имена файлов, полученные с помощью функции FileName, дополняются расширением .tst (заметим, что
|
|
|
|
|
|
в базовых группах File, Text и Param это расширение используется в именах всех исходных и результирующих файлов).
|
|
|
|
|
|
</p>
|
|
|
|
|
|
<p>Функция FileName используется также для генерации элементов строкового файла в процедуре MakerDemo6.
|
|
|
|
|
|
</p>
|
|
|
|
|
|
<p>Для того чтобы предотвратить возможность случайного совпадения имен файлов, в процедуре MakerDemo6 к созданным именам
|
|
|
|
|
|
добавляются префиксы: <code>1</code> для первого файла, <code>2</code> для второго, <code>3</code> для третьего.
|
|
|
|
|
|
В процедуре MakerDemo7 имя
|
|
|
|
|
|
временного файла дополняется префиксом <code>#</code>, что также гарантирует его отличие от имени основного файла задания.
|
|
|
|
|
|
</p>
|
|
|
|
|
|
<p>В процедуре MakerDemo6 использован новый вариант <a href="tmaker_proc1.html#TaskText">процедуры TaskText</a>,
|
|
|
|
|
|
появившийся в версии 4.11 задачника.
|
|
|
|
|
|
В этом варианте процедура TaskText принимает один строковый параметр, который определяет
|
|
|
|
|
|
<i>всю формулировку задания</i>, причем в качестве разделителей строк, входящих в формулировку, можно использовать
|
|
|
|
|
|
символы #13, #10 или их комбинацию #13#10 (в указанном порядке).
|
|
|
|
|
|
Новый вариант процедуры TaskText позволяет более наглядно отобразить формулировку задания и
|
|
|
|
|
|
не требует указания дополнительных параметров.
|
|
|
|
|
|
</p>
|
|
|
|
|
|
<p>При реализации задания на обработку текстовых файлов для генерации содержимого файла используются
|
|
|
|
|
|
функции <a href="tmaker_proc1.html#Sample">TextCount и TextSample</a>. Строка, возвращаемая функцией TextSample,
|
|
|
|
|
|
представляет собой текст, содержащий <i>маркеры конца строки</i> — символы #13#10. Указанные символы
|
|
|
|
|
|
<i>разделяют соседние строки текста</i> (в конце текста маркер конца строки не указывается).
|
|
|
|
|
|
Благодаря наличию маркеров конца строки полученный текст можно записать в текстовый файл с помощью единственной процедуры
|
|
|
|
|
|
writeln, которая, кроме записи текста, обеспечивает добавление маркера конца строки в конец файла.
|
|
|
|
|
|
</p>
|
|
|
|
|
|
<p>После разработки новых заданий необходимо изменить количество заданий в вызове процедуры CreateGroup на 7 и
|
|
|
|
|
|
включить вызовы новых процедур в основную процедуру группы InitTask:
|
2018-08-02 22:04:49 +03:00
|
|
|
|
</p>
|
|
|
|
|
|
<pre>procedure InitTask(num: integer);
|
|
|
|
|
|
begin
|
|
|
|
|
|
case num of
|
|
|
|
|
|
1..2: UseTask('Begin', num);
|
|
|
|
|
|
3: MakerDemo3;
|
|
|
|
|
|
4: MakerDemo4;
|
|
|
|
|
|
5: MakerDemo5;
|
|
|
|
|
|
6: MakerDemo6;
|
|
|
|
|
|
7: MakerDemo7;
|
|
|
|
|
|
end;
|
|
|
|
|
|
end;
|
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
2025-11-07 16:12:31 +03:00
|
|
|
|
<p>Приведем вид окна задачника для новых заданий:
|
2018-08-02 22:04:49 +03:00
|
|
|
|
</p>
|
|
|
|
|
|
<p class="ris"><img border="0" src="images\pt4make10.png">
|
|
|
|
|
|
</p>
|
|
|
|
|
|
<p class="ris"><img border="0" src="images\pt4make11.png">
|
|
|
|
|
|
</p>
|
|
|
|
|
|
|
2025-11-07 16:12:31 +03:00
|
|
|
|
<a name="dynamic"></a><h2>Добавление заданий на обработку динамических структур данных</h2>
|
2018-08-02 22:04:49 +03:00
|
|
|
|
|
2025-11-07 16:12:31 +03:00
|
|
|
|
<p>Наконец, добавим в нашу группу задание,
|
|
|
|
|
|
посвященное обработке динамических структур данных, причем представим его в двух
|
|
|
|
|
|
вариантах: традиционном, основанном на использовании записей типа TNode
|
|
|
|
|
|
и связанных с ними указателей типа PNode, и «объектном», характерном для .NET-языков
|
|
|
|
|
|
(C#, Visual Basic .NET, PascalABC.NET), а также языков Python и Java.
|
|
|
|
|
|
Следует подчеркнуть, что при <i>разработке</i> как традиционного, так и объектного варианта заданий
|
|
|
|
|
|
на динамические структуры надо использовать типы TNode и PNode и связанные с ними процедуры конструктора учебных заданий.
|
|
|
|
|
|
В то же время, при <i>выполнении</i> объектного варианта задания на соответствующем языке требуется
|
|
|
|
|
|
использовать объекты типа Node (которые при разработке задания не применяются).
|
2018-08-02 22:04:49 +03:00
|
|
|
|
</p>
|
2025-11-07 16:12:31 +03:00
|
|
|
|
<p>Задание, которое мы реализуем, дублирует задание Dynamic30, посвященное преобразованию
|
|
|
|
|
|
односвязного списка в двусвязный (подгруппа «Динамические структуры данных: двусвязный список»).
|
|
|
|
|
|
Оформим два варианта этого задания в виде процедур MakerDemo8 и MakerDemo8Obj:
|
2018-08-02 22:04:49 +03:00
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
|
|
<pre>var WrongNode: TNode;
|
|
|
|
|
|
|
|
|
|
|
|
procedure MakerDemo8Data;
|
|
|
|
|
|
var
|
|
|
|
|
|
i, n: integer;
|
|
|
|
|
|
p, p1, p2: PNode;
|
|
|
|
|
|
begin
|
|
|
|
|
|
if RandomN(1, 4) = 1 then
|
|
|
|
|
|
n := 1
|
|
|
|
|
|
else
|
|
|
|
|
|
n := RandomN(2, 9);
|
|
|
|
|
|
case CurrentTest of
|
|
|
|
|
|
2: n := 1;
|
|
|
|
|
|
4: n := RandomN(2, 9);
|
|
|
|
|
|
end;
|
|
|
|
|
|
new(p1);
|
|
|
|
|
|
p1^.Data := RandomN(10, 99);
|
|
|
|
|
|
p1^.Prev := nil;
|
|
|
|
|
|
p2 := p1;
|
|
|
|
|
|
for i := 2 to n do
|
|
|
|
|
|
begin
|
|
|
|
|
|
new(p);
|
|
|
|
|
|
p^.Data := RandomN(10, 99);
|
|
|
|
|
|
p^.Prev := p2;
|
|
|
|
|
|
p2^.Next := p;
|
|
|
|
|
|
p2 := p;
|
|
|
|
|
|
end;
|
|
|
|
|
|
p2^.Next := nil;
|
|
|
|
|
|
SetPointer(1, p1);
|
|
|
|
|
|
SetPointer(2, p2);
|
2025-11-07 16:12:31 +03:00
|
|
|
|
ResultP('Последний элемент: ', 2, 0, 2);
|
2018-08-02 22:04:49 +03:00
|
|
|
|
ResultList(1, 0, 3);
|
|
|
|
|
|
ShowPointer(2);
|
|
|
|
|
|
DataP(1, 0, 2);
|
|
|
|
|
|
p := p1;
|
|
|
|
|
|
for i := 1 to n do
|
|
|
|
|
|
begin
|
|
|
|
|
|
p^.Prev := @WrongNode;
|
|
|
|
|
|
p := p^.Next;
|
|
|
|
|
|
end;
|
|
|
|
|
|
DataList(1, 0, 3);
|
|
|
|
|
|
ShowPointer(1);
|
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
procedure MakerDemo8;
|
|
|
|
|
|
begin
|
2025-11-07 16:12:31 +03:00
|
|
|
|
CreateTask('Динамические структуры данных: двусвязный список');
|
|
|
|
|
|
TaskText('Дан указатель~{P}_1 на начало непустой цепочки ' +
|
|
|
|
|
|
'элементов-записей типа TNode,', 0, 1);
|
|
|
|
|
|
TaskText('связанных между собой с помощью поля Next. Используя ' +
|
|
|
|
|
|
'поле Prev записи TNode,', 0, 2);
|
|
|
|
|
|
TaskText('преобразовать исходную (\Iодносвязную\i) цепочку ' +
|
|
|
|
|
|
'в \Iдвусвязную\i, в которой каждый', 0, 3);
|
|
|
|
|
|
TaskText('элемент связан не только с последующим элементом ' +
|
|
|
|
|
|
'(с помощью поля Next),', 0, 4);
|
|
|
|
|
|
TaskText('но и с предыдущим (с помощью поля Prev). Поле Prev ' +
|
|
|
|
|
|
'первого элемента положить', 0, 5);
|
|
|
|
|
|
TaskText('равным \N. Вывести указатель на последний элемент ' +
|
|
|
|
|
|
'преобразованной цепочки.', 0, 0);
|
2018-08-02 22:04:49 +03:00
|
|
|
|
MakerDemo8Data;
|
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
procedure MakerDemo8Obj;
|
|
|
|
|
|
begin
|
2025-11-07 16:12:31 +03:00
|
|
|
|
CreateTask('Динамические структуры данных: двусвязный список');
|
2018-08-02 22:04:49 +03:00
|
|
|
|
TaskText(
|
2025-11-07 16:12:31 +03:00
|
|
|
|
'Дана ссылка~{A}_1 на начало непустой цепочки элементов-объектов типа Node,'#13 +
|
|
|
|
|
|
'связанных между собой с помощью своих свойств Next. Используя свойства Prev'#13 +
|
|
|
|
|
|
'данных объектов, преобразовать исходную (\Iодносвязную\i) цепочку в \Iдвусвязную\i,'#13 +
|
|
|
|
|
|
'в которой каждый элемент связан не только с последующим элементом (с помощью'#13 +
|
|
|
|
|
|
'свойства Next), но и с предыдущим (с помощью свойства Prev). Свойство Prev'#13 +
|
|
|
|
|
|
'первого элемента положить равным \O. Вывести ссылку~{A}_2 на последний'#13 +
|
|
|
|
|
|
'элемент преобразованной цепочки.'
|
2018-08-02 22:04:49 +03:00
|
|
|
|
);
|
|
|
|
|
|
SetObjectStyle;
|
|
|
|
|
|
MakerDemo8Data;
|
|
|
|
|
|
end;
|
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
2025-11-07 16:12:31 +03:00
|
|
|
|
<p>Анализируя приведенные варианты процедур, легко заметить, что они отличаются лишь деталями формулировки задания.
|
|
|
|
|
|
Алгоритмы генерации исходных и контрольных данных
|
|
|
|
|
|
для традиционного и объектного вариантов совпадают, поэтому они выделены в отдельную вспомогательную процедуру MakerDemo8Data.
|
|
|
|
|
|
В то же время <i>представления</i> динамических структур и связанных с ними
|
|
|
|
|
|
указателей или объектов будут отличаться (см. рисунки, приведенные ниже). Необходимые корректировки в представлении
|
|
|
|
|
|
динамических структур выполняются задачником автоматически, с учетом используемого языка программирования.
|
|
|
|
|
|
</p>
|
|
|
|
|
|
<p>Однако для
|
|
|
|
|
|
языка PascalABC.NET требуемую настройку необходимо выполнить явно, так как в нем можно использовать оба варианта
|
|
|
|
|
|
представления динамических структур: традиционный (как для обычного Паскаля в системах Delphi и Free Pascal Lazarus)
|
|
|
|
|
|
и объектный (как в языках C#, Visual Basic .NET, Python и Java).
|
|
|
|
|
|
Для того чтобы представление динамических данных при выполнении задания в среде PascalABC.NET соответствовало объектному
|
|
|
|
|
|
варианту, следует в начале процедуры, реализующей задание (перед вызовом любых процедур, связанных
|
|
|
|
|
|
с указателями и динамическими структурами), вызвать специальную процедуру без параметров
|
|
|
|
|
|
<a href="tmaker_proc2.html#SetObjectStyle">SetObjectStyle</a>. Для остальных языков данная процедура не выполняет никаких действий.
|
|
|
|
|
|
</p>
|
|
|
|
|
|
<p>Обратите внимание на возможность использования в формулировке задания более 5 экранных строк. Строки, которые
|
|
|
|
|
|
не умещаются в области формулировки задания, следует добавлять к заданию процедурой TaskText,
|
|
|
|
|
|
указывая в качестве последнего параметра процедуры число 0 (см. процедуру MakerDemo8).
|
|
|
|
|
|
Еще проще задавать «длинные» формулировки заданий с помощью нового варианта
|
|
|
|
|
|
процедуры TaskText с единственным строковым параметром, содержащим все строки формулировки (см. процедуру MakerDemo9).
|
|
|
|
|
|
При наличии подобных строк в окне задачника (если окно находится в режиме с фиксированной компоновкой)
|
|
|
|
|
|
слева от области формулировки появятся кнопки, обеспечивающие прокрутку формулировки задания;
|
|
|
|
|
|
кроме этих кнопок для прокрутки можно также использовать стандартные клавиши, в частности, клавиши со стрелками.
|
|
|
|
|
|
</p>
|
|
|
|
|
|
<p>Для того чтобы имя нулевого указателя (или объекта) соответствовало используемому языку программирования,
|
|
|
|
|
|
в формулировке задания применяются управляющие последовательности <code>\N</code> (имя нулевого указателя) и <code>\O</code> (имя нулевого объекта).
|
|
|
|
|
|
Для языка PascalABC.NET обе эти последовательности генерируют текст <code>nil</code>.
|
|
|
|
|
|
</p>
|
|
|
|
|
|
<p>Достаточно часто алгоритмы, разработанные учащимися для обработки динамических структур данных, дают неверные результаты
|
|
|
|
|
|
в случае особых (хотя и допустимых) структур, например, состоящих только из одного элемента. Поэтому желательно
|
|
|
|
|
|
предусмотреть появление подобных структур в тестовых наборах исходных данных.
|
|
|
|
|
|
В наших заданиях исходный список, состоящий из
|
|
|
|
|
|
<i>одного</i> элемента, будет предлагаться программе учащегося в среднем один раз при каждых четырех тестовых испытаниях.
|
|
|
|
|
|
Кроме того, благодаря использованию функции <a href="tmaker_proc1.html#CurrentTest">CurrentTest</a>, появившейся в
|
|
|
|
|
|
версии 4.11 конструктора, вариант списка с единственным элементом будет предложен программе учащегося для обработки
|
|
|
|
|
|
в тесте номер 2, а вариант списка с более чем одним элементом — в тесте номер 4. Таким образом, можно гарантировать,
|
|
|
|
|
|
что при прохождении набора из 5 тестовых испытаний программе будут предложены как «стандартные»,
|
|
|
|
|
|
так и «особые» наборы исходных данных.
|
|
|
|
|
|
</p>
|
|
|
|
|
|
<p>При формировании односвязной структуры неиспользуемые поля Prev для каждого элемента структуры следует
|
|
|
|
|
|
положить равными адресу «фиктивного» элемента (в нашем случае — переменной WrongNode),
|
|
|
|
|
|
не связанного с данной структурой. Заметим, что для всех элементов, кроме первого, значения поля Prev
|
|
|
|
|
|
можно было бы положить равными nil, однако это не подходит для
|
|
|
|
|
|
первого элемента: если поле Prev первого элемента будет равно nil, то слева от него будет выведен
|
|
|
|
|
|
«лишний» (в данной ситуации) текст <code>nil<</code>.
|
|
|
|
|
|
</p>
|
|
|
|
|
|
<p>Характерной особенностью разработки заданий на динамические структуры является <i>обратный порядок</i> создания этих структур:
|
|
|
|
|
|
вначале создаются <i>контрольные</i> структуры (которые сразу передаются в задачник), а затем они преобразуются в соответствующие
|
|
|
|
|
|
<i>исходные</i> структуры, которые должны не только передаваться в задачник, но и <i>оставаться в памяти</i>, чтобы в дальнейшем их можно было
|
|
|
|
|
|
использовать в программе учащегося, выполняющей это задание.
|
|
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
|
|
<p>Если в группу включаются задания на динамические структуры, то необходимо <i>анализировать текущий язык программирования</i>,
|
|
|
|
|
|
используемый задачником. Это обусловлено двумя причинами:
|
|
|
|
|
|
</p>
|
|
|
|
|
|
<ul><li> имеются языки, для которых отсутствует возможность выполнять
|
|
|
|
|
|
задания на обработку динамических структур (например, Visual Basic и 1C);
|
|
|
|
|
|
<li> в языках платформы .NET, а также Python и Java, необходимо использовать «объектный» стиль формулировок вместо
|
|
|
|
|
|
стиля, основанного на указателях и применяемого для языков Pascal и C++.
|
2018-08-02 22:04:49 +03:00
|
|
|
|
</ul>
|
2025-11-07 16:12:31 +03:00
|
|
|
|
<p>Кроме того, следует определиться с выбором стиля для языка PascalABC.NET, поскольку в нем
|
|
|
|
|
|
можно использовать как стиль указателей, так и стиль объектов. Можно, например, включить в группу заданий для языка
|
|
|
|
|
|
PascalABC.NET оба варианта каждого задания.
|
2018-08-02 22:04:49 +03:00
|
|
|
|
</p>
|
2025-11-07 16:12:31 +03:00
|
|
|
|
<p>Отмеченные обстоятельства приводят к тому, что для разных языков программирования создаваемая группа
|
|
|
|
|
|
может содержать разное число заданий и, кроме того, для этих заданий будут использоваться разные
|
|
|
|
|
|
инициализирующие процедуры.
|
2018-08-02 22:04:49 +03:00
|
|
|
|
</p>
|
2025-11-07 16:12:31 +03:00
|
|
|
|
<p>С учетом этих замечаний изменим основную процедуру группы InitTask следующим образом:
|
2018-08-02 22:04:49 +03:00
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<pre>procedure InitTask(num: integer);
|
|
|
|
|
|
begin
|
|
|
|
|
|
case num of
|
|
|
|
|
|
1..2: UseTask('Begin', num);
|
|
|
|
|
|
3: MakerDemo3;
|
|
|
|
|
|
4: MakerDemo4;
|
|
|
|
|
|
5: MakerDemo5;
|
|
|
|
|
|
6: MakerDemo6;
|
|
|
|
|
|
7: MakerDemo7;
|
|
|
|
|
|
8: if CurrentLanguage and lgWithPointers <> 0 then
|
|
|
|
|
|
MakerDemo8
|
|
|
|
|
|
else
|
|
|
|
|
|
MakerDemo8Obj;
|
|
|
|
|
|
9: MakerDemo8Obj;
|
|
|
|
|
|
end;
|
|
|
|
|
|
end;
|
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
2025-11-07 16:12:31 +03:00
|
|
|
|
<p>В этой процедуре используется функция <a href="tmaker_proc1.html#CurrentLanguage">CurrentLanguage</a>,
|
|
|
|
|
|
позволяющая определить текущий язык программирования,
|
|
|
|
|
|
используемый задачником. Если текущий язык относится к категории языков,
|
|
|
|
|
|
поддерживающих указатели (в том числе PascalABC.NET), то
|
|
|
|
|
|
в качестве задания номер 8 вызывается процедура MakerDemo8, в которой задание формулируется в терминах указателей.
|
|
|
|
|
|
В противном случае вызывается вариант задания, использующий объектную терминологию.
|
|
|
|
|
|
При использовании языка PascalABC.NET число заданий в группе будет равно 9; при этом дополнительное
|
|
|
|
|
|
задание номер 9 будет представлять собой «объектный» вариант задания номер 8.
|
2018-08-02 22:04:49 +03:00
|
|
|
|
</p>
|
|
|
|
|
|
|
2025-11-07 16:12:31 +03:00
|
|
|
|
<p>Функцию CurrentLanguage потребуется использовать и в начале процедуры inittaskgroup для того, чтобы
|
|
|
|
|
|
правильно определить количество заданий в группе для разных языков программирования.
|
|
|
|
|
|
Приведем фрагмент, на который надо заменить вызов процедуры CreateGroup и предшествующее ему ключевое слово begin
|
|
|
|
|
|
(обратите внимание на то, что теперь
|
|
|
|
|
|
в качестве предпоследнего параметра процедуры CreateGroup используется переменная n):
|
2018-08-02 22:04:49 +03:00
|
|
|
|
</p>
|
|
|
|
|
|
<pre>var
|
|
|
|
|
|
n: integer;
|
|
|
|
|
|
begin
|
|
|
|
|
|
n := 7;
|
|
|
|
|
|
if CurrentLanguage = lgPascalABCNET then
|
|
|
|
|
|
n := 9
|
|
|
|
|
|
else
|
|
|
|
|
|
if CurrentLanguage and (lgWithPointers or lgWithObjects) <> 0 then
|
|
|
|
|
|
n := 8;
|
2025-11-07 16:12:31 +03:00
|
|
|
|
CreateGroup('MakerDemo', 'Примеры различных задач',
|
|
|
|
|
|
'М. Э. Абрамян, 2013', 'qwqfsdf13dfttd', n, InitTask);
|
2018-08-02 22:04:49 +03:00
|
|
|
|
</pre>
|
2025-11-07 16:12:31 +03:00
|
|
|
|
<p>Приведенный набор условий будет правильно определять количество заданий и в случае,
|
|
|
|
|
|
если состав языков, поддерживаемых задачником, будет расширен. Это обеспечивается тем, что
|
|
|
|
|
|
в условиях используются не константы для конкретных языков (за исключением константы lgPascalABCNET),
|
|
|
|
|
|
а битовые маски lgWithPointers и lgWithObjects. Первая из этих масок включает все языки, для которых
|
|
|
|
|
|
в задачнике можно использовать варианты заданий на динамические структуры, основанные на указателях,
|
|
|
|
|
|
а вторая — все языки, позволяющие использовать варианты аналогичных заданий
|
|
|
|
|
|
в объектной терминологии.
|
2018-08-02 22:04:49 +03:00
|
|
|
|
</p>
|
|
|
|
|
|
|
2025-11-07 16:12:31 +03:00
|
|
|
|
<p>В среде PascalABC.NET можно протестировать оба варианта реализованного задания.
|
|
|
|
|
|
Приведем вид окна задачника для этого задания (первый рисунок соответствует
|
|
|
|
|
|
варианту задания, использующему указатели, второй — варианту, использующему объекты).
|
|
|
|
|
|
Обратите внимание
|
|
|
|
|
|
на кнопки, расположенные справа от формулировки задания и обеспечивающие ее прокрутку.
|
2018-08-02 22:04:49 +03:00
|
|
|
|
</p>
|
|
|
|
|
|
<p class="ris"><img border="0" src="images\pt4make12.png">
|
|
|
|
|
|
</p>
|
|
|
|
|
|
<p class="ris"><img border="0" src="images\pt4make13.png">
|
|
|
|
|
|
</p>
|
2025-11-07 16:12:31 +03:00
|
|
|
|
<p>Завершая оформление модуля PT4MakerDemo, добавим комментарии к новым подгруппам заданий (указанные операторы следует поместить
|
|
|
|
|
|
в конец процедуры inittaskgroup):
|
2018-08-02 22:04:49 +03:00
|
|
|
|
</p>
|
|
|
|
|
|
|
2025-11-07 16:12:31 +03:00
|
|
|
|
<pre> Subgroup('Двумерные массивы (матрицы): вывод элементов');
|
|
|
|
|
|
CommentText('Данное задание дублирует задание Matrix7.');
|
2018-08-02 22:04:49 +03:00
|
|
|
|
|
2025-11-07 16:12:31 +03:00
|
|
|
|
Subgroup('Символьные и строковые файлы');
|
|
|
|
|
|
CommentText('Данное задание дублирует задание File63.');
|
|
|
|
|
|
CommentText('Оно демонстрирует особенности, связанные с двоичными');
|
|
|
|
|
|
CommentText('\Iстроковыми\i файлами.');
|
2018-08-02 22:04:49 +03:00
|
|
|
|
|
2025-11-07 16:12:31 +03:00
|
|
|
|
Subgroup('Текстовые файлы: основные операции');
|
|
|
|
|
|
CommentText('Данное задание дублирует задание Text16.');
|
2018-08-02 22:04:49 +03:00
|
|
|
|
|
2025-11-07 16:12:31 +03:00
|
|
|
|
Subgroup('Динамические структуры данных: двусвязный список');
|
|
|
|
|
|
CommentText('Данное задание дублирует задание Dynamic30.');
|
|
|
|
|
|
CommentText('\PЗадание реализовано в двух вариантах: основанном на использовании указателей');
|
|
|
|
|
|
CommentText('(для языков Pascal и C++) и основанном на использовании объектов (для языков платформы .NET,');
|
|
|
|
|
|
CommentText('а также Python и Java). Для языка Visual Basic это задание недоступно.');
|
|
|
|
|
|
CommentText('В системе PascalABC.NET доступны оба варианта задания.');
|
2018-08-02 22:04:49 +03:00
|
|
|
|
</pre>
|
|
|
|
|
|
|
2025-11-07 16:12:31 +03:00
|
|
|
|
<p>Приведем заключительную часть html-страницы с описанием данной группы:
|
2018-08-02 22:04:49 +03:00
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
|
|
<p class="ris"><img border="1" src="images\pt4make14.png">
|
|
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
</body>
|
|
|
|
|
|
|
|
|
|
|
|
</html>
|
|
|
|
|
|
|
|
|
|
|
|
|