Игра Конвея Жизнь на Лампанели - Assembler

Узнай цену своей работы

Формулировка задачи:

Студенты тут часто постят задания связанные с какой-то Лампанелью. Я тут решил постичь это извращение. Памяти всего 256 байт на код, данные и стек, только 4 регистра и весьма убогая система команд, к тому-же расходующая память по 1 или 2 слова на команду. Оооо.... Изврат еще тот ! Надо попробовать утрамбовать в нее что-нибудь стоящее. И я утрамбовал. Игра Конвея Жизнь на Лампанели. Занимает все 256 байт памяти ровно. Включая 2 слова под стек. Использует ресурсы на 100%. До донышка. Упс ... Только это написал, как сократил код еще на пять слов. Так-что пять слов вышли свободны. Перебор, однако... Эт я перестарался.
MAIN:
MOV     @KOLONIJA, R3
OUT     (R3)+, P0    ;Вывод колонии на лампы Лампанели
OUT     (R3)+, P1
OUT     (R3)+, P2
OUT     (R3)+, P3
OUT     (R3)+, P4
OUT     (R3)+, P5
OUT     (R3)+, P6
OUT     (R3)+, P7
IN      P0, (R3)+
IN      P1, (R3)+
IN      P2, (R3)+
IN      P3, (R3)+
IN      P4, (R3)+
IN      P5, (R3)+
IN      P6, (R3)+
IN      P7, (R3)+
MOV     7F, R3       ;Здесь будем перебирать клетки вселенной 7F..0
SCAN:
XOR     R2, R2       ;Здесь будем считать соседей
CALL    SOSED_PRAVEE ;Есть ли сосед справа ?
SUB     10, R3
CALL    SOSED        ;Есть ли сосед справа-сверху ?
ADD     1, R3
CALL    SOSED        ;Есть ли сосед сверху ?
ADD     1, R3
CALL    SOSED        ;Есть ли сосед слева-сверху ?
ADD     10, R3
CALL    SOSED        ;Есть ли сосед слева ?
ADD     10, R3
CALL    SOSED        ;Есть ли сосед слева-снизу ?
CALL    SOSED_PRAVEE ;Есть ли сосед снизу ?
CALL    SOSED_PRAVEE ;Есть ли сосед справа-снизу ?
SUB     F, R3        ;Вернемся к своей клетке
CALL    OFFS_MASK
ADD     D2, R1       ;Лампанель ADD @KOLONIJA,R1 не понимает
CMP     2, R2        ;Если соседей < 2, то одиночество
JL      DEATH
CMP     3, R2
JG      DEATH        ;Если соседей > 3, то перенаселение
JNZ     @            ;Если соседей 3, то заселение клетки
OR      R0, (R1)     ;Рождение
JMP     @
DEATH:
NOT     R0
AND     R0, (R1)     ;Смерть
@:
SUB     1, R3        ;Следующая клетка
JGE     SCAN         ;Последняя ?
JMP     MAIN         ;Следующий шаг Жизни
 
OFFS_MASK:           ;Из номера клетки в R3 смещение в R1 и маску в R0
MOV     R3, R1
SHR     3, R1
MOV     R3, R0
AND     7, R0
ADD     CA, R0       ;Лампанель ADD @TABLE,R0 не понимает
MOVB    (R0), R0     ;Чтение маски из таблицы
AND     FF, R0
RET
 
SOSED_PRAVEE:
SUB     1, R3
SOSED:
CMPB    0, R3
JL      @@           ;Переход, если клетка за пределами вселенной
CALL    OFFS_MASK
ADD     E2, R1       ;Лампанель ADD @KOLONIJA_DO,R1 не понимает
AND     (R1), R0
JZ      @@
ADD     1, R2        ;Нашли еще одного соседа
@@:
RET
 
TABLE:               ;Таблица "номер_бита->маска" (тут адрес CA)
DATA    0201
DATA    0804
DATA    2010
DATA    8040
 
