Programming Taskbook


E-mail:

Пароль:

Регистрация пользователя   Восстановление пароля

English

ЮФУ

Электронный задачник по программированию

©  М. Э. Абрамян (Южный федеральный университет), 1998–2019

 

Решения | Pascal | Процедуры задачника

PrevNext


Вспомогательные типы и процедуры задачника

Описанные на данной странице типы и процедуры будут доступны в программе, если к ней с помощью оператора uses подключен модуль PT4. Начиная с версии 4.15, для сред Delphi и Free Pascal Lazarus в качестве имени модуля используется PT4Tasks, а имя PT4 оставлено для модуля среды PascalABC.NET.

Инициализация заданий, ввод-вывод данных


procedure Task(Name: string);

Процедура инициализирует задание с именем Name. Она должна вызываться в начале программы, выполняющей это задание (до вызова процедур ввода-вывода Get–Put). Если в программе, подключившей модуль задачника, не указана процедура Task, то при запуске программы будет выведено окно с сообщением «Не вызвана процедура Task с именем задания».

Имя задания Name должно включать имя группы заданий и порядковый номер в пределах группы (например, 'Begin3'). Регистр букв в имени группы может быть произвольным. Если указана неверная группа, то программа выведет сообщение об ошибке «Указана неверная тема задания» (список всех доступных групп можно получить с помощью программных модулей PT4Demo и PT4Load). Если указан недопустимый номер задания, то программа выведет сообщение, в котором будет указан диапазон допустимых номеров для данной группы. Если после имени задания в параметре Name указан суффикс «?» (например, 'Begin3?'), то программа будет работать в демонстрационном режиме.

Начиная с версии 4.8, процедура Task может также использоваться для генерации и вывода на экран html-страницы с текстом задания или группы заданий. Для этого необходимо указать в качестве параметра Name имя конкретного задания или группы заданий и суффикс «#», например, 'Begin3#' или 'Begin#'. Дополнительные сведения о генерации html-страниц с описаниями заданий приводятся в разделе, посвященном демонстрационному режиму задачника.

Начиная с версии 4.13, задачник обеспечивает автоматическое тестирование программы на нескольких наборах исходных данных при ее однократном запуске. Для отключения этой возможности достаточно указать в параметре Name после имени задания суффикс «!» (например, 'Begin3!'); в этом случае при запуске программы она будет протестирована на единственном наборе исходных данных, и для проверки правильности решения программу потребуется запустить несколько раз (как в предыдущих версиях задачника).

Если процедура Task вызывается в программе несколько раз, то все последующие ее вызовы игнорируются. Исключением является ситуация, когда процедура используется для генерации html-страницы с описанием нескольких заданий или групп заданий; в этом случае учитываются все вызовы данной процедуры.

Начиная с версии 4.12, параметр Name может содержать суффикс «_ru» или «_en», позволяющий явным образом задать язык интерфейса (русский или английский соответственно) для окна задачника и выполняемого задания. В версиях 4.12–4.14 специальные суффиксы «?», «#» и «!» должны указываться перед данным суффиксом, например, 'Begin3#_en'; начиная с версии 4.15, суффиксы могут указываться в любом порядке. В случае нескольких вызовов процедуры Task (для генерации html-страницы) учитывается только суффикс, указанный при первом вызове процедуры. При отсутствии суффикса используется язык интерфейса, определенный в качестве основного для данного рабочего каталога (в универсальном варианте задачника основной язык интерфейса можно настроить с помощью программного модуля PT4Load, используя его контекстное меню; в варианте задачника для среды PascalABC.NET основной язык интерфейса совпадает с языком интерфейса, установленным для этой среды с помощью команды «Сервис | Настройки»).


procedure GetB(var A: boolean); procedure GetN(var A: integer); procedure GetR(var A: real); procedure GetC(var A: char); procedure GetS(var A: string); procedure GetP(var A: PNode);

