ZX Spectrum графика 1994 г.

Белее сложные элементы программирования - Управление выполнением программ; Структура дисплейного файла; Быстрое преобразование содержимого экрана; Мультипликация; Свертка; Структура программ на бейсике (перенумерация и уничтожение); Структура программы на бейсике (эффективные программы); Синхронное изображение.


ГЛАВА 13

Белее сложные элементы программирования

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

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

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

Для написания хороших комментариев вполне достаточно одного только здравого смысла. Избегайте классических нелепостей вроде "нажмите 1 для получения двойной информации и 2 для одиночной". Для управления движения курсором старайтесь использовать курсорные клавиши (см. 3-ю опцию программы генератор символов), что кажется вполне естественным для лиц, использующих SPECTRUM достаточно часто. На листинге 13.1 приведена программа, рисующая многоугольники (как в упражнении 1.3). Подпрограмма ввода "INPUT" использует курсорные клавиши и "EDIT", что облегчает работу лицам, имеющим навык работы со SPECTRUMом.

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

С помощью строк, содержащих контрольные коды, можно создавать сложные графические изображения в любом месте экрана. Значение переменной строчного типа может быть присвоено за несколько шагов, а саму переменную можно поместить в скобках в операторе CHR$, а численные переменные с помощью функций STR$. Эти приёмы использовались в программе "WORM CAME" (листинг 1.16). Строки с кодами, управляющими цветом символов, и позицией, с которой они печатаются, могут использоваться в игровых программах, когда возникает необходимость быстро создавать изображение в различных частях экрана. В качестве примера применения этих методов мы приводим на листинге 13.2 меню гиперболической программы обработки файлов.

Обратите внимание на естественное использование цветов для предупреждения о потенциально опасных операциях.

LISTING 13.1

10 DIM X(10): DIM Y(10) 20 LET INPUT=200: LET LIST=300 30 GO SUB INPUT

40 PLOT X(10),Y(10): LET DX=X(10): LET DY=Y(10)

50 FOR I=1 TO 10: DRAW X(I)-DX,Y(I)-DY: LET DX=X(I): LET DY=Y(I): NEXT I

60 PAUSE 250: GO TO 30

200 REM INPUT COORDS.

210 LET I=1

220 GO SUB LIST

230 LET I$=INKEY$: IF I$="" THEN GO TO 230 240 IF I$=CHR$ 10 AND I<11 THEN LET I=I+1: GO TO 220 250 IF I$=CHR$ 11 AND I>1 THEN LET I=I-1: GO TO 220 260 IF I$<>CHR$ 7 THEN GO TO 230

270 IF I=11 THEN INPUT "END ? "-LINE I$: IF I$="Y" THEN CLS: RETURN 280 IF I=11 THEN GO TO 220

290 INPUT "XCOORD.=";X(I);" Y COORD.=";Y(I): GO TO 220

300 REM LIST DATA

310 CLS: FOR J=1 TO 10

320 PRINT AT J,1;"X COORD.=";X(J);" Y COORD.=";Y(J) 330 NEXT J: PRINT AT 11,1,-"END": PRINT AT I,0;">" 340 RETURN

Управляющие коды можно вводить с клавиатуры и вставлять их в символьные цепочки. Эти коды, которые во время выполнения программы игнорируются, можно включать в операторы программы для того, чтобы выделить те или иные участки текстов программ. Если на клавиатуре набрать код, соответствующий PAPER 6 (расширенное "6"), и сразу после этого нажать клавишу DELETE, то код для PAPER уничтожится и останется CODE 6, который устанавливает курсор на следующую границу строки или полустроки. CODE 6 можно использовать в программе для

пропуска строки перед началом нового раздела. Символ REM в начале комментария можно убрать, поместив код INK 0 (расширенное "0") после символов INK 7 (расширенное "7") перед REM. LISTING 13.2

100 DIM G(6):DIM A$(6,24)

110 FOR I=1 TO 6: READ G(I): NEXT I

120 DATA 1000,1000,1000,1000,1000,1000

130 LET A$(1)=" EDIT FILE ": LET A$(2)=" PRINT FILE "

140 LET A$(3)=" SAVE FILE ": LET A$(4)=" LOAD FILE "

150 LET A$(5)=CHR$ 17+CHR$ 2+CHR$ 16+CHR$ 7+" DELETE FILE "+CHR$ 17+CHR$ 7 160 LET A$(6)=CHR$ 17+CHR$ 2+CHR$ 16+CHR$ 7+" ERASE ALL FILES "+CHR$ 17+CHR$ 7 500 REM MENU/SELECT OPTIONS.

510 CLS :PRINT AT 2,8;"N.O.N. FILE HANDLER "

520 FOR I=1 TO 6

530 PRINT AT I*2+4,8;I;A$(I)

540 NEXT I

550 INPUT "SELECT OPTION ? ";OP 560 IF OP<1 OR OP>6 THEN GO TO 550 570 IF OP<5 THEN GO TO 600

