ZX-Ревю 1992 №9-10 1991 г.

Профессиональный подход - универсальное меню. Программа "PRIM".


УНИВЕРСАЛЬНОЕ МЕНЮ

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

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

Итак, предположим, что, загрузив "дебют", Вы исправили строку 3 программы. Теперь она вывела на экран название вашей будушей программы, Вашу фамилию, дату написания, и внизу экрана появилась табличка: "нажмите любую клавишу". Что же дальше?

Как правило, ни одна игра не начинается сразу. Необходимо сначала задать управление, выбрать уровень сложности и т.д. Для этого можно использовать цифровые и буквенные клавиши. Обычно это делается по принципу: 100 INPUT "Введите уровень сложности (1-5) : "; n или так:

100 PRINT "Бесконечные жизни (Y/N)?": PAUSE 0 110 IF INKEY$ "y" OR INKEY$ "Y" THEN ...

Однако наиболее профессиональным является вариант меню. Меню - это перечень возможных вариантов ответа, например:

KEMPSTON

SINCLAIR

PROTEK

CURSOR

KEYBOARD

Здесь каждая строка - это пункт меню. Один из пунктов меню всегда выделен (яркость, цвет, инверсия). При этом переход от одного пункта к другому происходит при нажатии клавишей "ВВЕРХ" или "ВНИЗ", а выбор выделенного пункта осуществляется и клавишами "ENTER" или "0" ("ОГОНЬ"). Таким образом, в различных ситуациях в зависимости от требуемого запроса будет меняться текст меню, а управление будет всегда одинаковым и может осуществляться, например, только курсор джойстиком, то есть без помощи клавиатуры. Я хочу предложить вниманию читателей достаточно отработанный вариант меню, которое применяю в своих программах. Оно хорошо смотрится на экране и легко перенастраивается под разные конкретные варианты. Чтобы пример не был абстрактным, предположим, что мы разрабатываем программу для обучения детей устному счету. В этой программе, (назовем ее "PRIM") компьютер задает примеры на сложение, вычитание и т.д. и контролирует результат игравшего. Кроме того, в игре предусмотрим режим, когда играющий сможет сам задавать примеры компьютеру. При этом компьютер превращается в калькулятор (забегая вперед, скажу, что моя дочь, например, с удовольствием проверяет таким способом домашнее задание). Этот режим делает игру более разнообразной, и к тому же, психологически это как бы ставит компьютер и играющего в равные условия. Зададим еще режим "КОНЕЦ РАБОТЫ", когда компьютер поблагодарит Вас за уделенное ему время.

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

ПРИМЕРЫ ЗАДАЕТ КОМПЬЮТЕР ПРИМЕРЫ ЗАДАЕТ ИГРАЮЩИЙ КОНЕЦ РАБОТЫ

Если Вы выберете первый пункт меню, то будет сделан переход на следующее меню, которое позволит выбрать тип решаемых примеров:

СЛОЖЕНИЕ

СЛОЖЕНИЕ И ВЫЧИТАНИЕ УМНОЖЕНИЕ

УМНОЖЕНИЕ И ДЕЛЕНИЕ ВСЕ ЧЕТЫРЕ ДЕЙСТВИЯ ТАБЛИЦА УМНОЖЕНИЯ КОНЕЦ РАБОТЫ

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

Продолжая придерживаться структуры "дебюта" "PROG", определим для главного меню строки с 200 по 299, а для второго меню - строки с 300 по 399. При этом строки начиная с 30 (до 40), являются подпрограммой, выполняющей действия, непосредственно связанные с работой меню.

Итак, текст программы, затем - дальнейшие комментарии.

4 GO TO 100

30 RANDOMIZE 3: GO SUB 10: BORDER 1: PAPER 7: INK 0: CLS

31 GO SUB 8: FOR M= 1 TO NN: READ M$: PRINT AT ,(Y0+(M-1)*DY),X0;M$: NEXT M: PRINT AT Y1,3;

INK 1; INVERSE 1; "SPACE,DOWN,UP,ENTER,BREAK"

32 IF MM<1 THEN LET MM=NN

33 IF MM>NN THEN LET MM=1

34 PRINT AT (Y0+(MM-1)*DY),X0-DX; PAPER 2; INK 6; BRIGHT 1; OVER 1;S$: BEEP .03,2*MM+10

35 PAUSE 0: LET I=(INKEY$=" " OR INKEY$:"6" OR CODE INKEY$=10)+(INKEY$="7" OR CODE

INKEY$=11)*2*(INKEY$="0" OR CODE INKEY$=12 OR CODE INKEY$=13)*3: GO TO (35+I)

