Select all adjacent values in multidimensional array - c#

I'm building a bubble breaker-kinda game. My code uses two 2D arrays, one containing color indexes (1 - 6) to represent colored circles, and one indicating whether the circle has been selected (1 or 0). I can succesfully select a circle, the right value in the second array changes and this is reflected correctly on screen.
This is the method that selects one circle and four adjacent circles. I pass in the X and Y coordinates that the user has selected on the grid. I set that position to selected (from 0 to 1 in the SelectedCircles array. Check whether any of the sides has a circle with the same color, if so, change that circle to selected too.
private void SelectSurroundingCircles(int xPosition, int yPosition)
{
SelectedCircles[yPosition, xPosition] = 1;
int colorKey = Circles[yPosition, xPosition];
int increment = 1;
for (int i = 0; i < Nickles.Length; i++)
{
if (Circles[yPosition - increment, xPosition] == colorKey)
SelectedCircles[yPosition - increment, xPosition] = 1; // TOP
if (Circles[yPosition + increment, xPosition] == colorKey)
SelectedCircles[yPosition + increment, xPosition] = 1; // BOTTOM
if (Circles[yPosition, xPosition + increment] == colorKey)
SelectedCircles[yPosition, xPosition + increment] = 1; // RIGHT
if (Circles[yPosition, xPosition - increment] == colorKey)
SelectedCircles[yPosition, xPosition - increment] = 1; // LEFT
}
}
What I want to achieve is that all circles of the same color that are next to each other get selected. Basically you first look at the circles adjacent as above, look at their adjacent circles, and so on... I tried various other things but somehow I couldn't figure it out. Hopefully someone can help me, I must be overlooking something.
Thanks.

Not sure this fullfills your exact selecting logic but isn't recursion the solution:
if ( SelectedCircles[yPosition - increment, xPosition] != 1 && Circles[yPosition - increment, xPosition] == colorKey) {
SelectSurroundingCircles(xPosition, yPosition - increment)
}
//... same for other 3 directions
The extra check if the position isn't selected already is important to prevent endless recursion

Nevermind, I solved it myself. I checked against the array of selected circles, this worked.
for (int y = 0; y < SelectedCircles.GetLength(0); y++)
{
for (int x = 0; x < SelectedCircles.GetLength(1); x++)
{
if (SelectedCircles[y, x] == 1)
{
if (y - 1 >= 0 && SelectedCircles[y - 1, x] != 1 && Circles[y - 1, x] == colorKey)
SelectedCircles[y - 1, x] = 1; // TOP
if (y + 1 <= 9 && SelectedCircles[y + 1, x] != 1 && Circles[y + 1, x] == colorKey)
SelectedCircles[y + 1, x] = 1; // BOTTOM
if (x + 1 <= 9 && SelectedCircles[y, x + 1] != 1 && Circles[y, x + 1] == colorKey)
SelectedCircles[y, x + 1] = 1; // RIGHT
if (x - 1 >= 0 && SelectedCircles[y, x - 1] != 1 && Circles[y, x - 1] == colorKey)
SelectedCircles[y, x - 1] = 1; // LEFT
}
}
}
}

Related

IndexOutOfRange occuring when retrieving nodes from Grid

