生命游戏内存优化

时间:2010-08-24 08:07:58

标签: c conways-game-of-life

您好我编写了一个简单的生命代码游戏,其中使用了2个数组,一个维护当前状态,另一个维护下一个状态。 任何人都可以建议如何优化此程序的内存消耗。理想情况下,我希望它的空间复杂度小于RC。

5 个答案:

答案 0 :(得分:4)

这取决于你的比赛场地有多稀疏。如果您的比赛场地密集,那么任何存储算法的空间复杂性将趋向于RC。 (具体来说,RC / 2,因为一旦你获得比非活动单元更多的活动单元,你可以只存储非活动单元,如果你真的非常关心最佳空间使用。)

如果比赛场地稀疏,你可以通过简单地存储每个活动单元格或其他sparse matrix structure的坐标对来获得与活动单元格数相比的缩放比例。

答案 1 :(得分:2)

我对GOL知之甚少,但假设有很多空的“方块”,你看过Sparse Matrixes吗?

答案 2 :(得分:1)

迟到的答案,但仍然。

查看golly的源代码:http://golly.sourceforge.net/

但在此之前,请转到:http://www.ibiblio.org/lifepatterns/lifeapplet.html
并看看那里的代码。它是用Java编写的,但速度非常快。

Alan Hensel网站的引用应该回答你的问题:

  

你是怎么做到这么快的?   好吧,不经意的观察者可能不会注意到我的applet非常快。您可能没有找到“变形速度”按钮,或者您可能没有使用它,或者您可能没有对它印象深刻。您可以跳到下一部分。

     

但是,有些人问过,你怎么这么快就走了?!对于好奇的人,或者那些想写自己的超快细胞自动机程序的人,我会解释。

     

我倾向于认为细胞自动机优化与数据压缩有关。这也是一个简单的概念,没有简单的解决方案,最好的解决方案取决于正在处理的数据类型。在Conway的生活中,模式往往是blobby。

     

对于blobby宇宙,人们应该考虑将宇宙划分为大约blob大小的块。对于生命来说,4x4到8x8似乎是合理的。为方便起见,我选择了上限8x8:一个字节中恰好有8位。我强烈考虑4x4,但它并没有那么好......

     

你应该将这些块放在某种列表中,这样你就可以在宇宙的空白部分浪费零时间。

     

已经注意到一个复杂问题:如果模式在块的边界上增长,则必须引入列表中的新元素,但我们必须知道块的邻居是否已经存在。您可以对列表进行简单的线性搜索,也可以进行二进制搜索,或保留某种地图。我选择制作哈希表。这仅用于查找新块的邻居;每个现有的块已经保留了一个指向其邻居的指针,因为它们将经常被引用。

     

块内还必须有一个有效的算法。我选择主要直接穿过每个街区。在处理块中的所有单元之前,没有内部循环。此外,采用快速查找表。我查找4x4块以确定内部2x2。

     

注意:CA程序通常由2个主循环(加上显示循环)组成,因为CA规则并行运行在单元上,而微处理器在概念上是串行的。这意味着必须有两个宇宙副本,以便在创建下一代的过程中不会破坏任何重要信息。这两份副本通常不对称。对我来说这是一场艰苦的斗争,因为几乎每次我从一个循环中拿出一些东西来加快速度,我不得不在另一个循环中添加其他内容!几乎每次都是这样;该规则的例外导致最佳优化。特别是,在位操作中需要考虑很好的权衡:移位,屏蔽,重组以在查找表中形成地址....

     

还可以认为,有时块的内容可以稳定,不需要进一步处理。您可以将块从列表中取出,使其处于“休眠”状态,只有在相邻块有一些活动溢出时才重新激活。这些块将占用零处理时间,就像宇宙的空白区域一样。

     

周期-2振荡器也可能不是很难检测,并且从处理时间中移除。这在生活中可能是值得的,因为闪光灯是最常见的随机碎片。更高周期的振荡器更为罕见。也可以检测和模拟滑翔机。除非你把它推向极端,否则你将从这种优化中获得收益递减(参见HashLife)。

     

此外,完全为空的单元格块可能不值得取消分配并从哈希表中删除一段时间。这需要一些处理时间,这在振荡器反复移入和移出其空间的情况下可能是重要的。只有当记忆力降低时,才能回收“太平间”中最古老的街区。

     

当程序足够快时,应该认为不值得以眼睛看到的方式显示世代,或者至少不比显示器的刷新率快得多。特别是在窗口环境中,显示时间可能是一个真正的瓶颈。

然后阅读这段源代码:http://www.ibiblio.org/lifepatterns/src.41d/LifeCell.java
它包含了拥有Alan's Life宇宙的数据结构。

忘记哈希生活,它是如此复杂,它将使你的头旋转。

答案 3 :(得分:0)

其他回答者在寻找您所在州的其他数据结构时有一个很好的观点。但无论如何,简单的优化可能会使用两个指向状态的指针(您可能已经这样做了)。因此,您不需要执行两个数组副本,而是执行一个副本和三个指针分配:

state curr, next;
[...]
for (;;) {
    next = advance(curr);
    curr = copy(next);
}

对此:

state s1, s2;
state *curr, *next;
[...]
for (;;) {
    *next = advance(*curr);
    /* swap pointers */
    state *tmp = curr;
    curr = next;
    next = tmp;
}

答案 4 :(得分:0)

我推荐稀疏矩阵,推荐使用nonnb和Amber。如果您有要刻录的处理器电源,或者想要序列化到磁盘,您还可以查看编码。基于RLE或令牌的压缩可能会让你到达某个地方。