День 9. Совершенствование игры

День 9. Совершенствование игры

Вариант игры от М.Максимова. Библиотека работы с экраном в текстовом режиме. Создание макета справочной системы.

Копался на сайте Forth нашел книжку на сайте Ильи Тарсова о Forth Слил все файла в один, переформатировал с ипсользованием стилей – получился более, как на мой взгляд, приятный и удобный вариант для прочтения, его можно взять отсюда. Брошюрка кратенькая, но описывает основные моменты: работа со стеком данных, возвратов, работа с вещественными числами, компиляция, работа с файлами. Оттуда узнал о новой технике работы с переменными через слова VALUE и TO Более толково и аргументировано объясняются векторные слова. Впервые, я увидел там упоминание о разделении памяти – для данных и для кода.

Также разместил книгу "Учебное пособие по языку ФOPT" Я его тоже несколько переформатировал. Оно кратенькое, описывает устаревший стандарт.

Но такое впечатление, что это была попытка сделать описание путе компиляции фрагментов текста с существующих книг и дописанием своих. Начинание получилось очень неплохое, по крайней мере, мне оно понравилось больше чем книжка Келли и Спайса. Дополнить бы его еще примерами...

М. Максимов разместил в форуме ссылку на свой вариант программы Жизнь Которую он переделал из моего. За что ему спасибо. Ибо позволит многое пересмотреть, увидеть что-то новое. Ниже приводится ее текст.

\  Life game
\  Alex Furashev  http://forth-j.narod.ru/day07.htm
\  Michail Maximov.

REQUIRE AT-XY ~day\common\console.f

: СоздатьМатрицу ( ширин высот адр ) \ ширин и высота -- кол-во элементов, поэтому отсчет 1! DUP @ 1000 > IF \ Освобождение памяти, если есть указатель - DUP FREE DROP \ какое-то относит. большое положит. число THEN >R 1 MAX ( ширин высот R: адр ) SWAP 1 MAX ( высот ширин R: адр ) \ получили длину + 2 ячейки под размер матрицы 2DUP * 1+ ( адр ширин высот длин ) CELLS \ Получили длину в байтах ! ALLOCATE IF -300 THROW THEN >R ( высот ширин R: адр адрМатр ) R@ ! ( высот R: адр адрМатр ) \ сохранил ширину матрицы R@ CELL+ ! ( R: адр адрМатр ) \ сохранил высоту матрицы R> R> ! \ сохранил адрес матрицы в переменной ; : ШиринаМатрицы ( адрМатр ) @ \ получил адрес памяти матрицы @ \ только теперь ширину ; ( шир ) : ВысотаМатрицы ( адрМатр ) @ CELL+ @ ; ( выс )

: ?LifeEXIT S" IF DROP 2DROP 0 EXIT THEN" EVALUATE ; IMMEDIATE

: ?LifeEXIT1 IF 2DROP 2DROP 0 RDROP THEN ;

: ЭлМатрицы ( х у адрМатр – adr|0 ) \ координаты начинаются с 0 !!! 2DUP ВысотаМатрицы 1- > ?LifeEXIT ROT ( y адрМатр x ) DUP 0< \ если х вышел за пределы диапазона, то возвращаю 0 ?LifeEXIT ( y адрМатр x ) OVER ШиринаМатрицы 1- OVER < \ должен быть строго меньше границы ?LifeEXIT ( y адрМатр x ) ROT ( адрМатр x y ) DUP 0< \ если y вышел за пределы диапазона, то возвращаю 0 ?LifeEXIT ( адрМатр x y ) \ проверку дипапазона закончили 2 PICK ВысотаМатрицы * + \ преобразовали двумерные координат в одномерные 2+ \ с учетом 2-х служебных ячеек CELL * \ получили адрес элемента относит блока памяти SWAP @ \ адрес блока памяти + @ \ абс. адрес элемента и его значение ;