580 INPUT ("DO YOU REALLY WANT TO ";+CHR$ 6+A$(OP)+" ");Y$

590 IF Y$<>"Y" THEN GO TO 500

600 GO SUB G(OP): GO TO 500

1000 REM REMAINDER OF ROUTINES

1010 RETURN

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

10 REM LOADER FOR MACHINE-CODE ROUTINE 20 CLEAR 63999 30 FOR I=0 TO 11: READ A 40 POKE 64000+I,A: NEXT I

100 REM DATA FOR MACHINE-CODE TRANSFER ROUTINE

110 DATA 17,0,64

120 DATA 33,0,80

130 DATA 1,0,8

140 DATA 237,176

150 DATA 201

200 REM - MAIN PROGRAM

210 CLS: FOR I=0 TO 21

220 FOR J=0 TO 31: PRINT AT I,J; CHR$(I+64): NEXT J

Структура дисплейного файла Мы знаем, что бейсик позволяет корректировать и просматривать непосредственно дисплейный файл, но для этого следует иметь представление об устройстве дисплейного файла. Каждая горизонтальная строка дисплея состоит из 32 байт, по восемь бит каждый. Эти 32 байта расположены в последовательных ячейках файла, однако ячейки, в которых хранится информация об изображении строчкой ниже, находятся на том же месте на следующей странице памяти. Для восьмиразрядных процессоров таких, как установленный в SPECTRUMe Z-80, страница памяти состоит из 256 байтов; для обозначения этого числа мы используем идентификатор PAGE. Такая организация дисплейного файла позволяет эффективно создавать изображение. На каждой странице хранится восемь линий по 32 байта. На первой станице хранятся верхние линии первых восьми символьных строк, а на семи последующих страницах -оставшиеся семь линий. За этими страницами идут ещё два набора по восемь страниц, на которых хранится информация об оставшейся части экрана.

Теперь мы знаем, как вычислить номера ячеек, в которых хранится верхняя линия символа, и знаем, что номера ячеек, в которых хранится информация о других линиях, получаются прибавлением 256 (количество байт в странице). Для определения номера ячейки, в которой хранится верхняя строчка символа, необходимо знать, в каком из трёх наборов (по восемь страниц) хранится этот символ. Нам также надо будет вычислить, в какой из 256 страницы находится нужная информация. Мы вычисляем номер ячейки, в которой хранится информация о первой строке символа, находящегося в R-ом ряду в C-ой строке с помощью следующей функции:

DEF FN A(R,C)=16384+INT(R/8)*2048+(R-INT(R/8)*8)*32+C В эту функцию входят четыре члена: 16384 - начало дисплейного файла

+ INT(R/8) *2048 - позиция строки в соответствующей трети экрана (0,1,2), умноженной на длину трети экрана (2048=8*PAGE)

+ (R-INT (R/8) *8) *32 - позиция строки в соответствующей трети (от 0 до 7), умноженная на 32 (количество столбцов в строке)

+ С - номер столбца (0-31) в этой строке.

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

соответствуют верхней линии символьного блока.

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

DEF FN D(A$)=PEEK 23606+РЕЕК 23607*256+8*CODE A$ Эта функция использует системную переменную CHAR$ (которая хранится в ячейках 23606 и 23607, см. главу 5) для определения начала таблицы символов, а затем умножает на восемь код соответствующего символа и таким образом находит адрес начала данных. Заметьте, что две эти функции могут быть использованы для занесения информации в две нижние строки экрана дисплея, что, как правило, нельзя сделать обычными средствами.

LISTING 13.3

100 REM MAIN PROGRAM

110 LET PRINT=500

120 LET P$="9 FAKE STATEMENT, 120:1": LET ROW=23: LET COL=0 130 GO SUB PRINT

140 LET P$="PRINT THIS PNYWH ERE ON THE SCREEN ": LET ROW=7: LET COL=16 150 GO SUB PRINT 160 PAUSE 250: STOP 500 REM PRINT ROUTINE

510 DEF FN A(R,C)=16384+INT(R/8)*2048+(R-INT(R/8)*8)*32+C

520 DEF FN D(A$)=PEEK 23606+256*PEEK 23607+8*CODE A$

530 FOR I=1 TO LEN P$

540 LET ADDRESS=FN A(ROW,COL)

550 LET DATA1=FN D(P$(I))

560 FOR J=0 TO 7

570 POKE ADDRESS+J*256,PEEK(DATA1+J) 580 NEXT J

590 LET COL=COL+1: IF COL=32 THEN LET COL=0 600 LET ROW=ROW+1: IF ROW=24 THEN LET ROW=0 610 NEXT I 620 RETURN

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

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

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

В SPECTRUMe команды машинного кода засылаются в операторы DATA, а затем заносятся в память операторами POKE. Операторы ассемблера удобно включать в строчки операторов DATA, используя инструкцию REM.

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

