День 7. Пишу дальше игру Жизнь

День 7. Пишу дальше игру Жизнь

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

Хотя и советуют писать корткие определения, пока это не очень получается. Все равно они довольно большие получаются.

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

\ Создание и работа с матрицами

USER Матр

: СоздатьМатрицу ( ширин высот адр ) \ ширин и высота -- кол-во элементов, поэтому отсчет 1! DUP @ 1000 > IF \ Освобождение памяти, если есть указатель - DUP FREE DROP \ какое-то относит. большое положит. число THEN

ROT ( высот адр ширин ) DUP 1 < IF \ Проверка диапазона DROP 1 THEN

ROT ( адр ширин высот ) DUP 1 < IF \ Проверка диапазона DROP 1 THEN \ получили длину + 2 ячейки под размер матрицы OVER OVER * 1+ ( адр ширин высот длин ) ALLOCATE IF 2DROP 0 ! \ если не удалось выделить память -- выход, и нулевой адрес EXIT THEN ( адр ширин высот адрМатр ) ROT OVER ! ( адр высот адрМатр ) \ сохранил ширину матрицы SWAP OVER CELL+ ! ( адр адрМатр ) \ сохранил высоту матрицы SWAP ! \ сохранил адрес матрицы в переменной ;

: ШиринаМатрицы ( адрМатр ) @ \ получил адрес памяти матрицы @ \ только теперь ширину ; ( шир )

: ВысотаМатрицы ( адрМатр ) @ CELL+ @ ; ( выс )

: ЭлМатрицы ( х у адрМатр ) \ координаты начинаются с 0 !!! ROT ( y адрМатр x ) DUP 0< IF \ если х вышел за пределы диапазона, то возвращаю 0 DROP 2DROP 0 EXIT THEN ( y адрМатр x ) DUP 2 PICK ШиринаМатрицы 1- > IF \ должен быть строго меньше границы DROP 2DROP 0 EXIT THEN ( y адрМатр x ) ROT ( адрМатр x y ) DUP 0< IF \ если y вышел за пределы диапазона, то возвращаю 0 DROP 2DROP 0 EXIT THEN DUP 3 PICK ВысотаМатрицы 1- > IF DROP 2DROP 0 EXIT THEN ( адрМатр x y ) \ проверку дипапазона закончили

2 PICK ВысотаМатрицы * + \ преобразовали двумерные координат в одномерные 1+ \ с учетом 2-х служебных ячеек CELL * \ получили адрес элемента относит блока памяти SWAP @ \ адрес блока памяти + @ \ абс. адрес элемента и его значение ;

: =ЭлМатрицы ( знач х у адрМатр ) \ координаты начинаются с 0 !!! ROT ( знач y адрМатр x ) DUP 0< IF \ если х вышел за пределы диапазона, то возвращаю 0 2DROP 2DROP EXIT THEN ( знач y адрМатр x ) DUP 2 PICK ШиринаМатрицы 1- > IF \ должен быть строго меньше границы 2DROP 2DROP EXIT THEN ( знач y адрМатр x ) ROT ( знач адрМатр x y ) DUP 0< IF \ если y вышел за пределы диапазона, то возвращаю 0 2DROP 2DROP 0 EXIT THEN DUP 3 PICK ВысотаМатрицы 1- > IF DROP 2DROP 0 EXIT THEN ( знач адрМатр x y ) \ проверку дипапазона закончили

2 PICK ВысотаМатрицы * + \ преобразовали двумерные координат в одномерные 1+ \ с учетом 2-х служебных ячеек CELL * \ получили адрес элемента относит блока памяти SWAP @ \ адрес блока памяти + \ абс. адрес элемента ! \ запоминаю его значение ;

: ОчиститьМатрицу ( адрМатр ) DUP ВысотаМатрицы 0 DO DUP ШиринаМатрицы 0 DO 0 J I 3 PICK =ЭлМатрицы LOOP LOOP ;

\ --- Тестирование определений ----- 0 Матр ! 15 14 Матр СоздатьМатрицу

\ 900 14 3 Матр =ЭлМатрицы \ Работает \ 14 3 Матр ЭлМатрицы . \ Работает Матр ОчиститьМатрицу

и тут ополучил уже встреченную ранее проблему с циклом DO. Слово ОчиститьМатрицу завершалось аврийно. Стоило мне только из циклов убрать обращения к счетчикам:

: ОчиститьМатрицу ( адрМатр )
 DUP ВысотаМатрицы 0 DO
 DUP ШиринаМатрицы 0 DO
        0 10 11 3 PICK =ЭлМатрицы
 LOOP
 LOOP