: =ЭлМатрицы ( знач х у адрМатр – adr|0 ) \ координаты начинаются с 0 !!! 2DUP ВысотаМатрицы 1- > ?LifeEXIT1 ROT ( знач y адрМатр x ) DUP 0< \ если х вышел за пределы диапазона, то возвращаю 0 ?LifeEXIT1 ( знач y адрМатр x ) 2DUP SWAP ШиринаМатрицы 1- > \ должен быть строго меньше границы ?LifeEXIT1 ( знач y адрМатр x ) ROT ( знач адрМатр x y ) DUP 0< \ если y вышел за пределы диапазона, то возвращаю 0 ?LifeEXIT1 ( знач адрМатр x y ) \ проверку дипапазона закончили 2 PICK ВысотаМатрицы * + \ преобразовали двумерные координат в одномерные 2+ \ с учетом 2-х служебных ячеек CELL * \ получили адрес элемента относит блока памяти SWAP @ \ адрес блока памяти + \ абс. адрес элемента ! \ запоминаю его значение ; : ОчиститьМатрицу ( адрМатр ) DUP ВысотаМатрицы 0 DO DUP ШиринаМатрицы 0 DO 0 I J 3 PICK =ЭлМатрицы LOOP LOOP DROP ; : ПоказатьМатрицу ( адрМатр ) DUP ВысотаМатрицы 0 DO DUP ШиринаМатрицы 0 DO I J 2 PICK ЭлМатрицы . LOOP CR LOOP DROP ; \ -------------------------------------------------------------------- \ ---------------------------- Данные -------------------------------- USER Среда 0 Среда ! USER Кол-воСоседей 0 Кол-воСоседей ! 20 20 Среда СоздатьМатрицу Среда ОчиститьМатрицу 20 20 Кол-воСоседей СоздатьМатрицу Кол-воСоседей ОчиститьМатрицу : ЗаселитьСреду Среда ВысотаМатрицы 0 DO Среда ШиринаМатрицы 0 DO I J * 5 MOD DUP 2 = OVER 3 = OR IF DROP 1 ELSE DROP 0 THEN \ определил -- живет здесь бактерия (1) или нет(0) J I Среда =ЭлМатрицы LOOP LOOP ; : ЕстьБактерия? ( x y ) Среда ЭлМатрицы \ если есть бактерия, то 1 иначе 0 ; ( 1 | 0 ) : РассчитатьКол-воСоседей Кол-воСоседей ВысотаМатрицы 0 DO Кол-воСоседей ШиринаМатрицы 0 DO I 1- J 1- ЕстьБактерия? \ нижний левый угол I 1- J ЕстьБактерия? + \ обход по часовой I 1- J 1+ ЕстьБактерия? + I J 1+ ЕстьБактерия? + I 1+ J 1+ ЕстьБактерия? + I 1+ J ЕстьБактерия? + I 1+ J 1- ЕстьБактерия? + I J 1- ЕстьБактерия? + ( колБакт ) I J Кол-воСоседей =ЭлМатрицы \ Сохранили значение LOOP LOOP ; : ПоказатьСовмещенно Кол-воСоседей ВысотаМатрицы 0 DO Среда ШиринаМатрицы 0 DO J I Среда ЭлМатрицы IF ." X" ELSE ." " THEN LOOP 2 SPACES Кол-воСоседей ШиринаМатрицы 0 DO J I Кол-воСоседей ЭлМатрицы . LOOP CR LOOP ; : ПоказатьСреду Среда ВысотаМатрицы 0 DO Среда ШиринаМатрицы 0 DO J I Среда ЭлМатрицы IF ." X" ELSE ." " THEN LOOP CR LOOP ; : ОбновитьСреду Среда ВысотаМатрицы 0 DO Среда ШиринаМатрицы 0 DO J I Кол-воСоседей ЭлМатрицы DUP 2 < IF DROP \ умерла от недостатка 0 J I Среда =ЭлМатрицы ELSE 4 > IF \ умерла от перенаселенности 0 J I Среда =ЭлМатрицы ELSE \ родилась новая или продолжает жить старая 1 J I Среда =ЭлМатрицы THEN THEN LOOP LOOP ; \ ------------------------------- : Main 4 3 TEXT-ATTR ЗаселитьСреду \ Инициализировали РассчитатьКол-воСоседей \ ПоказатьСовмещенно \ Для отладки BEGIN 0 0 AT-XY ПоказатьСреду ОбновитьСреду РассчитатьКол-воСоседей CR ." Q - выход" KEY 0x20 OR \ символы делаем маленькими [CHAR] q = UNTIL ; Main

