ZX-Ревю 1996 №9 1995 г.

Форум - обзор системных программ, аппаратных проблем и игр по письмам читателей.


   (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!
*********************************



СОДЕРЖАНИЕ:


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

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



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

Похожие статьи:
Анкета - Дaли бы вы пиз.ы Maху Iwamoto?
Эпилог - заключение и контакты редакции.
Japan wild cross - Рад сообщить всем почитателям Японских кроссвордов о том, что эта рубърика встретила положительные отзывы от читателей WeekEnd'а!
Проблемы PC - MахWell собирает себе 386`ой ! Да-да, это тот самый Mаксвелл (противник РC).
Авторы - Список авторов журнала и адрес редакции.

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