article
Клеточный автомат Жизнь
Сценарий реализует классическую игру “Жизнь” (Conway’s Game of Life).
Сценарий предназначен для демонстрации возможностей контроллера Telematic.


Алгоритм
Основные действия сценария включают:
- Инициализация поля: Создается пустое поле, после чего случайным образом активируются определенное количество клеток.
- Отображение поля: Активные клетки отображаются на дисплее контроллера в виде небольших прямоугольников.
- Подсчет соседей и обновление поколения: Для каждой клетки подсчитывается количество живых соседей, и на основе правил игры определяется, остается ли клетка живой, умирает или появляется новая.
- Управление процессом: Пользователь может запускать или останавливать симуляцию, а также наблюдать за текущим этапом и количеством живых клеток.
Возможности
- Настраиваемое начальное состояние: Пользователь может задать количество исходных живых клеток через регистр
rInitCellCount
, что позволяет варьировать начальные условия симуляции. - Управление симуляцией: Флаг
rIsRun
позволяет запускать и останавливать процесс моделирования игры. - Отслеживание прогресса: Регистры
rPhase
иrCellCount
предоставляют информацию о текущем этапе симуляции и количестве живых клеток соответственно. - Графическое отображение: Обновление дисплея происходит с интервалом 0.25 секунд, что обеспечивает плавную анимацию развития клеточного автомата.
Производительность
Замеры осуществлялись на тестовом образце
Время компиляции | 44 мс |
Среднее время выполнения тела цикла | 110 мс |
Использование стека | 408 байт (4.9%) |
Использование кучи | 3984 байт (6.6%) |
Сценарий
from display import rect, update, clear
from array import array
from dev import run, count, webconf, Reg
from random import randint
CELL_SIZE = const(4)
WIDTH = 128 // CELL_SIZE
HEIGHT = 64 // CELL_SIZE
TOTAL_CELLS = WIDTH * HEIGHT
# Создать пустое поле
def create_field():
return array('B', [0] * TOTAL_CELLS)
# Чтение значения клетки
def field_get(field, x, y):
if 0 <= x < WIDTH and 0 <= y < HEIGHT:
return field[y * WIDTH + x]
return 0 # Возвращаем 0 для границ
# Запись значения клетки
def field_set(field, x, y, val):
if 0 <= x < WIDTH and 0 <= y < HEIGHT:
field[y * WIDTH + x] = val
# Отображение поля
def display_field(field):
clear()
for index in range(TOTAL_CELLS):
if field[index] == 1:
x = index % WIDTH
y = index // WIDTH
rect(x * CELL_SIZE, y * CELL_SIZE, CELL_SIZE, CELL_SIZE)
update(False)
# Подсчёт живых соседей
def count_neighbors(field, x, y):
neighbors = 0
width_limit = WIDTH - 1
height_limit = HEIGHT - 1
for dy in (-1, 0, 1):
ny = y + dy
if 0 <= ny <= height_limit:
for dx in (-1, 0, 1):
if dx == 0 and dy == 0:
continue
nx = x + dx
if 0 <= nx <= width_limit:
neighbors += field[ny * WIDTH + nx]
return neighbors
# Шаг симуляции
def next_generation(current_field, next_field):
count = 0
for y in range(HEIGHT):
for x in range(WIDTH):
index = y * WIDTH + x
neighbors = count_neighbors(current_field, x, y)
cell = current_field[index]
# Применяем правила игры
if cell == 1 and neighbors in (2, 3):
next_field[index] = 1
count += 1
elif cell == 0 and neighbors == 3:
next_field[index] = 1
count += 1
else:
next_field[index] = 0
return count
# Устанавливаем начальную конфигурацию
current_field = create_field()
next_field = create_field()
# Конфигурацию пользовательских регистров
count(Reg=4)
rInitCellCount = Reg(0).conf(type='int', name='Исходное кол-во клеток', access='w', limits=[32, TOTAL_CELLS//2], default=(TOTAL_CELLS // 4))
rIsRun = Reg(1).conf(type='bool', name='Игра (Старт/Стоп)', access='w', default=0)
rPhase = Reg(2).conf(type='int', name='Этап', access='r')
rCellCount = Reg(3).conf(type='int', name='Кол-во клеток', access='r')
webconf(Reg=True, Display=True)
# Инициализация игры
def init():
global current_field, rPhase, rInitCellCount
rPhase.val(0)
c = rInitCellCount.val()
while c > 0:
x = randint(0, WIDTH - 1)
y = randint(0, HEIGHT - 1)
if field_get(current_field, x, y) == 0:
field_set(current_field, x, y, 1)
c -= 1
# Шаг алгоритма
def step():
global current_field, next_field, rPhase, rIsRun, rCellCount
if rIsRun.changed() and rIsRun.val():
init()
if not rIsRun.val():
return
count = next_generation(current_field, next_field)
rCellCount.val(count)
display_field(next_field)
current_field, next_field = next_field, current_field
rPhase.inc()
# Запуск игры
init()
rIsRun.on()
run(step, 0.25)