Первый же запуск порадовал – программа отображает колонию в цвете, интерактивно перерисовывает стадии. Правда, после выхода программа не восстанавливает цветовую гамму консоли.

Первое – использование библиотеки ~day\common\console.f для работы в текстовом режиме с цветом и произвольного доступа к любому месту на экране. Ее подключение и использование. Вызывает недоумение – а почему библиотеку нельзя было положить в \lib, где ей сосбственно и место?

Вынес слова для работы с матрицами в отдельный файл – библиотеку. Хотел переписать так чтобы переменные для матриц создавались бы словом VALUE а не USER Но, это невозвожно, т.к. слова VALUE и TO использует имя переменной на этапе компиляции определения, а матрицы в момент работы слов могут быть разные. Пока отказался от его использования. Во всяком случае, кажется, проще написать макрос подстановки. Что-то вроде

 USER A
  wbMACRO  A " A @"
  wbMACRO =A " A !"
\ Запись выражения A=A+6 поразному
  A @ 6 + A ! \ классически. Не очевидно и загромождено.
  A 6 + =A    \ так гораздо понятнее :) 

тот же вариант с использованием слов VALUE и TO

 0 VALUE A
 A 6 + TO A

Почти тоже что и с маросами, но макросы таки нагляднее :)

Понял, почему не срабатывало прошлый раз у меня слово INCLUDED Проблема была в кодировках – т.к. я использовал русскоязычные слова, а файлы были в разных кодировках (win и dos), то компилятор и не видел слов из разных файлов. Вот уж извечная проблема с кодировками...

Ага, подправлена стековая нотация – моя недоработка. И Михаил очень активно использует стек возвратов, чего я старательно избегал. Покрайней мере в активной форме я его не использую.

Правда, я переписал код с использованием локальных переменных и он стал более читаемым. Но это моя позиция на сегодня: лучше читабельный код, который легко читается, легко пишется и легко отлаживается, оптимизированному.

Сделал модульной структуру программу игры, работу с матрицами вынес в отдельный файл. Нашел баг – оставшийся рудимент от предыдущей версии, но который приводил к ошибке "исчерпание стека".

Стал экспериментирвоать с библиотекой ~day\common\console.f Вот еще одна проблема – константы цветов не описаны. Пришлось сделать такую вот прогу, которая и решил задачу

 REQUIRE AT-XY ~day\common\console.f
: test
 16 0 DO
  I 0  TEXT-ATTR
  I . ." xxxxxxxxxxxxxxxxxxxxxx" CR
 LOOP
;
test

а вот и сами константы цветов

 0 – черный
 1 – темно-синий
 2 – темно-зеленый
 3 – темно-голубой
 4 – коричневый, ближе к красному
 5 – темно-розовый
 6 – светло-коричневый, грязный
 7 – светло-серый
 8 – темно-серый
 9 – синий
10 – зеленый
11 – голубой
12 – красный
13 – розовый
14 – желтый
15 – белый



Если указывать числа сверх этого диапазона, то будет меняться еще и фон.

Переписал игру, теперь она в цвете, показыват мультик жизни колонии, считает поколения.

А вот слово MAX-XY в WindowsXP rus неверно выдает максимальные размеры текстового окна. Ширину выдала 128 при установленной 80, а высоту 43 при установленных 40.

Сегодня перешел работать в Far с подключенным модулем colorer. В основном из-за проблемы с русскими кодировками. Плюс подсветка синтаксиса очень удобна. Но во время отладки с такой тоской вспоминаю запуск по F8... Работать в Far можно более менее комфортно только при установленной большой высоте, 24 стандартных строк очень мало.

Главы 12, 13, 14