KOLONIJA:            ;Начальная и следующая колония (тут адрес D2):
DATA    0            ;Caterer
DATA    200          ;
DATA    8F0          ; (поставщик)
DATA    880          ; -
DATA    800          ; осциллятор
DATA    100          ;
DATA    600          ; периода
DATA    0            ; 3
KOLONIJA_DO:
;Тут адрес E2. Далее 8 слов под предыдущую колонию,
; пять неиспользованных слов и два слова под стек
В игру вставлен осциллятор игры Жизнь периода 3, который имеет собственное имя "поставщик". Это самый маленький из осцилляторов периода 3. Вот он и должен осциллировать на светодиодах Лампанели. Считаю эти светодиоды полем для Жизни 16*8. Зажженный светодиод - существо. Погашенный - пустая клетка. Вместо "поставщика" можно воткнуть любую другую колонию 16*8 после метки KOLONIJA Но эмулятор Лампанель так написан, что запустить эмуляцию в каком-то реальном времени я не понял как. Приходится 10 минут ждать пока Лампанель обсчитает колонию существ Жизни 16*8 с подсветкой исполнения команд. Т.е. 10 минут на один шаг игры Жизнь. Как эту подсветку отключить ? З.Ы. Осциллятор - это колония существ, которая после нескольких изменений возвращается к своему первоначальному виду. В данном случае такой возврат произойдет на 3-й шаг. Т.е период осциллятора 3. А самый длинный период среди найденных осцилляторов это 200
@Mikl От теперь я знаю толк в извращениях P.S. Поправил код чтоб быстрее был. P.P.S. И еще раз поправил.
P.P.S. Да, забыл. Здесь в алгоритме считается, что правая кромка поля лампочек 16*8 склеена с левой со сдвигом на одну клетку вверх по вертикали, а вот верхняя и нижняя границы абсолютные. Т.е. жизнь как бы идет на боковой поверхности чуть кривовато склеенного цилиндра. Сия топология суть последствия злостной нехватки ресурсов.

Решение задачи: «Игра Конвея Жизнь на Лампанели»

textual
Листинг программы
;Игра Конвея "Жизнь" во вселенной 16*8 с топологией тора
TABLE:               ;Таблица "номер_бита->маска"
DATA    01           ;NOP  Проедемся по данным, как по коду
DATA    02           ;NOP  Проедемся по данным, как по коду
DATA    04           ;NOP  Проедемся по данным, как по коду
DATA    08           ;NOP  Проедемся по данным, как по коду
DATA    10           ;NOP  Проедемся по данным, как по коду
DATA    20           ;NOP  Проедемся по данным, как по коду
DATA    40           ;NOP  Проедемся по данным, как по коду
DATA    80           ;NOP  Проедемся по данным, как по коду
MAIN:
MOV     @KOLONIJA, R2
MOV     R2, R1
OUT     (R2)+, P0    ;Вывод колонии на лампы Лампанели
OUT     (R2)+, P1
OUT     (R2)+, P2
OUT     (R2)+, P3
OUT     (R2)+, P4
OUT     (R2)+, P5
OUT     (R2)+, P6
OUT     (R2)+, P7
MOV     R2, R0
@:
MOV     (R1)+, (R2)+ ;Копирование текущей колонии в предыдущую
CMP     R0, R1
JNZ     @
MOV     FE, R3       ;Здесь будем перебирать клетки вселенной (7F..0)*2
SCAN:
XOR     R2, R2       ;Здесь будем считать соседей
CALL    SOSED_PRAVEE ;Есть ли сосед справа ?
SUB     20, R3
CALL    SOSED        ;Есть ли сосед справа-сверху ?
ADD     2, R3
CALL    SOSED        ;Есть ли сосед сверху ?
ADD     2, R3
CALL    SOSED        ;Есть ли сосед слева-сверху ?
ADD     20, R3
CALL    SOSED        ;Есть ли сосед слева ?
ADD     20, R3
CALL    SOSED        ;Есть ли сосед слева-снизу ?
CALL    SOSED_PRAVEE ;Есть ли сосед снизу ?
CALL    SOSED_PRAVEE ;Есть ли сосед справа-снизу ?
SUB     1E, R3       ;Вернемся к своей клетке
CALL    OFFS_MASK
ADD     BE, R1       ;Лампанель ADD @KOLONIJA,R1 не понимает
CMP     2, R2        ;Условия :
JZ      @@           ; если соседей < 2, то смерть от одиночества
OR      R0, (R1)     ;Рождение
CMP     3, R2        ; если соседей > 3, то смерть от перенаселения
JZ      @@           ; если у пустой клетки соседей 3, то заселение
XOR     R0, (R1)     ;Смерть
@@:
SUB     2, R3        ;Следующая клетка
JGE     SCAN         ;Последняя ?
JMP     MAIN         ;Следующий шаг Жизни
 
