Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
delphi / песни о паскале.pdf
Скачиваний:
63
Добавлен:
26.03.2016
Размер:
5.16 Mб
Скачать

Глава 49

Сложные массивы

Так была решена задача о минимальной сумме пошлин. Купцы, было, обрадовались, но вскоре явились с новым поклоном. Много ль толку от знания расходов, если не знаешь пути, по которому надо двигаться? «Сделай нам, братан, что-то типа навигатора для поиска кратчайшего пути между странами. Так, чтобы нам меньше этих пошлин платить, — умоляли купцы, — мы не поскупимся!» Ник обещал подумать, и продолжение истории следует.

Крестики-нолики

Кто не любовался яркой световой рекламой? Рекламный щит составлен из лампочек, а изображение «рисуется» их включением и отключением, — этим управляет микропроцессор. Компьютер у нас под рукой, почему бы не соорудить такой рекламный щит прямо на экране? Научим компьютер выполнять с изображением на нашем щите три действия: два зеркальных отражения (относительно горизонтальной и вертикальной осей), а также инверсию изображения (рис. 113).

Отражение

Оси

относительно

Исходное

вертикальной оси

изображени

 

Инверсия

Отражение

относительно

горизонтальной оси

 

Рис. 113 – Операции с изображением на щите

Прежде всего, определим, как представить исходное изображение так, чтобы ввод его в компьютер был по возможности прост. Неплохим вариантом будет текстовый файл, где исходная картинка нарисована двумя символами, например, крестиком и ноликом. Присмотревшись к рис. 114, вы разглядите в правом верхнем углу изображенную таким способом букву «F».

382

Глава 49

Сложные массивы

0000000000000000000000000000000000000000

000000000000000000000000000+++++00000000

000000000000000000000000000+000000000000

000000000000000000000000000+000000000000

000000000000000000000000000+++++00000000

000000000000000000000000000+000000000000

000000000000000000000000000+000000000000

000000000000000000000000000+000000000000

0000000000000000000000000000000000000000

0000000000000000000000000000000000000000

0000000000000000000000000000000000000000

0000000000000000000000000000000000000000

0000000000000000000000000000000000000000

0000000000000000000000000000000000000000

0000000000000000000000000000000000000000

0000000000000000000000000000000000000000

0000000000000000000000000000000000000000

0000000000000000000000000000000000000000

0000000000000000000000000000000000000000

0000000000000000000000000000000000000000

Рис. 114 – Исходный файл для представления рекламного щита, крестиками нарисована буква «F»

Размер картинки выберем таким, чтобы она помещалась на экране монитора. В текстовом режиме экран содержит 25 строк по 80 символов в каждой. Мы ограничимся 20 строками по 40 символов. Тогда воображаемая вертикальная ось нашего щита пройдет между 20-м и 21-м столбцами, а горизонтальная — между 10-й и 11строками.

Разобравшись с видимым представлением щита, обратимся к невидимому: придумаем способ хранения в памяти «лампочек» щита. Годятся ли символьные переменные, — те же крестики и нолики? Да, но мне приглянулся способ, лучше отвечающий природе рекламного щита. Ведь каждая из лампочек может быть либо включена либо погашена, — их состояние можно отразить в булевых переменных. А сколько их понадобится? Не так уж мало — 800 штук (20 строк по 40 в каждой). Разумеется, нужен массив, но каким он будет? Предположим, что тип «рекламный щит» (Desk) объявлен так.

type TDesk = array [1..800] of Boolean;

Здесь разумеем, что первые 40 элементов массива хранят верхнюю строку щита, следующие 40 элементов, — вторую строку и так далее. Не очень удобно, правда?

Можно сделать иначе: сначала объявить отдельную строку щита TLine как массив из 40 лампочек.

383

Глава 49

Сложные массивы

type TLine = array [1..40] of Boolean;

И тогда весь щит представится массивом из 20 таких строк, — это будет массив массивов.

type TDesk = array [1..20] of TLine;

То же самое можно записать развернуто, вот так.

type TDesk = array [1..20] of array [1..40] of boolean;

Подчеркнутое означает отдельную строку щита. Паскаль разрешает собрать все индексы объявления внутри одних скобок и записать всё это ещё короче.

type TDesk = array [1..20, 1..40] of boolean;

Так мы получили структуру, которую математики называют матрицей, а программисты — двумерным массивом. Матрицы состоят из строк и столбцов. Для доступа к элементам матрицы нужны два индекса, один из которых указывает номер столбца, а другой — номер строки. Например, элемент матрицы Desk, стоящий в 5-м столбце 3-й строки, доступен так.

Desk[3, 5]

Разумеется, что для индексов позволены числовые выражения, значения которых должны лежать в объявленных пределах. При обработке матриц применяют циклы, их можно организовать как по строкам, так и по столбцам. Возьмем для примера наш рекламный щит, объявим его тип, а потом заполним значением FALSE.

const Cx =

40;

{ количество столбцов (ширина) }

 

Cy =

20;

{ количество строк (высота) }

type

