ZX-Ревю 1991 №6 1990 г.

Профессиональный подход - мы продолжаем публиковать заметки знаменитого английского программиста Стива Тернера, автора не менее знаменитой игры OUAZATRON.


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

(Продолжение. Начало на стр. 49, 70)

Разработка программы.

Мой подход к разработке программ базируется на той профессиональной подготовке, которую я получил на фирмах ICL и IBM.

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

Этап 1. Постановка задачи.

Для чего предназначена программа, что она будет делать? Для игровых программ есть несколько важных моментов, которые должны быть определены уже на ранней стадии:

- каким будет экранный интерфейс (какой метод будет применяться для связи между программой и пользователем);

- тема игры;

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

Выходная информация:

Это прежде всего экраны, но сюда можно отнести и распечатки на принтере, если они предполагаются, здесь же должны быть намечены те выгрузки на ленту или диск, которые могут потребоваться по ходу игры. И, конечно же, должен использоваться звук. Любая программа, разумно его использующая, только выигрывает от этого.

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

Для игровых программ стоит рассмотреть в качестве выходных характеристик такие очевидные параметры, как:

- степень использования цвета;

- предполагаемая скорость;

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

Входная информация:

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

От того, как происходит управление игрой в большинстве случаев зависит судьба этой игры - успех или неудача.

Применение джойстика всегда вносит в игру ограничение в связи с тем, что у него только одна кнопка. Ах, если бы у него было две функциональных кнопки! Тогда первая исполняла бы какое-то действие, а вторая - переключала бы вид этого действия. Например, первая означала бы "огонь", а вторая переключала бы оружие: нож, пистолет, автомат, гранатомет и т.п.

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

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

Файлы и таблицы данных:

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

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

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

Этап 2. Проектирование программы.

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

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

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

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

Этап 3. Кодирование.

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

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

Н

апример:

Имя

Размер

Содержание

Примечание

BOMB

1 байт

0 - нет

Наличие бомбы устанавливается в процедуре GETBOMB.

1 - есть

Изменяется в процедуре USEBOMB.

Кроме справочника по переменным, надо вести еще и справочник по процедурам:

- имя процедуры;

- что делает;

- содержание регистров на входе;

- содержание регистров на выходе;

- какие переменные использует.

Н

апример:

Имя

Что делает

Вход

Выход

A - вид оружия 0...3

FIRE

Инициализирует

0 - нож

A - сила выстрела от 0

пакет процедур,

1 - пистолет

до 255

управляющих

2 - автомат

стрельбой.

3 - гранатомет

BC,DE,HL - не определены

F - флаг C=0 - выполнить стрельбу

- флаг C=1 - поменять оружие

- прочие флаги не определены

Используемые

WEAPON 1 байт Вид оружия

переменные:

CHARGE 3 байта Количество зарядов на каждый

вид оружия

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

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

Этап 4. Отладка.

Я предпочитаю всякую процедуру проверять сразу же после того, как написал. Как правило, для этого необходимо приписывать несколько строк, чтобы обеспечить те данные, которые эта процедура должна получать из главной программы. Иногда даже необходимо сразу писать несколько процедур, испытывать и отлаживать совместно, если они друг без друга не отлаживаются, но чем их меньше, тем лучше. Есть закон, согласно которому если размер текста возрастает вдвое, то количество ошибок в нем возрастет в четыре раза. Есть и другой закон - если количество ошибок возрастает вдвое, то время на их отыскание и устранение тоже возрастает в 4 раза. Так что сами думайте, какой размер должны иметь Ваши элементарные процедуры. Заканчивается проверка и отладка процедуры тогда, когда Вы уверены, что в проведенном независимом испытании она работает и делает все, что положено. Правда, к сожалению, это еще не дает 100%-ной уверенности в том, что она также надежно будет работать в комплексе с другими при запуске всей программы в целом. Но если этап проектирования был хорошо проработан, то Вы сможете подкорректировать ее работу в составе всей программы без нарушения работы других блоков.

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

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

Что такое хорошо и что такое плохо?

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

1. Использование "хитрых", головоломных приемов.

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

2. Злоупотребление применением стека.

Лучше оставить стек в покое. Особенно плохо применять его для хранения программных переменных. Вызов переменной по имени (в Ассемблере) - намного понятнее, быстрее и создает меньше условий для появления ошибок.

3. Неправильное использование процедур.

