Конструктор PT4MakerNetX для PascalABC.NET
Общее описание
Конструктор PT4MakerNetX входит в дистрибутив системы программирования
PascalABC.NET, начиная с версии 3.2, и является упрощенным вариантом конструктора
PT4TaskMaker. Использованные в нем возможности библиотеки платформы .NET и языка
PascalABC.NET позволяют разрабатывать новые группы заданий для электронного
задачника Programming Taskbook более простым и наглядным образом и впоследствии
легко модифицировать их.
Как и в случае использования базового варианта конструктора PT4TaskMaker, новые
группы должны оформляться в виде библиотек library с именами, имеющими префикс
PT4. Текст имени после префикса определяет имя группы.
Библиотека должна содержать две обязательные процедуры с фиксированными именами
inittaskgroup и activate, причем в первой процедуре должна вызываться процедура
NewGroup, а во второй процедура ActivateNET. Для включения в группу нового
задания достаточно оформить его в виде процедуры с именем, начинающимся с текста
Task.
Задания включаются в группу в соответствии с лексикографическим порядком
имен процедур, начинающихся с текста Task. Регистр букв не учитывается.
При определении порядка следования заданий следует учитывать, что пустой символ считается меньшим любого
непустого символа, цифровой символ считается меньшим любого буквенного символа.
Приведем пример имен, расположенных в лексикографическом порядке:
task01, Task01a, TASK01b, Task10, task11, taska, taska1, taska2, taskab, taskB, taskc.
Все процедуры и функции конструктора доступны не только в виде обычных подпрограмм, но и в виде статических методов
класса pt, что упрощает как ознакомление с ними, так и вызов: достаточно ввести имя pt с
точкой, чтобы получить список всех методов данного класса. При выборе метода из
списка и его последующем редактировании доступна контекстная подсказка, содержащая
краткое описание метода и список его параметров для всех перегруженных
вариантов. Класс pt также содержит методы без параметров
OptionAllLanguages, OptionPascalLanguages, OptionNETLanguages, OptionUseAddition,
OptionHideExamples, возвращающие значения одноименных констант.
Конструктор PT4MakerNetX включен в комплекс Teacher Pack for Programming Taskbook 4,
начиная с версии 3.1 комплекса.
В версию Teacher Pack 3.2 был добавлен файл xPT4MakerNetX.pas, являющийся вариантом конструктора,
предназначенным для генерации 64-разрядных библиотек с группами заданий.
Динамические библиотеки, создаваемые с помощью этого варианта, должны иметь префикс xPT4.
Описание компонентов конструктора PT4MakerNetX
const
OptionAllLanguages = 1; // группа доступна для всех языков
OptionPascalLanguages = 2; // группа доступна для всех реализаций Паскаля
OptionNETLanguages = 4; // группа доступна для всех NET-языков
OptionUseAddition = 8; // группа доступна только при наличии файла дополнений
OptionHideExamples = 16; // не отображать раздел с примером верного решения
Набор констант, позволяющих настроить дополнительные свойства создаваемой группы
(эти константы указываются в качестве последнего параметра процедуры NewGroup и
объединяются операциями or). В классе pt имеются методы с такими же именами,
возвращающие значения соответствующих констант.
При отсутстии дополнительных настроек задания группы будут доступны для выполнения только в системе PascalABC.NET.
procedure NewGroup(GroupDescription, GroupAuthor: string;
Options: integer := 0);
procedure ActivateNet(S: string);
Вспомогательные процедуры, которые обязательно должны использоваться в библиотеке,
определяющей группу.
Процедура NewGroup должна вызываться в процедуре inittaskgroup (без параметров).
Первый параметр процедуры NewGroup содержит краткое описание определяемой
группы, второй сведения о разработчике, третий (необязательный) набор констант,
определяющих дополнительные свойства группы (константы объединяются операциями
or). Краткое описание группы используется в качестве заголовка в ее html-описании.
Процедура ActivateNet должна вызываться в процедуре activate(S: string); параметр
процедуры ActivateNet должен совпадать с параметром процедуры activate.
procedure UseTask(GroupName: string; TaskNumber: integer);
procedure UseTask(GroupName: string; TaskNumber: integer; TopicDescription: string);
Процедура, позволяющая включать в группу задание из другой группы.
Первый параметр определяет имя существующей группы, второй номер задания из этой группы.
Третий, необязательный параметр позволяет изменить заголовок, связываемый с импортируемым заданием.
Должна вызываться в процедуре, имя которой начинается с текста Task.
procedure NewTask(Topic, TaskText: string);
procedure NewTask(TaskText: string);
Данная процедура должна вызываться первой при определении нового задания (кроме
случаев, когда задание импортируется из существующей группы процедурой UseTask, описанной выше).
Процедура определяет формулировку задания (в строке TaskText). Разрыв строки в формулировке задания должен
помечаться символами #13 или #10 (или их комбинацией #13#10). В формулировке задания могут использоваться
все виды управляющих последовательностей, описанные в разделе
«Форматирование текста заданий».
Параметр Topic является необязательным; при его
указании он определяет название подгруппы, в которую включается задание (название подгруппы
отображается в верхней строке окна задачника
и выводится в качестве заголовка подраздела в html-документе). Если
определяемая группа не предполагает деления на подгруппы, то параметр Topic не указывается; в этом случае
для всех заданий группы в верхней строке окна задачника отображается текст параметра
GroupDescription процедуры NewGroup с кратким описанием группы.
procedure DataComm(Comm: string);
procedure Data(Comm: string; A: object);
procedure Data(Comm1: string; A1: object; Comm2: string);
procedure Data(Comm1: string; A1: object; Comm2: string; A2: object);
procedure Data(Comm1: string; A1: object; Comm2: string; A2: object;
Comm3: string);
procedure Data(Comm1: string; A1: object; Comm2: string; A2: object;
Comm3: string; A3: object);
procedure Data(Seq: sequence of boolean);
procedure Data(Seq: sequence of integer);
procedure Data(Seq: sequence of real);
procedure Data(Seq: sequence of char);
procedure Data(Seq: sequence of string);
Процедуры этой группы позволяют задать исходные данные и комментарии к ним. Вызов каждой из процедур
заполняет одну строку раздела исходных данных, за исключением вариантов с параметром-последовательностью Seq,
которые могут заполнять несколько строк (число строк зависит от
размера последовательности). В качестве параметров типа object могут использоваться данные базовых типов
boolean, integer, real, char, string. При указании данных других типов выводится сообщение об
ошибке (на позиции, предназначенной для отображения этого элемента
данных).
Если после комментария не указывается элемент данных, то соответствующая часть строки
отводится только под комментарий.
Можно указывать не более 200 элементов исходных данных; если элементов более 200, то
в первой строке раздела с формулировкой задания выводится сообщение об ошибке.
procedure ResComm(Comm: string);
procedure Res(Comm: string; A: object);
procedure Res(Comm1: string; A1: object; Comm2: string);
procedure Res(Comm1: string; A1: object; Comm2: string; A2: object);
procedure Res(Comm1: string; A1: object; Comm2: string; A2: object;
Comm3: string);
procedure Res(Comm1: string; A1: object; Comm2: string; A2: object;
Comm3: string; A3: object);
procedure Res(Seq: sequence of boolean);
procedure Res(Seq: sequence of integer);
procedure Res(Seq: sequence of real);
procedure Res(Seq: sequence of char);
procedure Res(Seq: sequence of string);
Процедуры позволяют задать контрольные данные и комментарии к ним. Правила их использования аналогичны
правилам для процедур DataComm и Data, задающих исходные данные (см. их описание, приведенное выше).
Контрольные данные используются при проверке правильности результатов, полученных учебной программой,
и отображаются в разделе «Пример верного решения» окна задачника. Создаваемую группу заданий можно
настроить таким образом, чтобы раздел с примером верного решения не отображался на экране (например, если
группа предназначена для использования при проведении контрольной работы); для этого достаточно в процедуре NewGroup
указать дополнительную опцию OptionHideExamples.
Указанные процедуры определяют также способ отображения результатов, найденных учебной программой
(результирующие данные вместе с комментариями отображаются в разделе «Полученные результаты»).
procedure DataFileInteger(FileName: string);
procedure DataFileReal(FileName: string);
procedure DataFileChar(FileName: string);
procedure DataFileString(FileName: string);
procedure DataText(FileName: string; LineCount: integer := 4);
procedure ResFileInteger(FileName: string);
procedure ResFileReal(FileName: string);
procedure ResFileChar(FileName: string);
procedure ResFileString(FileName: string);
procedure ResText(FileName: string; LineCount: integer := 5);
Процедуры, позволяющие добавлять к заданию файловые данные (двоичные файлы типа
file of integer, file of real, file of char, file of ShortString и текстовые файлы типа text).
В задании можно использовать не более 5 исходных и не более 5 результирующих файлов.
Длина строк в файлах типа file of ShortString и text не должна превосходить 70. Текстовые файловые данные
должны храниться в однобайтной кодировке.
В каждом из разделов окна задачника, содержащих
файловые данные, должно определяться не более 5 строк с данными,
если считать, что на «обычные» данные отводится требуемое число строк, на двоичный файл
одна строка, а на текстовый количество строк, равное значению
параметра LineCount (параметр LintCount может принимать значения от 1 до 5; если при этом число строк в
разделе будет превышать 5, то значение параметра LineCount автоматически уменьшается).
Заметим, что несмотря на указанное выше формальное ограничение количества строк
(обусловленное особенностями базового варианта конструктора PT4TaskMaker),
фактически при отображении двоичных файлов будет использовано столько экранных строк,
сколько требуется для вывода всех их элементов, а содержимое текстовых файлов может
отображаться в двух вариантах: сокращенном (на LineCount строках) и полном.
procedure SetTestCount(N: integer);
Задает количество тестов N (от 2 до 9), при успешном прохождении которых
задание считается выполненным. По умолчанию количество тестов полагается равным 5.
procedure SetRequiredDataCount(N: integer);
Задает количество N начальных элементов из набора исходных данных, которые достаточно
ввести для правильного решения задачи. По умолчанию равно общему количеству всех
исходных данных.
procedure SetWidth(N: integer);
Задает минимальную ширину N поля вывода для числовых данных (числа выравниваются
по правому краю поля вывода, т. е. при необходимости дополняются слева пробелами).
Если параметр N не лежит в диапазоне 0..10, то вызов процедуры игнорируется. По
умолчанию минимальная ширина поля вывода полагается равной 0; в этом случае фактическая ширина
поля вывода определяется значениями исходных и контрольных числовых данных. Действие процедуры
продолжается до ее очередного вызова. Для нового задания восстанавливается значение
по умолчанию.
procedure SetPrecision(N: integer);
Задает количество N отображаемых дробных знаков для вещественных чисел. По
умолчанию N = 2. При положительных N числа отображаются в
формате с фиксированной точкой и N дробными знаками.
Если N = 0, то числа отображаются в
экспоненциальном формате с 6 дробными знаками. При отрицательных N числа отображаются в
экспоненциальном формате с |N| дробными знаками. Если |N| > 10, то вызов процедуры
игнорируется. Действие процедуры продолжается до ее очередного вызова. Для нового
задания восстанавливается значение по умолчанию.
function CurrentTest: integer;
Возвращает номер текущего теста (тесты нумеруются от 1). В случае демонстрационного
запуска возвращает значение 0. Дает возможность генерировать особые варианты тестов на
определенном этапе тестирования программы.
function Random(M, N: integer): integer;
function Random(A, B: real): real;
function Random1(A, B: real): real;
function Random2(A, B: real): real;
function RandomName(Len: integer): string;
Дополнительные функции генерации случайных данных. Функция RandomName
генерирует случайную строку длины Len, состоящую из цифр и маленьких латинских
букв. В функции Random(M, N) границы диапазона включаются в возможный набор
значений, в функции Random(A, B) возвращается вещественное число из полуинтервала
[A, B). Если второй параметр функции Random меньше или равен первому, то функция
возвращает значение первого параметра.
Функции Random1 и Random2 являются
вариантами функции Random для вещественных параметров, которые
генерируют случайное вещественное число на промежутке [A, B)
с одним или, соответственно, двумя дробными знаками
и случайной добавкой порядка 1e-7.
Если промежуток [A, B) пуст, то эти функции возвращают A, округленное
до одного или двух дробных знаков и снабженное добавкой порядка 1e-7.
Функции Random1 и Random2 позволяют получать вещественные числа, которые
отображаются в окне задачника практически без потерь значащих цифр, что в ряде
случаев позволяет избежать проблем, связанных с округлением. Например,
если задание состоит в том, чтобы найти сумму двух вещественных чисел,
и для его реализации используется «обычная» функция Random, то
для исходных чисел A = 2.3441... и B = 3.4242...
суммой будет число A + B = 5.768... .
В результате округления до двух знаков в окне задачника эти числа будут
выведены в следующем виде:
A = 2.34
B = 3.42
A + B = 5.77
Такой результат может смутить внимательных учащихся, если они не знают,
что при отображении вещественных данных задачник выполняет их округление.
Использование функций Random1 и Random2 позволяет избежать подобных проблем.
При этом небольшая случайная добавка порядка 1e-7 по-прежнему обеспечивает уникальность
генерируемых чисел (в частности, в наборе чисел всегда будет единственный минимальный
и единственный максимальный элемент).
function GetWords: array of string;
function GetEnWords: array of string;
function GetSentences: array of string;
function GetEnSentences: array of string;
function GetTexts: array of string;
function GetEnTexts: array of string;
Функции возвращают массивы слов, предложений и многострочных текстов, которые
можно использовать в качестве исходных данных. Варианты функций, в именах которых
присутствует текст En, возвращают данные на английском языке, варианты без этого
текста данные на русском. Строки в многострочных текстах разделяются символами
#13#10, в конце текста символы #13#10 отсутствуют. Длина предложений и строк в
многострочных текстах не превосходит 70 символов.
function RandomWord: string;
function RandomEnWord: string;
function RandomSentence: string;
function RandomEnSentence: string;
function RandomText: string;
function RandomEnText: string;
Функции возвращают случайный элемент из массива слов, предложений и
многострочных текстов. Варианты функций, в именах которых присутствует текст En,
возвращают данные на английском языке, варианты без этого текста данные на
русском. Строки в многострочных текстах разделяются символами #13#10, в конце текста
символы #13#10 отсутствуют. Длина предложений и строк в многострочных текстах не
превосходит 70 символов.
Структура библиотеки, определяющей группу заданий
library PT4Test; // имя библиотеки начинается с префикса PT4,
// после которого идет имя группы
uses PT4MakerNetX; // подключение конструктора
procedure inittaskgroup; // процедура инициализации группы должна иметь
// имя inittaskgroup, набранное маленькими буквами
begin
pt.NewGroup('Дополнительные задачи', ' М. Э. Абрамян, 2017');
end;
procedure activate(S: string); // в библиотеке должна быть описана процедура
// с именем activate (маленькими буквами),
// в которой вызывается процедура ActivateNet
begin
pt.ActivateNet(S);
end;
procedure Task1; // процедуры, определяющие задания.
// Признаком такой процедуры является имя, начинающееся
// со слова Task (регистр не важен)
begin
pt.NewTask('Дан текстовый файл. Определить число строк в нем.');
var name := RandomName(8)+'.tst';
var s := RandomText;
WriteAllText(name, s);
pt.Data('Имя файла: ', name, 'Содержимое файла:');
pt.DataText(name);
pt.Res('Число строк в файле: ', s.Count(e -> e = #13) + 1);
end;
procedure Task2; // процедура может импортировать задание из имеющейся группы
begin
pt.UseTask('Begin', 3);
end;
// Здесь могут располагаться другие задания, определенные в виде процедур
// с именами, начинающимися с текста Task, которые будут добавляться
// в группу в лексикографическом порядке их имен.
// Если при выполнении процедуры с заданием возникает исключение,
// то в окне задачника в начале раздела с формулировкой задания
// выводится имя исключения и строка с его описанием.
end.
Пример группы заданий, подготовленной с помощью
конструктора PT4MakerNetX
В данном пункте приводится текст демонстрационной группы NetXDemo, задания которой
совпадают с начальными 7 заданиями, описанными в демонстрационной группе MakerDemo
(см. раздел «Примеры»).
library PT4NetXDemo;
uses PT4MakerNetX;
procedure inittaskgroup;
begin
pt.NewGroup('Примеры различных задач', 'М. Э. Абрамян, 2017');
end;
procedure activate(S: string);
begin
pt.ActivateNet(S);
end;
procedure Task1;
begin
pt.UseTask('Begin', 1);
end;
procedure Task2;
begin
pt.UseTask('Begin', 2);
end;
procedure Task3;
begin
pt.NewTask('Ввод и вывод данных, оператор присваивания',
'Даны стороны прямоугольника~{a} и~{b}.'#13
'Найти его площадь {S}~=~{a}\*{b} и периметр {P}~=~2\*({a}\;+\;{b}).');
var a := pt.Random(1, 99) / 10;
var b := pt.Random(1, 99) / 10;
pt.SetWidth(5);
pt.Data('a = ', a, 'b = ', b);
pt.Res('S = ', a * b, 'P = ', 2 * (a + b));
pt.SetTestCount(3);
end;
procedure Task4;
begin
pt.NewTask('Двумерные массивы (матрицы): вывод элементов',
'Дана матрица размера~{M}\;\x\;{N} и целое число~{K} (1~\l~{K}~\l~{M}).'#13
'Вывести элементы {K}-й строки данной матрицы.');
var m := pt.Random(4, 8);
var n := pt.Random(4, 8);
var k := pt.Random(1, m);
pt.Data('M = ', m, 'N = ', n);
pt.SetWidth(5);
for var i := 0 to m-1 do
begin
var a := ArrGen(n, i -> pt.Random(-9.99, 9.99));
pt.Data(a);
if i = k - 1 then
pt.Res(a);
end;
pt.SetWidth(0);
pt.Data('K = ', k);
pt.SetTestCount(5);
end;
procedure Task5;
begin
pt.NewTask('Символы и строки: основные операции',
'Дана непустая строка~{S}.'#13
'Вывести ее первый и последний символ.');
var s := pt.RandomWord;
if pt.CurrentTest = 3 then
while s[1] = s[Length(s)] do
s := pt.RandomWord;
pt.Data('S = ', s);
pt.Res('Первый символ: ', s[1], 'Последний символ: ', s[s.Length]);
pt.SetTestCount(4);
end;
procedure Task6;
begin
pt.NewTask('Символьные и строковые файлы',
'Дано целое число~{K} (>\,0) и строковый файл.'#13
'Создать два новых файла: строковый, содержащий первые {K}~символов'#13
'каждой строки исходного файла, и символьный, содержащий {K}-й символ'#13
'каждой строки (если длина строки меньше~{K}, то в строковый файл'#13
'записывается вся строка, а в символьный файл записывается пробел).');
var s1 := '1' + pt.RandomName(5) + '.tst';
var s2 := '2' + pt.RandomName(5) + '.tst';
var s3 := '3' + pt.RandomName(5) + '.tst';
var fs1, fs2: file of ShortString;
var fc3: file of char;
Rewrite(fs1, s1);
Rewrite(fs2, s2);
Rewrite(fc3, s3);
var k := pt.Random(2, 11);
for var i := 1 to pt.Random(10, 20) do
begin
var s := pt.RandomName(pt.Random(2, 16));
write(fs1, s);
write(fc3, (s.Length >= k) ? s[k] : ' ');
write(fs2, copy(s, 1, k));
end;
Close(fs1);
Close(fs2);
Close(fc3);
pt.Data('K = ', k);
pt.Data('Имя исходного файла: ', s1, 'Содержимое исходного файла:');
pt.DataFileString(s1);
pt.Data('Имя результирующего строкового файла: ', s2);
pt.Data('Имя результирующего символьного файла: ', s3);
pt.ResComm('Содержимое результирующего строкового файла:');
pt.ResFileString(s2);
pt.ResComm('Содержимое результирующего символьного файла:');
pt.ResFileChar(s3);
end;
procedure Task7;
begin
pt.NewTask('Текстовые файлы: основные операции',
'Дан текстовый файл.'#13
'Удалить из него все пустые строки.');
var s1 := pt.RandomName(6) + '.tst';
var s2 := '#' + pt.RandomName(6) + '.tst';
var s := pt.RandomText;
WriteLines(s2, Seq(s));
WriteLines(s1, Seq(s.Replace(#13#10#13#10, #13#10)));
pt.ResText(s1);
RenameFile(s2, s1);
pt.Data('Имя файла: ', s1);
pt.DataText(s1);
pt.SetTestCount(3);
end;
end.
Добавление в группу заданий текста преамбулы
В конструктор PT4MakerNetX, в отличие от базового конструктора PT4TaskMaker, не
включены средства, позволяющие добавлять в группу дополнительный текст,
отображаемый в виде преамбулы группы или ее подгрупп. Это связано с тем, что в новых
версиях задачника подобные тексты можно определять в виде обычных текстовых файлов
(файлов дополнений) см. раздел
«Использование файлов дополнений».
Подобный подход является более гибким, так как позволяет
корректировать и дополнять поясняющие тексты без перекомпиляции dll-файла,
содержащего определение группы. Кроме того, в файлы дополнений можно включать
указания к любому из заданий, а также индивидуальные программы-заготовки
для различных заданий.
Если файл дополнений необходим для выполнения заданий из создаваемой группы
(например, в случае, когда для заданий группы требуется использовать индивидуальные программы-заготовки), то
в процедуре NewGroup следует указать дополнительную опцию OptionUseAddition.
Группа с такой опцией будет подключаться к задачнику только при наличии связанного с ней файла дополнений.
В качестве примера ниже приводится текст файла дополнений PT4NetXDemo.txt для
определенной в предыдущем пункте группы заданий NetXDemo. В нем указан текст
преамбулы к группе и ее подгруппам.
[=]
[text]
[0]
Данная группа демонстрирует различные возможности
%{I}конструктора учебных заданий%{i} %{M}PT4MakerNetX%{m}.
[~Ввод и вывод данных, оператор присваивания]
В этой подгруппе содержатся задания, импортированные
из группы Begin.
[~Двумерные массивы (матрицы): вывод элементов]
Данное задание дублирует задание Matrix7.
[~Символьные и строковые файлы]
Данное задание дублирует задание File63.
Оно демонстрирует особенности, связанные с двоичными
%{I}строковыми%{i} файлами.
[~Текстовые файлы: основные операции]
Данное задание дублирует задание Text16.
Ниже приводится html-описание группы NetXDemo с подключенным файлом дополнений, полученное с помощью модуля
PT4Demo.
|