;

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

: ОчиститьМатрицу ( адрМатр )
 DUP ВысотаМатрицы 0 DO
 DUP ШиринаМатрицы 0 DO
       I DROP
        0 10 11 3 PICK =ЭлМатрицы
 LOOP
 LOOP
;

ЕСТЬ!!! Два часа бдений и ошибка была найдена. Для этого была отключено расширение – организация словарей на основе хэш-таблиц. В spf.ini закоментирвоал обратно строку

\ REQUIRE QuickSWL ~pinka\spf\quick-swl2.f

и сразу полезли ошибки в слове ОчиститьМатрицу Методом последовательного исключения выяснил, что во время выделения памяти под Матрицу в слове СоздатьМатрицу я определял размер места в ячейках, но не масштабировал их на байты, поэтому места выделялось меньше! И соответсвенно, генерилось исключение.

Подправил слово, и тестовый вариант заработал.

: СоздатьМатрицу ( ширин высот адр ) \ ширин и высота -- кол-во элементов, поэтому отсчет 1!
 DUP @ 1000 > IF   \ Освобождение памяти, если есть указатель -
 DUP FREE DROP  \ какое-то относит. большое положит. число
 THEN

ROT ( высот адр ширин ) DUP 1 < IF \ Проверка диапазона DROP 1 THEN

ROT ( адр ширин высот ) DUP 1 < IF \ Проверка диапазона DROP 1 THEN \ получили длину + 2 ячейки под размер матрицы OVER OVER * 1+ ( адр ширин высот длин ) CELL * \ !!!! ВОТ ОНО -- Получили длину в байтах ! ALLOCATE IF 2DROP 0 ! \ если не удалось выделить память -- выход, и нулевой адрес EXIT THEN ( адр ширин высот адрМатр ) ROT OVER ! ( адр высот адрМатр ) \ сохранил ширину матрицы SWAP OVER CELL+ ! ( адр адрМатр ) \ сохранил высоту матрицы SWAP ! \ сохранил адрес матрицы в переменной ;

Но когда запустил нормальное слово ОчиститьМатрицу она опять завершалась аврийно.

: ОчиститьМатрицу ( адрМатр )
 DUP ВысотаМатрицы 0 DO
 DUP ШиринаМатрицы 0 DO
        0 I J 3 PICK =ЭлМатрицы
 LOOP
 LOOP
;

Уже понимая, что грабли где-то в неправильном выделении памяти и работы с ней решил посмотреть на каких значениях счетчиках сыпится слово. Его переправил вот так

: ОчиститьМатрицу ( адрМатр )
 DUP ВысотаМатрицы 0 DO
 DUP ШиринаМатрицы 0 DO
          I . J .
        0 I J 3 PICK =ЭлМатрицы
 LOOP
 LOOP
;

И увидел, что как раз на нулевых, т.е. слово =ЭлМатрицы на нулевых координатах явно не туда залазит. Тут уже быстро сообразил где может быть. Исправленное слово =ЭлМатрицы уже выглядило так.

: =ЭлМатрицы  ( знач х у адрМатр )    \ координаты начинаются с 0 !!!
 ROT       ( знач y адрМатр x )
 DUP 0< IF         \ если х вышел за пределы диапазона, то возвращаю 0
       2DROP 2DROP EXIT
 THEN    ( знач y адрМатр x )
 DUP 2 PICK ШиринаМатрицы 1- > IF  \ должен быть строго меньше границы
       2DROP 2DROP EXIT
 THEN   ( знач y адрМатр x )
 ROT  ( знач адрМатр x y )
 DUP 0< IF         \ если y вышел за пределы диапазона, то возвращаю 0
       2DROP 2DROP 0 EXIT
 THEN
 DUP 3 PICK ВысотаМатрицы 1- > IF
 DROP 2DROP 0 EXIT
 THEN
   ( знач адрМатр x y )    \ проверку дипапазона закончили

2 PICK ВысотаМатрицы * + \ преобразовали двумерные координат в одномерные 2+ \ ВОТ ОНО!!! 2 нужно прибавлять! с учетом 2-х служ ячеек CELL * \ получили адрес элемента относит блока памяти SWAP @ \ адрес блока памяти + \ абс. адрес элемента ! \ запоминаю его значение ;

Запустил – все заработало.

Попробовал подключить вновь созданную библиотеку – не получилось. Вообще, слово INCLUDED какое-то странное. Если не находит подключаемый файл, то интерпретатор говорит, что слово INCLUDED ... не найдено! Блин, это так поначалу с толку сбивает!