Процедуры обеспечивают ввод исходных данных в программу, выполняющую учебное задание. Они должны вызываться после вызова процедуры Task; в случае их вызова до вызова процедуры Task при запуске программы будет выведено сообщение об ошибке «В начале программы не вызвана процедура Task с именем задания».

Используемая процедура ввода должна соответствовать типу очередного элемента исходных данных; в противном случае выводится сообщение об ошибке «Неверно указан тип при вводе исходных данных» (такое сообщение будет выведено, например, если очередной элемент данных является символом, а для его ввода используется процедура GetN).

При попытке ввести больше исходных данных, чем это предусмотрено в задании, выводится сообщение об ошибке «Попытка ввести лишние исходные данные». Если исходные данные, необходимые для решения задания, введены не полностью, то выводится сообщение «Введены не все требуемые исходные данные».

Начиная с версии 4.13, в средах Delphi и Free Pascal Lazarus ввод исходных данных можно выполнять с помощью универсальной процедуры Get(A); при этом один вызов процедуры можно использовать для ввода только одного элемента данных. Ввод данных можно также осуществлять с помощью функций без параметров GetBoolean (функция-синоним GetBool), GetInteger (синоним GetInt), GetReal (синоним GetDouble), GetChar, GetString, GetPNode. Каждая функция возвращает значение очередного элемента исходных данных; тип элемента должен соответствовать типу, указанному в имени функции.


procedure PutB(A: boolean); procedure PutN(A: integer); procedure PutR(A: real); procedure PutC(A: char); procedure PutS(A: string); procedure PutP(A: PNode);

Процедуры обеспечивают вывод на экран результирующих данных, найденных программой, и их сравнение с контрольными данными (т. е. с правильным решением). Как и процедуры группы Get, эти процедуры должны вызываться после вызова процедуры Task; в противном случае при запуске программы будет выведено сообщение «В начале программы не вызвана процедура Task с именем задания».

В отличие от процедур группы Get, в качестве параметра процедур группы Put можно указывать не только переменные, но и выражения (в частности, константы соответствующего типа). Используемая процедура должна соответствовать типу очередного элемента результирующих данных, в противном случае выводится сообщение об ошибке «Неверно указан тип при выводе результатов».

Как и в случае процедур группы Get, при вызовах процедур группы Put программа осуществляет контроль за соответствием количества требуемых и выведенных результирующих данных. Если программа выведет недостаточное или избыточное количество результирующих данных, то после проверки этих данных появится сообщение «Выведены не все результирующие данные» или, соответственно, «Попытка вывести лишние результирующие данные».

Начиная с версии 4.13, вывод результатов можно выполнять с помощью универсальной процедуры Put(A); при этом один вызов процедуры можно использовать для вывода только одного элемента результирующих данных.

Дополнительные средства ввода-вывода для языка PascalABC.NET

В среде PascalABC.NET наиболее предпочтительным вариантом для ввода исходных данных является использование функций без параметров ReadBoolean, ReadInteger, ReadReal, ReadChar, ReadString, ReadNode. Данные функции удобно вызывать непосредственно при описании инициализируемых переменных, что позволяет осуществлять автоматический вывод типа, например:

var n := ReadInteger;
var a := ReadReal;

Предусмотрены варианты этих функций, возвращающие кортежи исходных данных указанного типа, состоящие из 2, 3 и 4 элементов, например:

var (a, b, c) := ReadReal3;

В версии 4.19 набор методов ввода был дополнен методами, упрощающими ввод линейных и двумерных структур данных. Каждая группа методов обеспечивает чтение структур с элементами одного из трех основных типов T: integer, real и string. Реализованы шесть групп методов, описанных ниже.

Методы ввода линейных структур представлены группами GetArr..., GetSeq... и GetList...  (например, GetArrInteger, GetSeqReal, GetListString). Они могут вызываться без параметров (и в этом случае вначале выполняют чтение целого числа — размера структуры, после чего считывают все ее элементы) или с одним параметром целого типа count, определяющим размер структуры (и в этом случае считывают только сами элементы). Методы группы GetArr... возвращают одномерный массив array of T, методы группы GetSeq — последовательность sequence of T, методы группы GetList... — список на базе массива List<T>.

