康威的生命游戏2D阵列不排队

时间:2013-05-25 18:16:59

标签: c# wpf xaml conways-game-of-life

我试图用XAML在C#中制作康威的生命游戏。该窗口允许用户使用滑块指定我的2D单元格数组的行数和列数。当我的Uniform Grid是一个完美的正方形(10x10,20x20甚至16x16)时,模拟工作没有问题。然而,当用户试图指定矩形均匀网格(13x14,15x26,24x14)时,细胞被差异抛出(即在33x27网格中,差异= 6,因此细胞适当向上,但被抛弃(左/右)差异)。我已经缩小了,这只发生在x轴上;细胞永远不会在y轴上脱落。 问题:为什么我的阵列会脱离x轴?这有什么问题吗?

据我所知,一切都应该正常。我设置了一个日志来检查我的2D数组和我的统一网格的尺寸。我不确定出了什么问题,我一直在为DAYS盯着调试。我的智慧结束了。请帮助,我希望有一些我根本没有抓到的东西。

代码图例: unigridOfCells是XAML中的统一网格。 slideWidth / slideHeight是滑块。  另外,我使用的资源转换器将我的isAlive属性转换为SolidColorBrush。

    private Cell[,] cells;
    private Cell[,] nextGenCells;
    private int codeColumn, codeRow, difference, secondDiff;

    public MainWindow()
    {
        InitializeComponent();
        unigridOfCells.Height = 500;
        unigridOfCells.Width = 500;
        setCellsOnGrid(10, 10);
    }

    //Sets all the cells on the grid, as well as setting the number of columns and rows to be reset for all arrays in the application
    public void setCellsOnGrid(int column, int row)
    {
        unigridOfCells.Rows = row;
        unigridOfCells.Columns = column;
        codeColumn = column;
        codeRow = row;
        time = new Timer(3000);

        cells = new Cell[codeColumn, codeRow];
        nextGenCells = new Cell[codeColumn, codeRow];
        for (int i = 0; i < codeColumn; i++)
        {
            for (int j = 0; j < codeRow; j++)
            {
                cells[i, j] = new Cell();
                Rectangle block = new Rectangle();
                block.Height = 10;
                block.Width = 10;
                block.DataContext = cells[i, j];
                block.MouseLeftButtonDown += cells[i, j].ParentClicked;
                //block.MouseLeftButtonDown += blockSpace;

                Binding b = new Binding();
                b.Source = cells[i, j];
                b.Path = new PropertyPath("isAlive");
                b.Converter = (BoolColorConverter)Application.Current.FindResource("cellLifeSwitch");
                block.SetBinding(Rectangle.FillProperty, b);
                unigridOfCells.Children.Add(block);
            }
        }

    }

    public void blockSpace(object sender, MouseButtonEventArgs e)
    {
        int spot = 0;
        int pick = 0;
        for (int i = 0; i < codeColumn; i++)
        {
            for (int j = 0; j < codeRow; j++)
            {
                spot = unigridOfCells.Children.IndexOf((Rectangle)sender);

            }
        }
        MessageBox.Show("" + spot + " : " + pick);
    }

    //Updates the cells. This is where the rules are applied and the isAlive property is changed (if it is).
    public void updateCells()
    {
        for (int n = 0; n < codeColumn; n++)
        {
            for (int m = 0; m < codeRow; m++)
            {
                nextGenCells[n, m] = new Cell();
                bool living = cells[n, m].isAlive;
                int count = GetLivingNeighbors(n, m);
                bool result = false;
                if (living && count < 2)
                {
                    result = false;
                }
                if (living && (count == 2 || count == 3))
                {
                    result = true;
                }
                if (living && count > 3)
                {
                    result = false;
                }
                if (!living && count == 3)
                {
                    result = true;
                }

                nextGenCells[n, m].isAlive = result;
            }
        }
        setNextGenCells();
    }

    //Resets all the cells in a time step
    public void setNextGenCells()
    {
        for (int f = 0; f < codeColumn; f++)
        {
            for (int k = 0; k < codeRow; k++)
            {
                cells[f, k].isAlive = nextGenCells[f, k].isAlive;
            }
        }
    }

    //Checks adjacent cells to the cell in the position that was passed in
    public int GetLivingNeighbors(int x, int y)
    {
        int count = 0;

        // Check cell on the right.
        if (x != codeColumn - 1)
            if (cells[x + 1, y].isAlive)
                count++;

        // Check cell on the bottom right.
        if (x != codeColumn - 1 && y != codeRow - 1)
            if (cells[x + 1, y + 1].isAlive)
                count++;

        // Check cell on the bottom.
        if (y != codeRow - 1)
            if (cells[x, y + 1].isAlive)
                count++;

        // Check cell on the bottom left.
        if (x != 0 && y != codeRow - 1)
            if (cells[x - 1, y + 1].isAlive)
                count++;

        // Check cell on the left.
        if (x != 0)
            if (cells[x - 1, y].isAlive)
                count++;

        // Check cell on the top left.
        if (x != 0 && y != 0)
            if (cells[x - 1, y - 1].isAlive)
                count++;

        // Check cell on the top.
        if (y != 0)
            if (cells[x, y - 1].isAlive)
                count++;

        // Check cell on the top right.
        if (x != codeColumn - 1 && y != 0)
            if (cells[x + 1, y - 1].isAlive)
                count++;
        return count;
    }

    //Fires when the next generation button is clicked. Simply makes the board go through the algorithm
    private void nextGenerationClick(object sender, RoutedEventArgs e)
    {
        updateCells();
    }

    //Fired when the "Reset Grid" button is pressed, resets EVERYTHING with the new values from the sliders
    private void resetGrid(object sender, RoutedEventArgs e)
    {

        MessageBox.Show("First Slide (width) value: " + slideWidth.Value + "\nSecond Slide (length) value: " + slideHeight.Value +  "\nDifference: " + (codeColumn - codeRow) + "\nColumns: " + unigridOfCells.Columns + " \nRows: " + unigridOfCells.Rows + "\nChildren count: " + unigridOfCells.Children.Count + " \nLengths: "
            + "\n\tOf 1D of cells: " + cells.GetLength(0) + "\n\tOf 1D of nextGenCells: " + nextGenCells.GetLength(0) + "\n\tUniform Grid Columns: " + unigridOfCells.Columns + " \nWidths: " 
            + "\n\tOf 2D of cells: " + cells.GetLength(1) + "\n\tOf 2D of nextGenCells: " + nextGenCells.GetLength(1) + "\n\tUniform Grid Rows: " + unigridOfCells.Rows);
        unigridOfCells.Children.Clear();
        setCellsOnGrid((int)slideWidth.Value, (int)slideHeight.Value);
    }