Одной из самых мощных команд процессора Z80 является команда 237, 176, или, на языке ассемблера LDIR, позволяющая пересылать данные из одного участка памяти в другой. Перед тем, как воспользоваться этой командой, следует заполнить некоторые регистры данными, а именно: DE - адресом, куда следует занести данные; HL - адресом, где находятся данные в настоящий момент; ВС - количество байт, подлежащих пересылке.

На рис. 41 приведена программа, составленная в машинных кодах, а также её эквивалент на языках ассемблере и бейсике.

Помните, что язык ассемблера - это всего лишь способ сделать машинный код более понятным. На листинге 13.4 приведена программа, заносящая оператором РОКЕ машинный код в память, а затем вызывающая подпрограмму. Эта программа копирует нижнюю треть дисплейного файла в верхнюю.

300 REM BASIC DATA TRANSFER 17,0,64 LD DE,16384 310 LET DE=16384

33,0,80 LD HL,20480 320 LET HL=20480

1,0,8 LD BC,2048 330 LET BC=2048

237,176 LDIR 340 LET A=PEEK HL: POKE DE,A

350 LET DE=DE+1: LET HL=HL+1 360 LET ВС=ВС-1 370 IF BC<>0 THEN GO TO 340 201 RET 380 RETURN

Рис. 41.

LISTING 13.4

10 REM LOADER FOR MACHINE-CODE ROUTINE

19 REM FOR 16K MACHINES USE CLEAR 31999.

20 CLEAR 63999

30 FOR I=0 TO 11: READ A

39 REM FOR 16K USE POKE 32000.

40 POKE 64000+I,A: NEXT I

100 REM DATA FOR MACHINE-CODE TRANSFER ROUTINE

REM LD DE,16384 REM LD HL,20480 REM LD BC,2048 REM LDIR REM RET

110 DATA 17,0,64 120 DATA 33,0,80 130 DATA 1,0,8 140 DATA 237,176 150 DATA 201 200 REM MAIN PROGRAM 210 CLS: FOR I=0 TO 21

220 FOR J=0 TO 31: PRINT AT I,J;CHR$ (I+64): NEXT J 230 NEXT I

240 PRINT AT 19,1; INVERSE 1;"PRESS ANY KEY";"TO START ROUTINE" 250 IF INKEY$="" THEN GO TO 250

259 REM FOR 16K CHANGE TO USR 32000.

260 LET A=USR 64000: STOP

После занесения оператором POKE команд машинного кода в память мы запускаем программу функцией USR, в которой указан адрес начала программы. Функция USR просто-напросто вызывает подпрограмму, написанную в машинном коде, чей адрес совпадает со значением параметра USR. В программе, написанной на бейсике, этот вызов осуществляется с помощью команды вроде LET A=USR 32000 (32000 - это адрес, в котором хранится 17, первый байт кода).

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

В SPECTRUMe с объёмом памяти 48К одновременно могут храниться пять различных изображений, называемых кадрами. С помощью программы на листинге 13.5 можно создать пять программ на машинном коде, расположенные в 30200, 30300, 30400 и 30500, которые будут пересылать эти данные на экран. Предположим, что на ленте записаны данные о пяти изображениях. Мы загружаем их в память в виде пяти альтернативных кадров, которые с помощью соответствующих программ могут быть занесены на экран. Этот приём можно использовать во время лекции или разговора с покупателем. После показа пяти изображений следует загрузить следующие пять, на что уходит около пяти минут, в то время как с диска они загружаются за 10 секунд.

Если использовать программу "SLIDESHOW", то для создания изображения на экране достаточно нажать одну из пяти клавиш "1"-"5".

LISTING 13.5

100 REM LOADER FOR MACHINE-CODE ROUTINES

110 CLEAR 29999: DIM F(5)

120 FOR I=1 TO 5: RESTORE

130 LET F(I)=120+27*(I-1)

140 FOR J=0 TO 11

150 READ A: POKE 30000+I*100+J,A

160 NEXT J

170 NEXT I

200 REM DATA TRANSFER FROM I,TH FRAME TO SCREEN

REM LD DE,16384 REM LD HL,FRAME(I) REM LD BC,27*256 REM LDIR REM RET

210 DATA 17,0,64 220 DATA 33,0,F(I) 230 DATA 1,0,27 240 DATA 237,176 250 DATA 201 300 REM LOAD FRAMES

310 FOR J=1 TO 10: BEEP 0.1,30: PAUSE 5: NEXT J 320 CLS: FOR I=0 TO 4

330 LOAD "" CODE (120+I*27)*256,27*256 340 NEXT I

350 FOR J=1 TO 10: BEEP 0.1,30: PAUSE 5: NEXT J 400 REM SLIDE SHOW

410 IF INKEY$<>"" THEN GO TO 410

420 LET A$=INKEY$: IF A$="" THEN GO TO 410

440 IF A$="A" THEN GO TO 500

450 IF A$>="1" AND A$<="5" THEN LET A=USR (30000+VAL A$*100)

460 GO TO 410