Ладно, прописал ему полный путь, файл увидел, а слов нем – нет. Т.е. поведение интерепретатора такое, будто определений в подключаемом файле нет!

 S" c:\spf\work\arr1.f" INCLUDED

ни хера не работает, блин!!!

Пришлось слить два файла в один.

После часа программирования игра, наконец, написана, работает. Последовательно отображает смену поколений при нажатии на любую клавишу, по клавише q – выход. Но только если ширина и высота совпадают. Где-то глУк. Завтра буду искать...

\  Life game
: СоздатьМатрицу ( ширин высот адр ) \ ширин и высота -- кол-во элементов, поэтому отсчет 1!
 DUP @ 1000 > IF   \ Освобождение памяти, если есть указатель -
 DUP FREE DROP  \ какое-то относит. большое положит. число
 THEN

ROT ( высот адр ширин ) DUP 1 < IF \ Проверка диапазона DROP 1 THEN

ROT ( адр ширин высот ) DUP 1 < IF \ Проверка диапазона DROP 1 THEN \ получили длину + 2 ячейки под размер матрицы OVER OVER * 1+ ( адр ширин высот длин ) CELL * \ Получили длину в байтах ! ALLOCATE IF 2DROP 0 ! \ если не удалось выделить память -- выход, и нулевой адрес EXIT THEN ( адр ширин высот адрМатр ) ROT OVER ! ( адр высот адрМатр ) \ сохранил ширину матрицы SWAP OVER CELL+ ! ( адр адрМатр ) \ сохранил высоту матрицы SWAP ! \ сохранил адрес матрицы в переменной ;

: ШиринаМатрицы ( адрМатр ) @ \ получил адрес памяти матрицы @ \ только теперь ширину ; ( шир )

: ВысотаМатрицы ( адрМатр ) @ CELL+ @ ; ( выс )

: ЭлМатрицы ( х у адрМатр ) \ координаты начинаются с 0 !!! ROT ( y адрМатр x ) DUP 0< IF \ если х вышел за пределы диапазона, то возвращаю 0 DROP 2DROP 0 EXIT THEN ( y адрМатр x ) DUP 2 PICK ШиринаМатрицы 1- > IF \ должен быть строго меньше границы DROP 2DROP 0 EXIT THEN ( y адрМатр x ) ROT ( адрМатр x y ) DUP 0< IF \ если y вышел за пределы диапазона, то возвращаю 0 DROP 2DROP 0 EXIT THEN DUP 3 PICK ВысотаМатрицы 1- > IF DROP 2DROP 0 EXIT THEN ( адрМатр x y ) \ проверку дипапазона закончили

2 PICK ВысотаМатрицы * + \ преобразовали двумерные координат в одномерные 2+ \ с учетом 2-х служебных ячеек CELL * \ получили адрес элемента относит блока памяти SWAP @ \ адрес блока памяти + @ \ абс. адрес элемента и его значение ;

: =ЭлМатрицы ( знач х у адрМатр ) \ координаты начинаются с 0 !!! ROT ( знач y адрМатр x ) DUP 0< IF \ если х вышел за пределы диапазона, то возвращаю 0 2DROP 2DROP EXIT THEN ( знач y адрМатр x ) DUP 2 PICK ШиринаМатрицы 1- > IF \ должен быть строго меньше границы 2DROP 2DROP EXIT THEN ( знач y адрМатр x ) ROT ( знач адрМатр x y ) DUP 0< IF \ если y вышел за пределы диапазона, то возвращаю 0 2DROP 2DROP 0 EXIT THEN DUP 3 PICK ВысотаМатрицы 1- > IF DROP 2DROP 0 EXIT THEN ( знач адрМатр 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 Среда ЭлМатрицы 0= IF ." " ELSE ." X" THEN LOOP

2 SPACES

Кол-воСоседей ШиринаМатрицы 0 DO J I Кол-воСоседей ЭлМатрицы . LOOP

CR LOOP ;

: ПоказатьСреду Среда ВысотаМатрицы 0 DO Среда ШиринаМатрицы 0 DO J I Среда ЭлМатрицы 0= IF ." " ELSE ." X" 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

ЗаселитьСреду \ Инициализировали РассчитатьКол-воСоседей

\ ПоказатьСовмещенно \ Для отладки BEGIN KEY 113 <> WHILE ПоказатьСреду ОбновитьСреду РассчитатьКол-воСоседей CR REPEAT

BYE ;

Main

А на сегодня – все!

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

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

Hosted by uCoz