ZX Review
#7-8-9-10
08 ноября 1997 |
|
Форум - Программа Multicolor на любой модели компьютера. Использование 2-го экрана для Multicolor'а. Демонстрация текста. Электронные журналы.
┌──────────────────────────────┐ │ │ │ ФОРУМ │ │ │ └──────────────────────────────┘ Music by ZET (c) KM SoftWare '1997 Итак, на первом месте прог- рамма, которая позволяет исполь- зовать MULTICOLOR на любой моде- ли компьютера. Входных данных программа не требует (только же- лательно очистить экран и уста- новить атрибуты). Выходные дан- ные: A - количество строк от на- чала бордюра (приход INT) до первой строки экрана. Пример использования: запус- каете этот тест, затем запускае- те свою программу, на прерыва- нии которой висит вывод MULTICO- LOR'а. То есть, для вывода MUL- TICOLOR'а нужно подождать n строк экрана (224 такта - 1 строка), где n - полученное тес- том число. Если вы не хотите сами пи- сать программу строковой задер- жки, то сделайте так: в метку RETURN запишите команду RET (код 201=#C9), и по приходу INT'а сразу передавайте управление на метку PRINT, а при возврате вы- водите MULTICOLOR. Второе: если вам нужна не первая, а какая-то другая стро- ка экрана, то поменяйте адрес в метке ADRES - это адрес первого байта нужной экранной строки. Программа занимает всего 201 байт.140. ORG 32768 TEST DI LD DE,#C001 ;формируем вектор LD BC,#0100 ;для IM 2 LD H,D ;3(с #C000=49152) LD L,C LD A,#C1 LD (HL),A PUSH AF DEC A LD (PRINT+1),A ;текущая строка LD I,A LDIR IM 2 ADRES LD HL,16384 ;рисуем на экране LD B,32 ;линию L1 LD (HL),255 INC HL DJNZ L1 POP HL LD L,H LD (HL),#FB ;программа обработки INC HL ;прерывания: EI:RET LD (HL),#C9 LD A,B OUT (#FE),A ;черный бордюр EI ;разрешили IM 2 LOOP HALT ;главный цикл CALL PRINT ;вывод линии CALL KLAV ;опрос клавиатуры JR NC,LOOP ;если не нажат огонь DI ;выход LD A,#3F LD I,A ;нормальный выход IM 1 LD A,(PRINT+1);берем номер INC A ;строки+1 EI RET ;выход ;опрос клавиатуры ;если выход по SCF,то нажат огонь. KLAV XOR A ;* эти строки в IN A,(#FE) ;*принципе можно CPL ;*убрать... AND #1F ;* JR Z,NOKEY ;*нет нажатых клавиш LD A,#FB IN A,(#FE) BIT 0,A ;клава "Q" JR Z,UP ;если да,то переход LD A,#FD IN A,(#FE) BIT 0,A ;клава "A" JR Z,DOWN LD A,#7F IN A,(#FE) RRA JP NC,FIRE ;клава "SPACE" NOKEY AND A ;нет нажатых клавиш RET FIRE SCF ;выход по "SPACE" RET ;передвижение строки вверх UP LD A,(PRINT+1) CP 20 JR Z,NOKEY ;ограничитель DEC A ;уменьшили номер LD (PRINT+1),A JR NOKEY ;выход ;передвижение строки вниз DOWN LD A,(PRINT+1) CP 255 ;ограничитель RET Z INC A ;увеличили номер LD (PRINT+1),A JR NOKEY ;выход ;вывод на бордюр строки синего цвета PRINT LD B,0 ;номер строки PAUSLIN EX (SP),IX ;* данная программка EX (SP),IX ;*3пропускает 224 EX (SP),IX ;*такта, то есть EX (SP),IX ;*одну строку EX (SP),IX ;* EX (SP),IX ;* EX (SP),IX ;* EX (SP),IX ;* LD HL,(0) ;* NOP ;* LD A,3 ;* DJNZ PAUSLIN;* EX (SP),IX ;пропускаем еще одну EX (SP),IX ;3строку (почти 224 EX (SP),IX ;такта - это нужно для EX (SP),IX ;коррекции положения EX (SP),IX ;строки от левого края EX (SP),IX ;бордюра. Почти - EX (SP),IX ;потому что уже были EX (SP),IX ;команды CALL, LD B,N LD DE,0 LD H,(HL) NOP RETURN OUT (#FE),A;синий бордюр EX (SP),IX ;3пропускаем 224 такта EX (SP),IX ;3-11 тактов на EX (SP),IX ;команду OUT (#FE),A EX (SP),IX EX (SP),IX EX (SP),IX EX (SP),IX EX (SP),IX LD A,(IX+0) NOP LD A,0 OUT (#FE),A;черный бордюр RET ;выход2 Данный тест работает правиль- но на машинах с 224 тактами в строке. Если у вас 220, то он, конечно, работать не будет. О правильности работы этой прог- раммы можно сказать вот что: у меня глючный Пентагон (66 строк вместо 80 до экрана) подлой фир- мы СОЛОН. Поэтому на нормальных машинах может быть отклонение. Если вы используете для задер- жки программу PRINT, то это не страшно, а вот если свою - тогда вам придется подкорректировать полученное значение (командами ADD A,N или SUB A,N). Кстати, из-за этой фирмы, на ее "Пентагонах" отвратительно идут все демы: то в ILLUSION шар пропадает (не успевает вывод на экран), то синхронизация MULTI- COLOR'а опаздывает на 3 знако- места (EYE ACHE) & куча т.п. глюков. Немного об использовании 2-го экрана для MULTICOLOR'а. Исполь- зовать его можно, а в некоторых случаях и нужно. С его помощью можно выводить в одном знакомес- те 4 цвета вместо 2-х, причем недостаток разрешения компенси- руется тем, что можно по гори- зонтали использовать хоть весь экран. Где это можно применить? Если вы видели демку VIBRATIONS, то можете понять... Там в нача- ле выводятся красивые линии; при ближайшем рассмотрении оказа- лось, что они двуцветные: точка фиолетовая - точка зеленая. Вро- де бы используется 2-ой экран (точно не знаю - эту демку я по- ка не ломал). С помощью 2-го эк- рана можно выводить скроллер текста по картинке, причем дру- гим цветом. Будет не очень чет- ко, но все-таки... Демонстрация текста. Электронные журналы. Данная статья - для тех, кто мечтает сделать свой электронный журнал или HELP, но не знает, с чего начать. Начнем с основ: главное в журнале - демонстратор текста. Естественно, он должен быть на уровне 97 года, т.е. обязательно цветной, и как с постраничным, так и с построчным скроллингом текста. Управляться это дело должно или клавишами (как в SPE- CTROFON'е) или стрелкой (ZX-FOR- MAT) - других интерфейсов для демонстраторов пока не придума- но. Итак, демонстратор текста де- лится на две отдельные програм- мы: управляющая и Текстовый скроллер. Данная программа должна обес- печивать скроллинг текста в 2-х направлениях построчно и постра- нично. Алгоритм работы таков (при команде "строка вверх"): 1. Если это начало текста, то выход. 2. Берем текущий адрес в тексте и передвигаем его на строку вверх. 3. Сдвигаем весь экран на одно знакоместо вниз. 4. Печатаем в верхней строке строчку из текущего адреса. 5. Выходим. Основная потеря времени идет на пункт 3: здедь мы можем из- брать один из двух путей - или очень сильно увеличить скорость скроллера - использовать стек или LDI (при этом используется почти вся память 48) или сде- лать скроллер не очень быстрым, но цветным. 1. Использование стека. Циклы развернуты. Используется практи- чески вся память 48 (если учиты- вать текст и рабочие программы). Процедура работает при запрещен- ных прерываниях, поэтому SOUND- TRACK невозможен. Весь экран пе- рестраивается за неполных 2 пре- рывания. Пример построения такой прог- раммы скроллинга экрана вверх. Данная программа строит скрол- лер с адреса 26000. При входе в 26000 прерывания запрещаются, затем происходит скроллинг экра- на вверх на одно знакоместо, восстановление стека, разрешение прерываний и возврат.140. ORG 25000 LD HL,26000 ;взяли адрес проги LD (HL),#F3 INC HL LD (HL),#ED INC HL LD (HL),#73 ;DI : LD (0),SP INC HL LD (HL),0 INC HL LD (HL),0 INC HL EX DE,HL LD BC,184*2 LOOP PUSH BC ;Теперь переносим LD HL,BLOK ;блок 184*2 раза. LD BC,ENDBLOK-BLOK LDIR ;для скроллинга POP BC ;одной линии нужно DEC BC ;2 блока. LD A,B OR C JR NZ,LOOP EX DE,HL LD (HL),#31 ;LD SP,0 : EI : RET INC HL LD (26000+3),HL INC HL INC HL LD (HL),#FB INC HL LD (HL),#C9 LD HL,26006 ;адрес первого SP+1 LD BC,184 ;184 строки LOOP1 LD DE,(ADRES1) LD (HL),E ;эта пп. заносит по INC HL ;командам LD SP,0 LD (HL),D ;нужные значения. LD DE,12 ADD HL,DE LD DE,(ADRES3) ;взяли адрес INC DE ;увеличили на 1 LD (HL),E ;занесли в LD SP,NN INC HL LD (HL),D LD DE,12 ;увеличили адрес ADD HL,DE ;до следующего LD SP LD DE,(ADRES2) LD (HL),E INC HL LD (HL),D LD DE,12 ADD HL,DE LD DE,(ADRES4) INC DE LD (HL),E INC HL LD (HL),D LD DE,12 ADD HL,DE EX DE,HL LD HL,(ADRES1) ;корректируем CALL DHL ;экранные адреса LD (ADRES1),HL ;(понижаем на 1 LD HL,(ADRES2) ;линию) CALL DHL LD (ADRES2),HL LD HL,(ADRES3) CALL DHL LD (ADRES3),HL LD HL,(ADRES4) CALL DHL LD (ADRES4),HL EX DE,HL DEC BC LD A,B OR C JR NZ,LOOP1 RET DHL INC H ;DOWN HL для LD A,H ;экрана. AND 7 RET NZ LD A,L ADD A,32 LD L,A RET C LD A,H SUB 8 LD H,A RET ADRES3 DW 16384+16-1 ;адреса в экране ADRES4 DW 16384+31 ADRES1 DW 16384+32 ADRES2 DW 16384+31+17 BLOK LD SP,0 ;блок для POP HL ;построения POP DE ;программы- POP BC ;скроллера POP AF EXX EX AF,AF POP HL POP DE POP BC POP AF LD SP,0 PUSH AF PUSH BC PUSH DE PUSH HL EXX EX AF,AF PUSH AF PUSH BC PUSH DE PUSH HL ENDBLOK2 2. Вместо стека используется LDI. Циклы также развернуты. Ис- пользуется почти в 2 раза мень- ше памяти, чем в первом случае. Программа работает при разре- шенных прерываниях, вывод музы- ки возможен. Скорость полного скроллинга: 4-6 прерываний. При- мер приводить не буду, так как она по принципу построения напо- минает 1-ый случай, а по струк- туре - 3-й (только все циклы развернуты). Блок для одной строки будет иметь такой вид: 140. BLOK LD HL,0 LD DE,0 LD BC,32 LOOP LDI LDI LDI LDI LDI LDI LDI LDI LDI LDI LDI LDI LDI LDI LDI LDI JP PE,LOOP 2 Разумеется, придется коррек- тировать не только адреса эк- рана, но и адрес перехода: JP PE,LOOP, т.к. если вместо JP PE,LOOP поставить еще 16 LDI, то программа получится очень боль- шой (даже больше чем 1-я). 3. Используется сжатый цикл LDI. Занимает очень мало памяти (200-400 байт), но скорость, ес- тественно, уменьшена до 10-15 прерываний. Прерывания разреше- ны. В принципе, идеальный ва- риант для цветных скроллеров (В SMM, MTV я применил именно этот способ). 140. ;пример скроллинга экрана вверх. LD DE,16384 ;куда(верх экрана) LD HL,16384+32 ;откуда (на ;знакоместо ниже) LD B,192-8 ;всего строк LOOP PUSH BC ;запомнили PUSH HL PUSH DE LDI ;332 LDI (32 байта LDI ;в строке). Можно LDI ;заменить на: LDI ;LD BC,32 LDI ;LDIR, LDI ;но это уже LDI ;совсем медленно LDI LDI LDI LDI LDI LDI LDI LDI LDI LDI LDI LDI LDI LDI LDI LDI LDI LDI LDI LDI LDI LDI LDI LDI LDI POP HL CALL DOWNHL POP DE EX DE,HL CALL DOWNHL POP BC DJNZ LOOP RET ;выход DOWNHL INC H ;экранная линия LD A,H ;вниз для HL. AND 7 RET NZ LD A,L ADD A,32 LD L,A LD A,H SUB 8 LD H,A RET 2 Если хотите сделать скроллер вверх, то отличаться он будет только парой вещей: в DE задади- те адрес 23296-31, в HL - адрес на знакоместо выше (23296-63), в BC то же самое (192-8), но толь- ко теперь нужно корректировать адрес не DOWNHL, а UPHL - экран- ная строка вверх. Выглядит так: 140. UPHL DEC H LD A,H AND 7 CP 7 RET NZ LD A,L SUB 32 LD L,A RET C LD A,H ADD A,8 LD H,A RET 2 Все приведенные выше процеду- ры работают только с графикой. Для цветного скроллинга придет- ся еще переносить атрибуты. Соб- ственно, переносить их можно двумя путями: 1. После переноса графики. Это быстрый способ, но есть один недостаток: если ваша программа скроллинга графики не уклады- вается в 1-2 прерывания, то эф- фект будет очень неприятным: мы увидим, как сначала перенесется графика, а потом атрибуты. 2. Параллельно с переносом графики. Более медленный и емкий способ, но зато скроллер будет выглядеть более-менее прилично. Для цветного скроллинга разобьем процедуру скроллирования на под- программу, которая бы переноси- ла 8 линий графики и 1 линию ат- рибутов. Текст программы: 140. LD DE,16384 ;куда(верх экрана) LD HL,16384+32 ;откуда (на ;знакоместо ниже) LD B,23 ;всего строк/8 EXX ;адрес атрибутов LD DE,22528 ;куда LD HL,22528+32 ;откуда EXX LOOP1 PUSH BC CALL SCROLL ;скроллинг 8 линий POP BC DJNZ LOOP1 RET ;выход SCROLL LD B,8 ;8 линий. LOOP PUSH BC ;запомнили PUSH HL PUSH DE LDI ;332 LDI (32 байта LDI ;в строке). Можно LDI ;заменить на: LDI ;LD BC,32 LDI ;LDIR, LDI ;но это уже LDI ;совсем медленно LDI LDI LDI LDI LDI LDI LDI LDI LDI LDI LDI LDI LDI LDI LDI LDI LDI LDI LDI LDI LDI LDI LDI LDI LDI POP HL CALL DOWNHL POP DE EX DE,HL CALL DOWNHL POP BC DJNZ LOOP EXX ;атрибуты LD BC,32 ;перенос строки LDIR EXX RET ;выход DOWNHL INC H ;экранная линия LD A,H ;вниз для HL. AND 7 RET NZ LD A,L ADD A,32 LD L,A LD A,H SUB 8 LD H,A RET 2 Как видите, ничего сложного... Немного о процедурах обработ- ки текста. Собственно, нам нуж- но 4 адреса - адрес начала тек- ста, адрес конца текста, адрес верхней строки в тексте (это ко- торая в данный момент выводится сверху на экране) и адрес нижней строки в тексте. Тогда вывод текста будет наиболее быстрым. Для скроллинга вверх набиваем такую программу: 140. SCRUP LD HL,(ADRES1) ;адрес верхней PUSH HL ; строки LD DE,(BADRES) ;адрес начала AND A ; текста SBC HL,DE ;если равны, то POP HL ; коррекция стека RET Z ; и выход DEC HL ;пропускаем байт DEC HL ;3 ENTER =13 (#0D) LD A,13 ;поиск следующей LOOP1 CP (HL) ; строки JR Z,FOUND ;строка найдена DEC HL ;уменьшили адрес JR LOOP1 ;в цикл FOUND INC HL ;в HL-адрес строки LD (ADRES1),HL ;запомнили LD HL,(ADRES2) ; DEC HL ; DEC HL ;Так же LOOP2 CP (HL) ;корректируем JR Z,FOUND1 ;адрес нижней DEC HL ;строки. JR LOOP2 FOUND1 INC HL LD (ADRES2),HL LD HL,(ADRES1) ;адрес печати PRNSTR LD C,0 ;счетчик LOOP3 LD A,(HL) CP 13 ;если конец строки, JR Z,DOP ;то допечатка INC C ;увеличили счетчик PUSH BC PUSH HL CALL PRINT ;печать символа POP HL POP BC INC HL ;увеличили адрес JR LOOP3 ;в цикл DOP LD A,32 ;допечатка строки SUB C ;(мы должны AND A ;напечатать ровно RET Z ;332 символа). LD B,A ;Оставшееся кол-во DOP1 PUSH BC LD A,32 ;код пробела CALL PRINT ;печать POP BC DJNZ DOP1 RET ;выход 2 Данный вариант для монохром- ного скроллинга. Для цветного придется немного потрудиться... Весь вопрос в том, что при цвет- ном скроллинге текст автомати- чески приобретает нестандартный формат - управляющие коды и т.п. Если вы сами используете эту программку только для себя, то в этом нет ничего плохого, но ес- ли для распространения, то при- дется писать свою утилитку для изменения текста. По-моему, для скроллера лучше всего использо- вать текст с таким форматом: пе- ред кодом атрибута стоит ка- кой-либо управляющий код (в SMM, например, 17). Данная комбина- ция должна быть в начале каждой строки. Программа печати (PRINT в нашем случае) должна при пос- туплении кода 17 установить но- вый атрибут (поступит при сле- дующем ее вызове) и печатать все символы до поступления кода 17 этим цветом. Тут еще одно: нужно переделать программу LOOP1 и LOOP2 (поиск кода 13 - конца строки). Теперь они будут такими (интересующий нас кусок процеду- ры): 140. SCRUP LD HL,(ADRES1) ;адрес верхней PUSH HL ; строки LD DE,(BADRES) ;адрес начала AND A ; текста SBC HL,DE ;если равны, то POP HL ; коррекция стека RET Z ; и выход DEC HL ;пропускаем байт DEC HL ;3 ENTER =13 (#0D) ;поиск следующей LOOP1 LD A,(HL) ; строки CP 13 JR Z,FOUND ;строка найдена PROPUSK DEC HL ;уменьшили адрес JR LOOP1 ;в цикл FOUND DEC HL LD A,(HL) CP 17 ;это был цвет ? JR Z,PROPUSK ;если да, переход INC HL INC HL ;в HL-адрес строки LD (ADRES1),HL ;запомнили LD HL,(ADRES2) ; DEC HL ; DEC HL ;Так же LOOP2 LD A,(HL) ;корректируем CP 13 JR Z,FOUND1 ;адрес нижней PROPSK1 DEC HL ;строки. JR LOOP2 FOUND1 DEC HL LD A,(HL) CP 17 JR Z,PROPSK1 INC HL INC HL LD (ADRES2),HL 2 Часть вторая: Управляющие процедуры. Говорить тут особо нечего. В последнее время в программах этого рода вместо клавиш стала применяться стрелка. Скажу одно: для "мышиных" это, может, и удобно, но если мышки нет, то только потеря времени. Лучшим вариантом было бы определение наличия мыши, и если она есть, то управление стрелкой, а ес- ли нет, то клавишами. По поводу клавиш больше говорить нечего, поговорим об управлении стрел- кой. Существует два алгоритма: первый применяется в ZX-POWER: когда нажат огонь, стрелка про- падает, затем экран скроллирует- ся, стрелка печатается, а затем опрашивается клавиатура. Но ес- ли все еще нажат огонь, то пе- чать и стирание стрелки пропа- дают зря. Стрелка начинает дико мерцать, а скроллер тормозить. Другой вариант применен в ZX-FORMAT'е: если нажат огонь, стрелка пропадает, скроллирует- ся экран, а потом снова опраши- вается огонь, и если он все еще нажат, то, не печатая стрелку, переходим на скроллинг, если же нет, то печать стрелки. Тут мы не теряем времени на ненужную печать/стирание, и все довольно быстро. Прим. ред. Автор подводит нас к мысли о том, что невозможно реализовать полноэк- ранный скроллинг, укладывающийся в преры- вание. Но в некоторых случаях это вполне возможно за счет уменьшения количества пе- ресылаемых байтов. Рассмотрим два таких случая. 1. Две верхние строки экрана заняты служебной информацией (название статьи и т.п.), а текст занимает оставшиеся 22 строки. Между строками текста оставлен промежуток в 2 пиксела (т.е. каждый символ по высоте занимает 6 пикселов). Посчитаем, сколько байтов должна пе- реслать процедура скроллинга, сдвигающая текст на одно знакоместо вверх или вниз. Должна быть перемещена 21 строка текста, т.е. 21*32*6=4032 байта, плюс атрибуты: 21*32=672 байта. Итого 4704 байта. Фраг- мент программы, выполняющий пересылку 16 байтов, выглядит так: LD SP,адрес источника POP AF POP BC POP DE POP HL EXX EX AF,AF' POP AF POP BC POP DE POP HL LD SP,адрес приемника+16 PUSH HL PUSH DE PUSH BC PUSH AF EXX EX AF,AF' PUSH HL PUSH DE PUSH BC PUSH AF Длина фрагмента 26 байт, время выполне- ния 204 такта. Посчитаем, сколько тактов уйдет на выполнение всей процедуры сдвига: 4704/16=294; 294*204=59976 тактов, т.е. еще останется достаточно времени на печать появившейся сверху или снизу новой строки текста и на вызов процедуры проигрывания музыки. Сколько места в памяти будет занимать такая процедура сдвига? 294*26=7644 байта. Но так как сдвиг должен выполняться и вверх и вниз, удваиваем это значение. По- лучим 15288 байтов. При наличии 128K памя- ти удобно выделить какой-либо банк (16384 байта) и разместить в нем процедуры сдви- га. Недостатком указанного способа является ограничение высоты символов текста - не более 6 пикселов. Это сразу делает невоз- можным вывод графики и псевдографики, да и шрифт придется подредактировать. 2. Две верхние строки экрана заняты служебной информацией (название статьи и т.п.), а текст занимает оставшиеся 22 строки. Но каждая строка текста занимает по ширине не 32 байта, а 20 (т.е. в строке умещается 20 символов 8х8, или 26 символов 6х8, или 40 символов 4х8). Снова посчитаем количество пересылаемых байтов: 21*20*8=3360, плюс атрибуты: 21*20 =420 байтов. Итого 3780 байтов. Фрагмент программы, выполняющий пересылку 20 бай- тов, выглядит так: LD SP,адрес источника POP AF POP BC POP DE POP HL EXX EX AF,AF' POP AF POP BC POP DE POP HL POP IX POP IY LD SP,адрес приемника+20 PUSH IY PUSH IX PUSH HL PUSH DE PUSH BC PUSH AF EXX EX AF,AF' PUSH HL PUSH DE PUSH BC PUSH AF Длина фрагмента 34 байта, время выпол- нения 262 такта. На выполнение всей проце- дуры сдвига уйдет 3780/20*262=49518 так- тов, а в памяти она займет 3780/20*34=6426 байтов (соответственно, обе процедуры, для сдвига вверх и вниз, займут 12852 байта). Достоинство этого способа - не ограни- чена высота символов, т.е. можно выводить и графику, и псевдографику. Можно задей- ствовать и две верхние строки экрана - времени на их обработку хватит (сдвиг бу- дет занимать 53710 тактов). Можно сделать плавный попиксельный скроллинг (хотя он будет красиво выглядеть, только если для всего текста установлены одинаковые атри- буты). Недостаток - не используются правый и левый края экрана. Хотя, с другой стороны, это может повысить удобочитаемость текста. Можно увеличить ширину строки до 24 байт (32 символа 6х8, как в оболочке ZX- Ревю), не сильно увеличив время сдвига. При этом придется дополнительно перенести 21*4*8=672 байта графики и 21*4=84 байта атрибутов, всего 756 байт. Фрагмент для переноса двух байтов выглядит так: LD HL,(адрес источника) LD (адрес приемника),HL и занимает 6 байт, а выполняется за 32 такта (т.е. 16 тактов на байт). Тогда вре- мя выполнения процедуры увеличится на 756* *16=12096 тактов и составит 49518+12096= 61614 тактов, а занимаемая память увели- чится на 756/2*6=2268 байт. Общая длина двух процедур будет равна 12852+2*2268= 17388 байт. Кстати, вовсе необязательно хранить в памяти обе процедуры сдвига - вверх и вниз. Можно хранить только одну из них, например, пусть это будет сдвиг вверх. Ко- гда пользователь нажимает кнопку для сдви- га в противоположном направлении - просто изменяем адреса в этой процедуре. И так при каждом изменении направления сдвига. * * *
Другие статьи номера:
Похожие статьи:
В этот день... 21 ноября