2013-05-25 2 views
2

XAML을 사용하여 Conway의 Game of Life를 C#으로 만들려고합니다. 창을 사용하면 슬라이더를 사용하여 2D 셀 배열의 행 및 열 수를 지정할 수 있습니다. 내 Uniform Grid가 완벽한 정사각형 (10x10, 20x20 또는 심지어 16x16) 일 때, 시뮬레이션은 문제없이 작동합니다. 그러나 사용자가 직사각형의 균일 한 격자 (13x14, 15x26, 24x14)를 지정하려고하면 셀은 차이 (즉, 33x27 격자, 차이 = 6)로 던져 지므로 셀은 적절하게 위로 이동하지만 꺼집니다 (왼쪽/오른쪽) 차이로). 나는 이것이 X 축에서만 발생한다는 것을 좁혔다. 셀은 결코 y 축에서 벗어나지 않습니다. 질문 : 내 배열이 왜 내 x 축에서 벗어나니까? 거기에 문제가 있습니까?Conway의 Game of Life 2D 배열이 일치하지 않습니다

제가 말할 수있는 한, 모든 것이 잘 작동합니다. 내 2D 배열과 제복 그리드의 치수를 확인하기 위해 로그를 설정했습니다. 나는 무엇이 잘못 되었는가에 대해 확신하지 못한다. 그리고 나는 문자 그대로의 날을 바라보고 있었고 디버깅을 해왔다. 나는 끝내 준다. 제발 도와주세요. 나는 단순히 잡히지 않는 뭔가가 있기를 바랍니다.

코드 범례 : 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); 
    } 
+0

안녕하세요 Carlos. 우연히도, 나는 C#/XAML/WPF의 삶에 대한 데모에 대해 최근에 [질문 [질문]했다. (http://stackoverflow.com/questions/16642461/brushes-white-slows-graphics-demo-down). 전체 코드가 게시되면 다른 접근 방식에 대해 궁금합니다. – dharmatech

+1

몇 장의 스크린 샷이 도움이 될 것입니다. – RBarryYoung

+0

'unigridOfCells.Rows = column;'과'unigridOfCells.Columns = row;'주위에'uniGridOfCells'에 대한 행/열 값을 교환 해보십시오. 이것은 x/y 논리를 혼란스럽게 만드는 고전적인 경우입니다 (스크린 샷은 RBarryYoung이 말한 것처럼 좋을 것입니다.) - 이것이 전체적인 문제인지 아닌지 여부는 현재 첫 번째 열을 먼저 추가하는 것이고 첫 번째 행을 채우는 것입니다 (그리고 ' t는 꽤 맞습니다.) 정상적으로 채워진 다음, 다음 행 등에 등을 맞 춥니 다. – VisualMelon

답변

1

문제는 당신이 세포를 생성하는 순서가 UniformGrid가 아이를 배열하는 순서와 다른 점이다.

setCellsOnGrid 메서드에서는 위에서 아래로, 왼쪽에서 오른쪽으로 셀을 만들고, UniformGrid에서 자식을 왼쪽에서 오른쪽, 위에서 아래 순서로 정렬합니다.

사각형 격자의 경우 눈금의 첫 번째 열의 셀은 UniformGrid의 첫 번째 행에 그려지 며 다른 열과 행의 경우에도 마찬가지입니다. 결국 그리드가 x = y 라인에 반영됩니다. 그러나 정사각형이 아닌 격자의 경우 행의 길이가 열의 길이와 같지 않으므로 그리드는 완전히 자리를 비 웁니다. 3 × 3 격자 예를 들어

은, 루프는 다음과 같은 순서로 실행됩니다

1 4 7 
2 5 8 
3 6 9 

그러나, 컨트롤이 다음 순서로 UniformGrid에 추가됩니다 (당신이 FlowDirection="Right"을 설정하지 않은 가정) : 3 × 4 그리드

를 들어
1 2 3 
4 5 6 
7 8 9 

은, 루프는 순서대로 실행

,512,

하지만 컨트롤이 순서

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

이있는 UniformGrid에 추가됩니다 즉, 당신의 cells 배열의 인접 그 반대의 경우도 마찬가지 UniformGrid에 인접한으로 그려 및되지 않을 수 있습니다 세포.

다행히도 수정 방법은 간단합니다. ij 루프의 순서를 setCellsOnGrid으로 변경하십시오. j 루프를 외부 루프로 만들고 i 루프를 내부 루프로 만듭니다.

덧붙여, 당신의 blockSpace 방법은 ij 루프 변수를 사용하여 표시되지 않습니다 - 그냥 같은 방법을 codeColumn * codeRow 번 호출합니다. 이것은 의도적입니까?

+0

정말 고마워요. 이 문제가 해결되었습니다. 나는 세포를 맨 아래로 세우고 있음을 깨닫지 못했습니다. 나는 너무 오랜 시간 동안 살아있는 이웃을 얻는 것에 대한 나의 논리가 틀렸다고 쳐다 보았다. 문자 그대로 그것을 단계적으로 디버깅했다. 다시 한번 고맙습니다. 감사드립니다. 또한 첫 번째 게시물이기 때문에 사진을 게시 할 수 없습니다. 하지만 고맙습니다. – Carlos

+0

또한 Blockspace 메서드는 2 차원 배열을 기준으로 클릭 한 셀의 위치를 ​​보는 데 사용하는 디버그 메서드 였지만 Array.IndexOf를 구현 한 후에는 2D 배열을 지원하지 않고 끝내지 않았습니다. – Carlos

관련 문제