500 REM MOVIE SHOW

510 FOR I=30100 TO 30500 STEP 100

520 LET A=USR I

530 IF INKEY$="S" THEN GO TO 400 540 NEXT I: GO TO 510

Развивая эти идеи, можно получить изображение движущихся объектов. Рассмотрим, например, пять кадров, созданных с помощью программ трёхмерной графики, приведенных в главе 12. Эти программы генерируют изображения сферы; значения параметров HORIZ=3.2, VERT=2.2, NUMH=10, NUMV=8 и PHI=0.4*PI*I/NUMH, где 0<=I<=4, глаз находится в точке (1,2,3), взгляд направлен в начало координат. Изображение вращающегося сфероида может быть получено, если показывать эти кадры, быстро сменяющие друг друга.

После прогона программ "MOVIE" и "SLIDESHOW" следует набрать на клавиатуре CLEAR 65367, в противном случае, при попытке загрузить какую-либо программу на экране дисплея появится надпись "OUT OF MEMORY" (в памяти нет свободного места). Упражнение 13.1

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

Свертка (16К и 48К)

Использование машинного кода для решения более сложных задач требует от программиста высокой квалификации. Здесь мы приводим ещё один пример программы в машинном коде (программа на листинге 13.6 "прокручивает" изображение на экране сверху вниз). Решаемая программой задача осложнена тем, что данные, записанные в дисплейном файле, разбиты по линиям, содержащим 32 байта. Для того, чтобы программа была эффективной, нам необходимо знать адрес ячейки, в которой хранится начало данных об этих линиях. Вычисление этого адреса в машинных кодах громоздко и неэффективно, поэтому мы используем так называемую адресную таблицу.

Для облегчения программирования в машинных кодах создается адрес, который хранится в шестнадцати битах, распределенных по двум ячейкам - нижней и верхней. Когда нам нужно узнать адрес какой-нибудь строчки, мы просто разыскиваем в таблице две половинки, соответствующие этим байтам. Для заполнения таблицы мы используем бейсик. Эти таблицы и сам машинный код могут быть записаны на ленту. На листинге 13.6 приведена та же программа, написанная на бейсике. Обратите внимание на то, что программа на бейсике предполагает существование той же таблицы, используемой программой, написанной в машинном коде. Упражнение 13.2

Напишите подпрограмму в машинном коде, которая бы за один вызов прокручивала файл атрибутов на одну строку. Напишите программу на бейсике, которая бы прокручивала в памяти файл атрибутов каждый раз после того, как графическое поле прокручивается на восемь линий. LISTING 13.6

10 REM LOADER FOR MACHINE-CODE ROUTINE

20 CLEAR 31999

30 FOR I=0 TO 74

40 READ A: POKE 32000+I,A

50 NEXT I

100 REM DOWRWARDS WRAP-AROUND SCROLL FOR GRARHICS AREA

110

DATA

1,175,0

REM

LD

BC,175

120

DATA

221,33,

75,125

REM

LD

IX,LOBYTE

130

DATA

221,9

REM

ADD

IX,BC

140

DATA

221,110

,0 :

REM

LD

L,(IX+0)

150

DATA

221,33,

251,125

REM

LD

IX,HIBYTE

160

DATA

221,9

REM

ADD

IX,BC

170

DATA

221,102

,0 :

REM

LD

H,(IX+0)

180

DATA

17,171,

126

REM

LD

DE,TEMP

190

DATA

205,67,

125 :

REM

CALL

MOVE

200

DATA

221,33,

75,125

REM

LD

IX,LOBYTE

210

DATA

221,9

REM

ADD

IX,BC

220

DATA

221,94,

0

REM

LD

E,(IX+0)

230

DATA

221,110

,-1

REM

LD

L,(IX-1)

240

DATA

221,33,

251,125

REM

LD

IX,HIBYTE

250

DATA

221,9

REM

ADD

IX,BC

260

DATA

221,86,

0

REM

LD

D,(IX+0)

270

DATA

221,102

,-1

REM

LD

H,(IX-1)

280

DATA

205,67,

125 :

REM

CALL

MOVE

290

DATA

13

REM

DEC

С

REM JR NZ,LINE REM LD DE,16384 REM LD HL,TEMP REM CALL MOVE REM RET REM PUSH ВС REM LD BC,32 REM LDIR REM POP ВС REM RET

400 REM CONSTRUCT TABLES OF DISPLAY-FILE LINE ADDRESSES 410 FOR I=0 TO 21: FOR J=0 TO 7

420 LET A=16384+INT(I/8)*2048+(I-INT(I/8)*8)*32

430 LET H=INT(A/256): LET L=A-H*256

440 POKE 32075+I*8+J,L: POKE 32251+I*8+J,H+J

450 NEXT J: NEXT I

500 REM MAIN PROGRAM

510 LIST 380

520 IF INKEY$ <>"" THEN LET A=USR 32000 530 GO TO 520

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

