ZX-Ревю 1993 №7-8 1992 г.

Профессиональный подход - применение статического генератора случайных чисел на примере программы "ELITE".


ПРОФЕССИОНАЛЬНЫЙ ПОДХОД

(C) Збитнев В. А., 1992, 1993. (г. Новосибирск)

Применение статического генератора случайных чисел на примере

программы "ELITE"

Вероятно, уже все знают о том, что такое RND. Во многих игровых и учебных программах этот оператор используется для того, чтобы поведение компьютера в некоторых ситуациях было непредсказуемым. Эту роль прекрасно исполняет генератор случайных чисел на ZX-SPECTRUMe. Он относится к типу динамических, то есть таких, которые изменяют свое состояние независимо от того, когда вызывается этот генератор. Свое значение "спектрумовский" RND вычисляет, используя переменную SEED (23670 DEC), которая изменяется с течением времени.

Но так бывает не во всех компьютерах. Многие, наверное, знают работу RND на других версиях Бейсика для компьютеров типа "Ямаха" (MSX), IBM. Сколько бы раз Вы не вызывали бы RND в своей программе (например для рисования звездного неба), он выдает одни и те же числа после команды RUN, RANDOMIZE (в случае рисования звездного неба одна и та же картина будет на экране, если Вы остановите программу и снова запустите ее через RUN).

Такой вид RND-генератора называется статическим. Он плох для непредсказуемых действий, но он прекрасно может работать в качестве хранилища огромного объёма данных, не требующих в памяти места. Но самое главное - эта информация будет постоянной, сколько бы раз эти данные не были бы затребованы. Простейший пример такого RND -генератора на ассемблере

RND: LD

A,(R1)

LD

D,A

LD

A,(R2)

LD

(R1),A

ADD

A,D

LD

D,A

LD

A,(R3)

LD

(R2),A

ADD

A,D

RLCA

LD

(R3),A

RET

R1, R2, R3 - переменные

В регистре A будет содержаться случайное число (0-255). Но подобный генератор случайных чисел все время будет генерировать очередные случайные числа. Теперь создадим программу, подобную RANDOMIZE в Бейсике.

RAND: LD

A,5

LD

(R1),

A

LD

A,90

LD

(R2),

A

LD

A,37

LD

(R3),

A

RET

Теперь, после вызова подпрограммы RAND некий указатель встаёт на начало некой таблицы, в которой хранится бесконечное количество байтов, которые и извлекаются из неё подпрограммой RND. Где это можно использовать? К примеру, в хорошо известной игре "ЖИЗНЬ" ("LIFE") нужна матрица со случайно расположенными в ней клетками. Вводить через DATA весь массив неудобно, медленно и не практично. Если заполнять массив через обыкновенный RND, то возникает проблема с тем, как снова воспроизвести картину, если это понадобится. Опять прибегаем к DATA. Но есть более практичный способ: задание массива через статический RND, который будет выдавать те же самые значения, что и в первый раз, стоит только вызвать RAND.

В игровых программах с большим количеством комнат таким путем можно запоминать все комнаты, как комбинацию трех (или другого числа байтов), в данном случае - 5, 90, 37. Стоит их только изменить и Вы имеете опять новую комнату. Программа "Demons" использует как раз такой способ, она чем-то напоминает "ЖИЗНЬ", но выглядит в 7 раз красивее и эффектнее. Попробуйте, не пожалеете!

Программа 1 Demons

Сброс генератора случайных чисел в исходное положение Заполнение экрана атрибутами через RND Старый массив Новый массив

768 байтов - размер области экранных атрибутов

ORG

CALL

CALL

LD

LD

LD

30000

RAND

RNDSC

IX,22528

HL,31000

BC,768

NXTPG

;Если слева, справа, сверху или снизу может кто-то ;"съесть" этот атрибут, то пусть "съедает".

LOOKS

A,(HL)

A

7

(IX+1)

Z,SEAT

(IX-1)

Z,SEAT

(IX+32)

Z,SEAT

(IX-32)

Z,SEAT

LD

INC

AND

CP

JP

CP

JP

CP

JP

CP

JP

Продолжить обработку массива

INC

INC

DEC

LD

OR

JP

EATED

HL

IX

BC

A,B

C

NZ,LOOKS

CALL COPY RET

"Съедаем" текущий атрибут

SEAT

(HL),A EATED

LD JR

Копирование нового массива в старый

COPY

HALT LD LD LD

LDIR RET LD LD

CALL

AND

LD

INC

DEC

LD

OR

JP

CALL RET

HL,31000 DE,22528 BC,768

RNDSC FILL

HL,31000 BC,768 RND1 7

(HL),A

HL

BC

A,B

C

NZ,FILL COPY

Заполняем новый массив байтами с числовым значением от 0 до 7

Копирование массива в старый массив

LD

A,5

LD

(R1),A

LD

A,90

LD

(R2),A

LD

A,37

LD

(R3),A

LD

HL,16384

LD

DE,16385

LD

BC,6144

LD

(HL),255

LDIR

RET

LD

A,(R1)

LD

D,A

LD

A,(R2)

LD

(R1),A

ADD

A,D

LD

D,A

LD

A,(R3)

LD

(R2),A

ADD

A,D

RLCA

LD

(R3),A

RET

5, 90, 37 - байты, означающие параметры экрана

RAND

RND1

Генератор случайных чисел

R1 DEFB 0 ;Исходные значения параметров

R2 DEFB 0

R3 DEFB 0

Следующая область применения - формирование статичной (неменяющейся) информации. Возьмем к примеру игру "ELITE". Откуда компьютер с таким небольшим объемом памяти берет названия и координаты всех 256 звезд, в каждой из восьми галактик, да ещё и неизвестно сколько всего этих галактик. Где хранятся данные о ценах на каждой из планет, её техническом уровне, общественном строе и населении.

Разумеется, это работа статического RND. Если Вы наберете программу 2 на Ассемблере или 2.1 на БЕЙСИКе, то сможете получить данные о всех названиях планет и их координатах. Остальная информация каким-то образом хранится в 6 основных байтах и может быть образована одним из 4 RND, вызываемых последовательно для каждой звезды. Может быть, удастся расшифровать и остальные данные.

Итак, статический RND может хранить в себе информацию. Можно, к примеру, сделать слоги русскими, задействовать остальные байты для русских имен, для пола, возраста, адреса и пожалуйста: у Вас есть картотека на 10000 человек, работающих на космическом корабле. Статический RND может быть применим и для динамической информации. Примером может служить игра SENTINEL, в которой все ландшафты имеют свой номер, а задание их в памяти невозможно - слишком расточительно. Но в процессе игры Вы можете некоторым образом изменять эту информацию уже в матрице, созданной этим RND.

Программа 2.1

Заполняет массив данными о планете, начиная с адреса 40000 в следующем

формате:

| Имя звезды | X | Y |

| 8 байтов |1б.|1б.| = 10 байтов на планету

30000

RAND

B,0

;256 звёзд ;Считать имя в NAME

STARS PUSH BC

CALL LDNAME

ORG

CALL

LD

CALL SAVNM ;Записать имя из NAME в массив, на который

POP BC ; указывает MASSV

DJNZ STARS RET

LDNAME LD HL,NAME ;Позиция в имени указывается переменной POS

LD (POS),HL

LD B,9 ;Очистили 9 байтов

CLEAR LD (HL),0 ;Имя будет равно 8 символам

INC HL

DJNZ CLEAR

LD A,(D0+1)

LD (D1),A ;Запишем координату Y

LD A,(D2+1)

LD (D3),A ;Координата X звезды

LD A,(D0) ;Условие, при котором 6-ой бит указывает на то,

AND 64 ; в слове нет последнего слога

PUSH AF

CALL LDSLG ;Три слога

CALL LDSLG

CALL LDSLG

POP AF

JR Z,RND2 ;Если нет последнего слога, то уход на холостой RND

LDSLG LD A,(D4+1) ;Условие отсутствия слога:

AND 31 ;номер слога = 0, т.е. слог "AL" - невозможен

JR Z,RND2

LD HL,SLOGS

ADD A,A ;Номер слога*2

LD E,A

LD D,0

LD HL,DE ;Находим позицию слога в SLOGS

LD A,(HL) ;Считываем первый символ слога

INC HL

PUSH HL

LD HL,(POS)

LD (HL),A ;Записываем первый символ по адресу POS

INC HL ;Следующий символ слога

EX DE,HL

POP HL

LD A,(HL) ;Если символ равен "?", то не записывать

CP 63 ;урезанный слог

JP Z,SAVPS

LD (DE),A ;Записываем 2-й символ слога

INC DE

SAVPS LD (POS),DE ; Сохраняем позицию

RND2 LD HL,(D0) ;Сама процедура RND

LD DE,(D2)

ADD HL,DE

EX DE,HL

LD HL,(D2)

LD (D0),HL

LD HL,(D4)

LD (D2),HL

ADD HL,DE

LD (D4),HL ; D0<—D2< — D4<—D0+D2+D4 RET

SAVENM LD HL,NAME ;Записываем имя в массив

LD DE,(MASSV)

LD BC,8 LDIR

LD A,(D1) ;Считываем Y

SRL A ;Преобразуем в нормальный вид

XOR 127

LD

(DE),A

INC

DE

LD

A,(D3)

LD

(DE),A

INC

DE

LD

(MASSV),DE

RET

RAND

LD

HL,RNDDAT

LD

DE,D0

LD

BC,6

LDIR

LD

HL,40000