I am implementing Breath First Search and trying to obtain the neighbour nodes but I am running into an IndexOutOfRange Error when obtaining neighbours from the Grid (Grid is 100x100). I understand the error but I do not understand why and how it's making its way outside the bounds of the grid. This implementation of finding neighbours works perfectly when running Dijkstra path finding but when I run BFS it seems to give me an IndexOutOfRange.
I have tried checking the current nodes x, z position to make sure its in bounds and then perform finding neighbours in the grid but this did not seem to work for me either, producing the same error. Would appreciate any insight into where I might be going wrong with this.
Grid class Grid.cs
BFS BFS.cs
Neighbours function
public List<Node> GetNeighbours(Node currentNode)
{
var x = Convert.ToInt32(currentNode.Position.x);
var z = Convert.ToInt32(currentNode.Position.z);
var neighbours = new List<Node>() // Unity mentions error occurring here
{
grid[x - 1, z],
grid[x + 1, z],
grid[x, z - 1],
grid[x, z + 1],
grid[x + 1, z + 1],
grid[x - 1, z + 1],
grid[x - 1, z - 1],
grid[x + 1, z - 1]
};
var walkableNeighbours = new List<Node>();
foreach (var neighbour in neighbours)
{
if (!IsCellOccupied(neighbour) && IsInLevelBounds(neighbour))
walkableNeighbours.Add(neighbour);
}
return walkableNeighbours;
}
I have tried checking the bounds before getting grid neighbours but this did not work either, giving me the same error weirdly.
private bool IsIndexInBounds(int x, int z)
{
if (x > 0 && x <= Width - 1 && z > 0 && z <= Height - 1)
return true;
return false;
}
public List<Node> GetNeighbours(Node currentNode)
{
var x = Convert.ToInt32(currentNode.Position.x);
var z = Convert.ToInt32(currentNode.Position.z);
if(IsIndexInBounds(x,z) { ... }
var neighbours = new List<Node>()
{
grid[x - 1, z],
grid[x + 1, z],
grid[x, z - 1],
grid[x, z + 1],
grid[x + 1, z + 1],
grid[x - 1, z + 1],
grid[x - 1, z - 1],
grid[x + 1, z - 1]
};
//...
}
Suggestions
Dynamically finding neighbours surrounding the current point
List<Node> neighbours = new List<Node>();
for (int w = Mathf.Max(0, x - 1); w <= Mathf.Min(x + 1, Width); w++)
{
for (int h = Mathf.Max(0, z - 1); h <= Mathf.Min(z + 1, Height); z++)
{
if (w != x || h != z)
{
neighbours.Add(grid[w, h]);
}
}
}
x - 1 .. z - 1 .. x + 1 .. z + 1 .. there is no check whether these are actually possible
You only check your current position
if(IsIndexInBounds(x, z) { ... }
but you would need to check for each of the neighbours whether it exists like e.g. the brute force way
var neighbours = new List<Node>();
var higherX = x + 1;
var lowerX = x - 1;
var higherZ = z + 1;
var lowerZ = z - 1;
if(IsIndexInBounds(lowerX, z) neighbours.Add(grid[lowerX, z]);
if(IsIndexInBounds(higherX, z) neighbours.Add(grid[higherX, z]);
if(IsIndexInBounds(x, lowerZ) neighbours.Add(grid[x, lowerZ]);
if(IsIndexInBounds(x, higherZ) neighbours.Add(grid[x, higherZ]);
if(IsIndexInBounds(higherX, higherZ) neighbours.Add(grid[higherX, higherZ]);
if(IsIndexInBounds(lowerX, higherZ) neighbours.Add(grid[lowerX, higherZ]);
if(IsIndexInBounds(lowerX, lowerZ) neighbours.Add(grid[lowerX, lowerZ]);
if(IsIndexInBounds(higherX, lowerZ) neighbours.Add(grid[higherX, lowerZ]);
Your IsIndexInBounds is not completely correct btw, indices in c# start with 0 so instead of > 0 you would actually want >= 0. You could also simply make it
private bool IsIndexInBounds(int x, int z)
{
return x >= 0 && x < Width && z >= 0 && z < Height;
}
I believe the problem you are facing is that you are not considering the edge cases, when you are in the x limit for example, there will be no x+1 posibility, so your combinations should only be:
var neighbours = new List<Node>()
{
grid[x - 1, z],
grid[x, z - 1],
grid[x, z + 1],
grid[x - 1, z + 1],
grid[x - 1, z - 1],
};
or if you are in the corner then the only possible neighbours would be [x - 1, z], grid[x, z - 1], grid[x - 1, z - 1]. Your current node creation always tried to find the 8 neighbours sorrounding the point but you have to keep in mind this will not alway be the case.
You can find an algorithm for finding this dynamically here or you can try adding the edge case combinations according to your case, if you prefer.

recursive stackoverflow minesweeper c#

I am writing a game of minesweeper. Below is code for 3 methods in minesweeper. The first method is to check all the spaces around the button pressed and to count how many bombs are around it. The next method is to be called recursively, in order that if the user pressed a button with 0 buttons around it, it will open all of the squares that also indicate 0 squares around it. The third method is to check that it will be in bound the check. The empty space recursive call is getting me a stackoverflow error, what am I doing wrong?
Thanks!
private int GameLogicChecker(int x, int y)
{
int count = 0;
if (_grid[x, y] != -1)
{
if (x + 1 < SizeX)
{ //Right
if (_grid[x + 1, y] == -1)
count++;
}
if (x - 1 > 0)
{ //Left
if (_grid[x - 1, y] == -1)
count++;
}
if (y + 1 < SizeY)
{ //Upper
if (_grid[x, y + 1] == -1)
count++;
}
if (y - 1 > 0)
{ //Lower
if (_grid[x, y - 1] == -1)
count++;
}
if (x + 1 < SizeX && y + 1 < SizeY)
{ //Right-Upper
if (_grid[x + 1, y + 1] == -1)
count++;
}
if (x + 1 < SizeX && y - 1 > 0)
{ //Right-Lower
if (_grid[x + 1, y - 1] == -1)
count++;
}
if (x - 1 > 0 && y + 1 < SizeY)
{ //Left-Upper
if (_grid[x - 1, y + 1] == -1)
count++;
}
if (x - 1 > 0 && y - 1 > 0)
{ //Left-Lower
if (_grid[x - 1, y - 1] == -1)
count++;
}
}
return count;
}
void OpenEmptySpace(int x, int y)
{
for (var k = -1; k <= 1; k++)
{
for (var l = -1; l <= 1; l++)
{
if (CheckBounds(x + k, y + l) && GameLogicChecker(x + k, y + l) == 0)
{
_buttons[x + k, y + l].Text = "0";
OpenEmptySpace(x + k, y + l);
}
}
}
}
private bool CheckBounds(int x, int y)
{
return x >= 0 && x < SizeX && y >= 0 && y < SizeY;
}
For k = 0 and l = 0, you are calling yourself again and again and again...
Thanks to #BenVoigt for pointing out that two zeroes adjacent to each other will also lead to infinite recursion. So, in order to solve that one method is to create a boolean grid too and set a particular cell's value to true if it has been run through once. Assuming the grid is called Explored, I've added the condition for it in the code below.
If you insist on your current code, try changing the condition to:
if (CheckBounds(x + k, y + l)
&& GameLogicChecker(x + k, y + l) == 0
&& !(k == 0 && l == 0)
&& !Explored[x + k, y + l])
{
Explored[x + k, y + l] = true;
_buttons[x + k, y + l].Text = "0";
OpenEmptySpace(x + k, y + l);
}
Here is another answer for you, rewriting your methods one-by-one following better coding practices. Like in the other answer, a boolean grid called Explored[SizeX, SizeY] has been assumed.
1. GameLogicChecker()
private int GameLogicChecker(int x, int y)
{
if (_grid[x, y] == -1) return 0;
int count = 0;
if (x + 1 < SizeX && _grid[x + 1, y] == -1) //Right
{
count++;
}
if (x - 1 > 0 && _grid[x - 1, y] == -1) //Left
{
count++;
}
if (y + 1 < SizeY && _grid[x, y + 1] == -1) //Upper
{
count++;
}
if (y - 1 > 0 && _grid[x, y - 1] == -1) //Lower
{
count++;
}
if (x + 1 < SizeX && y + 1 < SizeY && _grid[x + 1, y + 1] == -1) //Right-Upper
{
count++;
}
if (x + 1 < SizeX && y - 1 > 0 && _grid[x + 1, y - 1] == -1) //Right-Lower
{
count++;
}
if (x - 1 > 0 && y + 1 < SizeY && _grid[x - 1, y + 1] == -1) //Left-Upper
{
count++;
}
if (x - 1 > 0 && y - 1 > 0 && _grid[x - 1, y - 1] == -1) //Left-Lower
{
count++;
}
return count;
}
What's better? Quicker returning from the method for special case. Reduced nesting in If(...) blocks.
2. OpenEmptySpace()
public/private void OpenEmptySpace(int x, int y)
{
for (var deltaX = -1; deltaX <= 1; deltaX += 2)
{
for (var deltaY = -1; deltaY <= 1; deltaY += 2)
{
var thisX = x + deltaX;
var thisY = y + deltaY;
if (OpeningNotNeeded(thisX, thisY))
{
continue;
}
Explored[thisX, thisY] = true;
_buttons[thisX, thisY].Text = "0";
OpenEmptySpace(thisX, thisY);
}
}
}
private bool OpeningNotNeeded(int x, int y)
{
return !CheckBounds(x, y)
|| GameLogicChecker(x, y) != 0
|| Explored[x, y];
}
What's better? Properly named indexing variables in both loops. Properly written condition (+= 2 instead of ++). Reduced nesting in If(...). Easier to read method call in the If(...) instead of three predicates. Useful temporary variables added which make it clear what x + k and y + l were in the code written earlier.
3. CheckBounds() is written fine.

C# IndexOutOfRange Array Exception

I'm trying to create a 2D char array to hold a grid of chars which will be used as a sort of 'map' for a 2D console game.
I am getting a:
IndexOutOfRange exception
..and cannot see why. I've stepped through the code in debug mode and still cannot see the issue.
It steps through the code fine until it hits X = 25 and Y = 1, the upper right boundary of my grid.
I have _gameWidth and _gameHeight created as follows, outside of main but still inside the class:
static int _gameWidth = 25;
static int _gameHeight = 15;
Following is the code that fails, when trying to generate and populate the grid. It fails at this point:
else if (x == _gameWidth && y == 1)
_grid[x, y] = '╕';
static void GenerateGrid()
{
for (int y = 1; y <= _gameHeight; y++)
{
for (int x = 1; x <= _gameWidth; x++)
{
if (x == 1 && y == 1)
_grid[x, y] = '╒';
else if (x == _gameWidth && y == _gameHeight)
_grid[x, y] = '╛';
else if (x == _gameWidth && y == 1)
_grid[x, y] = '╕';
else if (x == 1 && y == _gameHeight)
_grid[x, y] = '╘';
else if ((x != 1 && y == _gameHeight) || (x != _gameWidth && y == 1))
_grid[x, y] = '═';
else if ((x == 1 && y > 1 && y < _gameHeight) || (x == _gameWidth && y > 1 && y < _gameHeight))
_grid[x, y] = '│';
else
_grid[x, y] = 'x';
}
Console.WriteLine("");
}
}
Change
for (int i = 1; i <= gameHeight; i++)
to
for (int i = 0; i < gameHeight; i++)
and do the same for width.
EDIT:
This is because array indexes start at the number 0 and end with the length of the array minus 1.
This exception means that you have accessed an invalid index. From the way you have written the loop I can tell that you think that indexes go from 1 to the length of the array. Arrays are zero-based, though. Use the standard loop form:
for (int i = 0; i < length; i++)
Your loop starts at one. You can use the Visual Studio for loop template. Just type "for<tab><tab>".
Your program might benefit from the Code Review Stack Exchange site.

Having trouble with connected component labeling algorithm

So I've been trying to write a connected-component labeling algorithm but it's not giving me the desired result. Right now I have an image with 3 roses (that are not overlapping) and I want to label each rose with its own grey value. Before I apply the labeling algorithm I use a threshold to get rid of the background and only keep the roses. The roses get the gray value 1 (which is completely white) and the background gets gray value 0 (which is black). Here's an image of what this looks like:
After doing this I apply the labeling algorithm. It should give the roses three different gray values according to the label they've been given. But instead the algorithm creates this weird sort of gradient pattern over the first two roses whereas the last one seems to be a single gray value. Here's an image:
The algorithm might look complicated but it's actually really simple. I recurse on the columns first and then the rows and for each non-background pixel I check if any of its neighbors are already labeled (meaning their objectArray value is not zero). If so I add them to a list of neighbors. I then proceed to check if this list is not empty, if so I uniquely label the current pixel by incrementing the objects value and assigning its value to the current pixel's label value and I also set the current pixel's parent value to this unique label. If it's not empty, I determine the smallest label value in the neighbor list, set all the neighbors' parent values to this label value and I set the current pixel's label and parent values to this label value. I repeat this for every pixel until the whole image has been labeled.
Once this is done I recurse on the pixel values again, this time to set each pixel's label value to its parent value. I then proceed to assign the pixel a new gray value depending on its label value.
I don't understand why the algorithm isn't labeling the roses properly. Can anybody help me out? Here's the algorithm:
public void label()
{
int objects = 1;
int[,] objectArray = new int[colors.GetLength(1), colors.GetLength(0)];
DisjointSets disjointSet = new DisjointSets();
int[,] parents = new int[colors.GetLength(1), colors.GetLength(0)];
List<List<int>> eqSet = new List<List<int>>();
for (int i = 0; i < colors.GetLength(1); i++) for (int j = 0; j < colors.GetLength(0); j++)
{
if (this[i, j].Gray == 1)
{
List<Label> neighbors = new List<Label>();
if (i > 0)
{
if (this[i - 1, j].Gray == 1)
{
if (objectArray[i - 1, j] != 0)
{
neighbors.Add(new Label(i - 1, j, 0));
}
}
if (j > 0)
{
if (this[i - 1, j - 1].Gray == 1)
{
if (objectArray[i - 1, j - 1] != 0)
{
neighbors.Add(new Label(i - 1, j - 1, 0));
}
}
}
if (j < colors.GetLength(0))
{
if (this[i - 1, j + 1].Gray == 1)
{
if (objectArray[i - 1, j] != 0)
{
neighbors.Add(new Label(i - 1, j, 0));
}
}
}
}
if (j > 0)
{
if (this[i, j - 1].Gray == 1)
{
if (objectArray[i, j - 1] != 0)
{
neighbors.Add(new Label(i, j - 1, 0));
}
}
if (i < colors.GetLength(1))
{
if (this[i + 1, j - 1].Gray == 1)
{
if (objectArray[i + 1, j - 1] != 0)
{
neighbors.Add(new Label(i + 1, j - 1, 0));
}
}
}
}
if (i < colors.GetLength(1))
{
if (this[i + 1, j].Gray == 1)
{
if (objectArray[i + 1, j] != 0)
{
neighbors.Add(new Label(i + 1, j, 0));
}
}
if (this[i + 1, j + 1].Gray == 1)
{
if (objectArray[i + 1, j + 1] != 0)
{
neighbors.Add(new Label(i + 1, j + 1, 0));
}
}
}
if (j < colors.GetLength(0))
{
if (this[i, j + 1].Gray == 1)
{
if (objectArray[i, j + 1] != 0)
{
neighbors.Add(new Label(i, j + 1, 0));
}
}
}
if (neighbors.Count == 0)
{
objects++;
objectArray[i, j] = objects;
parents[i, j] = objects;
}
if (neighbors.Count > 0)
{
int smallestLabel = 10000;
foreach (Label x in neighbors)
if (objectArray[x.X, x.Y] < smallestLabel)
smallestLabel = objectArray[x.X, x.Y];
foreach (Label x in neighbors)
parents[x.X, x.Y] = smallestLabel;
objectArray[i, j] = smallestLabel;
parents[i, j] = smallestLabel;
}
}
}
for (int i = 0; i < colors.GetLength(1); i++) for (int j = 0; j < colors.GetLength(0); j++)
{
if (this[i, j].Gray == 1)
{
if (objectArray[i, j] != 0)
{
objectArray[i, j] = parents[i, j];
ColorWrap c = this[i, j];
c.X = (float)objectArray[i, j] / objects;
c.Y = (float)objectArray[i, j] / objects;
c.Z = (float)objectArray[i, j] / objects;
this[i, j] = c;
}
}
}
}
You've got an index error when checking for the third neighbour:
if (this[i - 1, j + 1].Gray == 1)
{
if (objectArray[i - 1, j] != 0)
{
neighbors.Add(new Label(i - 1, j, 0));
}
}
That should be 'j + 1' in all three spots.
That doesn't solve your problem, though. Your algorithm has problems when it meets diagonal edges that are black to thze nortwest and white to the southeast.
You scan the image column-wise from left to right and each column row-wise from top to bottom. You check for eight potential neighbours, but in reality, you can only add pixels to your neighbour list that you have already passed, namely the three pixels in the column to your left and the pixel above your current position. The other four adjacent pixels will have a parent (or object index) of 0.
Now consider an edge like this:
#######...
######....
#####.....
####......
###O......
###.......
##x.......
#xx.......
('#' is black, '.' is unassigned white, 'x' is white that has been assigned a parent and 'O' marks your current position.)
You will only find black or unassigned adjacent tiles. Your neighbour list will be empty, which means that your algorithm creates a new object, although it should logically belong to the yet undiscovered object to the southeast.
(You try to back-track that by assigning all neighbour pixels the value of the new group, but that only fixes one pixel. It can also create empty groups, i.e. objects that have no corresponding pixel.)
I think that your approach is too complicated, anyway. It also doesn't account for the nooks above and to the left of the main body of components. There's no need to create extra data structures, you can do the labelling in the picture itself if you use a greyscale image. After converting the image to pure black and white, pass all pixels once. If a pixel is white, flood-fill the picture from there with a positive gray value that corresponds to the next object and increment the number of objects. Then pass all pixels again and adjust the grey value according to the object id and the number of objects.
Caveat: When I say you can do everything in the picture itself, you limit your labelling to 254 objects.
Aside: You might want to clean up your code a bit. You don't use eqSet and disjointSet, so please remove them from your code. The two arrays objectArray and parents are used alogside each other for the same thing; merge them into one. You should also refactor finding the eight neighbour pixels into a function (with one call for each potential neighbour) to make things easier to read and to avoid indexing errors as above.

Conway's Game Of Life 2D array doesn't line up

I am attempting to make Conway's Game of Life in C# with XAML. The window allows the user to specify the number of rows and columns of my 2D array of cells using a slider. When my Uniform Grid is a perfect square (10x10, 20x20, or even 16x16), the simulations work without a problem. However, when the user attempts to specify a rectangular uniform grid (13x14, 15x26, 24x14), the cells are thrown of by the difference (i.e. in a 33x27 grid, difference = 6, so the cell goes appropriately up, but is thrown off (left/right) by the difference). I have narrowed down that this only happens on the x-axis; the cells are never thrown off on the y-axis.
THE QUESTION: Why is my array throwing off my x axis? Is there something wrong with it?
As far as I can tell, everything should work fine. I set up a log to check the dimensions of my 2D arrays and my uniform grid. I'm not sure what is wrong, and I have been staring and debugging for literally DAYS. I'm at my wits end. Please help, I hope there is something that I am simply not catching.
Code Legend:
unigridOfCells is a Uniform Grid in XAML.
slideWidth/slideHeight are sliders.
Also, I am using a converter from my resource which converts my isAlive property to a 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);
}
The problem is that the order in which you create cells differs from the order in which the UniformGrid arranges its children.
In your setCellsOnGrid method, you create cells top-to-bottom, then left-to-right, whereas the UniformGrid arranges its children in the order left-to-right then top-to-bottom.
For a square grid, the cells in the first column of your grid are drawn in the first row of the UniformGrid, and similarly for other columns and rows. You end up with the grid being reflected in the line x = y. However, for a non-square grid, the length of a row does not equal the length of a column and so the grid is completely out of place.
For example, with a 3 × 3 grid, your loop runs in the following order:
1 4 7
2 5 8
3 6 9
However, the controls are added to the UniformGrid in the following order (assuming you haven't set FlowDirection="Right"):
1 2 3
4 5 6
7 8 9
For, for a 3 × 4 grid, your loop runs in the order
1 5 9
2 6 10
3 7 11
4 8 12
but the controls are added to the UniformGrid in the order
1 2 3
4 5 6
7 8 9
10 11 12
This means that cells that adjacent in your cells array might not be drawn as adjacent in the UniformGrid, and vice versa.
Fortunately, the fix is simple: switch the order of the i and j loops in setCellsOnGrid. Make the j loop the outer loop and the i loop the inner loop.
Incidentally, your blockSpace method doesn't appear to use the i and j loop variables - it just calls the same method codeColumn * codeRow times. Is this intentional?

Categories