Модульное построение программы
Нетрудно убедиться, что при разработке сложных сюжетов игр и соответствующих программ их блок-схемы также усложняются. Если такая схема будет содержать слишком много блоков и ветвей, то ее проверка окажется затруднительной: невозможно будет выяснить, все ли блоки учтены. Поэтому при составлении сложных программ чаще всего используют модульный принцип их построения (см. [7]).
Модулем называется самостоятельная часть программы, обеспечивающая решение какой-нибудь определенной части задачи. Например, в программе могут существовать модули ввода данных, печати результата, очистки экрана (как в предыдущей программе), модуль заставки, отдельных картин игрового пространства и т. д. Программа, разделяемая на модули при разработке блок-схемы и на следующих стадиях проектирования, имеет модульную структуру (рис. 4.4). Про такую программу можно сказать, что она строится по принципу «сверху вниз», потому что ее создание начинается с разработки укрупненного модуля (определяющего главную задачу) и далее «вниз», к модулям, которые входят в укрупненный как составные части. Модульное проектирование позволяет
разделить сложную программу на фрагменты, для каждого из которых проще разрабатывать свою блок-схему, а затем соответствующую этой блок-схеме подпрограмму.
Для того, чтобы почувствовать эффективность такого подхода, рассмотрим развлекательную программу ЖИЗНЬ.
На экране вами создается некоторая первичная колония существ, располагающихся на поле из клеточек (рис. 4.5). Существа могут как размножаться, так и умирать, подчиняясь при этом двум законам. Первый: если вокруг пустой клетки есть ровно три особи (считая по горизонтали, вертикали и диагоналям), то в этой клетке появляется новая особь. Она переходит в следующее поколение, когда в ближайших
клетках вокруг нее есть 2 или 3 другие особи. В противном случае она умирает: если рядом есть только один организм, то этого недостаточно для воспроизводства, а 4, 5 и более создают перенаселение. С помощью такой программы можно наблюдать развитие своеобразной «компьютерной жизни». Это развитие зависит от формы заданной вами исходной колонии (популяции) и количества особей в ней.
Если взглянуть на текст программы, воплощающей эту идею, то может показаться, что она слишком велика и разобраться в ней почти невозможно. Однако программа состоит из семи модулей, которые реализованы в виде самостоятельных подпрограмм, что значительно упрощает понимание. Примечательно, что модули используются в основной программе 16 раз, в результате чего вся она становится вполне обозримой, существенно экономится память компьютера и место на магнитной ленте, куда эта программа записывается. Итак, перейдем к се рассмотрению.
Программа 17. ЖИЗНЬ. 10 GO SUB 2000 20 GO SUB 1000 30 GO SUB 3000 40 BEEP .07,0 50 GO SUB 1000 60 DIM A$(30,20) 70 DIM B$(30,20)
80 LET S=0
90 PRINT AT 10,5; INK 5;"STANDARD COLONIA (Y/N)";INK 2;"?" 100 LET K$=INKEY$
110 IF K$="Y" OR K$="y" THEN BEEP .07,5: GO TO 200 120 IF K$="N" OR K$="n" THEN BEEP .07,5: GO TO 400 130 PAUSE 5
140 PRINT AT 10,27;" " 150 PAUSE 5: GO TO 90 200 REM -- standard---210 LET A$(14,9)="1" 220 LET A$(14,10)="1" 230 LET A$(14,11)="1" 240 LET A$(15,11)="1" 250 LET A$(16,11)="1" 260 LET A$(16,10)="1" 270 LET A$(16,9)="1" 280 LET xmin=13: LET xmax=17 290 LET ymin=8: LET ymax=12 300 LET K=7 310 GO TO 600
400 REM -- NO standard --410 GO SUB 1000 420 INK 5
430 PRINT AT 21,0; INK 4;"KOL-WO OSOBEY:" 440 INPUT K 450 FOR I=1 TO K
460 PRINT AT 21,0; INK 6;" X,Y ";I;" OSOBI: " 470 INPUT INK 3;"X=";X, INK 3;"Y=";Y 480 IF X<2 OR X>29 OR Y<2 OR Y>19 THEN GO TO 470 490 LET A$(X,Y)="1"
500 IF I=1 THEN LET xmin=X-1: LET xmax=X+1: LET ymin=Y-1:LET ymax=Y+1 510 GO SUB 6000 520 NEXT I 600 GO SUB 1000
610 LET xmin1=xmin: LET xmax1=xmax 620 LET ymin1=ymin: LET ymax1=ymax 630 LET S=S+1
640 PRINT AT 0,6;"STEP:";S;"nnnKOL-WO:";K;"nnn"
650 BEEP .1,25
660 FOR Y=Ymin1 TO Ymax1
670 FOR X=Xmin1 TO Xmax1
680 IF A$(X,Y)=" " THEN PRINT AT Y,X; INK 5;"C":GO TO 710 690 PRINT AT Y,X; INK 2;"B"
700 GO SUB 6000: IF INKEY$<>"" THEN GO SUB 7000: GO TO 20 710 NEXT X 720 NEXT Y
730 IF K=0 THEN PAUSE 100: GO SUB 7000: GO TO 20 740 LET K=0
750 FOR Y=Ymin TO Ymax 760 FOR X=Xmin TO Xmax 770 LET J=0
780 IF INKEY$<>"" THEN GO SUB 7000: GO TO 20 790 FOR N=-1 TO 1
800 IF X+N<1 OR X+N>30 THEN GO TO 830 810 IF Y>1 THEN IF A$(X+N,Y-1)="1" THEN LET J=J+1 820 IF Y<20 THEN IF A$(X+N,Y+1)="1" THEN LET J=J+1 830 NEXT N
840 IF Y<1 OR Y>20 THEN GO TO 870
850 IF X>1THEN IF A$(X-1,Y)="1" THEN LET J=J+1
860 IF X<30 THEN IF A$(X+1,Y)="1" THEN LET J=J+1
870 IF J=3 THEN LET K=K+1: LET B$(X,Y)="1": GO TO 900
880 IF J>1 AND J<4 AND A$(X,Y)="1" THEN LET K=K+1:LET B$(X,Y)="1": GO TO 900
890 LET B$(X,Y)=" "
900 NEXT X
910 NEXT Y
920 FOR Y=ymin TO ymax 930 FOR X=xmin TO xmax 940 LET A$(X,Y)=B$(X,Y) 950 NEXT X 960 NEXT Y 970 GO TO 610
1000 REM------C L S---------
1010 BORDER 0: PAPER 0: INK 6 1020 FLASH 0: OVER 0: BRIGHT 0 1030 CLS 1040 RETURN
2000 REM ------Graphics-------
2010 FOR I=1 TO 3: READ S$ 2020 FOR N=0 TO 7: READ S 2030 POKE USR S$+N,S 2040 NEXT N: NEXT I 2050 RETURN
2060 DATA "A",0,28,38,79,95,127,62,28 2070 DATA "B",0,60,126,86,126,102,60,0 2080 DATA "C",0,0,252,132,132,132,132,252
3000 REM ------SCREEN---------
3010 LET X=1: LET C=1 3020 FOR Y=1 TO 12
3030 PRINT AT Y-1,X;"ПППППППППППППППППППППППППППППППП": REM 32 Space
3040 GO SUB 3150
3050 IF INKEY$<>"" THEN RETURN
3060 BEEP .01,20: PAUSE 5
3070 NEXT Y
3080 FOR Y=11 TO 6 STEP -1
3090 GO SUB 3150
3100 IF INKEY$<>"" THEN RETURN
3110 PRINT AT Y+10,x;"ПППППППППППППППППППППППППППППППП": REM 32 Space
3120 BEEP .01,20: PAUSE 5
3130 NEXT Y
3140 GO TO 4000
3150 PRINT AT Y,X; INK C;
"AППППППППAAAAППAAAAAAAППAAAAAAAП
AПППППППППAAПППAППППППППAППППППП
AAППППППППAAПППAППППППППAППППППП
AAППППППППAAПППAППППППППAППППППП
AAППППППППAAПППAAAAAППППAAAAAППП
AAППППППППAAПППAAПППППППAAПППППП
AAППППППППAAПППAAПППППППAAПППППП
AAППППППППAAПППAAПППППППAAПППППП
AAAПППППППAAПППAAПППППППAAПППППП
AAAAAAA ППAAAA ППAAПППППППAAAAAAA"
3160 RETURN
4000 LET S$="ProgramППLIFE": LET XN=10: LET YN=1: LET C=4: GO SUB 5000 4010 LET S$="Sankt-Peterburg 1993": LET XN=6: LET YN=3: LET C=6: GO SUB 5000 4020 LET S$="Press any key to continue": LET C=7: LET YN=20: LET XN=4:GO SUB 5000 4030 LET Y=6
4040 LET C=C+1: IF C>7 THEN LET C=1 4050 GO SUB 3150 4060 PAUSE 50
4070 IF INKEY$="" THEN GO TO 4030
4080 RETURN
5000 REM -------------------
5010 LET S=LEN S$ 5020 FOR I=1 TO S 5030 LET L$=S$(I TO I)
5040 PRINT AT YN,XN+I-1; INK C;L$; PAPER 3;" " 5050 BEEP .01,25 5060 NEXT I
5070 PRINT AT YN,XN+S;" " 5080 RETURN
6000 REM ----------1----------
6010 IF xmin>X-1 AND xmin>1 THEN LET xmin=X-1 6020 IF xmax<X+1 AND xmax<30 THEN LET xmax=X+1 6030 IF ymin>Y-1 AND ymin>1 THEN LET ymin=Y-1 6040 IF ymax<Y+1 AND ymax<20 THEN LET ymax=Y+1 6050 RETURN
7000 REM ----- end ------
7010 BORDER 1: PAPER 1: CLS
7020 LET z$="nnnnnnnnnnnnnnn": REM 15 Space
7030 FOR n=9 TO 11
7040 PRINT AT n,8; PAPER 4;z$; PAPER 0;(" " AND n>9) 7050 NEXT n
7060 PRINT AT 12,9; PAPER 0;z$
7070 PRINT AT 10,13; PAPER 8; INK 2;"E N D"
7080 FOR N=-20 TO -30 STEP -1
7090 BEEP .1,N
7100 NEXT N
7110 PAUSE 350
7120 BEEP .06,15
7130 RETURN
Опишем вначале все подпрограммы, каждая из которых соответствует определенному модулю.
1000...1040 - подпрограмма, которую мы назовем CLS. Она устанавливает цвет бордюра, задает атрибуты экрана, очищает его и окрашивает соответствующим цветом;
2000...2080 - подпрограмма GRAPHICS формирует все объекты игры, их требуется всего три. Первый - шарик, использующийся в заставке. Ему соответствует клавиша А в графическом режиме. Второй - голубой квадратик, составляет основу фона, на котором развивается та или иная популяция. В графическом режиме ему соответствует клавиша С. Наконец, третий - рожица красного цвета, имитирующая особь. В графическом режиме ей соответствует клавиша В;
3000...4080 - подпрограмма SCREEN формирует заставку - слово LIFE, перемещающееся по экрану и составленное из больших, переливающихся разными цветами букв;
3150...3160 - подпрограмма печати слова LIFE, которая расположена внутри подпрограммы SCREEN. Так как слово LIFE появляется на экране многократно, а его печать осуществляется в графическом режиме (см. буквы «А» в строке 3150), то вполне естественно, что эта операция выделена в отдельную подпрограмму;
5000...5080 - подпрограмма «печатающий квадрат». Она выводит на экран различные надписи в заставке после того, как слово LIFE займет свое конечное положение посредине экрана;
6000...6050 - подпрограмма MIN/MAX в процессе счета постоянно уточняет границы вновь возникшей колонии. Эта процедура позволяет существенно ускорить работу алгоритма;
7000...7130 - подпрограмма END. Осуществляет печать слова END в рамке, вокруг которой расположена тень, и включает звуковое сопровождение.
Группы операторов, записанные в строках 200...310, 400...520 и 4000...4020, не выделены в подпрограммы потому, что используются только один раз.
Рассмотрим теперь программу в целом и более подробно.
10 - вызов подпрограммы GRAPHICS. Заранее формируются все образы игрового пространства, которые затем по мере надобности будут извлекаться из памяти компьютера;
20 - вызов подпрограммы CLS;
30 - вывод на экран заставки, которая останется на экране до тех пор, пока не будет нажата какая-нибудь клавиша;
50 - очистка экрана;
60, 70 - резервирование памяти под двухмерные символьные массивы. В дальнейшем элементы массивов будут принимать значения «пробел» и «1», причем «пробел» будет означать, что особь в клеточке отсутствует, а «1» - что она здесь имеется. В массиве А$(30,20) будет размещаться исходная популяция, а в В$(30,20) -следующая;
80 - задание номера шага;
90...150 - здесь полагается либо выбрать заданную конфигурацию колонии, либо задать ее самому. Строки 140 и 150 необходимы для мерцания на экране символа ? в конце текста, который выводит на экран 90-я строка программы;
210...270 - в массив А$(30,20) записывается стандартная популяция, которая на экране выглядит, как перевернутая буква «П»;
280, 290 - установка границ всей колонии;
300 - запись в переменную К количества особей;
310 - после выбора стандартной конфигурации осуществляется переход к алгоритму развития популяции;
400... 520 - ввод вашего варианта конфигурации колонии посредством задания общего числа особей и ввода их координат. В строке 480 проводится проверка значения координат, которые не должны выходить за пределы игрового поля. Если хотя бы одна из координат не соответствует заданным условиям, ее ввод требуется повторить;
600 - очистка экрана;
610, 620 - запоминание промежуточных значений границ популяции, так как в процессе развития они меняются;
660...720 - здесь выводится на экран популяция из массива А$(30,20), причем букве С в графическом режиме соответствует голубая клеточка, букве В - особь;
730 - если число особей стало равным нулю (популяция погибла), включается подпрограмма END, после чего осуществляется переход на начало игры;
740...910 - формирование новой популяции в массиве В$(30,20) из старой А$(30,20);
920...960 - массиву А$(30,20) присваивается значение массива В$(30,20), так как на печать выводится только массив А$(30,20) (см. строки 680, 690);
970 - безусловный переход на строку 610, с которой начинается новый цикл размножения особей;
Начиная со строки 1000, следуют семь подпрограмм, о которых мы говорили выше. Поскольку их длины невелики, а с некоторыми текстами мы познакомились ранее, то нет особой необходимости разбирать каждую строку в отдельности. Тем не менее, рекомендуем самостоятельно изучить подпрограмму 3000...4080.