ZX-Ревю 1991 №11-12 1990 г.

Профессиональный подход - Окончание.


ПРОФЕССИОНАЛЬНЫЙ ПОДХОД

Окончание. Начало на стр. 49,70,117,143,167.

В прошлый раз мы с Вами рассмотрели вопрос как избегать ошибок при программировании, как их находить и устранять. Сегодня мы заканчиваем печать статей Стива Тернера под общим заголовком "Профессиональный подход". Правда это не значит, что мы навсегда прощаемся с этим выдающимся программистом. Может быть ему не раз еще удастся поделиться с нами маленькими хитростями и своими профессиональными секретами.

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

Ниже приведена программа "Монитор реального времени" (MONITR) и на примере тестирования ее самой же и показано, как можно составить план тестирования.

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

Когда Ваша игровая программа работает, MONITR непрерывно ее сопровождает, но может ее прервать и передать управление главному монитору для глубокого анализа состояния программы в момент прерывания.

Вы можете значительно ускорить процесс тестирования программы благодаря тому, что Вам предоставлена возможность выставлять значения своих переменных перед тестовым запуском. Это неоценимо важно при настройке игровых программ. Вы сможете вносить изменение в какие-либо программные константы, от которых зависит скорость передвижения персонажей, интенсивность стрельбы, позиционирование объектов на экране и многое тому подобное. Все это позволяет достичь максимальной играбельности готового программного продукта.

DL

LD A,(MONON) AND A JR NZ,ISON LD BC,F7FE

3A27B1 A7 200F 01FEF7

ED78 F6FE

FEFF

C8

3E01 3227B1 210040 2D

20FD 25

20FA 01FEEF

ISON DELAY

KEYSCAN

IN A,(C) OR FE

CP FF

RET Z

LD A,01 LD (MONON),A LD HL,4000 DEC L

JR NZ,DELAY DEC H

JR NZ,DELAY DEFL

LD BC,EFFE

MONITR

Определение метки. Включение.

Проверка "Включен/выключен?" Переход, если включен. Задание адреса порта клавиатуры. Выставлен верхний ряд, левый полуряд. Прием информации от клавиатуры. Маскирование 7-ми младших битов.

Проверка не была ли нажата клавиша "1".

Поскольку MONON=0 и клавиша "1' не нажата - возврат. Если клавиша "1" была нажата, изменяем значение MONON. организация замедляющего цикла.

Определение метки. Установка адреса порта клавиатуры. Выставлен верхний ряд, правый полуряд.

ED78 IN A,(C)

F6E2 OR E2

6F LD L,A

01FEF7 LD BC,F7FE

ED76 IN A,(C)

17 RLA

F6DF OR DF

A5 AND L

FEFE CP FE

2003 JR NZ,NOQUIT

C30FF7 JP EXITAD

FEFF NOQUIT CP FF

CA36B0 JP Z,OPTYPE

1F RRA

1F RRA

0E0 LD C,0

1F FINDK RRA

3003 JR NC,KEYNO

18FA JR FINDK

79 KEYNO LD A,C

2128B1 LD HL,MONDIG

1129B1 LD DE, MONADD

FE03 CP 3

2811 JR Z,LEFTCR

FE02 CP 2

2316 JR Z,DOWN

FE01 CP 1

2816 JR Z,UP

Чтение данных с порта. Поступил байт, имеющий вид: 111????? - здесь и далее:

1 - бит включен;

0 - выключен;

? - не определен. Включение тех битов, которые нас не интересуют. E2 HEX = 1110 0010 BIN, имеем в итоге: 111? ??1? Сохранили значение. Установка адреса порта клавиатуры. Выставлен верхний ряд, левый полуряд. Чтение данных с порта. Поступил байт, имеющий вид 111? ???? Теперь байт имеет раскладку: 11?? ???1. Мы гарантированно включили младший нулевой бит, взяв его из 7-го бита. DF HEX = 1101 1111, имеем в итоге: 11?1 1111.

В аккумуляторе будет FE тогда и только тогда, когда нажата клавиша 0 и никакие другие клавиши верхнего ряда не нажаты.

Переход для продолжения работы. Если была нажата клавиша "0", здесь выполняется переход в главный монитор по адресу 0FF7, заданному константой EXITAD. Если Вы не пользуетесь монитором фирмы PICTURESQUE, задайте здесь свой адрес.

Если никакая клавиша не нажата, остаемся в режиме 1. Биты, выключаемые при нажатии клавиш "0" и "9" нас не интере-cуют и мы их "прокручиваем". C - выполняет роль счетчика оборотов байта. "Крутим" байт, пока не найден нулевой бит, т.е. нажатую клавишу.

Как только найдется нулевой бит, выполняется переход в KEYNO.