37 PRINT AT (Y0+(MM-1)*DY),X0-DX; OVER 1;S$: LET MM=MM-2*I+3:GO TO 32

38 BEEP .1,36: RETURN 190 LET MM=1

200 RESTORE 200: LET NN=3: LET Y0=8: LET X0 = 4: LET DY=2: LET DX=2: LET S$="

": LET Y1=18: GO SUB 30:GO TO 200+MM*10 210 LET MM= GO TO 300 220 GO TO 8000 230 GO TO 9000

299 DATA "ПРИМЕРЫ ЗАДАЕТ КОМПЬЮТЕР", "ПРИМЕРЫ ЗАДАЕТ ИГРАЮЩИЙ"," КОНЕЦ РАБОТЫ"

300 RESTORE 300: LET NN = 7: LET Y0=7: LET X0 = 6: LET DY=1: LET DX=2: LET S$="

": LET Y1 = 19: GO SUB 30: GO TO 300+MM*10

360 GO TO 1000

370 LET MM=3: GO TO 200

399 DATA "СЛОЖЕНИЕ", "СЛОЖЕНИЕ И ВЫЧИТАНИЕ","УМНОЖЕНИЕ","УМНОЖЕНИЕ И ДЕЛЕНИЕ", "ВСЕ ЧЕТЫРЕ ДЕЙСТВИЯ","ТАБЛИЦА УМНОЖЕНИЯ","КОНЕЦ РАБОТЫ"

Текстовые сообшения в программе напечатаны по-русски. Они будут так выглядеть на Вашем экране, если вы включите русско-латинский символьный набор командой GO SUB 8. Однако следует учесть, что имена переменный вводятся латинскими буквами, для этого надо включить режим CAPS LOCK.

В программе меню используются следующие переменные:

NN - число пунктов в меню.

X0 - левая граница (по горизонтали) текста меню.

Y0 - верхняя граница (по вертикали) текста меню.

DX - отступ выделяющей строки влево по отношению к тексту меню.

DY - шаг строк меню по вертикали.

Y1 - вертикальная координата вспомогательной строки с указанием управляющих клавишей.

MM - указатель меню.

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

Перед тем, как начнется выполнение меню со строки 200 или 300, необходимым предварительным условием является задание указателя меню MM. Это сделано для того, чтобы можно было, обращаясь к меню из разных мест программы, выделять тот пункт, выбор которого в данный момент наиболее вероятен. Это создает повышенное удобство в работе и придает "профессионализм" программе. Поясню это на нашем примере. Так, при старте программы выделяется первый пункт главного меню: "ПРИМЕРЫ ЗАДАЕТ КОМПЬЮТЕР" (в строке 190 задается MM=1) потому, что именно этот режим наиболее вероятен для выбора. Далее, нажав ENTER, мы перейдем ко второму меню. Если теперь выбрать "КОНЕЦ РАБОТЫ", то на экране появится главное меню с выделенным третьим пунктом, а не первый, как было при старте программы. Повторное нажатие ENTER, для подтверждения, и без лишних хлопот для оператора программа завершена. То есть в каждой конкретном случае обрашения к меню, может быть выделен тот пункт, который наиболее вероятно будет выбран оператором, то есть программа отличаясь "деликатностью", как бы "подыгрывает" оператору, облегчая его действия.

Учитывая вышесказанное, процедура вызова меню всегда одинакова и имеет вид:

LET MM=... : GO TO ...

Это, например, строка 210 (вызов второго меню) или 370 (вызов главного меню). Кроме того, это строка 190 (это тоже вызов главного меню; здесь нет необходимости указывать GO TO 200, так как следующей выполняемой строкой и так является строка 200).

Теперь конкретно о главном меню. Строка 200 задает начальные параметры: число пунктов в главном меню NN=3. Левая и верхняя границы текста меню X0 и Y0 - Вы можете подбирать их экспериментально, добиваясь симметричного расположения текста меню на экране. То же относится и к величине DX и количеству пробелов в переменной S$. Что касается параметра DY, то если меню состоит из небольшого количества пунктов (2... 5), то лучше смотрится вариант, когда текст написан через строчку, то есть DY=2. Если число пунктов в меню большое, то строки следуют вплотную друг к другу (DY = 1).

