从元胞自动机模拟中获取特定的单元格组

Get specific groups of cells from a cellular automata simulation

我正在 Unity 中制作一款游戏,玩家可以从我的模拟中删除一些单元格。
假设所有单元格仅通过其邻居连接到顶行。
玩家进来并删除单元格,创建一组分开的单元格。我想得到它们。
作为下图中玩家删除绿色单元格后的示例,我想获取红色周边的单元格。

好吧,它非常广泛,并且在很大程度上取决于您的数据结构。我能想到的快速而肮脏但直接的是

对于每个单元存储它的邻居——这显然是你在创建板时必须设置的东西——比如

public class Cell
{
    public bool Enabled;

    public Vector2Int position;

    public Cell top;
    public Cell bottom;
    public Cell left;
    public Cell right;
}

然后你可以通过

收集所有启用的单元格组
  • 遍历整个电路板并找到第一个启用的单元格
  • 创建一个新组
  • 将此单元格添加到组中
  • 每四个方向检查是否有另一个启用的单元格
  • 如果是,加入组并重复最后一步
  • 如果您第二次遇到单元格(=当它们已经在组中时),请忽略它们
  • 如果在所有方向上都没有更多已启用的单元格不在组中,您就完成了
  • 返回第一步但跳过任何组中已有的单元格
  • 当你到达棋盘的尽头时你就完成了

在代码中这可能有点像

// Assuming you have a board grid like
private Cell[,] grid = new Cell[width, height];

public List<HashSet<Cell>> FindGroups()
{
    var output = new List<HashSet<Cell>>();
    var alreadyTracked = new HashSet<Cell>();      

    // Iterate the grid
    for(var x = 0; x < width; x++)
    {
        for(var y = 0; y < height; y++)
        {
            var current = grid[x,y];

            // skip if not enabled
            if(!current.Enabled) continue;

            // skip if cell was already tracked in any group before
            if(alreadyTracked.Contains(current)) continue;

            // Create new group and fill it recursively
            var group = new HashSet<Cell>();

            current.FindConnectedEnabledCells(current, alreadyTracked, group);

            // Add that new group to the final output
            output.Add(group);
        }
    }

    return output;
}

// Finds all cells connected to the given cell that are enabled recursively
// and adds them to the given collections
private void GetConnectedEnabledCells(Cell current, HashSet<Cell> alreadyTracked, HashSet<Cell> group)
{
    // This cell is not enabled -> ignore
    if(!current.Enabled) return;

    // This cell is already in the group -> ignore
    if(group.Contains(current)) return;

    // Add the current cell to the collections itself
    group.Add(current);
    alreadyTracked.Add(current);

    // Recursively fetch all connected cells that are not null (e.g. Edge cells) and are enabled

    if(current.top?.Enabled) current.top.GetConnectedEnabledCells(cells);
    if(current.bottom?.Enabled) current.bottom.GetConnectedEnabledCells(cells);
    if(current.left?.Enabled) current.left.GetConnectedEnabledCells(cells);
    if(current.right?.Enabled) current.right.GetConnectedEnabledCells(cells);
}

然后因为您似乎已经知道顶行总是在那里,您可以忽略第一组,因为那是与您的“天花板”相连的组。

我不知道这是不是最有效的方法 ;)

您可能希望将 HashSet 替换为 List,具体取决于您的网格大小。对于大型集合,HashSetContains 中更好,但在 Add 中更差。

如果您认为对角线是“连接的”,则添加、填充并检查 Cell class.

中相应的额外四个单元格条目

注意:如果您的单元格 class 是 MonoBehaviour,则不用

if(current.top?.Enabled)

宁可使用

if(current.top && current.top.Enabled)