Переход на очередное вращение байта. Сколько оборотов сделали? Отсюда и будем вычислять какая клавиша была нажата. позиция курсора MONDIG.

3 оборота - клавиша "5". Переход на "курсор влево".

2 оборота - клавиша "6". Переход на "вниз".

1 оборот клавиша "7". Переход на "вверх".

В противном случае начинаем обрабатывать режим "курсор

вправо"

7E

LD A,(HL)

Ввели позицию курсора.

3C

INC A

Увеличили ее.

FE07

CP 07

Позиция не может быть более 6.

3028

JR NC,OPTYPE

Продолжение работы в режиме 1.

77

LD (HL),A

Запомнили позицию курсора в MONDIG.

1825

JR OPTYPE

Продолжение работы в режиме 1.

7E

LEFTCR

LD A,(HL)

FE00

CP 0

0 - минимальная позиция курсора.

2820

JR Z,OPTYPE

3D

DEC A

77

LD (HL),A

1B1C

JR OPTYPE

Продолжение работы в режиме 1.

0EFF

DOWN

LD C,FF

Ввод начального значения.

1802

JR TURNBT

Переход на изменение.

0E01

UP

LD C,1

Ввод начального значения

TURNBT

DEFL

Определение метки.

7E

LD A,(HL)

Ввод позиции курсора.

47

LD B,A

3апомнили ее в B.

2600

LD H, 00

CB2F

SRA A

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

6F

LD L, A

19

ADD HL,DE

HL указывает на младший или старший байт адреса, на который настроен монитор.

78

LD A,B

Старший или младший

E601

AND 01

полубайт?

79

LD A, C

2006

JR NZ,TOMONB

17

RLA

Если младший, то вращаем его

17

RLA

четыре раза.

17

RLA

17

RLA

E6F0

AND F0

86

TOMONB

ADD A,(HL)

Установленное значение отправ

77

LD (HL),A

ляется на хранение в программную переменную.

112E31

OPTYPE

LD DE,(MONLIN)

MONLIN указывает на начало выходного буфера.

3A29B1

LD A,(MONADD)

67

LD H,A

Теперь в HL -

3A2AB1

LD A,(MONADD+1)

анализируемый

6F

LD L, A

адрес.

3A2CB1

LD A,(MONOP)

A содержит код операции.

A7

AND A

Проверка на 0.

2806

JR Z,PEEK

Переход на процедуру исполнения режима PEEK.

FE20

CP 20H

Если там "пробел" -

2808

JR Z,POKE

Переход на процедуру исполнения режима POKE.

180A

JR NULLOP

В противном случае обрабатывается режим 0.

7E

PEEK

LD A,(HL)

Снимается значение из анализируемого адреса

322BB1

LD (MONVAL),A

и запоминается в программной переменной MONVAL.

1804

JR NULLOP

Продолжение работы.

3A2BB1

POKE

LD A,(MONVAL)

77

LD (HL),A

Засылка байта в адрес.

2129B1 NULLOP LD HL,MONADD ;В HL - адрес выходного буфера.

;В нем хранится образ экранной ;строки.

CD07B1 CALL HEX ;Для первой пары позиций вызывается

;конвертер перевода 16-;тиричного кода в ASCII. 23 INC HL ;Пропуск второй позиции 1-ой

;пары.

CD07B1 CALL HEX ;Для второй пары позиций.

13 INC DE ;Вводится пробельная позиция.

23 INC HL ;

CDO7B1 CALL HEX ;3-я пара.

13 INC DE ;Пробел.

23 INC HL

CD07B1 CALL HEX Обрабатывается последняя

;позиция.

3E20 LD A,20H ;20H - это код пробела.

3237B1 LD (BLANK),A ;Подготовка к "стиранию"

3A28В1 LD A,(MONDIG) ;Номер позиции.

210058 LD HL,58000 ;Адрес в дисплейном файле.

0620 LD B,20H ;Счетчик цикла.

360F COLMON LD (HL),0F ;Выставление

23 INC HL ; экранных

10FB DJNZ COLMON ;атрибутов.

210056 LD HL,58000 ;Адрес в дисплейном файле.

FE04 CP 04 ;4-ая позиция пробельная и

3806 JR C,YE ;не обрабатывается.

23 INC HL

FE04 CP 06 ;6-ая позиция пробельная и

3801 JR C,YE ;не обрабатывается.

23 INC HL

1600 YE LD D,0

5F LD E, A

19 ADD HL, DE

3630 LD (HL),30H ;Изменение цвета в позиции

;курсора.

3A29В1 PUTMON LD A,(MONADD) ;Подготовка

67 LD H,A ;к печати

3A2АВ1 LD A,(MONADD+1) ;содержимого

6F LD L, A ; ближайших

