Пишем игру "жизнь" на MATLAB

клеточный автомат, придуманный английским математиком в 1970 году by Grossmend (Декабрь 9, 2018 в 13:13)

Что наша жизнь? Игра!

Всем доброго времени суток. Сегодня посмотрим как реализовать простой алгоритм игры "жизнь". Удивительно в этой игре то, что при достаточно небольших правилах игры формируются огромные разнообразные формы. Итак приступим...

Игра «Жизнь» (англ. Conway's Game of Life) - клеточный автомат, придуманный английским математиком Джоном Конвеем в 1970 году.

Правила игры:

  • Место действия этой игры - «вселенная» - это размеченная на клетки поверхность или плоскость - безграничная, ограниченная, или замкнутая (в пределе - бесконечная плоскость).
  • Каждая клетка на этой поверхности может находиться в двух состояниях: быть «живой» (заполненной) или быть «мёртвой» (пустой). Клетка имеет восемь соседей, окружающих её.
  • Распределение живых клеток в начале игры называется первым поколением. Каждое следующее поколение рассчитывается на основе предыдущего по следующим правилам:

    1. в пустой (мёртвой) клетке, рядом с которой ровно три живые клетки, зарождается жизнь

    2. если у живой клетки есть две или три живые соседки, то эта клетка продолжает жить

    3. если у клетки меньше двух соседей, то эта клетка умирает от "одиночества"

    4. если у клетки больше трех соседей, то эта клетка умирает от "перенаселенности"
    Игрок не принимает прямого участия в игре, а лишь расставляет или генерирует начальную конфигурацию «живых» клеток, которые затем взаимодействуют согласно правилам уже без его участия (он является наблюдателем).

    Реализация:

    В функции "run_game_of_life.m" указываются параметры игры. Размер матрицы, начальная расстановка фигуры, кол-во поколений(итераций), также визуализация.

    
    % ----------------------------------------- параметры -----------------------------------------
    
    % размер решетки
    x = 150;
    y = 150;
    
    % кол-во итераций
    number_generation = 1000;
    
    % визуализация
    visual = true;
    
    % начальная матрица (пустая, небходимо присвоить значения)
    mat = zeros(x, y);
    
    % % генерируем случайные точки
    % idx = randsample(numel(mat), numel(mat)/10);
    % mat(idx) = 1;
    
    % при матрице(150x150) R-пентамино
    mat(75,76) = 1;
    mat(75,75) = 1;
    mat(76,75) = 1;
    mat(77,75) = 1;
    mat(76,74) = 1;
    
    % -------------------------------------------- main -------------------------------------------
    
    game_of_life(mat, number_generation, visual)
    
    Функция "game_of_life.m" состоит из четырех частей:
  • game_of_life - основной цикл программы
  • calcNeighbor - подсчет суммы соседних клеток
  • getNewMat - получение следующего поколения (можно добавлять свои правила)
  • visual - визуализация программы
  • 
    function game_of_life(mat, number_generation, is_visual)
    
    % основная функция программы
    
    if is_visual
        visual(mat);
        pause(5)
    else
        warning('визуализация не отображена!')
    end
    
    % основной цикл программы
    for i=1:number_generation
        
        % получаем следующее поколение
        mat = getNewMat(mat);
        
        % визуализация
        if is_visual
            visual(mat);
        end
        
    end
    
    end
    
    
    function countMat = calcNeighbor(m)
    
    % функция подсчета кол-ва соседей. Каждая клетка матрицы countMat размером m x m
    % отображет сумму соседей
    
    % инициализируем новую матрицу с "бесконечными полями"
    matInf = zeros(size(m)+2);
    
    % инициализируем матрицу счета соседей
    countMat = zeros(size(m,1), size(m,2));
    
    % "замыкаем" границы
    
    % добавляем вокруг исходной матрицы еще один слой клеток (для замыкания)
    matInf(2:end-1, 2:end-1) = m;
    % добавляем низ матрицы наверх нового слоя
    matInf(1, 2:end-1) = m(end, :);
    % добавляем вверх матрицы вниз нового слоя
    matInf(end, 2:end-1) = m(1, :);
    % добавляем правую сторону матрицы влево нового слоя
    matInf(2:end-1, 1) = m(:, end);
    % добавляем левую сторону матрицы вправо нового слоя 
    matInf(2:end-1, end) = m(:, 1);
    
    % "замыкаем" углы
    
    % добавляем нижний правый угол в верхний левый нового слоя
    matInf(1, 1) = m(end, end);
    % добавляем нижний левый угол в верхний правый нового слоя
    matInf(1, end) = m(end, 1);
    % добавляем верхний правый угол в левый нижний нового слоя
    matInf(end, 1) = m(1, end);
    % добавляем верхний левый угол в правый нижний нового слоя
    matInf(end, end) = m(1, 1);
    
    [xsize, ysize] = size(m);
    
    % получаем матрицу сумм каждой клетки
    for y = 2:ysize+1
        for x = 2:xsize+1
            % считаем сумму соседей каждой клетки (узкое место программы)
            countMat(x-1, y-1) = sum(sum(matInf(x-1:x+1, y-1:y+1))) - m(x-1, y-1);
        end
    end
    
    end
    
    function matNew = getNewMat(m)
    
    % функция формирует новую матрицу. По правилам игры
    
    [xsize, ysize] = size(m);
    
    % инициализируем новую матрицу
    matNew = zeros(size(m));
    
    % получаем матрицу кол-ва соседей каждой клетки
    countMat = calcNeighbor(m);
    
    idx = 0;
    
    % цикл по каждой клетке на поле
    for yInf = 2:ysize+1
        for xInf = 2:xsize+1
            
            idx = idx + 1;
    
            % получаем сумму клетки
            count = countMat(idx);
            
            % ----- проходим по правилам (можно добавлять/изменять свои) -----
            
             % правило 1: Если клетка мертва и у нее 3 соседей, то в ней зарождается жизнь
            if (m(idx) == 0) && (count == 3)
                matNew(idx) = 1;
            end       
            
             % правило 2: Если клетка жива и у нее 2 или 3 соседа, то она
            % остается жить
            if (m(idx) == 1) && ((count == 2) || (count == 3))
                matNew(idx) = 1;
            end       
            
            % правило 3: Если клетка жива и у нее соседей меньше двух, то она умирает от
            % одиночества
            if (m(idx) == 1) && (count < 2)
                matNew(idx) = 0;
            end
    
            % правило 4: Если клетка жива и у нее больше 3 соседей, то она
            % умирает от перенаселенности
            if (m(idx) == 1) && (count > 3)
                matNew(idx) = 0;
            end
            
        end
    end
    
    end
    
    function visual(mat)
    
    % визуализация
    
    spy(mat, 'b', 8)
    % disp(num2str([size(mat,1), size(mat, 2)]))
    % axis off;
    axis equal;
    % задаем оси
    xlim([0 size(mat,1)])
    ylim([0 size(mat,2)])
    title('Game of life')
    
    drawnow
    
    end
    
    Исходники доступы на GitHub

    Визуализация:

    Наглядная работа игры "жизнь" с начальной формой "R-пентамино"


    Красиво, как из 5 клеток образуются жизни. В следующей статье попробуем установить свои дополнительные правила. Подробнее "фигурах" клеток можно посмотреть тут.

    обновлено: Декабрь 9, 2018 в 20:35


    Количество комментариев: 0

    Комментариев нет



    Добавить комментарий: