C# 康威';生活的游戏没有正确更新

C# 康威';生活的游戏没有正确更新,c#,oop,conways-game-of-life,C#,Oop,Conways Game Of Life,我写了一个Conway的生命游戏的快速实现,但它运行得非常慢,主要是因为我检查相邻单元格的方法涉及到再次在整个单元格网格中循环,现在我改变了检查相邻单元格的方法,但不幸的是,它不再正确更新,它似乎工作得很好,只是它没有创造出它应该创造的那么多新细胞 现在,我已经花了好几个小时手动调试代码,使用断点检查代码,并尝试比较值和调用,但似乎我的getneights()方法正在工作,因此我向您承认,我自己无法找出问题所在。我已经提交了下面的代码以寻求帮助 编辑:你们中的一些人已经指出,我无法复制我的网格。

我写了一个Conway的生命游戏的快速实现,但它运行得非常慢,主要是因为我检查相邻单元格的方法涉及到再次在整个单元格网格中循环,现在我改变了检查相邻单元格的方法,但不幸的是,它不再正确更新,它似乎工作得很好,只是它没有创造出它应该创造的那么多新细胞

现在,我已经花了好几个小时手动调试代码,使用断点检查代码,并尝试比较值和调用,但似乎我的
getneights()
方法正在工作,因此我向您承认,我自己无法找出问题所在。我已经提交了下面的代码以寻求帮助

编辑:你们中的一些人已经指出,我无法复制我的
网格。单元格
数组。我将它改为使用
Array.Copy()
,但不幸的是,它仍然不能完全工作。我想不出来,但它似乎并没有在所有情况下创造出新的细胞

MainForm.cs

public partial class MainFom : Form
{
    Grid formGrid;
    CancellationTokenSource tokenSrc = new CancellationTokenSource();

    public MainFom()
    {
        InitializeComponent();
    }

    private void MainFom_Load(object sender, EventArgs e)
    {
        formGrid = new Grid();

        for (int i = 0; i < 50; i++)
        {
            int xCoord = 10 * i + 12;      

            Controls.Add(new Label() 
            { 
                AutoSize = true, 
                Text = i.ToString(), 
                Location = new Point(xCoord, 0),
                Font = new Font(Font.FontFamily, 6)
            });

            for (int s = 0; s < 50; s++)
            {
                int yCoord = 10 * s + 12;

                Controls.Add(new Label() 
                { 
                    AutoSize = true, 
                    Text = s.ToString(), 
                    Location = new Point(0, yCoord),
                    Font = new Font(Font.FontFamily, 6)
                });
            }
        }
    }

    private void MainFom_Paint(object sender, PaintEventArgs e)
    {
        e.Graphics.DrawImage(formGrid.toBitmap(), 0, 0);
        e.Graphics.Dispose();
    }

    private void startBtn_Click(object sender, EventArgs e)
    {
        Task tempTask = Task.Factory.StartNew(
            (x) =>
            {
                while (!tokenSrc.IsCancellationRequested)
                {
                    formGrid.UpdateGrid();
                    Graphics graphics = this.CreateGraphics();
                    graphics.Clear(this.BackColor);
                    graphics.DrawImage(formGrid.toBitmap(), 0, 0);
                    graphics.Dispose();
                }
            }, tokenSrc);

        startBtn.Hide();
        Button stopBtn = new Button() { Text = "Stop", Location = startBtn.Location, Size = startBtn.Size };
        this.Controls.Add(stopBtn);
        stopBtn.Click += new EventHandler(
            (x, y) => 
            { 
                tokenSrc.Cancel(); 
                stopBtn.Hide();
                startBtn.Show();
                tempTask.Wait();
                tokenSrc = new CancellationTokenSource();
            });

    }
}
class Grid
{
    #region Properties/Fields

    const int MAX_CELLS = 50;
    Random RNG = new Random();
    Cell[,] cells;
    int generations = new int();

    #endregion

    public Grid()
    {
        cells = new Cell[MAX_CELLS, MAX_CELLS];

        for (int x = 0; x < MAX_CELLS; x++)
        {
            int xCoord = 10 * x + 12; 

            for (int y = 0; y < MAX_CELLS; y++)
            {
                int yCoord = 10 * y + 12;
                Point point = new Point(xCoord, yCoord);

                if (RNG.Next(100) < 20) { 
                    cells[x, y] = new Cell(point, true); } 
                else {
                    cells[x, y] = new Cell(point, false);
                }
            }
        }
    }

