|
Программа PTGroupCreator
Общее описание
PTGroupCreator это вспомогательная программа из комплекса TeacherPack, которая позволяет разработчику
создавать заготовки новых групп заданий на языке C++, используя упрощенный конструктор
PT4TaskMakerX.
Программа PTGroupCreator входит в состав комплекса TeacherPack, начиная с версии 3.4.
Чтобы создать новую группу заданий с помощью данной программы, достаточно указать минимальный набор
информации о группе: название, каталог и локаль (язык) группы: комбинированная, английская или русская.
Если введенные данные корректны и все необходимые компоненты присутствуют в системе,
то при нажатии пользователем на кнопку Create
программа PTGroupCreator сгенерирует проект для новой группы в указанном каталоге.
Если группа с указанным именем и локалью уже существует, то кнопка изменит свой текст на Open,
нажатие на нее обеспечит открытие существующего проекта.
При наличии в системе редактора Visual Studio Code проект с группой заданий после своего создания откроется в нем.
Сборку динамической библиотеки можно выполнить непосредственно в редакторе Visual Studio Code, выбрав файл с реализацией заданий
и нажав клавишу F5. Также для компиляции в 32-разрядном и 64-разрядном режимах предусмотрены специальные bat-файлы,
которые имеют имена, совпадающие с названием группы и связанной с ней локалью
(для английской локали используется суффикс "_en", для русской локали суффикс "_ru",
для комбинированной локали суффикс не используется).
Для работы программы необходимо наличие задачника Programming Taskbook версии не ниже 4.25
в каталоге C:\Program Files (x86)\PT4,
а также наличие компилятора g++, поставляемого вместе со средой разработки Dev-C++. Желательно присутствие
в системе редактора Visual Studio Code, настроенного на работу с языком C++. В случае отсутствия какого-либо
компонента в окне программы выводится соответствующее сообщение. Все недостающие компоненты можно установить и настроить
с помощью программы PT4Setup, входящей в состав электронного задачника Programming Taskbook.
Имя создаваемой группы заданий должно удовлетворять стандартным условиям для групп электронного задачника Programming Taskbook:
его длина не должна превышать 9 символов, оно должно содержать только латинские буквы, цифры и знак подчеркивания и должно
оканчиваться буквой. При нарушении этих условий программа PTGroupCreator выводит сообщение об ошибке.
Имя динамической библиотеки с группой заданий определяется следующим образом. Оно всегда начинается с префикса PT4
(для 32-разрядного варианта) или xPT4 (для 64-разрядного варианта). Затем следует имя группы и суффикс вида
_en для английской локали и _ru для русской локали. Если создается группа для комбинированной локали, то
суффикс не используется. Таким образом, если группа заданий имеет имя DemoGroup, то на ее основе можно создать
следующие варианты динамических библиотек: PT4DemoGroup.dll, xPT4DemoGroup.dll, PT4DemoGroup_en.dll, xPT4DemoGroup_en.dll,
PT4DemoGroup_ru.dll, xPT4DemoGroup_ru.dll.
Разумеется, создавать все эти варианты нет необходимости.
Если предполагается использование группы заданий только для английской локали, то достаточно подготовить библиотеки
PT4DemoGroup_en.dll, xPT4DemoGroup_en.dll; в этом случае группа будет недоступна для русского варианта задачника.
Если разрабатываются различные варианты группы заданий для английского и русского языка, то можно реализовать
следующий набор библиотек: PT4DemoGroup_en.dll, xPT4DemoGroup_en.dll, PT4DemoGroup_ru.dll, xPT4DemoGroup_ru.dll.
Возможен и другой вариант: подготовить библиотеки PT4DemoGroup.dll, xPT4DemoGroup.dll, в именах которых не уточняется локаль.
В этом случае они будут использоваться для любого варианта задачника. Следует заметить, что с помощью средств конструктора
PT4TaskMakerX (функций pt::CurrentLocale
и pt::Loc) можно настраивать компоненты заданий из комбинированных библиотек
PT4DemoGroup.dll, xPT4DemoGroup.dll таким образом, чтобы они учитывали текущую настойку локали задачника.
Следует также подчеркнуть, что 32- и 64-разрядные варианты библиотек не требуется разрабатывать по отдельности.
После завершения разработки 32-разрядного варианта достаточно запустить пакетный файл (bat-файл), автоматически сгенерированный
программой PTGroupCreator, который создаст 64-разрядный вариант этой же библиотеки.
Рекомендуется разрабатывать новые группы заданий в стандартном рабочем каталоге задачника C:\PT4Work.
Это позволит тестировать созданные группы из любых других рабочих каталогов (связанных, например, с различными языками
программирования), поскольку при поиске групп заданий задачник анализирует не только текущий рабочий каталог и системный
каталог Lib электронного задачника, но и каталог C:\PT4Work. Допускается наличие в одном и том же каталоге нескольких проектов,
связанных с различными группами заданий (или с одной и той же группой для разных локалей).
Ниже приводится скриншот окна программы TaskGroup Creator с примером корректного названия группы и каталога.
Описание компонентов программы PTGroupCreator
Программа PTGroupCreator включает несколько компонентов, целостность которых необходима для успешной генерации
новой группы заданий. В созданную заготовку для новой группы заданий входят файлы упрощенного конструктора PT4TaskMakerX,
cpp-файл с шаблоном группы заданий, bat-файлы для компиляции динамической библиотеки посредством компилятора g++
и настройки каталога для работы Visual Studio Code. Кроме того, в заготовку входит
заголовочный файл linqcpp.h,
содержащий функции для обработки последовательностей данных с помощью запросов, аналогичных запросам LINQ платформы .NET.
Этот заголовочный файл можно подключить к проекту и использовать при реализации группы заданий.
Конструктор PT4TaskMakerX состоит из файлов базового конструктора pt4taskmaker.h, pt4taskmaker.cpp и pt4taskmaker.def,
а также из файлов pt4taskmakerX.h и pt4taskmakerX.cpp. Заголовочный файл pt4taskmakerX.h
включает документирующие комментарии на двух языках: английском и русском; эти комментарии
отображаются в редакторе Visual Studio Code при вводе имен и параметров соответствующих функций.
Некоторые файлы имеют в своем названии и содержимом вхождения строки __grouptemplate__. При генерации группы заданий
эта строка заменяется на название группы. Такими файлами являются, например, файлы __grouptemplate__-x64.bat
и __grouptemplate__-x86.bat, которые выполняют компиляцию динамической библиотеки. Шаблон файла с реализацией группы заданий
имеет имя __grouptemplate__.cpp и представлен в трех вариантах в подкаталогах en, ru и enru. Данные варианты
являются заготовками новой группы для английской, русской и комбинированной локали соответственно.
Ниже приведено содержимое файла __grouptemplate__-x64.bat. Данный текст представляет собой консольную команду,
которая выполняет компиляцию динамической библиотеки с помощью компилятора g++. Вместо полного пути к компилятору
указана строка __compiler__. Это связано с тем, что путь к компилятору неизвестен заранее,
он берется из конфигурационного файла задачника в момент запуска программы TaskGroup Creator.
"__compiler__" ^
-std=c++14 -m64 -fdata-sections -ffunction-sections -s -oS -Og -O2 ^
-shared pt4taskmaker.cpp pt4taskmakerX.cpp ^
__grouptemplate__.cpp ^
-o xPT4__grouptemplate__.dll ^
pt4taskmaker.def ^
-Wl,--enable-stdcall-fixup,--gc-sections
Ряд опций приведенной выше команды предназначен для минимизации размера итогового dll-файла с динамической
библиотекой. Следует заметить, что при использовании библиотеки потоков <fstream> языка C++ размер итогового файла
существенно возрастает, поэтому целесообразно отказаться от этой библиотеки в пользу более легковесной
библиотеки <cstdio> для работы с файлами.
Приведенные далее фрагменты кода представляют собой шаблоны новой группы заданий для английской, русской
и комбинированной локали. Они содержатся в файлах __grouptemplate__.cpp в соответствующем подкаталоге (en, ru и enru).
Именно этот шаблон нужно редактировать при реализации собственной группы.
[Шаблон для английской локали]
#include "pt4taskmakerX.h"
DefineGroupName;
void __stdcall inittaskgroup()
{
pt::NewGroup("Group description", "", "qwqfsdf13dfttd");
}
DefineTask(Task1)
{
pt::NewTask(R"(\STask name.\s Task formulation (line 1)
Task formulation (line 2)
\PNew paragraph of the task formulation (line 3))"
);
int a = pt::Random(1, 9);
pt::Data("Sample input data: a = ", a);
pt::Res("Sample result: 2 * a = ", 2 * a);
pt::SetTestCount(5);
}
[Шаблон для русской локали]
#include "pt4taskmakerX.h"
DefineGroupName;
void __stdcall inittaskgroup()
{
pt::NewGroup("Group description|Описание группы", "", "qwqfsdf13dfttd");
}
DefineTask(Task1)
{
pt::NewTask(R"(\SНазвание задания.\s Формулировка задания (строка 1)
Формулировка задания (строка 2)
\PНовый абзац формулировки задания (строка 3))"
);
int a = pt::Random(1, 9);
pt::Data("Пример входных данных: a = ", a);
pt::Res("Пример результирующих данных: 2 * a = ", 2 * a);
pt::SetTestCount(5);
}
[Шаблон для комбинированной локали]
#include "pt4taskmakerX.h"
DefineGroupName;
void __stdcall inittaskgroup()
{
pt::NewGroup("Group description|Описание группы", "", "qwqfsdf13dfttd");
}
DefineTask(Task1)
{
pt::NewTask(pt::Loc(
R"(\STask name.\s Task formulation (line 1)
Task formulation (line 2)
\PNew paragraph of the task formulation (line 3))",
R"(\SНазвание задания.\s Формулировка задания (строка 1)
Формулировка задания (строка 2)
\PНовый абзац формулировки задания (строка 3))"));
int a = pt::Random(1, 9);
pt::Data(pt::Loc("Sample input data: a = ",
"Пример входных данных: a = "), a);
pt::Res(pt::Loc("Sample result: 2 * a = ",
"Пример результирующих данных: 2 * a = "), 2 * a);
pt::SetTestCount(5);
}
Пример группы заданий, подготовленной с помощью
конструктора PT4TaskMakerX
В данном пункте приводится текст группы DemoCppX, задания которой
совпадают с начальными 7 заданиями из демонстрационной группы MakerDemo
(см. раздел «Примеры»).
Хотя в группе заданий используются формулировки заданий и комментарии на русском языке,
рекомендуется реализовать ее в режиме комбинированной локали, получив в результате библиотеки
PT4DemoCppX.dll и xPT4DemoCppX.dll, что позволит выполнять задания этой группы
в задачнике Programming Taskbook, настроенном на любую локаль.
#include "pt4taskmakerX.h"
DefineGroupName;
void __stdcall inittaskgroup()
{
pt::NewGroup("Examples of various tasks|Примеры различных задач",
"М. Э. Абрамян, 2017", "qwqfsdf13dfttd");
}
DefineTask(Task1)
{
pt::UseTask("Begin", 1);
}
DefineTask(Task2)
{
pt::UseTask("Begin", 2);
}
DefineTask(Task3)
{
pt::NewTask("Ввод и вывод данных, оператор присваивания",
R"(Даны стороны прямоугольника~{a} и~{b}.
Найти его площадь {S}~=~{a}\*{b} и периметр {P}~=~2\*({a}~+~{b}).)");
double a = pt::Random(1, 99) / 10,
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);
}
DefineTask(Task4)
{
pt::NewTask("Двумерные массивы (матрицы): вывод элементов",
R"(Дана матрица размера~{M}~\x~{N} и целое число~{K} (1~\l~{K}~\l~{M}).
Вывести элементы {K}-й строки данной матрицы.)");
int m = pt::Random(4, 8),
n = pt::Random(4, 8),
k = pt::Random(1, m);
pt::Data("M = ", m, "N = ", n);
pt::SetWidth(5);
for ( int i = 0; i < m; i++)
{
vector<double> a(n);
generate(a.begin(), a.end(), [](){ return pt::Random(-9.99, 9.99); });
pt::Data(a);
if (i == k - 1)
pt::Res(a);
}
pt::SetWidth(0);
pt::Data("K = ", k);
pt::SetTestCount(5);
}
DefineTask(Task5)
{
pt::NewTask("Символы и строки: основные операции",
R"(Дана непустая строка~{S}.
Вывести ее первый и последний символ.)");
string s = pt::RandomWord();
if (pt::CurrentTest() == 3)
while (s[0] == s[s.length() - 1])
s = pt::RandomWord();
pt::Data("S = ", s);
pt::Res("Первый символ: ", s[0], "Последний символ: ", s[s.length() - 1]);
pt::SetTestCount(4);
}
DefineTask(Task6) {
pt::NewTask("Символьные и строковые файлы",
R"(Дано целое число~{K} (>\,0) и строковый файл.
Создать два новых файла: строковый, содержащий первые {K}~символов
каждой строки исходного файла, и символьный, содержащий {K}-й символ
каждой строки (если длина строки меньше~{K}, то в строковый файл
записывается вся строка, а в символьный файл записывается пробел).)");
string s1 = "1" + pt::RandomName(5) + ".tst",
s2 = "2" + pt::RandomName(5) + ".tst",
s3 = "3" + pt::RandomName(5) + ".tst";
FILE *fs1 = fopen(s1.c_str(), "wb"),
*fs2 = fopen(s2.c_str(), "wb"),
*fc3 = fopen(s3.c_str(), "wb");
int k = pt::Random(2, 11),
n = pt::Random(10, 20),
jmax = 0;
for (int i = 1; i < n; i++) {
ShortString buf;
int j = pt::Random(2, 16);
if (jmax < j)
jmax = j;
string s = pt::RandomName(pt::Random(2, 16));
pt::ConvertToShortString(s, buf);
fwrite(buf, 256, 1, fs1);
char c = ' ';
if (j >= k)
{
c = s[k-1];
buf[0] = (char)k;
}
fwrite(buf, 256, 1, fs2);
fwrite(&c, 1, 1, fc3);
}
fclose(fs1);
fclose(fs2);
fclose(fc3);
pt::Data("K = ", k);
pt::Data("Имя исходного файла: ", s1, "Содержимое исходного файла:");
pt::DataFileShortString(s1);
pt::Data("Имя результирующего строкового файла: ", s2);
pt::Data("Имя результирующего символьного файла: ", s3);
pt::Res("Содержимое результирующего строкового файла:");
pt::ResFileShortString(s2);
pt::Res("Содержимое результирующего символьного файла:");
pt::ResFileChar(s3);
}
DefineTask(Task7) {
pt::NewTask("Текстовые файлы: основные операции",
R"(Дан текстовый файл.
Удалить из него все пустые строки.)");
string s1 = pt::RandomName(6) + ".tst",
s2 = pt::RandomName(6) + ".tst",
s = pt::RandomText();
FILE *t2 = fopen(s2.c_str(), "w"),
*t1 = fopen(s1.c_str(), "w");
fprintf(t2, (s + "\n").c_str());
fclose(t2);
const char* s0 = "\n\n";
size_t p = s.find(s0);
while (p != string::npos)
{
s.erase(p, 1);
p = s.find(s0);
}
fprintf(t1, (s + "\n").c_str());
fclose(t1);
pt::ResFileText(s1);
rename(s2.c_str(), s1.c_str());
pt::Data("Имя файла", s1);
pt::DataFileText(s1);
pt::SetTestCount(3);
}
Примечание. При реализации заданий на обработку файлов использовались средства
библиотеки cstdio (соответствующий заголовочный файл подключать не требуется, так как
он подключается в файле pt4taskmakerX.h). Полученный в результате компиляции файл
PT4DemoCppX.dll имеет размер 200 К. Если бы для работы с файлами использовался
заголовочный файл fstream, то размер dll-файла увеличился бы до 590 К.
Добавление в группу заданий текста преамбулы
В конструктор PT4TaskMakerX, в отличие от базового конструктора PT4TaskMaker, не
включены средства, позволяющие добавлять в группу дополнительный текст,
отображаемый в виде преамбулы группы или ее подгрупп. Это связано с тем, что в новых
версиях задачника подобные тексты можно определять в виде обычных текстовых файлов
(файлов дополнений) см. раздел
«Использование файлов дополнений».
Подобный подход является более гибким, так как позволяет
корректировать и дополнять поясняющие тексты без перекомпиляции dll-файла,
содержащего определение группы. Кроме того, в файлы дополнений можно включать
указания к любому из заданий, а также индивидуальные программы-заготовки
для различных заданий на разных языках программирования.
Если файл дополнений необходим для выполнения заданий из создаваемой группы
(например, в случае, когда для заданий группы требуется использовать индивидуальные программы-заготовки), то
в функции NewGroup следует указать дополнительную опцию OptionUseAddition.
Группа с такой опцией будет подключаться к задачнику только при наличии связанного с ней файла дополнений.
Поиск файлов дополнений проводится по тем же правилам, что и поиск динамических библиотек с группами заданий:
последовательно анализируется текущий рабочий каталог,
move-каталог (если он определен в файле loaddat.txt),
рабочий каталог по умолчанию C:\PT4Work и подкаталог LIB системного каталога электронного задачника.
В качестве примера ниже приводится текст файла дополнений PT4DemoCppX.txt для
определенной в предыдущем пункте группы заданий DemoCppX. В нем указан текст
преамбулы к группе и ее подгруппам. Заметим, что для различных локалей можно создавать
разные файлы дополнений; для этого достаточно снабдить имя файла дополнений суффиксом _en или _ru.
Можно также создавать разные файлы дополнений для различных языков программирования.
В данном примере файл будет использован для любых языков, поддерживаемых задачником, благодаря
директиве [=].
[=]
[text]
[0]
Данная группа демонстрирует различные возможности
%{I}конструктора учебных заданий%{i} %{M}PT4TaskMakerX%{m}.
[~Ввод и вывод данных, оператор присваивания]
В этой подгруппе содержатся задания, импортированные
из группы Begin.
[~Двумерные массивы (матрицы): вывод элементов]
Данное задание дублирует задание Matrix7.
[~Символьные и строковые файлы]
Данное задание дублирует задание File63.
Оно демонстрирует особенности, связанные с двоичными
%{I}строковыми%{i} файлами.
[~Текстовые файлы: основные операции]
Данное задание дублирует задание Text16.
Ниже приводится html-описание группы DemoCppX с подключенным файлом дополнений, полученное с помощью модуля
PT4Demo.
|