【问题标题】:Algorithms - Extreme specifics about Conways Game of Life算法 - 关于康威生命游戏的极端细节
【发布时间】:2016-07-29 14:11:04
【问题描述】:

我的问题很难描述,所以我会尽量简洁地解释它。

在康威的生命游戏中,假设我有一张这样的地图:

_   _   _   _   _
_   _   _   _   _
U   _   R   Y   _
_   T   _   X   _
_   Z   _   C   _

假设我将第 0 代中的每个活细胞都放在 LinkedList 中,而不是遍历每个单个单元格,包括不可能变得相关的死单元格。在每一代更新时,我都会遍历整个 LinkedList 并执行康威的生命游戏对它们中的每一个陈述的规则。这样我就可以避免无缘无故地迭代大跨度的死单元。

其中一条规则声明a dead cell with 3 living neighbors becomes living。由于我只在算法中迭代 细胞,所以我可以查看死细胞的 唯一 方法是查看我的 @987654325 中活细胞的邻居@。对于LinkedList 中的每个项目,我必须循环遍历所有相邻单元格到该单元格,对于每个相邻单元格,我必须环顾该单元格,计算它是否有三个邻居,然后将其设置为 @987654327 @ 然后将其添加为LinkedList 中的活单元格。

我的问题:

显然我的LinkedList 会很快变得杂乱无章,并且不会 不再处于左上角 -> 右下角的顺序。例如,在我上面提供的图中,我的linkedList 中的第一个单元格可能是C,第二个可能是R,第三个可能是T。随着新细胞的诞生,我会将它们添加到我的 LinkedList 中,并在下一代中以它们添加的任何顺序遍历它们。

根据游戏规则这是合法的,还是我需要从左上角到右下角遍历整个二维数组?规则非常模棱两可。

任何少于两个活邻居的活细胞都会死亡,好像是由于人口不足造成的。

任何有两三个活邻居的活细胞都可以传给下一代。

任何有超过三个活邻居的活细胞都会死亡,就像人口过剩一样。

任何只有三个活邻居的死细胞都会变成活细胞,就像通过繁殖一样。

是否需要遍历整个二维数组,做规则:

任何少于两个活邻居的活细胞都会死亡,好像是由于人口不足造成的。

然后再次循环整个二维数组并做规则:

任何有两三个活邻居的活细胞都可以传给下一代。

这到底有没有关系?我已经阅读了很多帖子,但似乎从来没有人提到过这个话题。

谢谢。

【问题讨论】:

  • 规则没有规定评估顺序。他们需要的是双缓冲。当前一代在一个缓冲区中,而您将下一代构建到另一个缓冲区中。请注意,虽然您的算法在只有少数活细胞时会很有效,但当大部分细胞是活细胞时,它会变得非常低效。
  • 如果你从上到下工作,你只需要一行作为缓冲区(不是洞场)。
  • @MrSmith42 - 只要你以某种线性方式遍历,我认为这很好,你只需要缓冲前一行。好主意!
  • 这似乎是一个几乎毫无意义的优化。我只是不明白扫描空单元格如何占用大部分处理时间,尤其是当您添加维护活单元格链接列表的开销,然后必须以某种方式识别将要复活的死单元格时.当您完成“优化”时,代码比扫描整个矩阵的简单代码更复杂、更慢。
  • @JimMischel 我认为这是一种给予和接受。例如,如果您有 5000 个单元格乘以 5000 个单元格的面积,人口为 4,我的方法只需要循环 4 个单元格而不是 5000 平方。当然,随着人口的增加,是否能节省任何时间是值得怀疑的。

标签: algorithm conways-game-of-life


【解决方案1】:

在康威的人生游戏中,整个矩阵应该只循环一次:所有的变化都是同时完成的。

实际上,这将导致需要两个矩阵:旧状态和新状态。对于旧状态中的每个单元,您计算一个实时邻居计数。然后,如果该单元格还活着并且有 2 或 3 个邻居,它就会继续存在于新的矩阵中。如果该单元格不存在并且有 3 个邻居,则它会生成。否则,它会死。

链表的问题是查找邻居计数。产生下一代将是O(n^2) 活细胞的数量,因为必须搜索整个列表来计算邻居。此外,您必须检查链表中单元格的每个邻居,因为它们生成。

【讨论】:

  • 没有两个矩阵有什么办法吗?还是这个生命游戏的整个现象是建立在完全分离一代人的基础上的?我的一般思维过程是准确的,对吧?因为在这个游戏中,事情只发生在活细胞周围。如果一个死细胞大约是其他 8 个死细胞,那么绕着他循环是一种浪费。
  • 没有两个矩阵的方法是(如果你可以有对象),也存储以前的邻居计数。矩阵的变化是同时发生的,因此每个单元格都会发生变化,就好像它是“第一个”变化的一样。
【解决方案2】:

您应该在每一步都重新创建您的链表。康威的生命游戏是轮流处理的,所有会变成活的死细胞在当前回合不算活,所有会死的活细胞在当前回合不算死。所以,使用LinkedList 方法,你持有两个列表(我会说哈希表,因为你需要一个快速函数来检查一个对象是否已经在列表中),一个代表当前的活细胞集,另一个代表收集到的一组在下一回合还活着的细胞。然后,您遍历第一组单元格,获取当前单元格的相邻单元格,将它们填充到下一回合的列表中,“邻居”等于 1,并增加每个处理的活细胞的值。此外,当前活细胞应添加到具有“活”标志集且邻居为 0 的集合中。伪代码:

ArrayCollection.<Cell> existing; // currently alive cells
ArrayCollection.<Cell> next; // next turn
void processTurn() {
    next.clear();
    for each (Cell cell in existing) {
        Cell nextTC=next.getByParameters(cell); // check presence by X and Y
        if (nextTC) nextTC.alive=true; else   
            next.addNewCell(cell.x,cell.y,0,true); // add a new element
            // 0 is current neighbors, true is alive flag
        for each (Cell neigh in cell.neighbors) {
            nextTC=next.getByParameters(neigh);
            if (nextTC) nextTC.neighbors++; else   
                next.addNewCell(cell.x,cell.y,1,false); // add a new element
                // added a dead cell with 1 neighbor - currently processed alive cell
        }
    }
    for each (cell in next) {
        if (!cell.alive && (cell.neighbors==3)) cell.alive=true; else
        if (cell.alive && ((cell.neighbors==2) || (cell.neighbors==3))) ; // no change
        else next.remove(cell); // dead cell that either was alive or failed to become alive
    }
    swap(current,next);
}

【讨论】:

  • 哇,是的……这肯定比我最初想象的要复杂得多。我以为你只是保持相同的矩阵更新并以某种方式循环通过它进行更改然后重新打印它。这种改变一切。
猜你喜欢
  • 2013-02-21
  • 1970-01-01
  • 1970-01-01
  • 2020-10-07
  • 1970-01-01
  • 2010-09-07
  • 2017-03-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多