1138B1 LD DE,MONDMP ;восьми байтов.

13 INC DE

0604 LD B,04 ;Сначала 4 байта.

CD07B1 HEXDMP CALL HEX ;Вызов 16-ричного конвертера.

23 INC HL

10FA DJNZ HEXDMP ;Основание цикла.

0604 LD B,04 ;еще 4 байта.

13 INC DE ;Пробельная позиция.

CD07B1 NEXTWO CALL HEX ;Вызов 16-ричного конвертера.

23 INC HL

10FA DJNZ NEXTWO ;Основание цикла.

11000 LD DE,0000H ;Установка начальной позиции

;печати строки на экране.

212DB1 LD HL,MONOUT

CD4AB1 CALL PRINT ;Вызов процедуры, печатающей

;результаты работы программы на ;экране. Можете здесь поставить ;свой адрес.

C9 RET ;Конец работы и возврат в

;исполняемую программу.

Конвертер 16-ричного кода в код символа ASCII.

AF HEX XOR A ;Обнуление аккумулятора.

ED6F RLD ;Вращение полубайта, подхватывая

;его значение из адреса (HL)

12 LD (DE),A

13 INC DE

ED6F BLD ;Второй полубайт.

12 LD (DE),A

ED6F RLD ;Восстановление значения в

;адресе, на который указывает ;HL, в исходное состояние.

1B DEC DE

1B DEC DE

0E02 LD C,2 ;Ввод параметра цикла.

1A DIGIT LD A, (DE)

FE0A CP 0AH

3004 JR NC,DOLET ;Если число больше 9 и должно

изображаться буквой - переход ;на DOLET.

C630 ADD 30H ;Перевод цифры в код ASCII.

1802 JR DONE ;Конец.

C637 DOLET ADD 37H ;Перевод буквы в код ASCII.

12 DONE LD (DE),A

13 INC DE 0D DEC C

20F0 JR NZ,DIGIT ;Возврат к началу цикла.

C9 RET ;Возврат в вызывающую программу.

Таблица программных переменных.

00 MONON DB 0 ;0- выкл. ; 1 - вкл.

00 MONDIG DB 0 ;Позиция курсора.

00AF MONADD DW AF00 ;Адрес вызова внешнего монитора.

00 MONVAL DB 0 ;Значение анализируемого адреса

00 MONOP DB 0 ;Код режима работы.

1C MONOUT DB 1C ;Количество символов в выходном буфере.

00000000 MONLIN DEFM ;Содержимое выходного буфера для

20000020 ;адреса и содержимого байта. 00

20 BLANK DB 20H ;Символ "пробел".

20000000 MONDMP DEFM ;Содержимое выходного буфера

00000000 ;для восьми ближайших байтов 00

20000000

00000000 00

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

Первое, что делает резидентный монитор - он обеспечивает выход из вашей игры, если нажата клавиша "0" и вход в главный монитор. Этот вход делается по методу установки точки прерывания, чтобы отработав в главной мониторе, можно было бы вновь вернуться и продолжить игру.

Я не знаю каким монитором в качестве главного пользуетесь Вы и поэтому не знаю какие команды он вставляет, когда устанавливает точку прерывания, но Вы можете легко это сами установить.

Работая со своим монитором, (например MONS 3) установите где-либо точку

прерывания, а потом посмотрите, что он туда подставил. Это будет либо команда CALL, либо JUMP. В зависимости от прочитанного адреса перевода замените в нижеприлагаемой программе монитора реального времени переменную EXITAD на то, что Вы там нашли. В приведенной распечатке там стоит адрес F70F (63247) - адрес вызова программы MONITOR 48 фирмы PICTURESQUE, которым я и пользуюсь.

Начинать процесс мониторинга игры надо из главного монитора. Стартуйте его, чтобы правильно прошла настройка его собственных переменных, а потом из него пойдите в тестируемую программу.

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

Что позволяет Вам делать резидентный монитор? Во время работы Вашей программы он изображает в верхней части экрана:

- адрес контролируемой Вами ячейки;

- содержимое данной ячейки;

- код режима работы;

- содержимое ближайших восьми байтов.

Печать на экране выполняется с помощью процедуры PRINT, которую мы рассматривали ранее (стр. 119).

На экране информация выглядит так:

6000 00 1 00010203 04050607

| | | содержимое 8-ми

адрес | | соседних байтов

содержимое!

код операции

Управляющие клавиши:

0 - прерывание работы резидентного монитора и переход в главный монитор.

1 - включение резидентного монитора.

5 - курсор влево (выбор цифры, подлежащей изменению);

8 - курсор вправо (выбор цифры, подлежащей изменению);

6 - изменение цифры вниз;

7 - изменение вверх.