Глава 12. Редакторы форта. Много интересного для себя я там не узнал. Можно порекомендовтаь в качестве исторической справки "как это было". Да еще показало, что текстовый редактор в принципе несложно написать. Приехали.

Следующая глава посвящено стилю работы с Forth Довольно полезная. Она больше филосовская. Плохо что все разбросано по всему тексту. не бы сейчас подошло бы больше краткая форма изложения. И, конечно, ориентация на блоки, тоже несколько портит восприятие – я-то веду разработку в файлах.

Глава 14. Память Форта. Словари.

Предлагается неплохая идея для определения карты памяти Forth Но не совсем понятно зачем это нужно. А во вторых идея сработает, только если принято подобное предустановленное разделение памяти. Часть объектов интерпретатора SP-Forth – другие. Например, хотя TIB и поддерживается, использовать его не рекомендуется.

Хм, действительно HERE в SP-Forth определено через DP Взято из spf_compile.f

: HERE ( – addr ) \ 94
  DP @
 DUP TO :-SET
 DUP TO J-SET
;

а само DP переопределяется в spf_compile0.f как

: DP ( – addr ) \ переменная, содержащая HERE сегмента данных
  IS-TEMP-WL
 IF GET-CURRENT 6 CELLS + ELSE (DP) THEN
;

как все загадочно... я думал, что все попроще.

память, начиная с HERE и далее, используется оператором WORD в качестве временного буфера или области для запоминания, а "плавающая" зона, отстоящая от HERE на фиксированное число байтов, является временным буфером, адрес которого сообщает PAD. Мне бы было бы проще думать об каких-то абстрактных участках памяти – буферах, с которыми работают те или иные слова.

И пошло описание реализации словарных статей Forth И зачем??? Меня сейчас очень живо интерсеует концепция словарей, управление ими. Может в SP-Forth другой механизм организации словарей... Блин, на сейчас это лишнее!

Создание нового контексного словаря – VOCABULARY

Адрес первого просматриваемого словаря – CONTEXT

Адрес подключенного контексного словаря – CURRENT

Сделать списком компиляции тот же список слов, что и первый список в порядке – DEFINITIONS Определен в compiler\spf_find.f Вообще там собраны все слова для работы со словарями, кажется.

  ИмяСловаря  DEFINITIONS

Основная причина сипользования контексных словарей – можно описывать наборы слов с идентичными именами, но с различными функциями, так что они не будут мешать друг другу.

 VOCABULARY HELPS   \ Создал новый словарь с именем HELPS
 HELPS DEFINITIONS  \ Сделал словарь HELPS текущим для помещения в него
                    \ ниже вводимых определений

: DUP ." = stack (n - n n) " CR ; \ попадет в словарь HELPS : DROP ." = stack (n - ) " CR ; \ тоже в HELPS FORTH DEFINITIONS \ восстанавливаю компиляцию на основной словарь

и... в таком виде работать не будет!! Выругается что не найдено слово DEFINITIONS. Этот пример также приведен в справочнике - docs/papers/spf_help.chm А вот такой код работать будет! И заодно разбираемся как он работает.

VOCABULARY HELP_S   \ Создал новый словарь с именем HELPS
GET-CURRENT         \ в стек положил ИД текущего списка словарей
ALSO                \ продублировал в списке поиска ИД верхнего словаря
HELP_S              \ Заменил верхний словарь в списке поиска на словарь HELPS
DEFINITIONS         \ включил его еще в список поиска 
                    \ на стеке у меня лежит какой-то ИД  
 : DUP ." = stack (n - n n) " CR ;  \ попадет в словарь HELPS
 : DROP ." = stack (n - ) " CR   ;  \ тоже в HELPS

PREVIOUS \ удалил с вершины списка словарей поиска верхний словарь SET-CURRENT \ взял со стека ИД предыдущего словаря и сделал его текущим \ куда будут помещаться определения

Блин! Блин! Есть два списка словарей: для компиляциии и для поиска. ну хрен его разберешься... Вроде въехал. Есть список словарей для поиска и один, куда помещаются все вновь вводимые определения. Вроде так... В итоге, общая схема должна выглядеть так