OFFS_MASK:           ;Из номера клетки в R3 смещение в R1 и маску в R0
MOV     R3, R1
SHL     8, R1        ;Топология вселенной Жизни - тор
SHR     C, R1
MOV     R3, R0
AND     E, R0
MOV     (R0), R0     ;Чтение маски из таблицы
RET
 
SOSED_PRAVEE:
SUB     2, R3
SOSED:
CALL    OFFS_MASK
ADD     CE, R1       ;Лампанель ADD @KOLONIJA_DO,R1 не понимает
AND     (R1), R0     ;Клетка пустая или заселенная ?
JZ      @@@
ADD     1, R2        ;Нашли еще одного соседа
@@@:
RET
 
KOLONIJA:            ;Начальная и следующая колония (тут адрес BE):
DATA    0            ;Caterer
DATA    200          ;
DATA    8F0          ; (поставщик)
DATA    880          ; -
DATA    800          ; осциллятор
DATA    100          ;
DATA    600          ; периода
DATA    0            ; 3
KOLONIJA_DO:
;Тут адрес CE. Далее восемь слов под предыдущую колонию,
; пятнадцать неиспользованных слов и два слова под стек

Объяснение кода листинга программы

  1. Первая часть кода (до строки с меткой MAIN) занимается поиском соседей для текущей клетки и выполнением условий для рождения, смерти от перенаселения или смерти от одиночества. Для этого используется цикл, который проходит по всем соседям клетки.
  2. Вторая часть кода (с строки с меткой MAIN) занимается выводом текущей колонии на лампы Лампанели и переходом к следующей клетке.
  3. Третья часть кода (с строки с меткой OFFS_MASK) занимается получением смещения и маски для следующей клетки.
  4. Четвертая часть кода (с строки с меткой SOSED_PRAVEE) используется для проверки наличия соседа справа-сверху и вызова соответствующей процедуры.
  5. Пятая часть кода (с строки с меткой SOSED) используется для проверки наличия соседа справа-сверху-сверху и вызова соответствующей процедуры.
  6. Шестая часть кода (с строки с меткой SOSED) используется для проверки наличия соседа слева-сверху и вызова соответствующей процедуры.
  7. Седьмая часть кода (с строки с меткой SOSED) используется для проверки наличия соседа слева-снизу и вызова соответствующей процедуры.
  8. Восьмая часть кода (с строки с меткой CMP) используется для проверки наличия соседа справа-снизу и вызова соответствующей процедуры.
  9. Девятая часть кода (с строки с меткой CMP) используется для проверки наличия соседа слева-снизу и вызова соответствующей процедуры.
  10. Десятая часть кода (с строки с меткой CMP) используется для проверки наличия соседа справа-снизу и вызова соответствующей процедуры.
  11. В первой части кода (до строки с меткой MAIN) используются следующие переменные: R0, R1, R2, R3, C, E, FE, KOLONIJA, R200, KOLONIJA_DO, CE, P0, P1, P2, P3, P4, P5, P6, P7, @, @@, @@@.
  12. Во второй части кода (с строки с меткой MAIN) используются следующие переменные: R0, R1, R2, R3, @, KOLONIJA, R2.
  13. В третьей части кода (с строки с меткой OFFS_MASK) используются следующие переменные: R3, R1, C, R0, E, R0.
  14. В четвертой части кода (с строки с меткой SOSED_PRAVEE) используются следующие переменные: R3, R0, R1, R2, @@.
  15. В пятой части кода (с строки с меткой SOSED) используются следующие переменные: R3, R0, R1, R2, @@.
  16. В шестой части кода (с строки с меткой SOSED) используются следующие переменные: R3, R0, R1, R2, @@.
  17. В седьмой части кода (с строки с меткой SOSED) используются следующие переменные: R3, R0, R1, R2, @@.
  18. В восьмой части кода (с строки с меткой CMP) используются следующие переменные: R0, R1, R2, R3, @.
  19. В девятой части кода (с строки с меткой CMP) используются следующие переменные: R0, R1, R2, R3, @.
  20. В десятой части кода (с строки с меткой CMP) используются следующие переменные: R0, R1, R2, R3, @.

ИИ поможет Вам:


  • решить любую задачу по программированию
  • объяснить код
  • расставить комментарии в коде
  • и т.д
Попробуйте бесплатно

Оцени полезность:

8   голосов , оценка 4.5 из 5