Методы ввода двумерных структур представлены группами GetMatr..., GetArrArr... и GetListList...  (например, GetMatrInteger, GetArrArrReal, GetListListString). Они могут вызываться без параметров и в этом случае вначале выполняют чтение двух целых чисел, определяющих размеры структуры по первому (число строк) и по второму индексу (число столбцов), после чего считывают все элементы по строкам. При указании одного целочисленного параметра m он определяет и число строк, и число столбцов (т. е. структура соответствует квадратной матрице порядка m); метод считывает только элементы структуры. При указании двух целочисленных параметров m и n первый из них определяет число строк, второй — число столбцов, в этом случае метод считывает только элементы структуры. Методы группы GetMatr... возвращают двумерный массив array [,] of T, методы группы GetArrArr... — массив массивов array of array of T, методы группы GetListList... — список списков List<List<T>>.

Для вывода результатов в среде PascalABC.NET можно использовать стандартные процедуры Write и Print с любым количеством параметров. При этом в качестве параметров можно указывать как скалярные данные, так и кортежи, а также линейные и двумерные структуры данных. Кроме того, для вывода структур данных можно использовать методы Write и Print (например, для вывода массива a можно использовать оператор a.Print). Для вывода линейных структур предусмотрены дополнительные методы WriteAll и PrintAll, при вызове которых вначале выводится размер структуры, а затем ее элементы.

Работа с динамическими структурами


type PNode = ^TNode; TNode = record Data: Integer; Next: PNode; Prev: PNode; Left: PNode; Right: PNode; Parent: PNode; end;

Типы PNode и TNode используются в заданиях групп Dynamic и Tree. В заданиях на стеки и очереди (Dynamic1–Dynamic28) при работе с записями типа TNode используются только поля Data и Next; в заданиях на двусвязные списки (Dynamic29–Dynamic80) используются поля Data, Next и Prev. В большинстве заданий на бинарные деревья (группа Tree) используются поля Data, Left и Right; в заданиях на обработку бинарных деревьев с обратной связью (Tree48–Tree56 и Tree70–Tree71) дополнительно используется поле Parent.

Все исходные и результирующие данные-указатели в заданиях имеют тип PNode; их ввод и вывод должен осуществляться с помощью процедур GetP и PutP.

В учебных программах не следует повторно описывать типы PNode и TNode.


procedure Dispose(var P: PNode);

Данная процедура переопределяет стандартную процедуру Dispose. Ее использование позволяет контролировать действия учащегося по освобождению памяти при выполнении заданий групп Dynamic и Tree (см. выше описание типа PNode).


type Node = class(IDisposable) public constructor Create; constructor Create(aData: integer); constructor Create(aData: integer; aNext: Node); constructor Create(aData: integer; aNext,aPrev: Node); constructor Create(left,right: Node; data: integer); constructor Create(left,right: Node; data: integer; parent: Node); procedure Dispose; property Next: Node; property Prev: Node; property Left: Node; property Right: Node; property Parent: Node; property Data: integer; end;

Тип Node реализован в системе PascalABC.NET и используется в заданиях групп ObjDyn, ObjTree, GCDyn, GCTree. В этих группах, в отличие от групп Dynamic и Tree, используются формулировки заданий в «объектном стиле». Метод Dispose требуется для освобождения ресурсов удаляемых объектов при выполнении заданий групп ObjDyn и ObjTree; в заданиях групп GCDyn и GCTree предполагается, что все ресурсы освобождаются автоматически сборщиком мусора (Garbage Collector — GC), поэтому метод Dispose использовать не требуется.

Все исходные и результирующие данные-объекты в заданиях групп ObjDyn, ObjTree, GCDyn, GCTree имеют тип Node; их ввод и вывод должен осуществляться с помощью процедур read (или Get) и write (или Put); для ввода можно также использовать функцию ReadNode (или GetNode).