Программы, написанные на бейсике, хранятся построчно в ячейках, находящихся с номера 23755. Первым элементом данных для каждой строчки является номер строчки (16 бит), занимающий две последовательные ячейки -нижнюю и верхнюю. Во всех остальных местах значения хранятся в стандартном нижне-верхнем представлении. Для иллюстрации этих идей предположим, что мы вводим строку 10 REM. Если наберем команду

PRINT PEEK 23755, РЕЕК 23756, то мы увидим, что в этих ячейках находятся значения 0,10. Если мы знаем 10-ю строчку и введем в начале программы строку с другим номером, то мы увидим, что теперь этот номер хранится в ячейках 23755 и 23756. В следующих двух ячейках хранится длина строки (эта информация может быть использована для поиска начала следующей строки). Затем идёт собственно строка программы на бейсике, причём каждый символ или ключевое слово занимает одну ячейку. Конец каждой строки отмечен кодом 13, соответствующим клавише ENTER. После каждого числа, записанного в десятичном представлении и хранящемся в символьном виде, идёт код 14, после которого идет это же число в двоичном представлении, занимающее пять байтов.

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

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

LISTING 13.7

10 REM BASIC VERSION SCROLL FOR GRAPHICS AREA 20 CLEAR 31999 30 GO TO 400

100 REM DOWNWARDS WRAP-AROUND SCROLL FOR GRAPHICS AREA

110 LET C=175: LET B=0: LET BC=C+B*256

120 LET IXLO=75: LET IXHI=125: LET IX=IXLO+IXHI*256

130 LET IX=IX+BC

140 LET L=PEEK(IX+0)

150 LET IXLO=251: LET IXHI=125: LET IX=IXLO+IXHI*256 160 LET IX=IX+BC

170 LET H=PEEK(IX+0): LET HL=L+H*256

180 LET E=171: LET D=126: LET DE=IXLO+IXHI*256

190 GO SUB 350

200 LET IXLO=75: LET IXHI=125: LET IX=IXLO+IXHI*256 210 LET IX=IX+BC 220 LET E=PEEK(IX+0) 230 LET L=PEEK(IX-1)

240 LET IXLO=251: LET IXHI=125: LET IX=IXLO+IXHI*256 250 LET IX=IX+BC

260 LET D=PEEK(IX+0): LET DE=E+D*256 270 LET H=PEEK(IX-1): LET HL=L+H*256 280 GO SUB 350

300 DATA 32,226 310 DATA 17,0,64 320 DATA 33,171,126 330 DATA 205,67,125 340 DATA 201 350 DATA 197 360 DATA 1,32,0 370 DATA 237,176 380 DATA 193 390 DATA 201

290 LET C=C-1: LET BC=C+B*256

300 IF C<>0 THEN GO TO 200

310 LET E=0: LET D=64: LET DE=E+256*D

320 LET L=171: LET H=256: LET HL=L+H*256

330 GO SUB 350

340 RETURN

350 LET S=BC

360 LET BC=32

370 LET A=PEEK HL: POKE DE,A: LET DE=DE+1: LET HL=HL+1: LET BC=BC-1: IF BC<>0 THEN GO TO 370

380 LET BC=S 390 RETURN

400 REM CONSTRUCT TABLES OF DISPLAY-FILE LINE ADDRESSES 410 FOR I=0 TO 21: FOR J=0 TO 7

420 LET A=16384+INT(I/8)*2048+(I-INT(I/8)*8)*32

430 LET H=INT(A/256): LET L=A-H*256

440 POKE 32075+I*8+J,L: POKE 32251+I*8+J,H+J

450 NEXT J: NEXT I

500 REM MAIN PROGRAM

510 LIST 380

520 IF INKEY$<>"" THEN GO SUB 100 530 GO TO 520

К сожалению, этого недостаточно в тех случаях, когда в программе используются такие операторы, как GO TO или GO SUB, и т.д. Поэтому мы должны найти все ключевые слова GO SUB, GO TO, RESTORE и RUN и, если за ними следует целое число, проверить, был ли изменен этот номер строки. LISTING 13.8

100 REM SELF-LISTING PROGRAM 110 LET I=23755: CLS

120 LET LINE=256*PEEK I+PEEK(I+1): IF LINE>9999.5 THEN STOP 130 PRINT " ";LINE;

140 LET I=I+2: PRINT PAPER 5;PEEK I;",";PEEK (I+1);" ";

150 LET LENGTH=PEEK I+256*PEEK(I+1)

160 LET NUM=0: LET I=I+1

170 FOR J=1 TO LENGTH: LET I=I+1

180 LET P=PEEK I: IF P>32 AND NUM<=0 THEN LET NUM=1 190 IF P=13 THEN PRINT PAPER 4;P: PRINT: GO TO 230 200 IF P=14 THEN LET NUM=6

210 IF NUM>0 THEN PRINT PAPER 6;P: PRINT: GO TO 230 220 PRINT CHR$ P; 230 LET NUM=NUM-1 240 NEXT J