VOCABULARY НовыйСловарь
GET-CURRENT ALSO НовыйСловарь DEFINITIONS ( ИДСтарогоСловаря – )
  ..............
  Определения слов для этого НовогоСловаря
  ..............
PREVIOUS SET-CURRENT

Хух, блин. Намучаешься тут с такими словарями. А вот динамическое переключение словарей.

ALSO     \ продублировали верхний словарь в списке поиска
HELPS    \ установили поиск производить с нового словаря
  .....

PREVIOUS \ вернул список словарей к первоначальному поиску...

Если принять парадигму, что все слова всегда компилируются в верхний словарь, то все несколько упрощаетяс и стек данных остается чистым

VOCABULARY НовыйСловарь
ALSO НовыйСловарь DEFINITIONS

........

PREVIOUS \ вернулся к предыдущему словарю DEFINITIONS \ и новые определения буду попадать теперь в него

Через задницу сделано упраление словарями! Указатель на компилируемый словарь нужно поместить в переменную и работать с ней так как с BASE. Управление стеком словарей можно сделать словами с подобными сокращеняим уже принятых. Например, так

 >V – переместить верхний ИД словаря в стек данных
 V> – положить ИД словаря со стека данных на вершину стека словарей
 NewVoc – создать новый словарь и положить его ИД на вершину стека словарей

Пример со справкой у меня выглядит вот так

VOCABULARY HELPS
ALSO HELPS DEFINITIONS  \ Сделал словарь HELPS текущим для помещения в него

: DUP ." = stack (n - n n) " CR PREVIOUS ; : DROP ." = stack (n - ) " CR PREVIOUS ;

PREVIOUS DEFINITIONS

: man ALSO HELPS ;

\ Использование man DUP

Но есть два недостатка. Второе слово всегда рассматривается как запрос на справку, и если оно не найдено, то будет выполнено рабочее. Исправленный вариант стал болле походить на то, что приведено в книжке

VOCABULARY HELPS
ALSO HELPS DEFINITIONS

: DUP ." = stack (n - n n) " CR ; : DROP ." = stack (n - ) " CR ;

PREVIOUS DEFINITIONS

: man ALSO HELPS ' DUP ['] HELPS \ слова из HELPS будут иметь ИД больше самого ИД словаря, \ т.к. были определены позже него > IF EXECUTE ELSE DROP ." Don't find" CR THEN

PREVIOUS ;

Но все равно одна непрятность осталась. Если слово вообще не найдено ни в одном словаре, то транслятор выдаст ошибку.

Исправленный вариант. Реагирует правильно на отсутсвующие слова, на не введенные параметры. Пока не может искать без учета регистра. Использует не специфичные слова SP-Forth

VOCABULARY HELPS
ALSO HELPS DEFINITIONS

: DUP ." = stack (n - n n) " CR ; : DROP ." = stack (n - ) " CR ;

PREVIOUS DEFINITIONS

: manman ." Справка. Использование: man слово" CR ;

: man ALSO HELPS NextWord \ Беру следующее слово после man ( с-addr u )

DUP 0= IF 2DROP manman EXIT THEN \ если ничего не ввели

SFIND \ ищу это слово в словаре \ если слово не найдено, то (с-addr u 0) 0= IF 2DROP ." Слово не найдено" CR PREVIOUS EXIT THEN \ Если слово было найдено то (ИДслова 1|-1) DUP ['] HELPS \ слова из HELPS будут иметь ИД больше самого ИД словаря, \ т.к. были определены позже него > IF EXECUTE \ если слово из этого словаря, то выполняю его ELSE DROP ." Don't find" CR PREVIOUS EXIT \ в противном случае -- выход THEN ;

А на сегодня все.

<<< Предыдущий Начало   Следующий >>>
Copyright © Alex Furashev 2004

При цитировании, ссылка на оригинальный текст обязательна. Допускается копирование материалов только целиком, без внесения каких-либо изменений в оригинальный текст, меняющих смысл, структуру материала и проч.

Hosted by uCoz