Каждая процедура должна иметь один вход и один выход. Если Вам их нужно больше, то вернитесь на этап 2 и повторите проектирование.

Никогда не имитируйте вызов процедуры (CALL) путем перехода (JP) с последующей манипуляцией стеком. Прием слишком головоломный, чтобы пользоваться им часто. Всегда завершайте процедуру естественным путем (команда RET в конце процедуры).

4. Злоупотребление переходами (JP).

Команда JP, как и GO TO в Бейсике очень затрудняет читаемость программы. При широком применении переходов JP Вы затрудняете себе отладку. Используйте JP только для организации циклов и для исполнения условного ветвления (IF... THEN...).

5. Работа с адресами.

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

К чертам хорошего стиля я отношу:

1. Определение имен со смыслом (название отражает содержание).

2. Комментарий к каждой процедуре.

3. Комментария к каждому "головоломному" (нестандартному) приему.

4. Применение регистров процессора по назначению:

A - аккумулятор;

B - восьмиразрядный обратный счетчик;

BC - шестнадцатиразрядный обратный счетчик;

HL - для хранения адреса или как двухбайтный аккумулятор.

DE - для хранения адреса в операциях, в которых необходимо использование двух адресов.

IX,IY - для выборки элемента из таблицы с использованием индексной адресации.

ПРИМЕЧАНИЕ ИНФОРКОМА.

Если Ваша программа предполагает обращение к системному ПЗУ "Спектрума", то лучше в регистр IY ничего не засылать, а использовать его для выбора данных из таблицы системных переменных "Спектрума", - прием, ставший стандартным.

Регистр же IX в этом случае наиболее часто используют в операциях загрузки/выгрузки.

В качестве примера распечатки программы в машинных кодах, обещанной в прошлом выпуске "ZX-РЕВЮ", мы приводим процедуру Стива Тернера для печати текстовых сообщений в любой точке экрана с точностью до пиксела (а не только в координатах знакомест).

Она может применяться в играх, например для выдачи на экран текущего счета.

Данный пример распечатает на экране две строки: EXAMPLE OF TEXT TABLE. Первая строка содержится в относительном адресе 00AB, а вторая - в 00B3. Обратите внимание на то, что перед строкой, выводимой на печать, должен стоять байт, в котором указана длина этой строки:

00AA - 07 (7 символов в слове "EXAMPLE")

00B2 - 0D (13 символов в строке "OF TEXT TABLE").

(Продолжение в следующем выпуске)

0000

00010

; Пример программы

0000

00020

; печати текста

0000

3E01

00030

LD A,1 ; Номер сообщения

0002

160A

00040

LD D,10 ; Координата "y" места печати

0004

1E0A

00050

LD E,10 ; Координата "x"

0006

CD0A00

00060

CALL TEXT

0009

C9

00070

RET

000A

00080

; Подпрограмма TEXT

000A

00090

; A - номер сообщения

000A

00095

; DE - координаты печати.

000A

00100

TEXT

000A

21AA00

00110

LD HL,TXADD;

000D

0600

00120

LOOK

LD B,0

000F

1803

00130

JR GOTRY

0011

4E

00140

LONG

LD C,(HL) ; поиск текста

0012

23

00150

INC HL

0013

09

00160

ADD HL,BC

0014

3D

00170

GOTRY

DEC A

0015

20FA

00180

JR NZ,LONG

0017

CD1B00

00190

CALL PRINT

001A

C9

00200

RET

001B

00210

001B

00220

001B

00230

; Подпрограмма PRINT

001B

22A800

00240

PRINT

LD (INPUT),HL

001E

7A

00250

LD A,D

001F

E638

00260

AND 38H ; определяем ряд

0021

87

00270

ADD A,A

0022

87

00280

ADD A,A

0023

83

00290

ADD A,E ; прибавили "x"

0024

5F

00300

LD E,A ; младший байт

0025

70

00310

LD A,D

0026

1F

00320

RRA

0027

1F

00330

RRA

0028

1F

00340

RRA

0029

E618

00350

AND 018H ; определяем треть экрана

002B

4F

00360

LD C,A

002C

7A

00370

LD A,D

002D

E607

00380

AND 07H ; строка в ряду

002F

81

00390

ADD C

0030

C640

00400

ADD 40H ; старший байт

0032

57

00405

LD D,A

0033

2AA800

00410

LD HL,(INPUT)

0036

ED53A400

00420

LD (OUTLIN),DE

003A

