В этой статье мы продолжим программировать слова, создающие простые рисунки из
текстовых символов. Попутно мы познакомимся с несколькими словами, перемещающими данные в стеке, что позволит
создать более сложные слова, выводящие символы на терминал.
Предыдущую статью мы закончили определением слова H-LINE , которое рисует горизонтальную линию заданной длины с началом в указанных координатах. Длина и координаты передаются в стеке.
Нам также необходимо слово V-LINE , рисующее вертикальную линию. Для единообразия слово должно получать в стеке длину и координаты, в том же порядке, что и H-LINE . Рисовать будем символом "восклицательный знак".
Разница между H-LINE и V-LINE заключается в том, что для каждого символа вертикальной линии мы должны устанавливать новую координату y. Нам понадобится слово, сохраняющее копию координат на вершине стека, потому что слово GO-XY , перемещающее курсор, удаляет их.
В Форте имеются слова DUP и 2DUP . Слово DUP (от duplicate) создает дубликат числа, лежащего на вершине стека. Если вернуться к аналогии с кирпичами, при выполнении слова DUP кирпич с вершины стека "клонируется" и его брат-близнец кладется поверх него. Таким образом, в стеке становится одним числом больше, причем на вершине оказывается пара идентичных чисел:
Слово 2DUP создает дубликат пары ячеек, лежащих на вершине стека, сохраняя порядок следования ячеек в паре. Это как раз то, что нам нужно для копирования координат.
Еще одно слово, которое нам пригодится, ROT . Это слово "вращает" три верхних ячейки стека таким образом, что третий сверху "кирпич" оказывается на вершине, а два верхних опускаются вниз:
И последняя пара слов, DROP и 2DROP . Слово DROP просто удаляет число, находящееся на вершине стека:
Слово 2DROP удаляет из стека верхнюю пару ячеек.
Теперь мы можем определить слово V-LINE :
: V-LINE \ len x y -- \
ROT
0 DO 2DUP GO-XY [CHAR] ! EMIT 1+ LOOP
2DROP ;
Пройдем по определению. Первым делом, с помощью ROT , на вершину стека перемещается длина линии, которая становится пределом цикла в следующей строке. В начале цикла на вершине находятся координаты x и y, которые мы копируем с помощью 2DUP . Копию координат использует слово GO-XY для перемещения курсора. Далее выводится символ ! .
После перемещения курсора в стеке находятся исходные координаты, причем на вершине лежит y. Слово 1+ увеличивает значение y на 1. Если слово LOOP не обнаруживает признака завершения цикла, выполнение повторяется сразу после слова DO , но с новой парой координат в стеке.
После выхода из цикла выполняется слово 2DROP , которое освобождает стек от оставшихся там координат.
Если вы выполняете рассматриваемые примеры, загрузите слова из прошлых статей и добавьте определение V-LINE . Теперь можно проверить, как это работает:
У нас уже имеется неплохой набор слов, позволяющий создавать сложные изображения из текстовых символов. Нарисуем рамку в центре экрана терминала. Для это создадим новое слово:
: FRAME
66 7 3 H-LINE 66 7 20 H-LINE
16 7 4 V-LINE 16 72 4 V-LINE ;
Слово FRAME рисует рамку, имеющую размер внутреннего поля 16 символов по высоте и 64 символа в ширину. Рамка расположена в центре экрана, поэтому верхний левый угол внутреннего поля будет иметь координаты x=8, y=4.
Чтобы предыдущий текст не мешал рисованию, выполним сначала очистку экрана:
CLRSCR FRAME
Вы должны увидеть вот такую картину:
У нас есть область внутри рамки, которую мы можем привязать к независимой системе координат. Добавим еще одно слово:
: FRAME-XY \ x y -- \
4 + SWAP 8 + SWAP GO-XY ;
Это слово перемещает курсор внутри рамки. Координаты 0;0 соответствуют верхнему левому углу внутреннего поля.
Нам потребовалось использовать новое слово, перемещающее данные в стеке. Слово SWAP меняет местами две ячейки на вершине стека:
После того, как мы добавили смещение 4 к y, мы меняем x и y местами (первое слово SWAP ), добавляем смещение 8 к x, после чего восстанавливаем порядок координат в стеке (второе слово SWAP ).
Проверим, как это работает, создав небольшой шедевр компьютерной графики. Определим новое слово:
: SKY CLRSCR FRAME
64 0 DO
16 0 DO
J I FRAME-XY STAR
LOOP
64 LOOP ;
Начинается определение очисткой экрана и выводом рамки.
Мы специально расположили текст "ступеньками", чтобы было видно два счетных цикла, вложенных один в другой.
Первый цикл имеет предел 64, он используется для перечисления координат x внутри рамки. Внутри этого цикла выполняется второй цикл, имеющий предел 16, что дает перебор координат y.
В определении появилось два новых слова. Слово I возвращает на вершине стека значение счетчика текущего цикла, а слово J – значение счетчика цикла, внешнего по отношению к текущему. Таким образом в стек помещаются координаты внутри рамки, которые мы передаем слову FRAME-XY для установки курсора. Слово STAR рисует звездочку в указанном месте.
Выполним слово SKY и понаблюдаем, как рамка заполняется "звездочками":
Конечно, считать это изображением звездного неба можно весьма условно, слово SKY – всего лишь шутка. Обратите внимание, развертка изображения по вертикали выполняется заметно медленнее, чем по горизонтали. Этот эффект должен учитываться при выводе больших массивов данных на терминал.
Спасибо за внимание.