250 LET I=I+1: GO TO 120

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

На листинге 13.9 приведены две программы: программа перенумерации запускается командой RUN 9900, а программа уничтожения - командой RUN 9970. Упражнение 13.3

Напишите подпрограмму, которая бы просматривала участок памяти, отведенный для хранения текстов программ на бейсике и находила любую заданную последовательность кодов. Используйте метод, примененный в программе уничтожения строк, для присвоения системной переменной ЕРРС (эта переменная контролирует положение курсора редактора) значения номера строки, где найдена эта последовательность. LISTING 13.9

9900 INPUT "RENUMBER LINES ";LOW;" TO ";UP,"STARTING AT ";NEW;" IN STEPS OF

";STEP

9901 LET X=9900: IF LOW>X OR UP>X OR LOW>UP THEN GO TO 9900

9902 IF NEW>X OR NEW<1 OR STEP>X OR STEP<1 THEN GO TO 9900

9903 PRINT AT 19,0;"RENUMBER LINES ";LOW;" TO ";UP,"STARTING AT ";NEW;" IN STEPS OF ";STEP,"PLEASE WAIT"

9904 LET START=23755: LET SCREEN=16384: LET HI=256

9905 LET A=START: LET B=SCREEN

9906 LET H=PEEK A: LET L=PEEK(A+1)

9907 POKE B,H: POKE B+1,L

9908 LET A=A+2: LET B=B+2

9909 LET LEN=PEEK A+PEEK(A+1)*HI: LET A=A+LEN+2

9910 IF H*HI+L<X THEN GO TO 9906

9911 LET A=START+A: LET B=SCREEN: LET W=NEW

9912 LET H=PEEK A: LET L=PEEK(A+1)

9913 LET N=HI*H+L: IF N<LOW OR N>UP THEN GO TO 9918

9914 IF W>X THEN GO TO 9955

9915 LET H=INT(W/HI): LET L=W-H*HI

9916 POKE A,H: POKE A+1,L

9917 LET W=W+STEP

9918 LET A=A+2

9919 LET LEN=PEEK A+PEEK(A+1)*HI: LET A=A+LEN+2

9920 IF N<X THEN GO TO 9912

9921 LET A=START: LET B=SCREEN

9922 LET H=PEEK A: LET L=PEEK(A+1): LET NN=PEEK B*HI+PEEK(B+1)

9923 LET N=H*HI+L: IF N=X THEN STOP

9924 PRINT AT 21,0;"CHECKING ";NN;" = NEW LINE ";N

9925 LET A=A+2: LET W=A+2

9926 LET LEN=PEEK A+PEEK(A+1)*HI: LET A=A+LEN+2

9927 LET T=PEEK W

9928 IF T=CODE("GO TO") OR T=CODE("GO SUB") OR T=CODE("RUN") OR T=CODE ("RESTORE") THEN GO SUB 9932

9929 IF T=14 THEN LET W=W+5

9930 LET W=W+1: IF W<A THEN GO TO 9927

9931 LET B=B+2: GO TO 9922

9932 LET V=W+1: LET A$=""

9933 LET S=PEEK V: IF S<>32 AND S<>14 AND NOT (S>=48 AND S<=57) THEN RETURN

9934 IF S<>14 THEN LET V=V+1: LET A$=A$+CHR$ S: GO TO 9933

9935 LET V=V+3: LET AT=PEEK V+PEEK(V+1)*HI

9936 IF NAT<LOW OR NAT>UP THEN RETURN

9937 GO SUB 9943: LET H=INT(NAT/HI): LET L=NAT-H*HI

9938 LET B$=STR$ NAT: IF LEN A$<>LEN B$ THEN GO SUB 9951

9939 POKE V,L: POKE V+1,H

9940 FOR I=1 TO LEN B$

9941 POKE W+I,CODE B$(I): NEXT I

9942 RETURN

9943 LET C=START: LET D=SCREEN

9944 LET H=PEEK D: LET L=PEEK(D+1)

9945 LET E=PEEK C*HI+PEEK(C+1)

9946 IF E>=X THEN LET NAT=0: RETURN

9947 IF H*HI+L=AT THEN LET NAT=E: RETURN

9948 LET C=C+2: LET D=D+2

9949 LET LEN=PEEK C+PEEK(C+1)*HI: LET C=C+LEN+2

9950 GO TO 9944

9951 LET DIFF=LEN A$-LEN B$

9952 IF DIFF>0 THEN FOR I=1 TO DIFF: LET B$=D$+" ": NEXT I: RETURN

9953 PRINT AT 16,0;"NO ROOM AT ";CHR$ T;AT;" IN LINE ";NN,"TYPE EDIT AND ADD ";-DIFF;" SPACE(S)","TO LABEL THEN RE-RUN PROGRAM."

9954 LET H=INT(NN/HI): POKE 23626,H: POKE 23625,NN-H*HI

9955 LET A=START: LET B=SCREEN

9956 LET H=PEEK A: LET L=PEEK(A+1)