В учебных программах не следует повторно описывать тип Node.

Вывод отладочной информации

Описываемые далее отладочные средства появились в версии 4.9 задачника Programming Taskbook. С их помощью можно выводить отладочную информацию непосредственно в окно задачника (в специальный раздел отладки). Для среды PascalABC.NET, начиная с версии 4.19, отладочные средства были существенно модифицированы (см. следующий пункт).


procedure Show(S: string);

Отображает текстовую строку S в разделе отладки окна задачника.

Если текущая экранная строка в разделе отладки уже содержит некоторый текст, то строка S снабжается начальным пробелом и приписывается к этому тексту, за исключением случая, когда при таком приписывании размер полученного текста превысит ширину области данных (равную 80 символам). В последнем случае вывод строки S осуществляется с начала следующей экранной строки; если же и в этой ситуации строка S превысит ширину области данных, то строка S будет выведена на нескольких экранных строках, причем разрывы текста будут выполняться по пробельным символам строки S, а при отсутствии пробелов — при достижении очередного фрагмента строки длины, равной 80.

Строка S может содержать явные команды перехода на новую экранную строку. В качестве таких команд можно использовать или символ с кодом 13 («возврат каретки»), или символ с кодом 10 («переход на новую строку»), или их комбинацию в указанном порядке (#13#10).


procedure Show([S: string;] A: integer[; W: integer]); procedure Show([S: string;] A: real[; W: integer]);

Перегруженные варианты процедуры Show, предназначенные для вывода числовых отладочных данных. Использование этих вариантов позволяет упростить действия учащегося, связанные с выводом числовых данных, поскольку избавляет его от необходимости применять стандартные средства языка Pascal, предназначенные для преобразования чисел в их строковые представления.

При вызове приведенных вариантов можно не указывать один или оба параметра, заключенные в квадратные скобки.

Строковый параметр S определяет необязательный комментарий, который указывается перед выводимым числом; если параметр S отсутствует, то комментарий полагается равным пустой строке.

Числовой параметр A определяет выводимое число.

Необязательный целочисленный параметр W определяет ширину поля вывода (т. е. количество экранных позиций, отводимое для вывода числа). Если указанной ширины W поля вывода недостаточно, то значение параметра W игнорируется; в этом случае (а также в случае, если параметр W отсутствует) используется ширина поля вывода, минимально необходимая для отображения данного числа. Если число не занимает всего поля вывода, то оно дополняется слева пробелами (т. е. выравнивается по правой границе поля вывода). В качестве десятичного разделителя для чисел с дробной частью используется точка.

Вещественные числа по умолчанию выводятся в формате с фиксированной точкой и двумя дробными знаками. Изменить формат вывода вещественных чисел можно с помощью вспомогательной процедуры SetPrecision, описываемой далее.


procedure ShowLine([S: string]); procedure ShowLine([S: string;] A: integer[; W: integer]); procedure ShowLine([S: string;] A: real[; W: integer]);

Модификации ранее описанных процедур Show; после вывода указанных данных в раздел отладки дополнительно осуществляют автоматический переход на следующую экранную строку. Смысл параметров — тот же, что и для соответствующих вариантов процедуры Show. Параметры, указанные в квадратных скобках, могут отсутствовать. Если процедура ShowLine вызывается без параметров, то она просто обеспечивает переход на новую экранную строку в разделе отладки.


procedure HideTask;

Вызов данной процедуры обеспечивает автоматическое скрытие всех разделов окна задачника, кроме раздела отладки. Если раздел отладки в окне задачника не отображается (в частности, если программа запущена в демонстрационном режиме), то вызов процедуры HideTask игнорируется. Игнорируются также все повторные вызовы данной процедуры.

Скрыть/восстановить основные разделы окна задачника после его отображения на экране можно также с помощью клавиши пробела или соответствующей команды контекстного меню раздела отладки.


procedure SetPrecision(N: integer);

Процедура предназначена для настройки формата вывода вещественных отладочных данных. Если параметр N положителен, то он определяет количество выводимых дробных разрядов; при этом число выводится в формате с фиксированной точкой. Если параметр N равен нулю, то число выводится в формате с плавающей точкой (экспоненциальном формате); при этом число дробных знаков для экспоненциального формата определяется шириной поля вывода (т. е. параметром W процедуры Show или ShowLine). При отрицательных значениях параметра N выполняется та же настройка, что и при N = 0.

Действие текущей настройки числового формата, определенной процедурой SetPrecision, продолжается до очередного вызова этой процедуры. До первого вызова процедуры SetPrecision вещественные числа выводятся в формате с фиксированной точкой и двумя дробными знаками.

Вывод отладочной информации в среде PascalABC.NET (версия задачника 4.19)


procedure SetWidth(w: integer); procedure SetPrecision(p: integer); procedure Show(params args: array of object); procedure ShowLine(params args: array of object); procedure HideTask;

В версии задачника 4.19 средства отладочного вывода для среды PascalABC.NET были усовершенствованы. Процедуры Show и ShowLine теперь могут принимать произвольное число параметров, причем можно настраивать ширину вывода данных, а также число дробных знаков для вещественных чисел. Кроме того, составные данные отображаются в наглядном виде, с применением вспомогательных форматирующих элементов. Действие процедуры HideTask осталось прежним: она обеспечивает автоматическое скрытие всех разделов окна задачника, кроме раздела отладки.

Процедура SetWidth(w) задает минимальную ширину w (w >= 0) поля вывода для элементов данных, выводимых процедурами Show и ShowLine; по умолчанию минимальная ширина полагается равной 0. Действие указанной настройки распространяется на все последующие вызовы процедур Show и ShowLine. Числовые данные выравниваются по правой границе, прочие данные — по левой.

Процедура SetPrecision(d) устанавливает количество d дробных знаков при выводе вещественных чисел (при d <= 0 используется формат с плавающей точкой; число дробных знаков в этом случае равно –d или 6, если d равно 0); по умолчанию d = 2. В качестве десятичного разделителя используется точка. Действие указанной настройки распространяется на все последующие вызовы процедур Show и ShowLine.

В версии 4.19 реализация процедур Show и ShowLine изменена таким образом, чтобы обеспечивать форматированный вывод наборов данных, в том числе вложенных. При оформлении выводимых наборов данных используются следующие обозначения: кортежи обрамляются круглыми скобками; для большинства типов, реализующих интерфейс Enumerable (в частности, массивов и списков List), используются квадратные скобки; исключение составляют множества (HashSet и SortedSet) и словари (в частности, Dictionary и SortedDictionary), для которых применяются фигурные скобки. Элементы словарей, как и кортежи, обрамляются круглыми скобками, кроме того, ключи (key) и значения (value) этих элементов разделяются двоеточием.

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

Элементы любых наборов данных разделяются запятыми (за исключением элементов, которые реализуют интерфейс Enumerable, после которых запятая не указывается, поскольку, как было отмечено выше, такие элементы разделяются разрывами строк).

Начиная с версии 4.19, процедура ShowLine выполняет дополнительный переход на следующую строку только в случае, если последним выводимым элементом данных не является Enumerable-объект, поскольку после вывода подобных объектов всегда выполняется переход на новую строку.

Ниже приводятся примеры использования процедуры Show для вывода различных наборов данных. Фрагмент программы, обеспечивающий отладочный вывод, имеет следующий вид (было использовано задание Matrix80, в котором дается вещественная квадратная матрица):

     Task('Matrix80');
     HideTask;
     ShowLine('Матрица вещественных чисел (width = 5):');
     var a := ReadMatrReal(ReadInteger);
     SetWidth(5);
     ShowLine(a);
     ShowLine('Словарь строк (width = 0):');
     var b1 := new Dictionary<integer, string>();
     b1[1] := 'ABCD';
     b1[3] := '123';
     b1[10] := '!*****!';
     SetWidth(0);
     ShowLine(b1);
     ShowLine('Словарь строковых массивов (width = 3):');
     var b2 := new Dictionary<integer, array of string>();
     b2[1] := new string[] ( 'ab', 'd' );
     b2[2] := new string[] ( '123', '45', '7' );
     b2[22] := new string[] ( '**', '#', '@@@' );
     SetWidth(3);
     ShowLine(b2);
     ShowLine('Список списков, содержащих числовые строки (width = 6):');
     var c1 := new List<List<string>>();
     c1.Add(new List<string>());
     c1[0].Add('ABCD'); c1[0].Add('123'); c1[0].Add('!****!');
     c1.Add(new List<string>());
     c1[1].Add('abcd'); c1[1].Add('56789');
     SetWidth(6);
     ShowLine(c1);
     ShowLine('Массив массивов, содержащих числовые массивы (width = 2):');
     var c2 : array of array of array of integer;
     SetLength(c2, 3);
     SetLength(c2[0], 2);
     c2[0][0] := new integer[] ( 1, 2, 3 );
     c2[0][1] := new integer[] ( 4, 5, 6 );
     SetLength(c2[1], 3);
     c2[1][0] := new integer[] ( 7, 8, 9 );
     c2[1][1] := new integer[] ( 10, 11, 12 );
     c2[1][2] := new integer[] ( 60, 61, 62 );
     SetLength(c2[2], 2);
     c2[2][0] := new integer[] ( 13, 14, 15, 50 );
     c2[2][1] := new integer[] ( 16, 17, 18, 19, 20 );
     SetWidth(2);
     ShowLine(c2);

В приведенном далее образце содержимого раздела отладки следует обратить внимание на то, что при выводе скалярных элементов или элементов-кортежей они разделяются запятыми, тогда как после каждого элемента, реализующего интерфейс Enumerable (массива или списка List), выполняется переход на новую строку. Кроме того, следует обратить внимание на использование отступов при выводе многомерных списков, а также на настройку ширины области вывода с помощью процедуры SetWidth.

  1>  Матрица вещественных чисел (width = 5):
  2>  [ [  2.07 ,  4.75 ,  4.15 ,  6.20 ,  0.59 ]
  3>    [  4.47 ,  3.12 ,  7.51 ,  7.98 ,  9.45 ]
  4>    [  5.50 ,  8.67 ,  2.51 ,  2.64 ,  5.90 ]
  5>    [  2.45 ,  6.45 ,  4.24 ,  4.35 ,  4.51 ]
  6>    [  2.87 ,  1.46 ,  6.67 ,  5.57 ,  5.00 ]
  7>  ]
  8>  Словарь строк (width = 0):
  9>  { ( 1 : ABCD ) , ( 3 : 123 ) , ( 10 : !*****! ) }
 10>  Словарь строковых массивов (width = 3):
 11>  { (   1 : [ ab  , d   ]
 12>  ) (   2 : [ 123 , 45  , 7   ]
 13>  ) (  22 : [ **  , #   , @@@ ]
 14>  ) }
 15>  Список списков, содержащих числовые строки (width = 6):
 16>  [ [ ABCD   , 123    , !****! ]
 17>    [ abcd   , 56789  ]
 18>  ]
 19>  Массив массивов, содержащих числовые массивы (width = 2):
 20>  [ [ [  1 ,  2 ,  3 ]
 21>      [  4 ,  5 ,  6 ]
 22>    ]
 23>    [ [  7 ,  8 ,  9 ]
 24>      [ 10 , 11 , 12 ]
 25>      [ 60 , 61 , 62 ]
 26>    ]
 27>    [ [ 13 , 14 , 15 , 50 ]
 28>      [ 16 , 17 , 18 , 19 , 20 ]
 29>    ]
 30>  ]

PrevNext

 

Рейтинг@Mail.ru

Разработка сайта:
М. Э. Абрамян, В. Н. Брагилевский

Последнее обновление:
08.03.2019