(c) Аблаев Сергей
г. Екатеринбург, 1996
Пакет процедур для создания системы опроса клавиатуры,
определяющей одновременное нажатие многих клавиш.
Несколько слов о пакете. Главное достоинство программы -
возможность независимого определения нажатия хоть всех сорока
клавиш одновременно. Скорость работы вполне неплохая.
Процедура "DEFINE" сделана для поиска первой попавшейся
клавиши. Это необходимо при выборе клавиш пользователем. К ней
надо обращаться в цикле. При этом, если какая-то клавиша была
нажата, то флаг 'C'=0, и в регистре 'A' находится код нажатой
клавиши. Если флаг 'C'=1 то ни одна клавиша не нажата (в ПЗУ
есть процедура выполняющая аналогичную функцию и можно сэкономить
ОЗУ не используя 'DEFINE', а обращаясь: CALL #028E. Только
нажатие клавиши при этом надо контролировать не по флагу 'C', а
по содержимому регистра 'E' - в нем находится #FF если клавиши не
трогали, иначе там код нажатой клавиши).
ORG 30000 ; Нужный адрес.
DEFINE CALL OPROS ; Заполним буфер информацией
; о клавишах.
LD BC,#0800 ; В 'B' - длина буфера.
LD HL,ADRES ; Адрес буфера.
L3 LD A,(HL)
CP %00011111
JR NZ,L1 ; Если флаг 'Z'=1 то клавиши
; полуряда не нажаты.
INC C ; В 'C' - номер байта в буфере
; (полуряда клавиатуры).
INC HL
DJNZ L3
SCF ; Флаг переноса будет свидетельствовать,
; что ни одна клавиша не нажата.
RET
L1 LD B,0
CALL SLA_A ; Сдвигаем 3 старших бита.
L4 SLA A
JR NC,CONT ; Если флаг 'C'=0, то бит найден.
INC B ; В 'B' - номер клавиши от
; внутреннего края полуряда.
JR L4
CONT LD A,B
CALL SLA_A
XOR C
RET
Эта процедура, собственно, опрашивает клавиатуру и заносит в
буфер информацию о всех клавишах.
OPROS LD D,#08 ; Цикл по 8-ми полурядам.
LD BC,#7FFE
LD HL,ADRES ; Адрес буфера под 8 байт информации.
L11 IN A,(C) ; Опрос полуряда.
AND %00011111 ; Гасим 3 ненужных бита.
LD (HL),A ; Заносим информацию о клавишах
; полуряда в буфер.
INC HL
RRC B ; Переход к следующему полуряду.
DEC D
JR NZ,L11
RET
2 процедуры ('OPROS' и 'FINDKEY') являются основными и
уникальными в данном пакете.
Процедура 'FINDKEY' служит для определения факта нажатия
нужной клавиши. При обращении к ней, в регистра 'А'- код клавиши,
по возвращению из процедуры флаг 'С'=1, если клавиша не
нажата (соответственно, флаг 'С'=0 если клавиша нажата).
Перед использованием 'FINDKEY' необходимо обновлять содержимое
буфера 'CALL OPROS'. НО НЕОБЯЗАТЕЛЬНО(!) делать это каждый раз -
достаточно (и даже желательно) один раз, в общем цикле программы,
выполнить 'CALL OPROS' и потом проверять нажатие любого
количества нужных клавиш ('LD A,"cod_key" и 'CALL FINDKEY' - для
каждой клавиши).
FINDKEY LD HL,ADRES ; В 'HL' - адрес буфера.
LD C,A ; Сохраним код клавиши.
SRL A
SRL A
SRL A
LD B,A ; В 'B' - номер клавиши в полуряду.
LD A,C ; Восстановим код клавиши.
AND #07 ; Выделим номер байта в буфере.
OR A ; Выставим флаги.
JR Z,L12
L22 INC HL ; Переход к следующему байту.
DEC A
JR NZ,L22
L12 LD A,(HL) ; В 'HL' адрес нужного байта буфера.
CALL SLA_A ; Сдвигаем 3 лишних бита (можно 'CALL SLA_A'
; заменить на содержимое 'SLA_A' для
; ускорения если это критично).
INC B
L32 SLA A ; Заносим левый бит во флаг 'C'.
DJNZ L32
RET ; Теперь во флаге 'C' бит нужной клавиши
; при этом если клавиша нажата, то 'C'=0
; и наоборот.
; Т.к. коды выдаваемые 'DEFINE' (их же требует 'FINDKEY')
;являются 'основными' кодами клавиш (от 0 до 40), то для печати
;символа, закрепленного за клавишей (например при определении
;игровых клавиш), надо перевести коды клавиш в коды символов.
; Для этого служит процедура 'MAIN_K'; при обращении к ней в 'A'
;- код клавиши. По возвращению - в 'A' - код символа (заглавной
;буквы или цифры), при этом если в 'A' код спец-клавиши, то
;'MAIN_K' вернет #E3 для 'CAPS', #0E для 'SYMBOL' и #0D для
;'ENTER'.
MAIN_K LD E,A
JP #0347
SLA_A SLA A
SLA A
SLA A
RET
ADRES DEFM '!SERGEY!' ; буфер.
Рекомендация к работе с пакетом: коды клавиш (выбранные
пользователем по 'DEFINE', или закрепленные стационарно
'sinclair' и т.п.) заносятся в системные переменные, откуда и
извлекаются для 'FINDKEY'.
P.S. Я тут открыл то, что многие, возможно,
не знают - при использовании прерываний ('IM 2'), в
программе обработки прерываний НЕ НАДО выполнять 'DI' (запрещение
прерываний)!!! Проведя серию тестов, я установил, что процессор
САМ(!), перед тем, как выполнить переход на адрес, установленный
вектором прерываний, ЗАПРЕЩАЕТ прерывания!
*****************************************************
(C) Лещев Олег, г.Ижевск, 1996
В ZX-Ревю за 1996 год в разделе "Форум" была опубликована просьба помочь
чем-нибудь по игре "LIFE". Я хочу поделиться своими разработками. Года два
назад, когда я еще только начинал изучать ассемблер, я тоже сильно увлекся
этой замечательной математической игрой. Узнал я о ней из книги Мартина
Гарднера "Крестики-Нолики". В нее вошли отдельные главы из других его книг.
Срди них три главы полностью посвящены игре "Жизнь". Меня эта игра очень
заинтриговала и я начал подумывать о ее реализации на компьютере. Опыта у меня
тогда было мало, и я решил, для "разгона", написать программу на Паскале. Это у
меня получилось, но впечатления от работы программы были далеко не лучшие.
Тогда у меня был компьютер местного производства - "Компаньон" и турбо-режима,
естественно, не было, да и вряд ли он помог бы. Я понимал, что ничего хорошего
из реализации игры с маленьким полем не выйдет (ничего интересного не
получится), и на Паскале я сделал версию с полем 86x50, что объясняется
графическими и ресурсными особенностями Спектрума (одна клетка - 3x3 пиксела:
2x2 -цвета INK и остается расстояние между клетками в один пиксел, чтобы на
экране клетки не "слипались". В принципе, на экране по вертикали умещается до
58 клеток, но компилятору не хватило памяти).
В первой версии этой программы я использовал
самый простой алгоритм: сканирование пространства вокруг абсолютно всех ячеек
массива (игрового поля). Скорость была ужасная. Немножко подумав, я нашел
более умный алгоритм. Скорость обработки одного поколения возросла в десятки
раз и некоторое время меня удовлетворяла. Но когда я приобрел кое-какой опыт
в программироваии на ассемблере, я решил написать аналог на ассемблере. В этом
деле мне весьма помог отладчик "MON2" и, в конце концов, программа заработала.
Итак, об алгоритме. Его идея заключается в том, чтобы сканировать соседей
не у всех возможных ячеек, а только у активных (живых) клеток. Для реализации
такого алгоритма необходимо завести три двумерных массива, размер которых
зависит от величины требуемого игрового поля. Каждый элемент этих массивов
будет использоваться в качестве основного - именно в нем находится информация
о текущем поколении. Второй и третий массивы - вспомогательные.
Итак, вся обработка поколения заключается в поиске активных элементов
первого массива (т.е. игрового поля). Когда программа натыкается на активный
элемент, она подсчитывает количество его активных соседей. Сделав это, она
делает вывод о жизнеспособности этой клетки. Эту информацию сразу использовать
нельзя, т.к. это повлияет на дальнейшую обработку, а, по правилам игры "Жизнь",
все изменения происходят в один и тот же момент. Поэтому свои выводы программа
не "воплощает в жизнь", а помечает соответствующие ячейки второго массива.
Если в следующем поколении ячейка изменит свой статус (исчезнет или
появится), то это отмечается во втором вспомогательном массиве (в принципе,
можно там формировать следующее поколение, но затраты времени будут примерно
такие же, и здесь можно поступать кому как нравится). После этого
организовывается новое сканирование соседних ячеек, теперь уже в поисках
выключенных ячеек. У таких ячеек, опять же, подсчитывается число соседей, из
которого делается вывод о том, появится ли на их месте живая клетка в следующем
поколении. Если да, то включаем соответствующую ячейку во втором вспомогательном
массиве. Для того, чтобы не тратить драгоценное процессорное время на повторное
изучение некоторых неактивных клеток (такая ситуация будет появляться довольно
часто и может значительно повлиять на время работы программы), используется
третий вспомогательный массив. После проверки каждой неактивной ячейки в третьем
вспомогательном массиве, включается соответствующий элемент. Перед обработкой
очередной неактивной ячейки программа ищет подтверждение на это в третьем
массиве. Если соответствующий элемент там включен, программа пропускает эту
ячейку.
В заключение, после обработки всего поля, начинается его переработка в
соответствии с подготовленными данными, во время которой массив поля
окончательно преобразовывается к следующему поколению, а экран обновляется.
Вот, в общем, и весь алгоритм. Несколько слов об ассемблерной реализации.
Программа, в общем-то, нехитрая, но для оптимизации ее использована маленькая
хитрость: при подсчете соседей активной ячейки, "по пути" обрабатываются
неактивные. Все три массива расположены в одной области памяти. В каждом байте
этой области используются первые три бита. Нулевые биты используются в
качестве первого массива, первые - в качестве второго и вторые - в качестве
третьего. Как видно, пять битов пропадают зря, но если использовать все восемь
битов, то затраты машинного времени, использованного для расчета адреса и
номера бита какого-то элемента массива, вряд ли окупатся экономией памяти. К
тому же, хороший программист вполне может найти какое-то другое применение
этим битам (например, там можно запоминать предыдущие поколения).
Теперь о том, как решается проблема ограниченности игрового пространства.
Для того, чтобы при достижении края поля колонии жизни не уничтожались, я
применил, так называемые, "прозрачные края". Эта идея заключается в том, что
при попытке программы получить информацию о ячейке, находящейся за краем поля,
она получает информацию о соответствующей ячейке с противоположного края поля.
Достигается это благодаря дополнительным полям, прикрепляемым к основному полю
сверху, снизу, справа и слева. Перед началом обработки очередного поколения в
эти поля копируется информация с противоположных сторон поля. Эти поля
представляют собой просто дополнительные ячейки, являющиеся соседями крайних
ячеек видимого (основного) поля. По причинам, о которых будет сказано ниже,
ширина такого дополнительного поля с каждой стороны основного поля равна двум
ячейкам. Таким образом, если планируется видимое поле сделать размером X x Y,
то реальный размер (размер в памяти), необходимый для нормальной работы, будет
X+4 x Y+4. При этом в обмене между противоположными сторонами будут
участвовать самые крайние клетки видимого поля и первый "слой" дополнительного
поля. Как видно, при этом часть памяти не используется, но это сделано для
того, чтобы при обработке невидимых активных ячеек не запортилась информация,
находящаяся за границами адресного пространства, выделенного под массив. Итак,
в программе обеспечена замкнутость игрового пространства. Теперь не будет
внезапных искажений популяции "жизни" при ее приближении к краю поля.
Теперь рассмотрим программу, реализующую вышеизложенное. Она включает в
себя четыре программы, используемые как друг другом, так и
программой-редактором популяций. Это подпрограмма рисования поля, подпрограмма
очистки поля, подпрограмма рисования активной ячейки с заданными координатами
и, конечно, программа обработки очередного поколения.
10 FIELD EQU 36000 ;адрес начала массивс поля в памяти
20 COUNT EQU FIELD-2 ;адрес счетчика активных ячеек
30 XSIZE EQU 85 ;видимый размер по горизонтали
40 YSIZE EQU 58 ;видимый размер по вертикали
50 XREAL EQU XSIZE+4 ;реальный размер по горизонтали
60 YREAL EQU YSIZE+4 ;реальный размер по вертикали
70 CORNER EQU FIELD+(2*XREAL)+2 ;адрес левого верхнего угла
видимого поля
80 ORG 44500
90 Life JP START ;вызов процедуры обработки очередного
поколения
100 InvCll JP PNTBAS ;вызов процедуры инвертирования
ячейки с заданными координатами
110 Clear JP CLEAR ;вызов процедуры очистки поля
120 DrawSc JP DRAWSC ;вызов процедуры рисования поля
130 START DI
140 MOVING LD HL,CORNER
150 LD DE,XSIZE
160 LD B,YSIZE
170 LEFRIG LD A,(HL)
180 ADD HL,DE
190 LD (HL),A
200 DEC HL
210 LD A,(HL)
220 AND A
230 SBC HL,DE
240 LD (HL),A
250 ADD HL,DE
260 LD A,B
270 LD BC,5
280 ADD HL,BC
290 LD B,A
300 ENDIR DJNZ LEFRIG
310 LD HL,FIELD+XREAL+(XREAL*YSIZE)
320 LD DE,FIELD+XREAL
330 LD BC,XREAL
340 LDIR
350 LD HL,FIELD+(2*XREAL)
360 LD DE,FIELD+(2*XREAL)+(XREAL*YSIZE)
370 LD BC,XREAL
380 LDIR
390 MAINIP LD HL,FIELD+XREAL+1
400 LD B,YSIZE+2
410 GLOBY LD C,B
420 LD B,XSIZE+2
430 GLOBX LD A,(HL)
440 RRCA
450 JR NC,NXTPOS
460 LD DE,XREAL+1
470 AND A
480 SBC HL,DE
490 LD E,0
500 PUSH BC
510 LD B,3
520 MSCANY LD C,B
530 LD B,3
540 MSCANX LD A,(HL)
550 RRCA
560 JR NC,EMPTY
570 INC E
580 JR NEXT
590 EMPTY RRCA
600 RRCA
610 JR C,NEXT
620 LD A,E
630 LD DE,XREAL+1
640 AND A
650 SBC HL,DE
660 LD E,A
670 PUSH BC
680 LD B,3
690 INSCNY LD C,B
700 LD B,3
710 INSCNX LD A,(HL)
720 RRCA
730 JR NC,NOINC
740 INC D
750 NOINC INC HL
760 DJNZ INSCNX
770 PUSH DE
780 LD DE,XREAL-3
790 ADD HL,DE
800 POP DE
810 LD B,C
820 DJNZ INSCNY
830 PUSH DE
840 LD DE,2*XREAL-1
850 AND A
860 SBC HL,DE
870 POP DE
880 LD A,D
890 SUB 3
900 JR NZ,NORES
910 LD A,6
920 JR DONE
930 NORES LD A,4
940 DONE LD (HL),A
950 POP BC
960 NEXT INC HL
970 DJNZ MSCANX
980 LD A,E
990 LD DE,XREAL-3
1000 ADD HL,DE
1010 LD E,A
1020 LD B,C
1030 DJNZ MSCANY
1040 POP BC
1050 LD A,E
1060 LD DE,2*XREAL-1
1070 AND A
1080 SBC HL,DE
1090 CP 3
1100 JR Z,NXTPOS
1110 CP 4
1120 JR Z,NXTPOS
1130 LD A,3
1140 LD (HL),A
1150 NXTPOS INC HL
1160 DJNZ GLOBX
1170 LD B,C
1180 INC HL
1190 INC HL
1200 DJNZ GLOBY
1210 REWORK LD BC,#7FFD ---¬
1220 LD A,#17 ¦
1230 OUT (C),A ¦
1240 LD HL,16384 ¦
1250 LD DE,49152 +-- только для 128 Кб
1260 LD BC,6912 ¦
1270 LDIR ¦
1280 LD A,#18 ¦
1290 LD BC,#7FFD ¦
1300 OUT (C),A ----
1310 LD HL,CORNER
1320 LD B,YSIZE
1330 RWRKY LD C,B
1340 LD B,XSIZE
1350 RWRKX LD A,(HL)
1360 RRCA
1370 RRCA
1380 JR C,INVERT
1390 RLCA
1400 RLCA
1410 LD A,0
1420 RLA
1430 JR NOINV
1440 INVERT RLCA
1450 RLCA
1460 LD D,H
1470 LD E,L
1480 LD HL,(COUNT)
1490 JR C,DECR
1500 INC HL
1510 LD A,1
1520 JR CONT
1530 DECR DEC HL
1540 XOR A
1550 CONT LD (COUNT),HL
1560 LD H,D
1570 LD L,E
1580 LD (HL),A
1590 LD A,XSIZE
1600 SUB B
1610 LD D,A
1620 LD A,YSIZE
1630 SUB C
1640 LD E,A
1650 CALL POINT
1660 JR NXTPNT
1670 NOINV LD (HL),A
1680 NXTPNT INC HL
1690 DJNZ RWRKX
1700 LD DE,4
1710 LD B,C
1720 ADD HL,DE
1730 DJNZ RWRKY
1740 LD BC,#7FFD --¬
1750 LD A,#10 +- только для 128 Кб
1760 OUT (C),A ---
1770 EI
1780 ENDWRK RET
1790 DRAWSC DI
1800 LD HL,CORNER
1810 LD B,YSIZE
1820 DRWY LD C,B
1830 LD B,XSIZE
1840 DRWX LD A,(HL)
1850 RRCA
1860 JR NC,NXTDRW
1870 LD A,XSIZE
1880 SUB B
1890 LD D,A
1900 LD A,YSIZE
1910 SUB C
1920 LD E,A
1930 CALL POINT
1940 NXTDRW INC HL
1950 DJNZ DRWX
1960 LD DE,4
1970 LD B,C
1980 ADD HL,DE
1990 DJNZ DRWY
2000 EI
2010 ENDDRW RET
2020 PNTBAS LD HL,(23563)
2030 LD BC,4
2040 ADD HL,BC
2050 LD D,(HL)
2060 LD C,8
2070 ADD HL,BC
2080 LD E,(HL)
2090 POINT PUSH HL
2100 PUSH BC
2110 PUSH DE
2120 LD A,D
2130 ADD A,D
2140 ADD A,D
2150 LD D,A
2160 LD A,E
2170 ADD A,E
2180 ADD A,E
2190 LD E,A
2200 INC D
2210 INC E
2220 CALL PLOT
2230 INC D
2240 CALL PLOT
2250 INC E
2260 CALL PLOT
2270 DEC D
2280 CALL PLOT
2290 POP DE
2300 POP BC
2310 POP HL
2320 ENDPNT RET
2330 PLOT LD A,E
2340 AND A
2350 RRA
2360 SCF
2370 RRA
2380 AND A
2390 RRA
2400 XOR E
2410 AND #F8
2420 XOR E
2430 LD H,A
2440 LD A,D
2450 RLCA
2460 RLCA
2470 RLCA
2480 XOR E
2490 AND #C7
2500 XOR E
2510 RLCA
2520 RLCA
2530 LD L,A
2540 LD A,D
2550 AND #07
2560 LD B,A
2570 INC B
2580 LD A,#01
2590 LOOP RRCA
2600 DJNZ LOOP
2610 LD B,A
2620 LD A,(HL)
2630 XOR B
2640 LD (HL),A
2650 ENDPLT RET
2660 CLEAR LD HL,COUNT
2670 LD DE,COUNT+1
2680 LD BC,XREAL+YREAL
2690 XOR A
2700 LD (HL),A
2710 LDIR
2720 ENDCLR RET
В этом тексте программа представлена так, чтобы для изменения размеров
массива надо только перекомпилировать программу, изменив лишь значения XSIZE и
YSIZE в начале текста (для задания новых размеров поля), и процедуру POINT,
уменьшив или увеличив размер точки, представляющей активную ячейку на экране.
После такой перекомпиляции надо изменить программу-редактор, чтобы она
работала с новыми размерами. Если кто-нибудь захочет что-нибудь
усовершенствовать в программе, что наверняка повлечет за собой изменение ее
размеров, это не повлияет на работу редактора, пользующегося некоторыми
подпрограммами, находящимися в этой программе, так как в начале программы
расположены универсальные точки входа в подпрограммы, используемые редактором.
Эти точки имеют следующие метки:
Life - обработка текущего поколения
InvCll - инвертирование ячейки с заданными координатами
(только на экране).
Вызывается из редактора следующим образом:
DEF FN p (x,y) = USR InvCll
Clear - очистка поля в памяти
DrawSc - рисование всего поля на экране.
В программе реализован счетчик активных ячеек с адресом (FIELD-2). Он
обновляется при каждом акте "смерти" или "рождения" ячеек, поэтому его
изменение всегда равно изменению количества активных ячеек (таким образом,
если перед вызовом программы-обработчика в счетчике верное значение, то после
ее работы там также будет то количество, что и есть на самом деле). Не надо
забывать отслеживать в счетчике количество активных ячеек во время
редактирования поля.
Еще одна проблема, возникающая в процессе использования программы,
заключается в медленной переработке изображения на экране. Это незаметно при
не очень большом количестве изменений на экране, но если популяция на экране
довольно большая, то заметно, что изменение изображения проходит не
одновременно на всем поле, а сверху вниз. Эту проблему я решил для машин
128 Кб, используя второй экран. Перед изменением изображения текущий экран
копируется в седьмую страницу памяти (во второй экран), и происходит
переключение на второй экран. Затем, после окончания изменения, программа
переключается обратно на первый экран, и изменение картинки на мониторе
происходит почти мгновенно. Если у Вас не 128 Кб, надо удалить строки,
отмеченные в программе для использования на этих компьютерах.
Как уже говорилось, изменение размеров поля не представляет особого труда
(для достижения этого потребовалось немало арифметических вычислений во время
компиляции. Все эти вычисления прекрасно "перевариваются" ассемблером TASM 3.1
и 2.0. Если ассемблер не захочет воспринимать эти выражения, то их необходимо
вычислить вручную). Для примера переделаем программу на размер поля 127 x 87.
Для этого надо изменить значения XSIZE с 85 на 127, а YSIZE - с 58 на 87;
теперь точек на экране будет больше, поэтому надо изменить процедуру рисования
точки: убрать строки 2140 и 2180. В результате для получения экранных
координат точки, координаты точки в памяти будут умножаться не не три, а на
два, в результате точек на экране уместится как раз столько, сколько надо,
т.е. 127 x 87 (те, кому не нравится, что теперь точки "слипаются", могут
оставить в программе только один вызов подпрограммы PLOT, а остальные три
убрать. При этом на каждую клетку уходят все те же 2x2 точки, но между точками
остается зазор). Конечно, не надо забывать об изменении адреса начала поля в
памяти, т.к. этот массив может запортить программу, а также о переделке
редактора в соответствии с новыми размерами поля.
Так как программа составлена достаточно просто, то ее нет смысла
комментировать, чтобы начинающие сами разобрались как она работает. А теперь
значения некоторых фрагментов программы:
1. С метки MOVING до метки MAINLP реализован обмен информацией между
противоположными краями поля.
С метки MOVING до метки ENDLR - между правым и левым краями;
с метки ENDLR до метки MAINLP - между верхним и нижним.
2. С метки MAINLP до метки REWORK происходит обработка основного поля с
подготовкой информации в первых битах об изменении поля к следующему
поколению.
3. С метки REWORK до метки ENDWRK - изменение к следующему поколению с
помощью предыдущего фрагмента. Заодно обновляется экран и счетчик
активных ячеек.
4. С метки DRAWSC до метки ENDDRW расположена процедура рисования поля на
экране.
5. С метки POINT до метки ENDPNT расположена подпрограмма изображения на
экране активной ячейки, причем перед ее вызовом надо в регистр D
поместить координату x, а в E - y этой ячейки.
Точка входа POINT используется программами REWORK и DRAWSC.
Точка входа PNTBAS может использоваться из BASIC'а вызовом DEF FN.
6. С метки CLEAR до метки ENDCLR находится подпрограмма очистки поля со
счетчиком.
Также предлагаю редактор на бейсике. Он использует следующие клавиши:
S - вверх, X - вниз, O - влево. P - вправо, C - очистка, A - обнуление
счетчика поколений, Q - для выхода в режим развития популяции. В этом режиме
работают две клавиши: Space для временной задержки и Q для выхода в редактор.
Внизу экрана при развитии находятся две строки:
Generation - номер текущего поколения относительно начальной
конфигурации
Population - количество активных ячеек.
Редактор после набора необходимо сохранить командой SAVE "LIFE" LINE 9998.
В строке 9998 необходимо указать имя кодового файла.
1 DEF FN p(x,y)=USR 44503: DEF FN n()=PEEK 35998+256*PEEK 35999
2 PAPER 1: BORDER 1: INK 7: CLS
3 LET g=0: LET adr=36180: LET x=0: LET y=0: LET count=FN n()
5 CLS
7 RANDOMIZE USR 44509
10 OVER 1: PLOT 0,1: DRAW 255,0: DRAW 0,174: DRAW -255,0: DRAW 0,-173
20 LET count=FN n(): GO SUB 500
30 PAUSE 0: LET a$=INKEY$
32 IF a$="c" OR a$="C" THEN RANDOMIZE USR 44506: LET count=0: LET g=0: GO TO 5
35 IF a$="q" OR a$="Q" THEN GO TO 1000
40 IF a$=" " THEN GO SUB 600: GO TO 30
43 IF a$="a" OR a$="A" THEN LET g=0: BEEP .1,30
45 GO SUB 500
50 LET x=x+(a$="p")-(a$="o"): LET adr=adr+(a$="p")-(a$="o")
60 LET y=y+(a$="x")-(a$="s"): LET adr=adr+(a$="x")*89-(a$="s")*89
70 IF x=-1 THEN LET x=84: LET adr=adr+85
80 IF x=85 THEN LET x=0: LET adr=adr-85
90 IF y=-1 THEN LET y=57: LET adr=adr+5162
100 IF y=58 THEN LET y=0: LET adr=adr-5162
110 GO TO 20
500 PLOT x*3,175-y*3: DRAW 3,0: DRAW 0,-3: DRAW -3,0: DRAW 0,2: RETURN
600 IF PEEK adr=0 THEN POKE adr,1: LET count=count+1: GO SUB 2000: GO TO 620
610 IF PEEK adr=1 THEN POKE adr,0: LET count=count-1: GO SUB 2000
620 RANDOMIZE FN p(x,y)
630 RETURN
1010 GO SUB 500: BEEP .5,30
1030 PRINT #0;AT 0,0;"Generation: ";g'"Population: ";FN n();" ": IF INKEY$="q" OR INKEY$="Q" THEN BEEP .5,30: PRINT #0;AT 0,0;" ": GO TO 20
1035 IF INKEY$=" " THEN GO TO 1035
1040 RANDOMIZE USR 44500: LET g=g+1: BEEP .001,30: GO TO 1030
2000 LET hi=INT (count/256): POKE 35999,hi
2010 LET lo=count-256*hi: POKE 35998,lo
2020 RETURN
9998 RANDOMIZE USR 15619: REM : LOAD "LIFE1C"CODE
9999 RANDOMIZE USR 44506: LET count=0: GO SUB 2000: GO TO 1
Далее приводим кодовый блок "Жизни":
ADD4: C3 E0 AD C3 19 AF C3 6B :8A
ADDC: AF C3 F5 AE F3 21 54 8D :93
ADE4: 11 55 00 06 3A 7E 19 77 :45
ADEC: 2B 7E A7 ED 52 77 19 78 :30
ADF4: 01 05 00 09 47 10 EE 21 :16
ADFC: 23 A1 11 F9 8C 01 59 00 :5D
AE04: ED B0 21 52 8D 11 7C A1 :7D
AE0C: 01 59 00 ED B0 21 FA 8C :58
AE14: 06 3C 48 06 57 7E 0F 30 :66
AE1C: 6C 11 5A 00 A7 ED 52 1E :A5
AE24: 00 C5 06 03 48 06 03 7E :6F
AE2C: 0F 30 03 1C 18 38 0F 0F :A6
AE34: 38 34 7B 11 5A 00 A7 ED :C8
AE3C: 52 5F C5 06 03 48 06 03 :BA
AE44: 7E 0F 30 01 14 23 10 F8 :EF
AE4C: D5 11 56 00 19 D1 41 10 :71
AE54: EC D5 11 B1 00 A7 ED 52 :6B
AE5C: D1 7A D6 03 20 04 3E 06 :96
AE64: 18 02 3E 04 77 C1 23 10 :D9
AE6C: BE 7B 11 56 00 19 5F 41 :73
AE74: 10 B2 C1 7B 11 B1 00 A7 :89
AE7C: ED 52 FE 03 28 07 FE 04 :9B
AE84: 28 03 3E 03 77 23 10 8D :D5
AE8C: 41 23 23 10 85 01 FD 7F :D3
AE94: 3E 17 ED 79 21 00 40 11 :6F
AE9C: 00 C0 01 00 1B ED B0 3E :01
AEA4: 18 01 FD 7F ED 79 21 54 :C2
AEAC: 8D 06 3A 48 06 55 7E 0F :57
AEB4: 0F 38 07 07 07 3E 00 17 :13
AEBC: 18 23 07 07 54 5D 2A 9E :2C
AEC4: 8C 38 05 23 3E 01 18 02 :B7
AECC: 2B AF 22 9E 8C 62 6B 77 :E4
AED4: 3E 55 90 57 3E 3A 91 5F :64
AEDC: CD 25 AF 18 01 77 23 10 :EE
AEE4: CD 11 04 00 41 19 10 C3 :A1
AEEC: 01 FD 7F 3E 10 ED 79 FB :C6
AEF4: C9 F3 21 54 8D 06 3A 48 :E8
AEFC: 06 55 7E 0F 30 0B 3E 55 :60
AF04: 90 57 3E 3A 91 5F CD 25 :F4
AF0C: AF 23 10 EE 11 04 00 41 :E1
AF14: 19 10 E4 FB C9 2A 0B 5C :25
AF1C: 01 04 00 09 56 0E 08 09 :4E
AF24: 5E E5 C5 D5 7A 82 82 57 :85
AF2C: 7B 83 83 5F 14 1C CD 45 :FD
AF34: AF 14 CD 45 AF 1C CD 45 :95
AF3C: AF 15 CD 45 AF D1 C1 E1 :E3
AF44: C9 7B A7 1F 37 1F A7 1F :19
AF4C: AB E6 F8 AB 67 7A 07 07 :1E
AF54: 07 AB E6 C7 AB 07 07 6F :8A
AF5C: 7A E6 07 47 04 3E 01 0F :0B
AF64: 10 FD 47 7E A8 77 C9 21 :EE
AF6C: 9E 8C 11 9F 8C 01 97 00 :19
AF74: AF 77 ED B0 C9 00 00 00 :AF
*****************************************************************
ИФК: На вопрос по игре *JUNGLE WARRIOR отвечает Федор Пашнин из
г.Копейск Челябинской обл.
Корр: В ZX РЕВЮ был напечатан вопрос, можно ли ухватиться за
воздушный шарик, вылетающий из воды. Отвечаю: можно. Только нужно
очень точно прыгнуть, так, чтобы руками уцепиться за кольцо (оно висит
на веревочке, привязанной к шарику).
*********************************
ИФК: Совет по игре *BURATINO дает Алесандр Бухалов из г.Тобольск
Тюменской обл.
Корр: Когда Вы получите у черепахи Тортиллы ключ, за Вами начнут
гоняться полицейские. В одном экране они будут появляться слева, в
другом справа и т.д. Вся проблема заключается в том, что в безопасный
город они Вас не пустят, появляясь всегда с той стороны, где находится
вход. Как же пройти игру? Запомните то место, где лежала конфета
(которую Вы отдали Мальвине). По ходу игры там тупик, но когда у Вас
ключ, в этом месте открывается проход в город, к победе.
*********************************
ИФК: Владимир Зайцев из Харькова отвечает на вопросы читателей:
Корр: *MEGA BUCKS я прошел полностью, но отвечаю лишь на
конкретные вопросы Алексея Новикова.
1. Принесите венок на кладбище, возложите на могилу,и зажгутся
свечи.
2. Чтобы пройти робота в склепе, необходимо добыть ROBOT CONTROL
в подвале (от телефона в подвале направо). Для этого необходимо,
спустившись вниз, надеть резиновые сапоги, защищающие Вас от удара
током, нацепить на нос прищепку, чтобы не досаждало зловоние тухлой
рыбы, подойти с ломиком к ящику. Поесть, дабы иметь максимальную
энергию и взломать ящик. Взять динамит, взорвать им стенку (дальше в
подвале). За стенкой - тот самый ROBOT CONTROL. Маленький нюанс: Вы не
сможете взять этот предмет, находясь непосредственно на нем.
Покрутитесь влево-вправо и найдите верную точку.
*********************************
Корр: Относительно *STREAKER.
Все лучи (BEAM), кроме зеленого, перебрасывают туда, где
находится соответствующего цвета POD. Если дверь закрыта, то при
использовании BEAM пополняется энергия. Лучи переносят: сиреневый - в
подвал (где супермаркет), голубой - в трактир (PUBLIC HOUM), красный -
в гостиницу (HOTEL), которая никогда не закрывается. Зеленый BEAM -
особый. Он всегда наполняет энергией, но, если на Вас, вместо
полотенца, надеты трусы и майка, то Вас переместит в TRAVEL CENTER.
В бюро путешествий ничего нет, кроме входа на LAUNCH PAD,
конечную цель игры, потому что там находится ракета.
Чтобы появились предметы, которых вначале нет, надо дать каждому
вору по три любимых им предмета. В число этих предметов не входит вся
снедь, молоток (при помощи которого можно съесть орехи), открывалка
банок (чтобы есть бобы или суп в банке), одежда и часы.
Легко выяснить первый любимый предмет: увидев его у Вас в руках,
вор скажет "дай" (в меню появится GIVE и TAKE). Легко выяснить и
второй любимый предмет - если Вы дадите его вору, он перестанет Вас
раздевать и обижать. С третьим предметом сложнее - здесь поможет "опыт,
сын ошибок трудных, и гений, парадоксов друг": если вор получил
желанный предмет, а Вы сбегали в travel centre. Вернитесь теперь
обратно и обследуйте любимые места, посещаемые этим вором - там должен
появится новый вожделенный предмет.
Если Вам интересно самому подобрать предметы, пропустите
следующий абзац. Проще всего угодить Abuer, ведь осмотрев его, мы
получим совершено четкие подсказки - он играл в бейсбол и очень боится
темноты. Следовательно, увидев у Вас в руках фонарик (torch), он
попросит его, а если отдать ему еще и лампу, он перестанет Вас
обижать. Очевиден третий любимый предмет - бейсбольный мяч.
Ladon - яблоко глиняное, лук и, т.к. он следит за посетителями,
то камера.
Cyklop - монокль, телескоп, и, поскольку он игрок, а все игроки
суеверны - подкову на удачу.
Golem - робот, чип, и машинка для подготовки научных трудов.
Jasper - сундук, замок и веревка для упаковки вещей в гостиничной
лавке.
Faust - башмак, шляпа и, как фокуснику, гусиное яйцо, чтобы он
вынимал его из шляпы.
Как видите, не так уж и трудно определить любимые каждым вором
предметы. Но если долго возиться, перебирая варианты с третьим
подарком, то воры начинают красть появившиеся предметы, и процесс
затягивается. Впрочем, из появившихся предметов нам нужна только одежда.
В трактире мы находим белые штаны. Взяв красный ключ в
супермаркете, открываем красную дверь в гостинице и находим рубашку.
Надев штаны и рубашку, приобретаем приличный вид, позволяющий нам
попасть во все комнаты, кроме TRAVEL CENTRE.
Как только Вы оделись, надо тут же рвануть в казино, где
находится белый смокинг (при необходимости, используйте часы). Такая
поспешность нужна, чтобы воры случайно не забрали смокинг. Надев его,
становимся личностью, достойной путешествовать по миру, а потому, идем
в TRAVEL CENTRE, идем в LAUCH PAD и уезжаем.
Предметы, которые появляются: золотой ключ в спортзале, белые
штаны в трактире, красный ключ в супермаркете, меч в кафе, рубашка за
красной дверью в гостинице. В лабораторию можно попасть, отперев дверь
белым ключом, но в ней нет ничего полезного для нас.
Если Вы начнете испытывать голод, то достаточно съесть что-нибудь
съедобное, и силы восстанавливаются. Если у Вас недостаток сна, то
надо пойти в свою спальню (открыть дверь синим ключом). В меню
появится пункт GO SLEEP. Можно спать, поставив "будильник".
*********************************
ИФК: Сергей Машков из г.Тамбов вносит дополнение к описанию игры
*STALINGRAD.
Корр: Как известно, в начале игры в Вашем распоряжении шесть
армий. Есть еще седьмая армия, но, чтобы ее получить, надо обойти
черное море одной из дивизий и дать команду напасть на Керчь. На самом
деле в Керчь Вы не попадете, так как Вам мешает пролив, но, простояв
1-2 хода на месте, а затем отведя свою армию (дивизию) назад, Вы
получите еще одну, дополнительную, армию. Это облегчит Вам игру.
*********************************
ИФК: Наш корреспондент из Черкесска, Олег Бобрышев, прислал
советы по некоторым играм:
Корр: *MUGSY. Ни в одном известном мне источнике не упоминается,
что когда за Вами посылают убийцу, можно отбиваться. Управление, как в
FORMULA ONE MANAGER - Q, Z, I, P, N.
*********************************
Корр: Кстати, о *FORMULA ONE MANAGER. Если на трассе шесть или
меньше машин, то ни одна из них не разобьется.
Небольшое замечание об уровнях этой игры. Чем они выше, тем выше
расходы (WAGES), повышается также и плата за машину.
*********************************
Корр: *KENNY DAGLISH SOCCER MANAGER. Программа обладает, мягко
говоря, своеобразным способом обработки результатов матча. В игре
возможны два варианта - "скоростной", когда опасные моменты не
показывают, и медленный. В первом случае, включив матч, Вы сразу
узнаете его результат. Во втором случае Вам будут показывать удары по
воротам.
Так вот, если Вы поставите "медленную" игру, результат матча
будет зависеть от соотношения сил команд. Если же игра "быстрая", то в
9 случаев из 10 Ваша команда почему-то проигрывает. Если же Вы
все-таки выиграете, то команда *обязательно потеряет игрока.Таким
образом, если Вы хотите выиграть - никогда не ставьте "быстрый"
вариант!
*********************************
ИФК: Мы уже поднимали вопрос о совпадении имен персонажей в игре
*REBEL STAR с именами реальных и литературных героев. Олег Бобрышев
прислал нам еще одно подтверждение этого.
Корр: В игре *REBEL STAR 2 есть боец по имени LUKE SOLO.
Очевидно, это LUKE SKYWALKER + KHAN SOLO - знаменитые герои "Звездных
войн".
*********************************
Корр: Еще Олег дополняет опубликованное нами описание игры *JOHNY REB - II.
Корр: В описании А.Буловятова (ZX-РЕВЮ 96/1-2) упущена одна
подробность: отличия игры на разных уровнях сложности.
Так, на первом уровне сложности игра идет по классической схеме -
сначала приказы отдаете Вы, затем ходит компьютер, и, наконец, Вы
наблюдаете результаты.
На втором уровне игра становится значительно веселее: Ваши и
компьютерные приказы выполняются одновременно, то есть игра идет в
режиме реального времени.
Третий уровень - самый интересный. Здесь Вы также управляете
войсками в режиме реального времени, а, кроме того, Вы видите
соединения противника только тогода, когда они подходят близко к Вам.
*********************************
Корр: В игре *PARIS DAKAR я обнаружил очень занимательный факт:
дорога, если ехать по ROAD BOOK, так петляет, что Вы накручиваете
десятки лишних километров. Так как цель программы - доехать от старта
до финиша, а не проехать всю трассу - срезайте углы! На втором уровне
можно просто, не обращая ни на что внимания, ехать к финишу - по песку
машина идет почти так же, как и по дороге.
Третий уровень игры - самый сложный. Но и его можно пройти, если
выполнять два простых правила:
- не прыгать через двойные трубы;
- не прыгать через озера.
Если подобные препятствия объезжать, Вас ждет долгая и счастливая
жизнь. Не увлекайтесь особо ездой по бездорожью - вода кончается
стремительно, а на этом уровне очень мало заправок. Руководствоясь
этими правилами, мне удалось пройти игру со временем 12 ч. 50 мин.
*********************************
Корр: Еще я застрял в игре *BLOODWYCH. Это симпатичная программа
жанра D&D. Уничтожив всех монстров на трех уровнях, я зашел в глухой
тупик: имеется две "мертвые" двери - те, что открываются (очевидно) -
после того, как Вы наступите на определенную "полосатую" плиту пола.
Таких плит на подходе к дверям целых три, но двери они явно не
открывают.
Кстати, о "полосатых" плитах. На изученных мною трех этажах их
было штук восемь. Одна из них открывает "мертвую" дверь, за которой
сидит демон, еще две - оживляют в случае смерти, а одна -
поворачивает. Но что делают остальные?
Маленькие советы по прохождению игры:
Почти у каждого монстра есть свой "фирменный" предмет, который он
может Вам продать. Кроме того, у каждого монстра неограниченное
количество еды. Лучше сначала купить у чудовища его предмет, а лишь
затем убивать. В этом случае от монстра останется несколько яблок, а
иначе - только "фирменный" предмет.
Не покупайте у монстров еду. Если у Вас есть хоть одно яблоко, Вы
можете обгрызть его до огрызка, а затем продать его монстру за одну
монету. Затем на эту монету Вы покупаете еще одно яблоко и т.д.
И, наконец, "жучок". Все монстры могут обменять находящиеся у них
предметы на... пустой карман (EMPTY SLOT)! Затем Вы сможете вновь его
купить за одну монету. Но и это еще не все! Если Вы положите в этот,
вновь приобретенный, карман какой-нибудь предмет, который представлен
в игре в нескольких экземплярах (стрелы, деньги, ключи), то этот
предмет размножится! Положил в карман одну монету, а получил 25!
*********************************