Сценарий реализует классическую игру “Жизнь” (Conway’s Game of Life).

Сценарий предназначен для демонстрации возможностей контроллера Telematic.

Скриншот панели управления Скриншот панели управления

Алгоритм

Основные действия сценария включают:

  1. Инициализация поля: Создается пустое поле, после чего случайным образом активируются определенное количество клеток.
  2. Отображение поля: Активные клетки отображаются на дисплее контроллера в виде небольших прямоугольников.
  3. Подсчет соседей и обновление поколения: Для каждой клетки подсчитывается количество живых соседей, и на основе правил игры определяется, остается ли клетка живой, умирает или появляется новая.
  4. Управление процессом: Пользователь может запускать или останавливать симуляцию, а также наблюдать за текущим этапом и количеством живых клеток.

Возможности

  • Настраиваемое начальное состояние: Пользователь может задать количество исходных живых клеток через регистр 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)