7E

00430

LD A,(HL)

003B

A7

00440

AND A

003C

C8

00450

RET Z ; неверное значение

003D

4F

00460

LD C,A

003E

ED53A600

00470

PROLET

LD (OUTPUT),DE

0042

23

00480

INC HL

0043

22A800

00490

LD (INPUT),HL

0046

7E

00500

LD A,(HL)

0047

FEFF

00510

CP 0FFH

0049

2016

00520

JR NZ,CHAR

004B

00530

; переход к новой строке

004B

00540

; под первой

позицией

004B

00550

; печати

004B

ED5BA400

00560

LD DE,(OUTLIN)

004F

7B

00570

LD A,E

0050

C620

00580

ADD 20H

0052

5F

00590

LD E,A

0053

D0

00600

RET NC

0054

7A

00610

LD A,D

другая треть экрана

0055

C608

00620

ADD 8

0057

FE58

00630

CP 58H

0059

D0

00640

RET NC

005A

57

00650

LD D,A

005B

ED53A400

00660

LD (OUTLIN),DE

005F

183C

00670

JR REJOIN

0061

00680

0061

6F

00690

CHAR

LD L,A

поиск символа

0062

2600

00700

LD H,0

0064

29

00710

ADD HL,HL

0065

29

00720

ADD HL,HL

0066

29

00730

ADD HL,HL

0067

ED5B365C

00740

LD DE,(CHASET)

006B

19

00760

ADD HL,DE

006C

ED5BA600

00770

LD DE,(OUTPUT)

0070

7A

00780

LD A,D

0071

FE58

00790

CP 58H

0073

D0

00800

RET NC

0074

0608

00810

LD B,8

0076

7E

00820

EIGHT

LD A,(HL)

0077

12

00830

LD (DE),A

выдает

0078

23

00840

INC HL

восемь

0079

7A

00850

LD A,D

строк

007A

E607

00860

AND 07

символа

007C

3C

00870

INC A

007D

FE08

00880

CP 8

007F

200E

00890

JR NZ,NONEW

0081

7A

00900

LD A,D

0082

E6F8

00910

AND 0F8H

0084

57

00920

LD D,A

0085

7B

00930

LD A,E

0086

C620

00940

ADD 20H

0088

5F

00950

LD E,A

0089

3005

00960

JR NC,NEXTSL

008B

7A

00970

LD A,D

008C

C608

00980

ADD 8

008E

57

00990

LD D,A

008F

14

01000

NONEW

INC D

0090

10E4

01010

NEXTSL

DJNZ EIGHT

0092

ED5BA600

01020

LD DE,(OUTPUT)

0096

1C

01030

NEXTLT

INC E

0097

2004

01040

JR NZ,REJOIN

0099

7A

01050

LD A,D

009A

C608

01060

ADD A,8

009C

57

01070

LD A,D

009D

2AA800

01080

REJOIN

LD HL,(INPUT)

00A0

0D

01090

DEC C

00A1

209B

01100

JR NZ,PROLET

00A3

C9

01110

RET

00A4

01120

00A4

0000

01130

OUTLIN

DW 0

начальная строка

00A6

0000

01140

OUTPUT

DW 0

адрес печати

00A8

0000

01150

INPUT

DW 0

адрес текста

5C36

01160

CHASET

EQU 23606

указывает на

00AA

01170

адрес шрифта в ПЗУ ми

00AA

01180

нус 256 байтов

00AA

01190

; Таблица текста

00AA 07 01200 TXADD

00AB 4558414D 01210

00AF 504C45

00B2 0D 01220

00B3 4F462054 01230

00B7 45585420

00BB 5441424C

00BF 45

00000 TOTALERRORS

DEFB 7

DEFM 'EXAMPLE'

DEFB 13

DEFM 'OF TEXT TABLE'




СОДЕРЖАНИЕ:


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

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



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

Похожие статьи:
Мнение - обзор игры жанра D&D - Last Herp of Light Force.
Другие двадцатые - Alco: "я не понял, почему C-jeff грустил, я представлял его не так - думал, поговорим.. Удивлялся, как непринужденно Alff беседует с Gasman'ом на буржуазно-империалистическом языке.. Hе узнал, почему M.M.A. ходил убитый.."
Обзор - Обзор электронных изданий.
Аперативчик - Новогодний выпуск DEJA VU...
Месть афродиты - О чем умалчивают исследователи древних мифов?

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