Далее в строке 200 идет выполнение подпрограммы меню: GO SUB 30. Такое выделение процедур выполнения меню в подпрограмму позволяет значительно сэкономить память компьютера в программах, где требуется сложная сеть многоступенчатых, взаимосвязанных между собой меню. Если в вашей программе меню используется только один раз, то, в принципе, можно было бы раскрыть подпрограмму, расположив весь текст меню в строках с 200. Но я не рекомендую это делать, вполне вероятно, что в будущем Вы захотите усовершенствовать программу, введя какие-то дополнительные режимы, для которых потребуются новые меню. Тогда Вы оцените такой подход.

Теперь подробно рассмотрим подпрограмму меню.

Строка 30 задает возврат при ошибке на перезапуск программы сначала при нажатии клавиши BREAK (со строки 3; подробно об этом говорилось в ZX-РЕВЮ). Далее идет задание цветов BORDER, PAPER, INK и очистка экрана.

Строка 31 выводит на экран текст меню, а также вспомогательный текст с указанием управляющих клавишей. При этом команда GO SUB 8 включает русско-латинский символьный набор.

Строки 32 и 33 проверяют указатель меню MM на допустимые пределы и "зацикливает" переход от одного пункта меню к другому, то есть, если нажать клавишу "ВНИЗ", то, дойдя до последнего пункта, при следующем нажатии будет сделан скачок к первому пункту. Аналогично - при движении вверх. Вы можете ликвидировать "зацикливание", сделав замену:

32 IF MM<1 THEN LET MM=1

33 IF MM>MM THEN LET MM=NN

Строка 34 выделяет пункт меню, определенный указателем MM. При этом звуковой сигнал как бы подтверждает этот факт, а тон сигнала ориентировочно указывает на предлагаемый выбор.

Строка 35 - режим ожидания нажатия клавиши. При этом в зависимости от нажатой клавиши меняется параметр I.

I=1, если нажаты клавиши "SPACE" или "6" или "ВНИЗ" (CAPS SHIFT+6)

I=2, если нажаты клавиши "7" Или "ВВЕРХ" (CAPS SHIFT+7)

I=3, если нажаты клавиши "0" или "DELETE" (CAPS SHIFT+0) или "ENTER"

I=0, если нажата любая другая клавиша.

Далее в строке 35 следует переход на строку 35+I. То есть, в последнем случае (I=0), будет сделан переход на эту же строку 35 и ожидание нового нажатия клавиши, в случае I=1 - переход на строку 36, но так как ее нет, то будет сделан переход на ближайшую следующую строку, то есть 37, как и в случае I = 2.

В строке 37 (если I=1 или 2) выделенный пункт меню становится невыделенным, указатель меню MM в зависимости от величины I либо увеличивается на единицу, либо уменьшается на единицу и работа меню повторяется со строки 32, то есть проверка MM на допустимые пределы, выделение нового пункта меню и ожидание нажатия клавиши.

В случае, когда I=3, строка 38 осуществляет выход из меню и действия, связанные с этим, например, звуковой сигнал. Экспериментируя с меню, попробуйте изменить строку 38:

38 FOR M=1 TO NN: PRINT PAPER 8: INK 8. BRIGHT 8; OVER (M=MM);FLASH (M=MM);AT (Y0+(M-1)*DY),X0-DX;S$: NEXT M: PRINT AT Y1, 0;" (32 пробела) ": BEEP

.1,36: PAUSE 10: RETURN

Такой вариант интереснее смотрится на экране. Попробуйте сами придумать какие-нибудь другие варианты.

По команде RETURN в конце строки 38 закончится работа меню (GO SUB 30) и мы возвращаемся на строку 200, где после GO SUB 30 следует переход на строку, номер которой вычисляется выражением 200+MM*10, то есть для трех возможных вариантов главного меню: строки 210,220,230.

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

Второе меню (строки 300...399) полностью идентично первому. Отличие состоит только в числе пунктов, работа его абсолютно такая же, как и главного меню.

Строка 300, в случае нажатия "ENTER" или "0", адресует программу к строкам, начиная с 310 по 370, в зависимости от величины указателя MM. Отсюда уже выполняются переходы на дальнейшие фрагменты программы. Так как строки 310, 320, 330, 340 и 350 -отсутствуют, то в случае MM=1...6 будет переход на строку 360, а отсюда должен быть организован переход на начало основной части программы - запрос уровня сложности игры.