1 个答案:

答案 0 :(得分:1)

问题在于,您创建单元格的顺序与UniformGrid排列其子项的顺序不同。

在您的setCellsOnGrid方法中,您可以从上到下创建单元格,然后从左到右创建单元格,而UniformGrid按顺序从左到右排列,然后从上到下排列汉字。

对于方形网格,网格第一列中的单元格在UniformGrid的第一行中绘制,对于其他列和行也是如此。您最终将网格反映在x = y行中。但是,对于非方形网格,行的长度不等于列的长度,因此网格完全不合适。

例如,对于3×3网格,您的循环按以下顺序运行:

1 4 7
2 5 8
3 6 9

但是,控件按以下顺序添加到UniformGrid(假设您尚未设置FlowDirection="Right"):

1 2 3
4 5 6
7 8 9

对于3×4网格,您的循环按顺序

运行
1 5 9
2 6 10
3 7 11
4 8 12

但控件按顺序

添加到UniformGrid
1  2  3
4  5  6
7  8  9
10 11 12

这意味着cells数组中相邻的单元格可能不会在UniformGrid中被绘制为相邻,反之亦然。

幸运的是,修复很简单:在i中切换jsetCellsOnGrid循环的顺序。使j循环为外循环,i循环为内循环。

顺便提一下,您的blockSpace方法似乎没有使用ij循环变量 - 它只调用相同的方法codeColumn * codeRow次。这是故意的吗?