    public void UpdateGrid()
    {
        Cell[,] copy = cells;

        for (int x = 0; x < MAX_CELLS; x++)
        {
            for (int y = 0; y < MAX_CELLS; y++)
            {
                int neighboursCtr = GetNeighbours(x, y);

                //Rule 1: Any live cell with fewer than two live neighbours dies, as if caused by under-population.
                if (cells[x, y].IsAlive && neighboursCtr < 2)
                {
                    copy[x, y].Kill();
                }
                //Rule 2: Any live cell with more than three live neighbours dies, as if by overcrowding.
                if (cells[x, y].IsAlive && neighboursCtr > 3)
                {
                    copy[x, y].Kill();
                }
                //Rule 3: Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.
                if (!cells[x, y].IsAlive && neighboursCtr == 3)
                {
                    copy[x, y].Alive();
                }
            }
        }

        cells = copy;

        generations++;
    }

    public Bitmap toBitmap()
    {
        Bitmap gridBmp = new Bitmap(1000, 1000); // TODO: Find optimal size for bmp
        Size cellSize = new Size(10, 10);

        using (Graphics gfxObj = Graphics.FromImage(gridBmp))
        {
            // Draw grid here and Dispose() on Pen, gfxObj is implicitly disposed
            Pen myPen = new Pen(Color.LightGray);
            SolidBrush myBrush = new SolidBrush(Color.Black);

            for (int x = 0; x < MAX_CELLS; x++)
            {
                for (int y = 0; y < MAX_CELLS; y++)
                {
                    if (!cells[x, y].IsAlive)
                    {
                        gfxObj.DrawRectangle(myPen, new Rectangle(cells[x, y].point, cellSize));
                    } else
                    {
                        gfxObj.FillRectangle(myBrush, new Rectangle(cells[x, y].point, cellSize));
                    }
                }
            }
            myPen.Dispose();
            myBrush.Dispose();
        }

        return gridBmp;
    }

    private int GetNeighbours(int column, int row)
    {
        int neighbours = new int();
        int[] starts = new int[] { Math.Max(0 ,column - 1), Math.Max(0, row - 1) };
        int[] ends = new int[] { Math.Min(49, column + 1), Math.Min(49, row + 1) };
        double colAndRow = column + row/10;

        for (int x = starts[0]; x < ends[0]+1; x++)
        {
            for (int y = starts[1]; y < ends[1]+1; y++)
            {
                double xAndY = x + y/10;
                if (cells[x, y].IsAlive && xAndY != colAndRow)
                {
                    neighbours++;
                }
            }
        }

        return neighbours;
    }
}
struct Cell
{
    public bool IsAlive { get; private set; }
    public readonly Point point;

    public Cell(Point point, bool isAlive) : this()
    {
        this.point = point;
        IsAlive = isAlive;
    }

    public void Alive()
    {
        IsAlive = true;
    }

    public void Kill()
    {
        IsAlive = false;
    }
}

问题出在
UpdateGrid()
方法中。您只需将原始数组的引用分配给一个新变量:

Cell[,] copy = cells;
但这仍然是同一个目标;特别是,调用
copy[x,y].Kill()和
单元格[x,y].Kill()之间没有区别。因此,在计算过程中修改状态会影响代码的逻辑


使用
数组复制原始文件。复制
应该可以正常工作(您的算法似乎没有其他问题)。

数组是引用类型,这意味着

Cell[,] copy = cells;
不知道你可能想做什么。它不是源数组的副本,因此它将在分析相邻数组时对此进行操作,这将导致错误的结果


使用
Array.Copy

可以做很多改进。 看一看

您可以从使用开始,以更快地使用位图

您可以使用并行编程来改进循环:

您还可以改进算法,避免每次扫描整个矩阵,而是维护一个活动单元列表,只单步扫描这些单元及其邻居。
我已经在下面实现了这样的算法。

使用
Array.Copy
来备份你的cells数组。好的,我会这样做,但这并不是错误的真正“来源”。这个问题似乎是离题的,因为StackOverflow不是调试错误代码的服务。“我搞不懂我写的程序”不是问题,而是事实。如果有具体问题,请回来。我不相信
Array
ToArray()
方法(或扩展方法)。@decPL这是一种LINQ扩展方法
IEnumerable
上有一种,但多维数组没有实现该接口。显然,您可以使用
Cast()
,然后使用
ToArray()
,但这会给您一个一维数组,在这里可能没有什么帮助。