Игра Конвея Жизнь на Лампанели - Assembler
Формулировка задачи:
Студенты тут часто постят задания связанные с какой-то Лампанелью.
Я тут решил постичь это извращение. Памяти всего 256 байт на код,
данные и стек, только 4 регистра и весьма убогая система команд,
к тому-же расходующая память по 1 или 2 слова на команду.
Оооо.... Изврат еще тот !
Надо попробовать утрамбовать в нее что-нибудь стоящее.
И я утрамбовал.
Игра Конвея Жизнь на Лампанели. Занимает все 256 байт памяти ровно.
Включая 2 слова под стек. Использует ресурсы на 100%. До донышка.
Упс ... Только это написал, как сократил код еще на пять слов.
Так-что пять слов вышли свободны. Перебор, однако... Эт я перестарался.
В игру вставлен осциллятор игры Жизнь периода 3, который имеет собственное
имя "поставщик". Это самый маленький из осцилляторов периода 3. Вот он и
должен осциллировать на светодиодах Лампанели. Считаю эти светодиоды полем
для Жизни 16*8. Зажженный светодиод - существо. Погашенный - пустая клетка.
Вместо "поставщика" можно воткнуть любую другую колонию 16*8 после метки KOLONIJA
Но эмулятор Лампанель так написан, что запустить эмуляцию в каком-то
реальном времени я не понял как. Приходится 10 минут ждать пока Лампанель
обсчитает колонию существ Жизни 16*8 с подсветкой исполнения команд.
Т.е. 10 минут на один шаг игры Жизнь. Как эту подсветку отключить ?
З.Ы.
Осциллятор - это колония существ, которая после нескольких изменений
возвращается к своему первоначальному виду. В данном случае такой возврат
произойдет на 3-й шаг. Т.е период осциллятора 3. А самый длинный период
среди найденных осцилляторов это 200
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 слов под предыдущую колонию, ; пять неиспользованных слов и два слова под стек
@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. Далее восемь слов под предыдущую колонию, ; пятнадцать неиспользованных слов и два слова под стек
Объяснение кода листинга программы
- Первая часть кода (до строки с меткой MAIN) занимается поиском соседей для текущей клетки и выполнением условий для рождения, смерти от перенаселения или смерти от одиночества. Для этого используется цикл, который проходит по всем соседям клетки.
- Вторая часть кода (с строки с меткой MAIN) занимается выводом текущей колонии на лампы Лампанели и переходом к следующей клетке.
- Третья часть кода (с строки с меткой OFFS_MASK) занимается получением смещения и маски для следующей клетки.
- Четвертая часть кода (с строки с меткой SOSED_PRAVEE) используется для проверки наличия соседа справа-сверху и вызова соответствующей процедуры.
- Пятая часть кода (с строки с меткой SOSED) используется для проверки наличия соседа справа-сверху-сверху и вызова соответствующей процедуры.
- Шестая часть кода (с строки с меткой SOSED) используется для проверки наличия соседа слева-сверху и вызова соответствующей процедуры.
- Седьмая часть кода (с строки с меткой SOSED) используется для проверки наличия соседа слева-снизу и вызова соответствующей процедуры.
- Восьмая часть кода (с строки с меткой CMP) используется для проверки наличия соседа справа-снизу и вызова соответствующей процедуры.
- Девятая часть кода (с строки с меткой CMP) используется для проверки наличия соседа слева-снизу и вызова соответствующей процедуры.
- Десятая часть кода (с строки с меткой CMP) используется для проверки наличия соседа справа-снизу и вызова соответствующей процедуры.
- В первой части кода (до строки с меткой MAIN) используются следующие переменные: R0, R1, R2, R3, C, E, FE, KOLONIJA, R200, KOLONIJA_DO, CE, P0, P1, P2, P3, P4, P5, P6, P7, @, @@, @@@.
- Во второй части кода (с строки с меткой MAIN) используются следующие переменные: R0, R1, R2, R3, @, KOLONIJA, R2.
- В третьей части кода (с строки с меткой OFFS_MASK) используются следующие переменные: R3, R1, C, R0, E, R0.
- В четвертой части кода (с строки с меткой SOSED_PRAVEE) используются следующие переменные: R3, R0, R1, R2, @@.
- В пятой части кода (с строки с меткой SOSED) используются следующие переменные: R3, R0, R1, R2, @@.
- В шестой части кода (с строки с меткой SOSED) используются следующие переменные: R3, R0, R1, R2, @@.
- В седьмой части кода (с строки с меткой SOSED) используются следующие переменные: R3, R0, R1, R2, @@.
- В восьмой части кода (с строки с меткой CMP) используются следующие переменные: R0, R1, R2, R3, @.
- В девятой части кода (с строки с меткой CMP) используются следующие переменные: R0, R1, R2, R3, @.
- В десятой части кода (с строки с меткой CMP) используются следующие переменные: R0, R1, R2, R3, @.
ИИ поможет Вам:
- решить любую задачу по программированию
- объяснить код
- расставить комментарии в коде
- и т.д