2. 3. 1. Выбор формата шаблона.
Выбор Формата, в котором Вы храните данные, необходимые
для успешной работы Вашей программы - это очень важный творчес-
кий процесс. Нерационально выбранный Формат может очень сильно
замедлить скорость работы программы и привести к излишнему рас-
ходу памяти. Более того, как показывает практика программирова-
ния. в большинстве случаев структура грамотно составленной про-
граммы (рабочих процедур) оказывается очень сильно связанной со
структурой данных, которые этими процедурами обрабатываются,
так что непродуманный выбор Формата данных может привести и к
еше более неприятнону последствию, когда программист путается в
своих процедурах, теряет логику работы программы и. запутав-
шись. бросает едва начатое дело.
Существует много различных типов структур данных, которые
могут применяться в практической работе. Вам. конечно известна
такая структура, как "стек", когда данные закладыватся сверху и
сверху же и извлекаются по принципу "последним пришел, первым
уйдешь". В книге "Элементарная графика" в разделе 3. 11 мы рас-
сматривали такую структуру, как "конвейер", существует еше
стркутурэ. называемая "очередь", отличающаяся от "стека" тем.
что данные закладываются сверху, а извлекаются снизу по. прин-
пипу "пследним пришел, последним уйдешь". Но все это структуры
для работы с динамически меняющимися данными, а графические
шаблоны, размещаемые в памяти заранее, очевидно к таким не от-
носятся. Для них очень хорошо подходит организация в таблицы и
векторы.
вариант 1.
что такое таблицы данных очевидно знают все. это массивы,
которые бывают двумерными, трехмерными и т. д. Многих начинающих
программистов пугает неуклюжее слово "вектор", которое нередко
встречается в текстах пояснений к программам. Со школы все
помнят, что "вектор" - это отрезок прямой, для которого кроме
длины зачем-то важно знать еше координаты начала и конца и
направление, к нашим векторам данных это окольное понятие хоть
и имеет косвенное отношение, но такое далекое, что лучше о нем
и не вспоминать. Дело пойдет гораздо проше. если сказать, что
вектор - это простой и всем понятный одномерный массив данных,
в этом снысле и символьная строка - тоже как бы вектор. Если
таблица - это набор строк и столбцов, то любая строка в ней -
вектор и любой столбец - тоже вектор.
Таким образом, вектор данных - это просто одномерная упо-
рядоченная структура, иногда в программах употребляют векторы-
указатели. это тоже одномерные массивы, каждый элемент которых
на что-то указывает. Например. Вы храните в програнне 500 раз-
личных шаблонов, каждый из которых имеет разную длину. первый
шаблон начинается с адреса 40000, второй - с 40025-го, третий -
с 40157-го и т. п.. тогда массив из 500 чисел:
40000. 40025, 40157 ...
и будет вектором указателем на Вашу таблицу шаблонов, а размес-
тить его Вы иожете где угодно, например начиная с базового ад-
реса 39000. оставив 1000 байтов на 500 чисел (по два байта на
каждое).
Итак, вот Вам первый способ хранения шаблонов в паияти
компьютера. У него есть очевидные достоинства и недостатки,
к достоинствам можно отнести то, что это. по-видимому, самый
быстрый способ отыскания адреса, с которого начинается Ваш
шаблон.
LD DE. ADDR_1 ; Базовый адрес вектора указателя.
LD HL HUHBEF ; Ноиер нужного Вам шаблона.
ADD HL. HL ;Умножили его на 2 (по 2 байта на
;каждый адрес).
ADD HL.DE остановили указатель на адрес
; нужного Вам шаблона.
LD A. (HL) :| стандартный прием исполнения
INC HL ; I команды LD HL. (HL).
LD н. (hl) ; i которой к сожалению нет
LD L.А : в процессоре Z-80.
Если Вы не собираетесь хранить в программе графические об-
разы по размеру большие, чем 5X5 (6X4. 3X9) знакомест, то рас-
ход памяти на вектор-указатель иожно сократить в два раза, от-
водя не по два байта на хранение каждого адреса начала шаблона,
а только по одному байту на хранение его длины (при малых раз-
мерах шаблона она уложится в один байт). Тогда способ отыскания
адреса начала шаблона будет таким:
ld de. addp l ; Базовый адрес вектора указателя.
ld hl.addr 2 ; Базовый адрес таблицы шаблонов.
ld вс.kuhber :Ноиер нужного Ван шаблона.
ld А. с ; | Поменяли местами регистры
LD С. в ; I Сив, поскольку счетчик
LD В. А . Я младшего разряда удобнее
; I делать в В.
loop ld a. (de) ; Взяли длину шаблона в аккунулятор.
IHC de ; Переход к следуюией позиции вектор.
; указателя.
OR А ; Сбросили Флаг переноса.
ADD A. L .Прибавили К HL
LD L. А ; длину шаблона.
JR NC. PASS ; Если аккумулятор переполнился.
IHC н ; то увеличиваем старший регистр HL.
PASS DJNZ LOOP ;Если младший разряд счетчика не
; исчерпан, возврат на loop.
ld А. с ; I стандартный прием проверки
OR В .I старшего разряда счетчика
RET Z ; I на ноль.
DEC С ;Уменьшили старший разряд.
jr loop ; Повтор вычислений.
К недостаткам на первый взгляд хочется отнести дополни-
тельный расход памяти для хранения вектора-указателя, но это не
совсем верно, дело в той. что если не строить вектор-указатель,
то пришлось бы вместе с каждым шаблоном хранить данные по его
длине и это заняло бы ничуть не меньший объем памяти.
Более очевидный недостаток - сложность в подготовке про-
гранны к работе и в ее отладке. Незначительные изиенения в
шаблонах будут приводить к тому, что "поплывут" все адреса и
вектор-указатель надо будет переделывать заново.
Конечно, самой радикальной рекомендацией было бы использо-
вать все шаблоны в программе только одного размера, тогда мно-
гое бы упростилось, уменьшились бы разиеры расходуемой памяти и
возросла бы скорость работы программы, а именно к этому Вы и
должны стремиться.
Тогда вроде бы и нет бмысла употреблять такую структуру и
мы не стали бы о ней и говорить, но есть один случай, когда
она может оказаться весьма и весьма полезной. Дело в тон. что с
точки зрения расхода памяти хранить в программе все графические
образы - дело очень расточительное. Рано или поздно программист
приходит к тому, что их надо архивировать путем компрессии (как
это делают, мы ~ поговорим в свое время), и в этом случае даже
если у Вас первоначально все шаблоны имели равную длину, то
после компрессии их разиеры могут оказаться какими угодно.
Вместо упорядоченной таблицы шаблонов Вы получите беспорядочный
набор данных и там вектор-указатель может Ваи очень пригодить-
ся. при этом сложность в подготовке вектора-указателя и в от-
ладке программы парируют%тем. что рутинную работу по исполнению
вектора поручают самой компрессирующей программе (а это легко
сделать, поскольку она-то имеет дело с шаблонами одинаковой
длины).
Вариант 2.
Во втором варианте ны обойдемся без вектора-указателя и
рассмотрим такой Формат шаблонов, при котором все необходимые
данные хранятся вместе с самим шаблоном. Опять хе будем предпо-
лагать. что речь идет о хранении в памяти произвольных шаблонов
различной длины. Решим для себя вопрос о том. в каком порядке
будут храниться байты, представляющие из себя раскладку шабло-
на. Например так. как показано на рис. 3.
Затем разработаем для себя Формат шаблона, например такой:
в первых двух байтах (а может быть Ван достаточно и одно-
го байта) хранится суммарная длина шаблона, включая сюда все
атрибуты, а также и сами эти два контрольных байта. За ними
идут два байта, указывающие на размер шаблона по горизонтали и
по вертикали. Затем m«n«8 байтов занимает черно-белая конструк-
ция шаблона. Ясно, что на каждое знакоместо нам надо отвести по
в байтов. На цветовые атрибуты отводим столько байтов, сколько
знакомест занимает Ваш шаблон - ш«п байтов. Если БЫ создете
игровую программу, то Ваши иаблоны могут иметь и дополнительные
аркадные атрибуты. О том, что это такое, мы расскажем чуть поз-
же. а пока скажем, что и под них нужно предусмотреть место.
Размер этого места целиком зависит от Вашей Фантазии, но для
примера предположим, что тоже по одному байту на каждое знако-
место.
Итак, один шаблон мохет иметь размер т«п«10*4 байта,
сканирование по Файлу шаблонов организовать несложно:
LD HL. ADDR_1 : Базовый адрес таблицы шаблонов.
LD ВС. HUHBER ; Номер нужного Вам шаблона.
LD А. С ; Поменяли местами регистры
LD С. В ; СиВ. поскольку счетчик
LD В. А ; младшего разряда удобнее
; делать в В.
LOOP LD Е.(HL) ; Загрузили в Е младший байт длины.
IHC HL ; Перешли к старшему байту.
LD D.(HL) ; Загрузили в D старший байт.
DEC HL Скорректировали нежелательное
; последствие команды INC HL.
ADD HL. DE ;Нашли начало очередного шаблона.
DJHZ LOOP ;Проверили младший разряд счетчика
;шаблонов на ноль.
LD А. С ;| Стандартный прием проверки
OR в ; I старшего разряда счетчика
RET 1 ; 8 (регистр С) на ноль.
DEC С ; уненьшили старший разряд.
JR LOOP ;Повтор вычислений.
В результате работы этой процедуры в регистровой паре HL
будет установлен адрес, с которого начинается нужный нам шаб-
лон. хотя надо помнить, что это еше не сам шаблон, а первые
четыре служебных байта (два байта на длину и два байта на его
размер).
2.3.2. Печать шаблона с цветовыми атрибутами.
Итак, мы определились с Форматом, в котором в оперативной
памяти компьютера хранится файл шаблонов и написали процедуру,
которая по заданному номеру шаблона найдет его начало в этом
Файле. Следующая задача - напечатать этот шаблон вместе с атри-
бутами в заданных координатах левого верхнего угла (координаты
заданы в знакоместах).
Исходное состояние: адрес начала шаблона в регистровой
паре HL:
Процедура печати шаблона с атрибутами состоит как бы из
двух частей, на первом этапе печатается черно-белая конструкция
шаблона, а на втором зтапе на нее накладываются цветовые
атрибуты.
addr_s dkfw 0000 ;Адрес в дисплейном файле.
addf_a defw оооо ;Адрес в Файле атрибутов.
coords defw 0000 ; Координаты X и V
number defb 00 : Номер шаблона.
bitmap defw 0000 ;Адрес начала Файла шаблонов.
atrmap defw 0000 ;Адрес начала атрибутов.
size.x defb 00 : Размер шаблона по горизонтали
; (в знакоместах).
SIZE.V DEFB оо ; Размер шаблона в знакоместах
; по вертикали.
inc hl ;Пропускаем два байта, хранящие
inc hl ;длину шаблона.
ld A.(HL) ; Высота шаблона (V).
ld size_y. а ;
ihc hl ;
LD A.(HL) ;Ширина шаблона (X).
LD SIZE_X.A
ihc hl ;Теперь hl указывает на начало
ld bithap.hl ; графической информации шаблона.
ld de. (coords) ; Координаты x и Y.
ld a.e
amd 1bh
OR 40 Расчет адреса в дисплейном
LD Н.А файле по координате, задан-
LD А.Е ной в знакоместах.
AHD 07
OR А
rra
RRA
rra
rra
ADD A.D
LD L. А
LD (ADDR.S).HL ;Запомнили адрес в дисплейном
; файле.
LD HL.BITHAP ;
LD DE. (ADDR_S) ;Адрес в дисплейном файле.
LD в.SIZE_V ; Счетчик знакомест по вертикали.
LD с. SIZE_X ;Счетчик знакомест по горизонтали.
L00P_3 PUSH DE ; Сохранили адрес экрана.
LOOP_2 PUSH ВС ; Сохранили счетчики на стеке.
LD с.8 ; Организовали счетчик линий в
;знакоместе.
LD В.8 ;Организовали счетчик пикселов в
;текущей линии знакоместа.
PUSH DE :Сохранили экранный адрес
;еше раз.
L00P_1 LD A. (HL) ;загрузили в аккумулятор
; очередной байт шаблона.
LD (DE).A ;Перенос текущего байта из
; оперативной памяти в экранную.
IHC D ;Переход к следующей линии
; знакоместа на экране снизу.
IHC HL ; Переход к следующему байту
; шаблона.
-DJHZ LOOPЛ ; Конец цикла копирования шаблона
:в X в.
POP DE ; Восстановили экранный адрес.
LD А.гон
ADD А. Е : Переход к следующему экранному
LD е. а ; ряду.
POP ВС : Восстановили счетчики знакомест.
-DJHZ LOOP_2 ;Если не все знакоместа по
; вертикали скопировали, возврат
; назад.
pop de ;
IHC Е ; Переход к следующему знакоместу
; справа.
DEC С ;Уненыпили счетчик столбцов.
LD А.с ;Проверка Счетчика
or в ;на ноль.
-JR HZ.LOOP-3 ;Если не весь шаблон скопирован.
;возврат на LOOP_3.
LD ATRHAP. HL ; Сейчас HL указывает в шаблоне на
:начало информации по атрибутам.
LD DE. (COORDS) ; Координаты X и Y.
LD А. Е
AHD 16Н Расчет адреса в Файле
SRL А атрибутов.
SRL А
SRL А
OR 56Н
LD Н.А
LD А.Е
AHD 07
or а
RRA
RRA
RRA Ц
RRA
ADD A.D
LD L. A |
LD ADDR.A. HL ; Запомнили адрес в Файле
; атрибутов.
LD HL, ATKHAP ;Адрес атрибутов в шаблоне.
LD DE,ADDR.A ; Адрес в файле атрибутов.
LD с, SIZE_X ; Счетчик знакомест по горизонтали.
-LOOP_5 LD в, SIZE. Y : Счетчик знакомест по вертикали.
-LOOP. 4 LD A. (HL) И
IHC HL
LD (DE),A
LD A. E переброска одного
OR А вертикального столбца.
ADD А. гон
LD E, A
JR HC PASS
INC D
—PASS DJHZ L00P_4
DEC С Уменьшение счетчика столбцов.
LD А. С
OR В ' Проверка регистра с на ноль
RET z Выход, если все столбцы закрашены
LD DE.ADDR.A
IHC DE Переход к следующему
LD ADDR_A. DE столбцу на экране.
-JR LOOP.5