LD

(MASSV),HL

RET

D0

DEFW

00

D1

DEFW

00

D2

DEFW

00

D3

DEFW

00

D4

DEFW

00

MASSV

DEFW

00

NAME

DEFW

SLOGS

DEFM

"ALLEXEGEZA

DEFM

"CEBISOUSES

DEFM

"ARMAINDIRE

DEFM

"A?ERATENBE

DEFM

"RALAVETIED

DEFM

"ORQUANTEIS

DEFM

"RION"

RNDDAT

DEFB

74

DEFB

90

DEFB

72

DEFB

2

DEFB

83

DEFB

183

;Записываем в массив

;Считываем X и записываем в массив

;Запоминаем позицию в массиве

;Копируем данные о галактике в массив RND

;61...66 байты в отгружаемом блоке состояния ELITE

Переменные

Программа 2.1

Печать имён планет всех галактик ELITE.

10 PAPER 0: INK 6: BORDER 0

20 CLS: PRINT "ELITE SPACE.....1-STAR NAMES.....2-PLOTS OF STARS

30 LET k$=INKEY$: IF k="1" THEN GO TO 60 40 IF k$="2" THEN GO TO 200 50 GO TO 30

Подпрограмма вывода названий.

60 LET n=0: GO SUB 1070: GO SUB 1010: REM установка генератора случайных чисел в исходное положение и установка стринга n$, содержащего слоги всех названий планет.

70 CLS: PRINT INK 5; "NO NAME"

80 FOR f=1 TO 20

90 LET r=d0-INT (d0/256)*256

100 GO SUB 2000: REM В строках 100...120 и 150 содержатся четыре вызова генератора для одной звезды.

110 GO SUB 2000

120 GO SUB 2000

130 IF r>127 THEN LET r=r-128

140 IF r-64<0 THEN GO SUB 1030: REM Если 6-ой бит равен нулю, то производится холостой вызов RND и слово становится короче на один слог.

150 GO SUB 2000

170 LET n=n+1: IF n=256 THEN STOP: REM Если число звёзд равно 256, то конец работы.

180 NEXT f: BEEP .1, 30: PAUSE 0: GO TO 70: REM Формируется следующее имя

Вывод позиций звёзд

200 CLS: PLOT 0,23: DRAW 255,0: DRAW 0,129

205 DRAW -255,0: DRAW 0,129

210 GO SUB 1010

220 FOR f=0 TO 256

230 LET y=INT (d0/256): LET y=INT (y/2)+24

240 LET x=INT (d2/256)

250 PLOT OVER 1;x,175-y: REM Вывод звезды

260 GO SUB 1030: GO SUB 1030

270 GO SUB 1030: GO SUB 1030

280 NEXT f: STOP

1000 REM Подпрограмма инициализации статического генератора* 1010 RESTORE: READ d0, d2, d4: RETURN

1020 REM *Статический генератор случайных чисел* 1030 LET s=d0+d2: IF s>65535 THEN LET s=s-65536

1040 LET s=s+d4: IF s>65535 THEN LET s=s-65536: REM s=d0+d2+d4 (двухбайтное логическое

сложение) 1050 LET d0=d2: LET d2=d4 1060 LET d4=s: RETURN

1065 REM *Генерация списка возможных слогов* 1070 LET n$="ALLEXEGEZACEBISOUSESARMAINDIREA?" 1080 LET n$=n$+"ERATENBERALAVETIEDORQUANTEISRION" 1090 RETURN

2000 REM *Выбор случайного слога*

2010 LET h=INT (d4/256): LET h=h-INT (h/32)*32

2020 IF h=0 THEN GO SUB 1030: RETURN

2030 LET h=h*2: PRINT n$(h+1)

2040 LET h=h+1

2050 IF n$(h+1)="?" THEN GO SUB 1030: RETURN 2060 PRINT n$(h+1): GO SUB 1030: RETURN

3000 DATA 74+90*256 3010 DATA 72+2*256 3020 DATA 83+183*256

3030 REM этот блок данных соответствует галактике с параметрами 74, 90, 72, 2, 83, 183 (байты 61...66 в блоке состояния программы ELITE)




СОДЕРЖАНИЕ:


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

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



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

Похожие статьи:
Новости - пару новостишек из Сибири: Kas29 готов представить миру свою новую игру, Buddy чинит свою крышу и совсем забил на Спек, NOT-Soft вся банда занята подготовкой к CSP.
Автобиография - история Уфимского спектрумиста: B.V.C aka Agressor из группы Chemnesoft.
Чемпионат - Чемпионат вирусов в игре Треснутая пробирка.
От автора - Вот и четвертый номер газеты.
Обзор игр - The Cezar, 8-й Отдел, Clickmania, 4x4 Puzzle, Xixit, Tower Pod.

В этот день...   3 декабря