TDesk = array [1..Cy, 1..Cx] of boolean; { тип «рекламный щит» }

var

Desk : TDesk;

{ переменная «рекламный щит» }

 

 

 

 

 

Здесь пределы для индексов указаны через константы Cx и Cy. Заполнить матрицу значением FALSE можно двумя вложенными циклами:

for y:=1 to Cy do

for x:=1 to Cx do Desk[y, x]:= False;

То же самое делается быстрее и короче известной вам процедурой заполнения

FillChar:

384

Глава 49

Сложные массивы

FillChar(Desk, SizeOf(Desk), false);

Здесь значение SizeOf(Desk) составит 800 — это количество элементов матрицы.

Можно обрабатывать и отдельные строки, и отдельные столбцы матрицы. Например, заполнить значением TRUE 5-й столбец.

for y:=1 to Cy do Desk[y, 5] := True;

А для заполнения 3-й строки организовать такой цикл:

for x:=1 to Cx do Desk[3, x] := True;

Если вам понятна техника работы с матрицами, перейдем к программе

P_49_2.

Начнем с процедуры ReadDesk, что вводит матрицу из файла. Условимся считать, что крестикам в матрице Desk соответствует TRUE, а ноликам — FALSE. Входной файл обрабатываем построчно: сначала очередную строку читаем во вспомогательную строковую переменную S, а затем символы этой строки преобразуем в булевы значения оператором сравнения (вы помните, что оператор сравнения дает булев результат?).

Desk[y,x]:= S[x]='+'; { TRUE, если S[x] содержит крестик }

Следовательно, для ввода матрицы нужны два вложенных цикла: внешний — по строкам и внутренний — по столбцам.

Схоже работает и процедура WriteDesk, выводящая матрицу на экран. Здесь внутренний цикл формирует строку из 40 символов, каждый из которых может быть либо крестиком либо ноликом. Выбор пары символов — дело вкуса, в нашем случае пара определяется строковой константой CSymbols.

const CSymbols : string = '0+';

Нужный символ из этой строки выбирается по индексу.

S:= S + CSymbols[1+ Ord(Desk[y, x])];

Так, для значений Desk[y,x], равных FALSE, будет выбран первый символ строки ('0'), а для TRUE — второй ('+'), что равнозначно следующему громоздкому оператору.

385

Глава 49

Сложные массивы

if Desk[y, x]

then S:= S + CSymbols[2]

else S:= S + CSymbols[1]

Далее следуют две простые процедуры зеркального отражения матрицы относительно горизонтальной и вертикальной осей, — они всего лишь переставляют симметрично расположенные элементы.

Процедура инверсии рекламного щита ещё проще, — она меняет значения элементов матрицы на противоположные. Наконец, в главной программе после чтения из файла исходного изображения организован цикл ввода и обработки команд пользователя. Вводя одну из трёх команд (1, 2 или 3), пользователь крутит изображение туда-сюда, а также инвертирует его. Вот полный текст этой программы.

{ P_49_2 – Рекламная панель "крестики-нолики" }

const Cx = 40; { количество столбцов (ширина) } Cy = 20; { количество строк (высота) }

type TDesk = array [1..Cy, 1..Cx] of boolean; var Desk : TDesk;

{ Чтение исходного состояния панели из текстового файла } procedure ReadDesk(var F: Text);

var x, y: integer; { x – индекс столбца, y – индекс строки } S: string;

begin

FillChar(Desk, SizeOf(Desk), false); y:=1;

while not Eof(F) and (y<=Cy) do begin

Readln(F, S); x:=1;

while (x<=Length(S)) and (x<=Cx) do begin

Desk[y,x]:= S[x]='+';

 

Inc(x);

{ x:=

x+1

}

end;

 

 

 

Inc(y);

{ y:=

y+1

}

end end;

386

Глава 49

Сложные массивы

{ Вывод текущего состояния панели в текстовый файл } procedure WriteDesk(var F: Text);

const CSymbols : string = '0+'; var x, y: integer; S: string; begin

for y:=1 to Cy do begin S:='';

for x:=1 to Cx do S:= S + CSymbols[1+ Ord(Desk[y, x])]; Writeln(F, S);

end;

end;

{Вспомогательная процедура обмена местами булевых переменных } procedure Swap (var a, b : boolean);

var t : boolean; begin

t:=a; a:=b; b:=t; end;

{Отражение относительно вертикальной оси }

procedure Vert;

var x, y: integer;

begin

for y:=1 to Cy do

for x:=1 to Cx div 2 do Swap(Desk[y, x], Desk[y, Cx-x+1])

end;

{Отражение относительно горизонтальной оси } procedure Horisont;

var x, y: integer; begin

for y:=1 to Cy div 2 do

for x:=1 to Cx do Swap(Desk[y, x], Desk[Cy-y+1, x])

end;

{Инверсия рекламной панели }

procedure Invers;

var x, y: integer;

begin

for y:=1 to Cy do

for x:=1 to Cx do Desk[y, x]:= not Desk[y, x]

end;

387

Соседние файлы в папке delphi