9957 IF H*HI+L=X THEN PRINT AT 0,0;"RENUMBER ABORTED": STOP

9958 POKE A,PEEK B: POKE A+1,PEEK(B+1)

9959 LET A=A+2: LET B=B+2

9960 LET LEN=PEEK A+PEEK(A+1)*HI: LET A=A+LEN+2

9961 GO TO 9956

9970 INPUT "DELETE LINES ";LOW;" TO ";UP: IF LOW<2 OR LOW>=UP THEN GO TO 9970

9971 PRINT AT 20,0;"DELETE LINES ";LOW;" TO ";UP,"PLEASE WAIT"

9972 LET START=23755: LET SCREEN=16384: LET HI=256

9973 LET A=START: LET B=SCREEN

9974 LET H=PEEK A: LET L=PEEK(A+1)

9975 IF H*HI+L>=LOW THEN PRINT AT 0,0;"PLEASE ENTER LINE ";LOW-1;" REM","AND RE-RUN PROGRAM": STOP

9976 LET H=PEEK A: LET L=PEEK(A+1)

9977 IF H*HI+L>=LOW THEN GO TO 9981

9978 LET NN=H*HI+L: LET LAST=A: LET A=A+2

9979 LET LEN=PEEK A+PEEK(A+1)*HI: LET A=A+LEN+2

9980 GO TO 9976

9981 LET LAST=LAST+2

9982 LET LONG=PEEK LAST+PEEK(LAST+1)*HI

9983 IF H*HI+L>UP THEN PRINT AT 0,0;"NO LINES IN RANGE": STOP

9984 LET H=PEEK A: LET L=PEEK(A+1): IF H*HI+L=UP THEN GO TO 9990

9985 LET A=A+2: LET LONG=LONG+2

9986 LET LEN=PEEK A+PEEK(A+1)*HI: LET A=A+LEN+2: LET LONG=LONG+LEN+2

9987 IF H*HI+L<>UP THEN GO TO 9984

9990 LET H=INT(LONG/HI): POKE LAST+1,H: POKE LAST,LONG-H*HI 9995 LET H=INT(NN/HI): POKE 23626,H: POKE 23625,NN-H*HI 9999 PRINT AT 0,0;"TYPE EDIT AND ENTER": STOP

Структура программы на бейсике (эффективные программы) Когда мы программируем на бейсике, то знание того, как строки хранятся в памяти, помогает писать эффективные программы, быстро работающие и экономящие память. Каждая числовая константа сопровождается её двоичным кодом, так что нет необходимости перевода числа из символьного представления в двоичное каждый раз, когда выполняется эта строка программы. Если же мы присвоим это число в качестве значения переменной, то для этого потребуется количество байт памяти, равное числу символов в имени переменной. Для присвоения значения мы используем символы ":", "LET", "=", а также имя переменной. Если число используется часто, то это дает существенную экономию памяти. В качестве иллюстрации вышесказанного рассмотрим первые две строки программы

10 PRINT AT 1,1 20 LET A=1: PRINT AT A,A 30 PRINT AT 1,1 40 PRINT AT A,A

Строка с номером 10 занимает 17 байт памяти: "PRINT", "AT", "1", 14, 0, 0, 1, 0, 0, "1", 14, 0, 0, 1, 0, 0. Строка с номером 20 занимает 16 байт памяти: "LET", "А", "=", "1", 14, 0, 0, 1, 0, 0, ":", "PRINT", "AT", "A",

",", " А".

Для кодирования второй строки требуется меньше символов, чем для первой; вторая строка использует символ A, который занимает в любом месте программы шесть байт. Если мы хотим повторить произведенные выше операции, как это сделано в 30-ой и 40-ой строках программы, то обнаружим, что 30-ая строка занимает 17 байт, а строка 40 - всего пять. Мы видим, что если число встречается в программе достаточно часто, то использование переменных дает существенную экономию памяти.

Экономию памяти также дает размещение на одной строке максимального числа операторов. Следует отметить, однако, что это снижает удобочитаемость программы. Каждая новая строка занимает пять байт памяти: в один записывается код 13, отмечающий конец предыдущей строки, в двух других байтах - номер строки и ещё два байта отводятся под длину строки. Для двоеточия между операторами требуется только один байт.

Рассмотрим, например, небольшую программу, состоящую из 90 операторов: если первоначально операторы записаны по одному в строке, а затем нам удается поместить на каждой строке по три оператора, то этим достигается экономия в 60*(5-1)=240 байт. В больших программах этот способ позволяет сэкономить более 1К памяти. Кроме того, использование меньшего числа строк сокращает время выполнения таких команд, как GO TO и GO SUB, гак как тратится меньше времени на поиск нужной строки.

Наиболее часто используемые подпрограммы следует располагать ближе к началу программы. Если же нет необходимости в экономии времени, то подпрограммы следует располагать в порядке логического следования. Упражнение 13.4

