Выбрать главу

procedure MakerDemo3;

var

a, b: real;

begin

CreateTask('Ввод и вывод данных, оператор присваивания');

TaskText('Даны стороны прямоугольника~{a} и~{b}.', 0, 2);

TaskText('Найти его площадь {S}~=~{a}\*{b} и периметр {P}~=~2\*({a}\;+\;{b}).',

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;

Описание процедуры MakerDemo3 (как и описания всех других процедур, обеспечивающих формирование новых заданий) следует разместить перед описанием процедуры InitTask.

Процедура MakerDemo3 включает все основные действия, используемые при формировании нового задания:

инициализацию нового задания (процедура CreateTask; мы указали в этой процедуре, что данное задание должно входить в подгруппу Ввод и вывод данных, оператор присваивания", т. е. в ту же подгруппу, что и два предыдущих задания); определение его формулировки (процедуры TaskText; обратите внимание на используемые в этих процедурах управляющие последовательности); определение исходных (процедуры DataR) и результирующих данных (процедуры ResultR); при этом исходные данные генерируются с помощью датчика случайных чисел (процедура RandomN); указание количества успешных тестовых запусков программы учащегося, достаточных для регистрации задания как выполненного (процедура SetTestCount; для нашего простого задания достаточно трех проведенных подряд успешных тестовых запусков). Необходимо также включить вызов созданной процедуры в основную процедуру группы MakerDemo, связав его с номером 3:

procedure InitTask(num: integer);

begin

case num of

1..2: UseTask('Begin', num);

3: MakerDemo3;

end;

end;

Наконец, следует откорректировать число заданий в вызове процедуры CreateGroup, изменив его на 3.

Запустив тестирующую программу, мы увидим в html-описании группы MakerDemo формулировки трех заданий, а выполнив обратную замену в этой программе символа #" на "?" (в результате вызов процедуры Task опять примет вид Task('MakerDemo?')) и повторно запустив программу на выполнение, мы увидим окно задачника с загруженным заданием MakerDemo3. Заметим, что при последующих запусках проекта мы будем получать в окне задачника различные исходные данные; это связано с тем, что при генерации исходных данных используется датчик случайных чисел.

Добавление заданий на обработку двумерных массивов и символьных строк

Добавим к группе MakerDemo еще два задания: первое из них дублирует задание Matrix7 (подгруппа Двумерные массивы (матрицы): вывод элементов"), а второе не имеет полного аналога в группе String, однако может быть отнесено к ее первой подгруппе: "Символы и строки: основные операции". Реализуем эти задания в процедурах MakerDemo4 и MakerDemo5:

procedure MakerDemo4;

var

m, n, i, j, k: integer;

a: array [1..5, 1..8] of real;

begin

CreateTask('Двумерные массивы (матрицы): вывод элементов');

TaskText('Дана матрица размера~{M}\;\x\;{N} и целое число~{K} (1~\l~{K}~\l~{M}).',

0, 2);

TaskText('Вывести элементы {K}-й строки данной матрицы.', 0, 4);

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

CreateTask('Символы и строки: основные операции');

TaskText('Дана непустая строка~{S}.', 0, 2);

TaskText('Вывести ее первый и последний символ.', 0, 4);

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);

ResultC('Первый символ: ', s[1], xLeft, 3);

ResultC('Последний символ: ', s[Length(s)], xRight, 3);

SetTestCount(4);

end;

Обратите внимание на использование вспомогательной функции Center для центрирования строк матрицы в области исходных и результирующих данных: каждый элемент матрицы занимает 5 экранных позиций, а между элементами размещается по одному пробелу. В процедуре MakerDemo4 не вызывается процедура SetTestCount; в этом случае число успешных тестов, необходимых для регистрации задания как выполненного, по умолчанию полагается равным 5.

При выводе элементов исходной матрицы и результирующей матричной строки дополнительные комментарии указывать не требуется, поэтому используется вариант процедур DataR и ResultR, в котором комментарий отсутствует (этот вариант процедур групп Data и Result добавлен в версию 4.11 конструктора учебных заданий).

В процедуре MakerDemo5 для получения исходных символьных строк используются функции WordCount и WordSample. С помощью этих функций можно получать различные варианты русских слов. Заметим, что в конструкторе PT4TaskMaker имеются также функции EnWordCount и EnWordSample, с помощью которых можно получать варианты английских слов.

В процедуре MakerDemo5 использована еще одна возможность, появившаяся в версии 4.11 конструктора: функция CurrentTest, возвращающая порядковый номер текущего тестового запуска. Использование этой функции позволяет связать какой-либо особый вариант теста с некоторым номером тестового испытания, и тем самым гарантировать, что программа с решением задачи обязательно будет проверена на этом особом варианте теста. В нашем случае строка S выбирается из набора слов-образцов, среди которых имеется сравнительно большое число слов, начинающихся и оканчивающихся одной и той же буквой. Для более надежного тестирования решения желательно гарантировать, что в наборе тестов будет хотя бы один тест, в котором начальный и конечный символ исходной строки различаются. Разумеется, можно было бы всегда выбирать подобные строки, используя соответствующий цикл while. Однако при наличии функции CurrentTest в этом нет необходимости: достаточно выполнять подобный цикл для единственного теста, например, с номером 3, как это сделано в приведенной реализации задания. В дальнейшем мы рассмотрим более содержательный пример использования функции CurrentTest.

Осталось изменить количество заданий в вызове процедуры CreateGroup на 5 и включить вызовы новых процедур в основную процедуру группы InitTask:

procedure InitTask(num: integer);

begin

case num of

1..2: UseTask('Begin', num);

3: MakerDemo3;

4: MakerDemo4;

5: MakerDemo5;