Сценарий реализует классическую игру “Жизнь” (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)