康威在 Python 中的人生游戏

我身边的另一个基于代理的模拟示例!在本文中,我将使用基于代理的建模框架abm_framework在 Python 中实现 Conway 的生活游戏。您可以通过单击下面的链接找到该框架。

Conway 的生命游戏很好地介绍了基于代理的建模,正是出于这个原因,它也在大学里教授。一般来说,它也是对 Python 编程的一个很好的介绍。

我最近分享了一系列示例,说明如何在 Python 中实现abm_framework以进行基于代理的建模。你可以在这里找到框架:

以下部分描述了康威人生游戏的规则。之后,我用 Python 实现了生命游戏。

康威人生游戏规则

从概念上讲,生命游戏由一个网格组成。单元格中的每个网格都由一个代理填充。代理要么死了,要么活着。从初始状态开始,生命游戏在迭代中更新迭代。在每次迭代期间,以下规则适用:

  • 如果一个代理是活的,并且它的相邻单元格包含 2 或 3 个活代理,则该代理会存活到下一轮。然后它在下一轮还活着。否则代理死亡并在下一轮死亡。
  • 如果一个已死的代理在其附近恰好有 3 个活着的代理,则该代理将重生并在下一轮中存活。

这些规则足以为康威的人生游戏建模。初始状态由模拟开始时的死或活代理定义,是模拟运行所需的唯一输入。在本文中,我运行了模型的三个版本。前两个版本具有活体细胞的随机初始分布。第三个版本有一个特定的初始种子模式的活代理。在第一版和第三版中,网格是无穷无尽的。这意味着如果您退出左侧的网格,您将进入右侧的网格,如果您退出顶部的网格,您将进入底部的网格。第二个版本应用有边界的网格,即不是无限的网格。

用 Python 实现人生游戏

使用 Python 中的abm_framework(我在 Github 上提供)我在 Python 中实现了模型。我创建了一个包含 100 个单元的模拟网格。初始状态(称为种子)由随机分布在网格中的 50 个活代理组成。下面的代码实现了模拟模型的无限网格版本。

__author__ = "Linnart Felkl"
__email__ = "LinnartSF@gmail.com"

if __name__ == "__main__":

    print("demo starts")

    import sys
    from pathlib import Path
    file = Path(__file__).resolve()
    parent, root = file.parent, file.parents[1]
    sys.path.append(str(root))

    # remove the current file's directory from sys.path, unless already removed
    try:
        sys.path.remove(str(parent))
    except ValueError:
        pass

    import data
    import stats
    import config
    import framework
    import random
    import animation

    # setup database manager and connection
    db = data.Database("sqlite3", config.path_databasefile)
    db_manager = data.Manager(db)
    
    # create an empty environment
    env = framework.Environment(1, True, 10, 10, db_manager) # Environment constructor implicitly resets environment table in database

    # create initial population of healthy humans
    attrs = ["life_t0","life_t1"]
    datatypes = ["INTEGER","INTEGER"]
    pops = framework.Populations(amount = 1, env = env, db_manager = db_manager, attributes = attrs, datatypes = datatypes)
    pops.add_population(name = "units", 
                        size = 100, 
                        attributes = attrs, 
                        datatypes = datatypes, 
                        initialvals = [0, 0]
                        )
   
    # set seed of simulation (number of agents alive and their pattern)
    agents = pops.get_agents()
    random.shuffle(agents)
    for i in range(50):
        agents[i].set_attr_value("life_t0",1)

    # setup simulation
    sim = framework.Simulation(50)

    # make sure that environment and agents tables in database are setup at this time
    pops.write_env_to_db(sim.Iteration)
    pops.write_agents_to_db(sim.Iteration)

    # execute simulation run; with centralized simulation control
    while sim.run():
        
        for agent in agents:

            # get that agents neighbourhood
            neighbours = env.get_neighbourhood(agent, mode = "moore", radius = 1)

            _neighbours_alive = 0
            for neighbour in neighbours:
                
                if neighbour.get_attr_value("life_t0") == 1: 
                    _neighbours_alive  += 1

            if agent.get_attr_value("life_t0") == 1: 

                if _neighbours_alive == 2 or _neighbours_alive == 3: 
                    
                    agent.set_attr_value("life_t1", 1)

                else:

                    agent.set_attr_value("life_t1", 0)

            elif _neighbours_alive == 3:

                agent.set_attr_value("life_t1", 1)

            else:

                agent.set_attr_value("life_t1", 0)
                
        # update results in database, for agents and for environment
        pops.write_agents_to_db(sim.Iteration)
        pops.write_density_to_db(sim.Iteration)

        # update attributes for next round
        for agent in agents:

            agent.set_attr_value("life_t0", agent.get_attr_value("life_t1"))
    
    # get dataframes with simulation results
    density_df = db_manager.get_densitydf()

    # visualize simulation data
    stats.set_fontsizes(8,10,12)

    animation.animate_density(
        df = density_df,
        filename = "gol_randomendless",
        attr = "life_t1",
        defaultsize = 50,
        color = "black",
        tpf = 0.30
    )

    # end program
    db.close()
    print("demo ends")

在模型的第二个版本中,我实现了一个不是无穷无尽的网格。代码中唯一的调整是在 Environment 构造函数调用中,将无限网格参数设置为 False 而不是 True。

康威人生游戏动画

下面是康威的 Python 人生游戏动画。第一个动画表示具有无限网格的模型。

下面显示的第二个动画表示具有边界网格的模型。

最后,我运行了一个场景,在该场景中我定义了一个特定的初始模型状态。动画如下所示,代表一个无尽的网格。

您可以通过简单的 Google 查询找到各种生活游戏示例。还有各种工具可用于指定您自己的种子并逐步运行模型。

结束语

在本文中,我使用我命名为abm_framework的框架在 Python 中实现了 Conway 的生活游戏。我运行了三个场景,网格边界定义(无限与非无限)和初始种子(随机初始种子与特定初始种子)不同。如果你想学习在 Python 中实现生命游戏的基于代理的建模,这对你来说可能是一个很好的第一步。

You May Also Like

Leave a Reply

Leave a Reply

您的电子邮箱地址不会被公开。 必填项已用 * 标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据