Теперь отдельно обсудим момент, связанный с работой блока кодов "ON ERROR GO TO". Я использую следующий прием. Если в тот момент, когда на экране находится меню, нажать клавишу "BREAK", то программа перезапускается со строки 3 (см. строку 30), выводя на экран вступительную заставку с названием, фамилией и т.д. Почему именно со строки 3 -см. статью о структуре программы и дебюте "PROG". При этом обеспечивается "полухолодный" (или "полугорячий") старт программы, в отличие от полностью "холодного" старта со строки 2, где может быть размещена загрузка каких-либо кодовых кусков, например, скомпилированных кодов мелодии для озвучивания игры, приготовленных при помощи музыкального редактора "WHAM". Это могут быть и какие-нибудь другие усовершенствования, поэтому лучше не занимать строку 2.

Так выглядит работа универсального меню.

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

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

Вообще, я делаю так. Дебют "PROG" набран и хранится отдельно. Начиная воплощать в жизнь какую-то идею, я прежде всего загружаю его. Затем решаю, понадобится ли для этой программы меню. Если понадобится, то догружаю при помощи "MERGE" текст меню, который также набран и хранится отдельно (строки с 30 по 38). При этом вовсе не обязательно определяться с необходимостью меню в начале написания программы. Например вы пишете какую-то простенькую вспомогательную программу для своих целей, и вот, когда задача успешно выполнена, Вы решаете, что хорошо было бы добавить в программу какие-то новые режимы. Вот тут то Вы имеете возможность догрузить меню в вашу программу и с его помощью организовать новые режимы работы. Сами же отдельные фрагменты программы, тоже могут быть набраны и опробованы отдельно, так как для каждого блока программы определяются свои области, которые не должны перекрываться (со строк 1000, 2000 и т.д.). Смысл в том, что придерживаясь идеи "дебюта" и структуры программы, вы в любой момент можете усовершенствовать или видоизменить ее по

Вашему желанию. В этом и заключаются преимущества структурного программирования, о котором уже говорилось на страницах "ZX-РЕВЮ".

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

Наберите для этого простенькую программку: 10 RANDOMIZE 20 LET X=RND*100 30 LET Y=RND*100 40 PLOT X,Y 50 GO TO 20

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

Для того, чтобы задать начальный параметр для функции случайной величины, служит оператор RANDOMIZE n, где n - числовой параметр. Если этот параметр равен нулю (RANDOMIZE 0 или просто RANDOMIZE), то начальный параметром для RND служит значение системной переменной FRAMES - счетчика кадров. Так обеспечивается практически случайное число.

Измените теперь строку 50: 50 GO TO 10

И запустите программу RUN. то, что Вы видите сейчас, вовсе не похоже на дождь. То есть для нормального функционирования RND нельзя включать RANDOMIZE внутрь цикла работы RND. А то как бы все время функция RND запускается заново а первое ее значение совсем не случайно, оно определяется системной переменной FRAMES.

Продолжаем наше исследование. Измените строку 10: 10 RANDOMIZE 13345

(можете подставить любое число) и запустите программу. Теперь вообще нет никакого "дождя", все "капли" попадают в одну и ту же единственную точку на экране. Сейчас мы каждый раз в начале цикла задаем для RND одно и то же число и поэтому каждый раз получаем одинаковый результат. Все эти детали нужны вот для чего. В основе программы "PRIM" лежит использование функции RND для задания примеров ("ПРИМЕРЫ ЗАДАЕТ КОМПЬЮТЕР"). А сплошь и рядом в тексте программы будут встречаться: RANDOMIZE или RANDOMIZE USR ... это вызов SOUND или SOUND 2, подготовка двухбайтных данных для блока кодов "ON ERROR GO ТО", запуск самого этого блока. Естественно, все эти RANDOMIZE попадают внутрь цикла работы RND, нарушая его функционирование.

Измените строку 10: 10 RANDOMIZE USR 124

По адресу 124 в ПЗУ находится команда RET, то есть сразу выполняется возврат, ничего не делая, но имитируется выполнение программы в машинных кодах. Запустите программу. На экране по-прежнему одна единственная точка. Как же выполнить программу в машинных кодах, не прибегая к помощи RANDOMIZE? Это сделать можно, используя вместо RANDOMIZE USR ... другой вариант: 10 LET S=USR 124

Примечание "ИНФОРКОМа"

Возможно использование также RESTORE USR, PRINT USR, PLOT USR и т.д. Кратко принцип формулируется следущим образом: "Если в программе используется генерация случайных чисел, то использовать RANDOMIZE для запуска машинного кода нельзя".

Подробности вы можете посмотреть в нашей новой книге "Элементарная графика". М:."ИНФОРКОМ", 1993, 207 стр. (это первый том готовящегося четырехтомника).

Измените строку 10 и запустите программу. Вот теперь на экране опять "дождь". RND работает правильно.