Так, перемещаясь между цифрами, изображаемыми на экране, Вы можете их изменять. Например, Вы можете изменить адрес, содержимое которого изображается на дисплее. Вы можете изменить режим работы резидентного монитора.

Всего он имеет три режима.

Режим - 0. В этом режиме происходит считывание (PEEK) содержимого заданного адреса и изображение его на экране.

Если Вы не успеваете отслеживать происходящие изменения, то "замедлить" работу программы можно перейдя в режим 1. Это основной режим, принимаемый по умолчанию. В этом режиме можно задать байт и задать адрес для исполнения POKE.

Режим 2 служит для засылки выставленного байта в выставленный адрес. После выполнения этого вернитесь в режим 0. Оставлять резидентный монитор в этом режиме опасно.

Для справки я привожу структурную схему монитора реального времени.

Теперь на примере программы MONITR рассмотрим план тестирования реальной программы. Ниже перечислены точки, в которых можно выполнить тестирование и намечено, что в этих точках подвергается проверке.

1. MONITR.

Никаких действий не должно выполняться, если переменная MONON равна нулю, т.е. если не нажата клавиша "1".

2. MONITR.

При нажатии "1" MONON должна принимать значение = 1.

3. MONITR.

Если MONON = 1 процедура должна запускаться и работать при нажатии любой клавиши, кроме "0".

4. DELAY.

Проверяется не слишком ли быстро работает программа.

5. KEYSCAN.

Должна прерываться работа при нажатии клавиши "0".

6. KEYNO.

Не должно происходить никаких изменений при нажатии любых клавиш, кроме "5", "6", "7", "8".

7. KEYNO.

При нажатии клавиши "8" (курсор вправо) должно возрастать значение переменной MONDIG, но не более 6.

8. LEFTCR.

При нажатии клавиши "5" должно уменьшаться значение MONDIG, но не ниже, чем до

0.

9. DOWN.

При нажатии клавиши "5" значения цифры на экране должны убывать.

10. UP.

При нажатии клавиши "6" значения цифры на экране должны возрастать.

11. TURNBT.

Проверяется изменение второй цифры в изображаемом на экране содержимом

байта.

12. TURNBT.

Проверяется изменение второй пары цифр в изображаемом адресе.

13. OPTYPE.

Проверяется влияние переменной MONOP на режим работы программы. Выполняется ли PEEK, когда MONOP равно 0? Выполняется ли POKE, когда MONOP = 2? При любых других значениях ничего не должно выполняться.

14. PEEK.

Читается ли содержимое памяти?

15. POKE.

Вводится ли в память установленное значение байта?

16. HEX.

Вывод на экран соответствует шестнадцатеричному представлению чисел?

17. NULLOP.

Формат печати информации на экране соответствует требуемому?

18. COLMON.

Есть ли курсор на экране? он передвигается? Он перепрыгивает через промежутки между числами? После прохождения курсора по числу его цвет восстанавливается исходный?

19. PUTMON.

Проверяется правильность изображения на экране данных по 8-ми соседним байтам. Также проверяется их занесение в буфер MONDMP.

20. HEXTWO.

Окончательно проверяется качество печати.

И, в заключение, пару интересных наблюдений.

Может быть Вы заметили, что план тестирования программы в значительной степени отражает структурную диаграмму, и это не случайно. Если бы было желание дробить диаграмму до более мелких деталей, Вы бы увидели, что они вообще идентичны. Каждому блоку на диаграмме соответствовал бы один тест. Отсюда важный вывод - еще и не приступив к работе над программой, занимаясь только ее проектированием и исполнением структурных диаграмм, Вы уже закладываете основы и возможность будущей отладки и задаете надежность будущей программы.

Как говорится, что заложите, то и получите и остается только еще раз повторить: "Сначала тщательное проектирование - программирование потом".

И второе. Несмотря на то, что список возможных тестов оказался достаточно длинным проверка всего того, что в нем понаписано занимает у меня 30 секунд! (Конечно если все работает, но ведь и в этом тоже надо убедиться).




СОДЕРЖАНИЕ:


  Оставте Ваш отзыв:

  НИК/ИМЯ
  ПОЧТА (шифруется)
  КОД



Темы: Игры, Программное обеспечение, Пресса, Аппаратное обеспечение, Сеть, Демосцена, Люди, Программирование

Похожие статьи:
Gameland - Прохождение игры Черный Ворон: Неизвестные Отгрузки. Диск 2.
Очепятки - Kтo играет с динамитoм - тoт придёт дoмoй убитым.
Новости - презентация нового европейского демопати - FOREVER 2E3.
Полезные сведения - знаете ли Вы,что...
Лит.Страничка - Трагедия "Король Бардик Пятый".

В этот день...   21 ноября