Перепишите и перерасположите графические подпрограммы с тем, чтобы они занимали меньше места и тратили меньше времени на выполнение.

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

Команда PAUSE 1 не всегда дает задержку в 1/50 долю секунды, так как эта команда выполняется до момента появления нового изображения. Этот факт делает возможным соотносить моменты запуска команд с моментами смены кадра на дисплее. Если во время заполнения экрана мы меняем командой BORDER цвет рамки, то для этого кадра верхняя часть рамки будет одного цвета, а нижняя - другого. Очевидно, что мы можем использовать команду PAUSE для того, чтобы подождать смены кадров и повторить операции с новым кадром. Если мы будем постоянно повторять эту операцию, то на экране возникнет неподвижное изображение.

Команды SAVE и LOAD используют для этой цели подпрограммы, написанные в машинных кодах, в результате чего на рамке появляются полосы. Пусть программа начинается так:

1 GO TO 10

2 PAUSE 1: BORDER 7: BORDER 2: BORDER 6: BORDER 4: BORDER 5: BORDER 1: BORDER 3: BORDER 7: BORDER 7: GO TO 2

Подпрограмма заканчивается командой GO TO 2, в результате чего после построения рисунка на рамке появляется последовательность цветных полос. Следует отметить, что если эти строчки поместить не в начале программы, то выполнение команды GO TO может занять слишком много времени.

Упражнение 13.5

Напишите программу, которая бы окрашивала рамку в красный и циановый цвета, не используя для этой цели оператора PAUSE. Для этого вставьте между операторами дополнительные двоеточия, пока время выполнения команды не составит в точности 1/50 с, что и даст неподвижное изображение (подсказка примите время выполнения команды BORDER за 10, GO TO за 13, двоеточия - за 1, и подберите такое количество операторов, чтобы в этих единицах время выполнения всей строки равнялось 160).

Список программ

1. Листинги 13.1. Входные данные: десять наборов координат X и Y. На экране появляется таблица этих значений, за которыми идет надпись "END". Установленный в начальный момент у первой строки курсор можно передвигать вниз нажатием клавиши прописное "6" и вверх нажатием клавиши прописное "7". После того как курсор установлен у нужной строки, следует нажать "ENTER" (прописное "I"), компьютер запрашивает координаты элемента изображения, соответствующего этой строке. После того, как вы ввели все данные, установите курсор у надписи E, нажмите EDIT (прописное "I") и "Y". Программа нарисует многоугольник, соединив 10 точек.

2. Листинг 13.2. Входные данные: число для файловой системы. Введите любое число от "1" до "6". Если вы введете "5" или "6", то компьютер потребует подтвердить, что вы дали верный ключ: если вы подтверждаете, то напечатайте "Y", если нет, то "". По команде BREAK программа прекращает работу.

3. Листинг 13.3. Входных данных нет, по команде BREAK программа прекращает работу.

4. Листинг 13.4. Наберите любую последовательность символов. По команде BREAK программа прекращает

работу.

5. Листинг 13.5. После звукового сигнала следует загрузить с ленты пять кадров. Напечатайте "1", "2", "3", "4", "5" для воспроизведения соответствующего изображения, " " для получения эффекта мультипликации, " ", чтобы прекратить смену кадров.

6. Листинг 13.6. После заполнения экрана любая клавиша вызовет "свертку " изображения на экране, а команда BREAK остановит этот процесс.

7. Листинг 13.7. Таже программа, что и в пункте 6, но написанная на бейсике.

8. Листинг 13.8. Входных данных нет.

9. Листинг 13.7 и 13.9. Наберите RUN 9900 для перенумерации строк и RUN 9970 для уничтожения строки. Пример - редактирование листинга 13.7:

RUN 9900

RENUMBER LINES 10 ТО 30

STARTING AT 601 STEPS OR 5

Теперь посмотрите, какие изменения произошли в программе.

RUN 9970

DELETE LINES 60 ТО 99

Остановка: перед удаляемым куском должна быть хотя бы одна строка.

RUN 9970

DELETE LINES 65 ТО 99

EDIT (прописная "I")

LIST




СОДЕРЖАНИЕ:
  1. Трёхмерная декартова геометрия - Определение прямой; Угол между двумя направляющими векторами; Определение плоскости70 Точка пересечения прямой и плоскости; Расстояние от точки до прямой; Точка пересечения двух прямых; Плоскость, проходящая через три неколлинеарные точки; Точка пересечения трёх плоскостей; Линия пересечения двух плоскостей; Функциональное представление поверхности; Лежит ли точка по ту же сторону от плоскости, что и начало координат?; Каково направление обхода двумерного многоугольника, заданного последовательностью своих вершин?


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

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



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

Похожие статьи:
Юмор - Анекдоты.
Anigdot №28 - После долгого перерыва, мы опять вышли.
Review - NedoLang programming language
Партийная зона - Официальные результаты Computer Art'99. Впечатления о CAFE'99.
Groups - анкеты действующих групп: RUSH.

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