Кроме того, придется отказаться от услуг RANDOMIZE по превращению чисел в двухбайтную форму. Для этого сделаем новую подпрограмму в строке 15. Число, подлежащее преобразованию в двухбайтную форму обозначим W. Тогда старший (HI) и младший (LO) байты будут вычисляться в строке 15:

15 LET HI=INT (W/256): LET LO=W-HI*256: RETURN: REM 2-BYTE CONVERTER

Учитывая все вышесказанное, начальные служебные строки (с 7-й) будут теперь такими:

7 LET W=PEEK

UDG

8 LET W=PEEK

РУС

9 POKE 25606

10 GO SUB 15

LO: POKE PEEK 23635+256*PEEK 23636+994,HI:

23635+256*РЕЕК 23636+773: GO SUB 15: POKE 23675,LO: POKE 23676,HI: RETURN: REM 23635+256*PEEK 23636-251: GO SUB 15: POKE 23606,LO: POKE 23607,HI: RETURN: REM

0: POKE 23607,60: RETURN: REM ЛАТ POKE PEEK 23635+256*PEEK 23636+993, LET S=USR (PEEK 23635+256*PEEK 23636+941): RETURN

11 LET S = USR (PEEK 23635+256*PEEK 23636+1014): RETURN: REM SODND 1

12 LET S = USR (PEEK 23635+256*PEEK 23636+1046): RETURN: REM SOUND 2 15 см. выше

Для инициирования блока кодов "ON ERROR GO TO" например в строке 30 вместо:

RANDOMIZE 3: GO SUB 10

теперь используется другая конструкция:

LET W=3: GO SUB 10

а в начало строки 10 теперь подставлено GO SUB 15, где число и преобразуется в двухбайтную форму.

Если Вы догружаете программу меню с магнитофона, то не забудьте изменить начало строки 30.

Программа "PRIM"

Теперь, наконец, переходим к тексту остальных строк программы "PRIM". Комментарии - потом.

0 REM коды

3 LET W=3: GO SUB 10: GO SUB 7: GO SUB 8: BORDER 1: PAPER 0: INK 6: BRIGHT 0: CLS : PRINT

BRIGHT 1;AT 2,2: "ПРОГРАММА ДЛЯ ОБУЧЕНИЯ СЧЕТУ": PAPER 2; INK 7; INVERSE 1; AT 7,9: ";AT 8,9; " P R I M ";AT 9,9;" "; PAPER 0: INK 2: INVERSE 0:AT

14,6:"АВТОР: АЛЕКСЕЕВ А.Г."

4 PRINT INK 4: BRIGHT 1; AT 17,12;"01,06,92": BEEP .1,26: BEEP .1,20: GO SUB 20: GO TO 100

5 GO SUB 9: SAVE "PRIM" LINE 2: VERIFY "PRIM"

6 GO TO 5

7

. см. выше 15

20 INPUT ;: PRINT #0; " НАЖМИТЕ ЛЮБУЮ КЛАВИШУ

22 LET W=22: GO SUB 10: PAUSE 0

24 IF INKEY$="q" OR INKEY$="Q" THEN GO TO 9999

26 RETURN

30

. см. текст программы меню 38

40 LET T=0: RETURN

41 LET T=INT (RND*2): RETURN

42 LET T=2: RETURN

43 LET T=INT (RND*2+2): RETURN

44 LET T=INT (RND*4): RETURN

45 LET T=2: RETURN 50 LET W=50: GO SUB 10: INPUT O 52 IF O=0 THEN GO TO 4000 54 PRINT O;

56 LET W=3: GO SUB 10: RETURN

60 PRINT TAB 20; PAPER 2: INK 7; BRIGHT 1; " ОШИБКА 62 GO SUB 12 64 LET E=E+1: LET U=U+1

66 RETURN

70 PRINT TAB 20; PAPER 4; " ВЕРНО ""

72 GO SUB 11

74 LET R=R+1: LET I=I+1

76 RETURN

100 RANDOMIZE

190 LET MM=1 200

. см. текст программы меню 399

1000 BORDER 7: PAPER 7: INK 0; CLS

1010 LET W=1010: GO SUB 10: INPUT "ЗАДАЙТЕ УРОВЕНЬ : "; LINE L$ 1020 IF L$="" OR L$<="0" THEN LET MM=2: GO TO 200 1030 LET L = VAL L$

1040 LET W=3: GO SUB 10: LET N=L: LET R = 0: LET E=0: LET I=1

1050 PRINT AT 11,0;"ДЛЯ ЗАВЕРШЕНИЯ РАБОТЫ ВВЕДИТЕ 0": ВЕЕР .05,32

1100 PRINT AT 19,10; "УРОВЕНЬ ";INT L

1110 LET U=0

1120 FOR C=1 TO 5

1130 LET X=INT (RND*.7*L+.3*L+.5)

1140 LET Y=INT (RND*.7*L+.3*L+.5)

1150 PRINT AT 21,1; I;"."

1160 GO SUB 40+MM-1

1170 GO SUB 2000+100*T

1180 NEXT C

1200 PRINT .....

1210 IF U=0 THEN PRINT AT 17,10:PAPER 6; INK 2; BRIGHT 1; " ОТЛИЧНО ": LET L = L+.2*L"(MM<>6)

1220 IF U=1 THEN PRINT AT 17,10;PAPER 5; INK 1;" ХОРОШО "

1230 IF U>=2 THEN PRINT AT 17,10; PAPER 1; INK 5; BRIGHT 1; " ПЛОХОВАТО ": LET

L=L=.2*L*(MM<>6) 1240 GO TO 1100 2000 LET Z=X+Y

2010 PRINT AT 21,5;X;"+";Y;"="; 2020 GO SUB 50

2030 IF O<>Z THEN GO SUB 60: GO TO 2010 2040 GO TO 70 2100 LET Z=X+Y

2110 PRINT AT 21,5;Z;"-";X;"="; 2120 GO SUB 50

2130 IF O<>Y THEN GO SUB 60: GO TO 2110 2140 GO TO 70 2200 LET Z=X*Y

2210 PRINT AT 21,5;X;"x";Y;"="; 2220 GO SUB 50

2230 IF O<>Z THEN GO SUB 60: GO TO 2210 2240 GO TO 70 2300 LET Z=X*Y

2310 PRINT AT 21,5;Z;":";X;"="; 2320 GO SUB 50

2330 IF O<>Y THEN GO SUB 60: GO TO 2310 2340 GO TO 70

4000 LET W=3: GO SUB 10: BORDER 4: CLS : PRINT AT 1,5;"ТИП ПРИМЕРОВ: "; AT 3,6; 4010 RESTORE 300: FOR A=1 TO MM: READ A$: NEXT A: PRINT A$

4020 PRINT AT 7,5; "НАЧАЛЬНЫЙ УРОВЕНЬ : ";^АТ 9,5;"КОНЕЧНЫЙ УРОВЕНЬ : "; INT L

4030 PRINT AT 14,10; PAPER 4;" ВEPHO "; PAPER 7;" : ";R;AT 15,10; PAPER 2; INK 7; BRIGHT 1;

" ОШИБОК "; PAPER 7; INK 0; BRIGHT 0; " : "; E 4040 BEEP .1,36: BEEP .1,20: PAUSE 0 4050 LET MM=3: GO TO 200

8000 LET W=3: GO SUB 10: BORDER 7: PAPER 7: INK 0: CLS

8010 PRINT AT 11,0;"ДЛЯ ЗАВЕРШЕНИЯ РАБОТЫ ВВЕДИТЕ 0": ВЕЕР .05,32

8020 PRINT AT 21,0;"ВВЕДИТЕ ПРИМЕР ( БЕЗ ЗНАКА = ) :"

8030 LET W=8030: GO SUB 10: INPUT LIKE X$: IF X$="0" THEN LET MM=1: GO TO 200

8040 LET X=VAL X$

8050 PRINT "AT 21,0;X$;" = ";X"'

8060 GO SUB 11: GO TO 8020

9000 LET W=9030: GO SUB 10: BORDER 3: PAPER 7: INK 0: CLS

9010 PRINT AT 11,10: INK 1;"ДО СВИДАНИЯ....... ПРИЯТНО БЫЛО С ВАМИ ПОРАБОТАТЬ!"

9020 ВЕЕР .1,26: ВЕЕР .1,20: PAUSE 0

9030 RANDOMIZE USR 0 9999 BORDER 7: PAPER 7: INK 0: BRIGHT 0: INVERSE 0: POKE 23658,8

Переменные, используемые в программе. L$, L - уровень чисел для счета N - начальный уровень R - счетчик правильных ответов Е - счетчик ошибочных ответов I - порядковый номер примера

U - счетчик ошибочных ответов в "столбике" из пяти примеров

С - параметр цикла, определяющий число примеров в "столбике"

X,Y,Z - операнды для задания примеров

T - тип примера

T=0 - сложение

T=1 - вычитание

T=2 - умножение

T=3 - деление

O - ответ, вводимый играющим.

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

На подпрограммах в строках 40...66 мы остановимся по ходу работы основной части программы. Основная часть - режим задания примеров компьютером - начинается со строки 1000.

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

Если не задавая никакого уровня нажать "ENTER", или задать уровень 0, то произойдет возврат в главное меню с выделением второй строки меню (установка режима задания примеров играющим). Чтобы реализовать возможность простого нажатия ENTER, в строке 1010 вместо INPUT L стоит INPUT LINE L$ и далее в строке 1030 числовой переменной L присваивается значение текстовой переменной L$.

Обратите внимание на применение блока кодов "ON ERROR GO TO". В строке 1010 перед INPUT стоит конструкция LET W=1010: GO SUB 10, которая в случае ошибки при вводе уровня возвратит программу на строку 1010 и повторит ввод. Такая ошибка может произойти в начале строки 1030, если, например, вместо числа, задать букву. Когда опасность такой ошибки миновала, корректно будет возвратить блок "ON ERROR GO TO" в исходное состояние (то есть при ошибке программа перезапускается со строки 3, как мы договаривались выше). Это происходит в строке 1040. Здесь также запоминается начальный уровень для подведения итогов в конце игры, обнуляются счетчики верных и ошибочных ответов, счетчику примеров присваивается номер 1.

Строка 1050 информирует играющего о том, как он может завершить работу программы.

Со строки 1100 начинается следующий этап в работе программы - задание "столбика" из пяти примеров. Вначале выводится текущее значение уровня чисел для счета. Затем в строке 1110 обнуляется счетчик ошибок в одном столбике (U). Затем (в строке 1120) организуется цикл, определяющий пять примеров в "столбике".

В строках 1130 и 1140 задаются значения операндам, участвующим в примерах, при этом числа для счета получаются в диапазоне от 0.3*L до L. Такое ограничение позволяет, если уровень чисел для счета задан, например 100, избежать примеров типа: "1+2=".

Строка 1150 выводит на экран номер решаемого примера.

Подробнее разберемся со строкой 1160. Здесь, в зависимости от того, какой вариант из второго меню был выбран (указатель MM), выполняется соответствующая подпрограмма, задавая тип примера (Т). Если было выбрано только сложение (MM=1), то выполняется GO SUB 40, то есть T становятся равным 0. Если сложение и вычитание (MM=2), то выполняется GO SUB 41, где T может принять одно из двух значение: 0 или 1 и т.д. В зависимости от величины T находится тип конкретного задаваемого примера:

T=0 - сложение

T=1 - вычитание

T=2 - умножение

T=3 - деление

Далее, строка 1170 в зависимости от величины T, вызывает выполнение соответственно одной из четырех подпрограмм из строк 2000, 2100, 2200 или 2300 для каждого типа примеров. Они идентичны, за исключением некоторых деталей. Для того, чтобы при вычитании не получалось отрицательных чисел, а при делении - дробных чисел, используется простой прием. Сначала подсчитывается результат, а пример строится, используя результат, как исходные данные.

Рассмотрим, для примера, подпрограмму со строки 2000. В строке 2000 осуществляется подсчет результата, в 2010 - вывод примера на экран. В следующей строке GO SUB 50 - это ввод играющим ответа и проверка его на ноль для выхода из игры. В этом случае будет переход на строку 4000 (см. строку 52). Так как при работе INPUT опять возможны всякие неприятности, в строке 50 активизируется блок "ON ERROR GO TO", заставляя программу возвращаться на эту строку, на ввод ответа. И опять корректно будет, завершая подпрограмму ввода ответа вернуть блок "ON ERROR GO TO" к переходу по ошибке на строку 3 перед тем, как выполнить RETURN в строке 56. Далее в строке 2030 идет анализ величины ответа, и, если ответ неверный, то выполнение подпрограммы GO SUB 60 -это реакция программы на ошибку и далее, возврат на повторение этого примера еще раз (со строки 2010).

В подпрограмме со строки 60 идет вывод таблички "ОШИБКА", затем звуковой сигнал SOUND 2, а также на единицу увеличивается счетчик ошибок (Е) и счетчик ошибок в этом столбике (U).

Строка 2040 - выполнение подпрограммы при правильном ответе. Вообще-то наверное понятнее в строке 2040 было бы записать:

GO SUB 70: RETURN

То есть выполнение подпрограммы "ВЕРНО", затем возврат в вызывавшую подпрограмму - на строку 1180. Но результат одинаковый. В том варианте, который приведен в листинге, в вызывающую программу (на строку 1180) управление вернет оператор RETURN из строки 76. Подпрограмма со строки 70 - это вывод таблички "ВЕРНО", звуковой сигнал SOUND 1, затем увеличение на единицу счетчика правильных ответов (R) и увеличение на единицу сквозной нумерации примеров (I).

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

Строки 1210, 1220 и 1230 выполняют анализ числа неправильных ответов в одном столбике. Если неправильных ответов нет (строка 1210), то выводится оценка "отлично". Уровень чисел увеличивается на 20 процентов (но только в тех случаях, если не была выбрана таблица умножения, то есть если MM<>6), иначе уровень сложности не

увеличивается.

Если в столбике один неправильный ответ (строка 1220), то выводится сообщение "ХОРОШО", а уровень - не изменяется.

Если в столбике два или более неправильных ответов (строка 1230), то выводится табличка "ПЛОХОВАТО", а уровень чисел понижается на 20 процентов (если только это не режим таблицы умножения).

Когда будете придумывать текст сообщений компьютера оператору, следует воздержаться от резких и категоричных высказываний типа: "ОЧЕНЬ ПЛОХО" или "ВЫ НИЧЕГО НЕ ЗНАЕТЕ". Компьютер должен быть вежлив в общении с оператором, тем более, если оператор - ребенок. Даже если он совсем ничего не знает или невнимателен при вводе ответа, компьютер не ругает его нехорошими словами, а лишь слегка "недоумевает" по поводу неправильного результата. В этом случае у ребенка не возникает раздражения и не "отпадает охота", а появляется желание играть в эту игру и дальше. А ведь как раз это и нужно для того, чтобы развить способности к устному счету.

Кстати, вместо "ПЛОХОВАТО" можно выводить совсем нейтральное: "УПРОСТИМ ЗАДАЧУ".

Далее (строка 1240), работа программы возобновляется со строки 1100, то есть задание нового "столбика" примеров.

Если при выполнении подпрограммы ввода ответа (GO SUB 50) будет принят ноль (строка 52), то управление передается на строку 4000 - это подведение итогов работы, где на экран выводится следующая информация, число решенных примеров, их тип, начальный и конечный уровни решенных примеров, а также число верных и ошибочных ответов. Затем (строка 4050) вызывается главное меню, предлагая завершить программу (выделен третий пункт меню).

Строки с 8000 - эта часть программы выполняет режим калькулятора и может использоваться, например, при проверке учеником домашнего задания. В случае ошибки при вводе ответа, блок "ON ERROR GO TO" вернет программу на ввод примера, на строку 8030.

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

Для того, чтобы в процессе отладки можно было останавливать программу, установлен "жучок" в строке 24, переводящий на строку 9999, которая обеспечит удобные для работы цвета бумаги, чернил и т.д., включение режима курсора [С] и остановку программы с сообщением 0 ОК, так как это последняя строка программы. Практически, для остановки программы надо войти в любое меню, затем нажать BREAK (для перехода в титульную заставку), затем нажать "Q".

Остановку программы можно обеспечить по-другому, например непосредственно из режима меню.

Для этого измените строку 35: 35 PAUSE 0: LET I=(INKEY$=" " OR INKEY$="6" OR CODE INKEY$=10) +(INKEY$="7" OR CODE

INKEY$=11)* 2+(INKEY$="0" OR CODE INKEY$=12 OR CODE INKEY$=13)*3+(INKEY$="q" OR INKEY$="Q")*4: GOTO (35+I)

И добавьте строку 39: 39 GO TO 9999

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

как его развить и использовать дальше - это на Ваше усмотрение.

* * *

В тексте часто упоминаются блоки кодов SOUND 1 и SOUND 2. Они сформированы при помощи программы "SOUND". За основу этой программы была взята программа "SPECSOUND" фирмы "OZ SOFTWARE", которая была "доведена до ума" и переведена на русский язык. Следующая статья будет посвящена этой теме. Я подробно остановлюсь на работе этих блоков кодов, а также предложу читателям программу "SOUND".




СОДЕРЖАНИЕ:


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

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



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

Похожие статьи:
Авторы - авторы газеты.
ZX Ресурсы в Интернете - сайты создателей газеты.
Немного статистики - Итак, подведем некоторые итоги.
Опрос - Нa дaнный мoмент oтветилo всегo семь челoвек ...
Обзор - Первое собрание СисОпов: интервью с McMAKER, Stinger, ARS, Wolfsoft.

В этот день...   29 марта