Stack overflow exception error in a recursive function - c#

I just started learning c# however I have some experience with java, so one of the things I wanted to do is to generate a 2d array map filled with 1's and 0's and recursively check if there is a path without stepping on 1's.
However after writing the code and running it it shows me the stack overflow exception error.
Where did I do something wrong?
Edit: the end of the array(the cell with the largest value 9,9(it's a 10x10 array) in this case is set to 6 as the end point)
Code for the recursive method:
public static int recursiveCheck(int[,] grid,int x, int y, int finalX, int finalY, int paths)
{
if (grid[x, y] == 6)
{
paths++;
return paths;
}
if ((grid[x + 1, y] != 1) && (x+1 < finalX))
return recursiveCheck(grid, x + 1, y, finalX, finalY, paths);
if ((grid[x, y+1] != 1) && (y+1 < finalY))
return recursiveCheck(grid, x, y+1, finalX, finalY, paths);
if ((grid[x - 1, y] != 1) && (x > 0))
return recursiveCheck(grid, x - 1, y, finalX, finalY, paths);
if (grid[x, y - 1] != 1 && y >0)
return recursiveCheck(grid, x, y - 1, finalX, finalY, paths);
return 0;
}
Array Initialization code:
public static int[,] gridGen()
{
int[,] grid = new int[10, 10];
Random rnd = new Random();
int lim;
for (int i = 0; i < 10; i++)
{
for (int c = 0; c < 10; c++)
{
lim = rnd.Next(0, 2);
//Console.WriteLine($"lim: {lim} ");
grid[i, c] = lim;
}
}
grid[0, 0] = 2;
grid[grid.GetLength(0) - 1, grid.GetLength(1) - 1] = 6;
for (int i = 0; i < 10; i++)
{
for (int c = 0; c < 10; c++)
{
Console.Write(grid[i, c] + " ");
}
Console.WriteLine();
}
return grid;
}

You're not keeping track of which spaces you've already visited. So supposing your grid has two zeros right next to each other, your function will move to one in the first level of recursion, then to the other in the second level, then back to the first in the third level (even though the first level of recursion is still on the stack) and so forth forever.
There are a number of ways that you could keep track of where you've already visited. If you're willing to modify the input array temporarily when this method is called, you could just set the space you're currently on to 1 before looking at the ones around it.
public static int recursiveCheck(int[,] grid,int x, int y, int finalX, int finalY, int paths)
{
var originalValue = grid[x, y];
if (originalValue == 6)
{
paths++;
return paths;
}
grid[x, y] = 1; // prevent deeper recursion from coming back to this space
if ((grid[x + 1, y] != 1) && (x+1 < finalX))
return recursiveCheck(grid, x + 1, y, finalX, finalY, paths);
if ((grid[x, y+1] != 1) && (y+1 < finalY))
return recursiveCheck(grid, x, y+1, finalX, finalY, paths);
if ((grid[x - 1, y] != 1) && (x > 0))
return recursiveCheck(grid, x - 1, y, finalX, finalY, paths);
if (grid[x, y - 1] != 1 && y >0)
return recursiveCheck(grid, x, y - 1, finalX, finalY, paths);
grid[x, y] = originalValue; // allow other path checking to revisit this space.
return 0;
}
Also note that you can probably simplify things a little bit by turning the recursion upside down a little: do your boundary checks and wall checks as exit criteria right away, and use the number of paths purely as a return value rather than an input.
public static int recursiveCheck(int[,] grid, int x, int y, int finalX, int finalY)
{
if(x < 0 || x > finalX || y < 0 || y > finalY)
{
return 0;
}
var originalValue = grid[x, y];
if (originalValue == 1)
{
return 0;
}
if (originalValue == 6)
{
return 1;
}
grid[x, y] = 1; // prevent deeper recursion from coming back to this space
var paths = recursiveCheck(grid, x + 1, y, finalX, finalY)
+ recursiveCheck(grid, x, y + 1, finalX, finalY)
+ recursiveCheck(grid, x - 1, y, finalX, finalY)
+ recursiveCheck(grid, x, y - 1, finalX, finalY);
grid[x, y] = originalValue; // allow other path checking to revisit this space.
return paths;
}

Here's another way of doing it.
Start with a function that returns the valid neighbours of a specific location in the grid:
private IEnumerable<(int r, int c)> GetNeighbours(int[,] grid, (int r, int c) reference)
{
for (int i = -1; i <= 1; i++)
for (int j = -1; j <= 1; j++)
{
var neighbour = (r: reference.r + i, c: reference.c + j);
if ((i != 0 && j != 0)
|| neighbour == reference
|| neighbour.r < 0 || neighbour.r >= grid.GetLength(0)
|| neighbour.c < 0 || neighbour.c >= grid.GetLength(1))
{
continue;
}
yield return neighbour;
}
}
This returns the left, right, up, and down neighbour so long as it is in the valid grid.
Then we'll make a public method that triggers off the building of a path:
public List<(int r, int c)> RecursiveCheck(int[,] grid, (int r, int c) initial, int goal)
{
var path = new List<(int r, int c)>(new[] { initial });
return RecursiveCheck(grid, path, goal);
}
Its purpose is to take the initial starting point and turn that in to a path of one element and then it calls the true recursive function.
And here it is:
private List<(int r, int c)> RecursiveCheck(int[,] grid, List<(int r, int c)> path, int goal)
{
foreach (var neighbour in GetNeighbours(grid, path.Last()))
{
if (!path.Contains(neighbour))
{
var next = path.Concat(new[] { neighbour }).ToList();
if (grid[neighbour.r, neighbour.c] == goal)
{
return next;
}
else if (grid[neighbour.r, neighbour.c] == 0)
{
return RecursiveCheck(grid, next, goal);
}
}
}
return new List<(int r, int c)>();
}
This takes the existing path, finds all of neighbours of the last element in the path. It checks that it hasn't visited those neighbours and then builds the next path. It then checks if it hits the goal, and if so, returns the path. Otherwise if the current cell has the value 0 it then recurses to find a solution. If it can't find a solution it returns an empty path.
Here's an example usage:
int[,] grid = new int[3, 5]
{
{ 0, 1, 0, 0, 0},
{ 0, 1, 0, 1, 0},
{ 0, 0, 0, 1, 6},
};
List<(int r, int c)> path = RecursiveCheck(grid, (r: 0, c: 0), 6);
Console.WriteLine(path.Count);
That outputs 11 (which is the correct length to find the 6 from the top-left).

Related

least sum of vertical line in 2d array

I have a 2D array I have the
number of rows = H
number of columns = W
the 2d array itself = arr
they are all integers
I am tasked to return the lowest sum of the vertical line starts with each point at first row
input
1 2 3
4 5 6
7 8 9
output 12
I thought about a way to solve this by using recursion but i don't get right results.
the function takes the array, the position i want to calculate minimum sum at (should be on the first-row coz it's a line) number of columns and rows and res is to return the sum res is initialized in the main function by arr at row x and column y
I am sure about the idea but the way I am summing is probably wrong
static int Summ(int [,]arr,int x,int y,int W,int H,int res)
{
if (x == H - 1)
res += arr[x, y];
else
if (y == 0)
res += Math.Min(Summ(arr, x + 1, y, W, H, res), Summ(arr, x + 1, y + 1, W, H, res));
else if (y== W-1)
res += Math.Min(Summ(arr, x + 1, y, W, H, res), Summ(arr, x + 1, y - 1, W, H, res));
else
res+= res += Math.Min(Math.Min(Summ(arr, x + 1, y, W, H, res), Summ(arr, x + 1, y + 1, W, H, res)),Summ(arr,x+1,y-1,W,H,res));
return res;
}
An iterative solution may be simpler:
static int MinSum(int [,]arr)
{
int min = Int32.MaxValue;
for (int j = 0; j < arr.GetLength(1); ++j)
{
int sum = 0;
for (int i = 0; i < arr.GetLength(0); ++i)
{
sum += arr[i, j];
}
min = Math.min(min, sum);
}
return min;
}
EDIT:
Given the clarification in the comment below, this solution is not correct.
Instead, you could iterate over the rows and sum the minimal value in each row:
static int MinSum(int [,]arr)
{
int sum = 0;
for (int i = 0; j < arr.GetLength(0); ++i)
{
int minCol = arr[i, 0];
for (int j = 1; j < arr.GetLength(1); +_j)
{
minCoal = Math.min(minCol, arr[i, j]);
}
min += minCol;
}
return sum;
}

prim's algorithm generated maze missing walls

So I'm implementing a maze generator using prim's algorithm.
the maze itself generates pretty much fine, however two (touching) walls would always be missing.
the mazes I'm generating (the right and bottom walls are missing):
Maze 1
here the left and top walls are missing:
Maze 2
The code I use to generate the maze:
int _height = 50;
int _width = 50;
private bool[,] maze = new bool[_height, _width];
private void generateMaze()
{
//_height = 50
//_width = 50
List<MazeCell> walls = new List<MazeCell>();
int randX = genRand(1, _height-1);
int randY = genRand(1, _width-1);
maze[randX, randY] = true;
MazeCell start = new MazeCell(randX, randY, null);
for (int i = -1; i <= 1; i++)
{
for(int j = -1; j <= 1; j++)
{
if ((i == 0 && j == 0) || (i != 0 && j != 0))
continue;
try
{
if (maze[randX + i, randY + j])
continue;
}
catch(Exception e)
{
continue;
}
walls.Add(new MazeCell(randX + i, randY + j, start));
}
}
while (walls.Count > 0)
{
int index = genRand(0, walls.Count - 1);
MazeCell cur = walls[index];
MazeCell op = cur.opposite();
walls.RemoveAt(index);
try
{
if(!maze[cur.x, cur.y])
{
if(!maze[op.x, op.y])
{
maze[cur.x, cur.y] = true;
maze[op.x, op.y] = true;
for (int i = -1; i <= 1; i++)
{
for (int j = -1; j <= 1; j++)
{
if (i == 0 && j == 0 || i != 0 && j != 0)
continue;
try
{
if (maze[op.x + i, op.y + j])
continue;
}
catch (Exception e)
{
continue;
}
walls.Add(new MazeCell(op.x + i, op.y + j, op));
}
}
}
}
}
catch (Exception e) { }
}
}
private int genRand(int min, int max)
{
Random rnd = new Random();
return rnd.Next(min, max);
}
And the mazeCell class:
public class MazeCell
{
public int x;
public int y;
public bool passage = false;
MazeCell parent;
public MazeCell(int x, int y, MazeCell parent)
{
this.x = x;
this.y = y;
this.parent = parent;
}
public MazeCell opposite()
{
if (x.CompareTo(parent.x) != 0)
return new MazeCell(x + x.CompareTo(parent.x), y, this);
if (y.CompareTo(parent.y) != 0)
return new MazeCell(x, y + y.CompareTo(parent.y), this);
return null;
}
}
the code is an adaptation of java code I found here: http://jonathanzong.com/blog/2012/11/06/maze-generation-with-prims-algorithm
I can't find where it suddenly decides to remove walls.
Any help is greatly appreciated!
I tried your code and if you move the new Random outside the method to a member variable (so it's created just once), then it seems to work just fine.
There is no code to ensure that there is a boundary around the edge of the whole maze: the maze will happily wander right up to any edge. What you are seeing is an artifact of non-randomness caused by resetting Random every time.
If set Random to the same seed over and over in that method I see long runs down two sides also.
Here's sample output for 15x15 with proper random values:
XXXXXXXXX X X X
X X X X
X X XXXXXXXXXXX
X X X X X
XXXXXXXXX X X X
X X X X
X XXX XXXXXXX X
X X X X
XXXXX X X XXX X
X X X
XXXXXXX X XXXXX
X X X X X X
X XXX XXXXXXX X
X X X X
XXX X X XXXXXXX
I would suggest to tackle this more from a graph-based perspective and not from some specific representation of a "maze".
See also my answer to this question.

How to check for the previous path searched on a maze C#

I am trying to code an algorithm that solves a maze problem but I am facing some difficulty to apply it correctly.
The algorithm runs over the walls instead of changing the direction after finding the valid point.
Complete Code on Github
I do not understand clearly how to check for the previousPoint and then from that point check for the next valid move.
Could someone help me giving me some tips on which direction I could go?
class MapPathFinder
{
public bool[,] correctPath = new bool[12,12];
public int[,] previousPoint = new int[12, 12];
public bool startPointFound = false;
public bool nextValidMove(MapFile map, int y, int x)
{
if ((y == map.width) && (x == map.height)) {
return false; //Checks if at the edge and terminates the method
}
if ((map.Matrix[y, x]) == 1 ) {
return true; // check if at a wall and terminate the method
}
if (y != 0)
{
if (nextValidMove(map, y-1,x))
{
map.Matrix[y, x] = 9; //changes the color of the position
correctPath[y, x] = true;
return correctPath[y, x];
}
if (y != map.width - 1) //check if at the limit of the map
{
if (nextValidMove(map,y + 1, x))
{
map.Matrix[y, x] = 9;
correctPath[y, x] = true;
return correctPath[y, x];
}
}
if (x != 0)
{
if (nextValidMove(map, y, x - 1))
{
map.Matrix[y, x] = 9;
correctPath[y, x] = true;
return correctPath[y, x];
}
}
if (x != map.height - 1)
{
if (nextValidMove(map, y, x + 1))
{
map.Matrix[y, x] = 9;
correctPath[y, x] = true;
return correctPath[y, x];
}
}
}
return false;
}
public bool PathFinder(MapFile map)
{
for (int y = 1; y < map.width; y++)
{
for (int x = 1; x < map.height; x++)
{
var status = MapDisplay.DisplayMap(map);
if (status)
{
nextValidMove(map, x, y);
}
}
}
return true;
}
I tried to implement the answer given by Paul but could not really get anywhere from it and I am completely lost.
That is what I got from your answer:
public bool nextValidMove(MapFile map, int y, int x)
{
if ((y == map.width) || (x == map.height)) return false;
if(y<0 || x<0) return false;
if ((map.Matrix[y, x]) == 1) return true; // check if at a wall and terminate the method
if (map.Matrix[y, x] == 5) return map.end;
if (y - 1 >= 0 && map.Matrix[y-1, x] == 2 && !nextValidMove(map, y-1, x))
{
map.Matrix[y, x] = 9;
previousPoint[y, x] = map.Matrix[y, x];
return false;
}
// Test the East wall...
if (x + 1 <= map.width - 1 && map.Matrix[y + 1, x] == 2 && !nextValidMove(map, y, x+1))
{
map.Matrix[y, x] = 9;
previousPoint[y, x] = map.Matrix[y, x];
return false;
}
// Test the South wall...
if (y + 1 <= map.height - 1 && map.Matrix[y, x + 1] == 2 && !nextValidMove(map, y+1,x))
{
map.Matrix[y, x] = 9;
previousPoint[y, x] = map.Matrix[y, x];
return false;
}
// Test the West wall...
if (x - 1 >= 0 && map.Matrix[y, x - 1] == 2 && !nextValidMove(map, y, x-1))
{
map.Matrix[y, x] = 9;
previousPoint[y, x] = map.Matrix[y, x];
return false;
}
return false;
}
When I run it I get a stack overflow error.
When I am checking the possible points and calling the function recursively with
!nextValidMove(map, y-1, x)
I don't really understand why I am checking the nextValidMove(y-1,x) since it was already true at the begining of my if statement:
if(map.Matrix[y-1, x] == 2 && !nextValidMove(y-1,x))
I thought of checking the previousPoint together, like this:
if(nextValidMove(map, y - 1, x)&&!previousPoint[y-1,x])
But I am getting a stackoverflow error. I have no clue how to get out of there anymore.
I have rewriten your MapPathFinder class to make it work.
class MapPathFinder
{
public const byte WALL = 1;
public const byte ROAD = 2;
public const byte START = 3;
public const byte FINISH = 5;
public const byte ALREADY_THERE = 9;
public bool NextValidMove(MapFile map, int x, int y)
{
// Check edges
if (x < 0 || x > map.width || y < 0 || y > map.height)
return false;
byte currentPosition = map.Matrix[x, y];
// Check walls or already there
if (currentPosition == WALL || currentPosition == ALREADY_THERE)
return false;
// Print
var status = MapDisplay.DisplayMap(map);
if (status)
{
// Check finish
if (currentPosition == FINISH)
{
return true; // We've arrived!
}
// Road
//
// Set ALREADY THERE
map.Matrix[x, y] = ALREADY_THERE;
// Left
if (NextValidMove(map, x - 1, y))
return true;
// Right
if (NextValidMove(map, x + 1, y))
return true;
// Up
if (NextValidMove(map, x, y - 1))
return true;
// Down
if (NextValidMove(map, x, y + 1))
return true;
// Not the correct path..
map.Matrix[x, y] = ROAD;
}
return false;
}
public bool PathFinder(MapFile map)
{
// Looking for start point
for (int x = 0; x < map.width; x++)
{
for (int y = 0; y < map.width; y++)
{
if (map.Matrix[x, y] == START)
return NextValidMove(map, x, y);
}
}
return false;
}
}
However I left some work for you:
No storing of the correct path.
If there are two correct paths, this algorithm won't take always the shorter one, but the first found.
Your walls are determined by there being a # in any of the adjacent cells or a . for the floor, S start and F finish.
In that case, you want to simply check on a rotational basis, starting at, say, North, then move onto the next position round, until you arrive back at North. Each check should be pushed on the stack and popped off when it gets nowhere. That way, at least, you'll be able to trace your way backward each time.
// Test to see if we've found Utopia...
if(map.Matrix[x, y] == 'F') return true;
// Test the North wall...
if(y-1>=0 && map.Matrix[x, y-1]=='.' && !nextValidMove(map, x, y-1)) return false;
// Test the East wall...
if(x+1<=map.width && map.Matrix[x+1, y]=='.' && !nextValidMove(map, x+1, y)) return false;
// Test the South wall...
if(y+1<=map.height && map.Matrix[x, y+1]=='.' && !nextValidMove(map, x, y+1)) return false;
// Test the West wall...
if(x-1>=0 && map.Matrix[x-1, y]=='.' && !nextValidMove(map, x-1, y)) return false;
The recursive calls should then unwind naturally.
Note that you'll need to look at the success criteria a little better than I have there, and you may need to play with how the routine unwinds. The code here gives a demonstration, though, of how to check your adjoining walls.
Notice that && only performs the next check if the prior one was successful in the first place.

StackOverflow if using Parallel.For

I'm currently trying to make a code, that will help to count efficient reactors set for game StarMade.
I'm using recursive method to explore the 3d tree of elements and find all related groups. For ex. group - it's a cluster of elements, that stay close to each other.
On picture something like this:
XOX
OOX
XXO
where O is nothing, and X is reactor (element).
On this picture there are 3 groups of elements. [0,0], [2,0]-[2,1], [0,2]-[1,2]
Another variant:
XXX
OOX
XXX
Here is only one group, because all elements stay close to each other.
Here is my code:
void CheckGroup(int x, int y, int z, Group group)
{
if(x >= maxz || x < 0 || y >= maxy || y < 0 || z >= maxz || z < 0)
{
return;
}
if (reactorsChecked[x, y, z])
{
return;
}
reactorsChecked[x, y, z] = true;
if (reactors[x, y, z])
{
if (group == null)
{
group = new Group();
group.MaxX = x;
group.MaxY = y;
group.MaxZ = z;
group.MinX = x;
group.MinY = y;
group.MinZ = z;
group.Blocks = 1;
}
else
{
group.MaxX = Math.Max(group.MaxX, x);
group.MaxY = Math.Max(group.MaxY, y);
group.MaxZ = Math.Max(group.MaxZ, z);
group.MinX = Math.Min(group.MinX, x);
group.MinY = Math.Min(group.MinY, y);
group.MinZ = Math.Min(group.MinZ, z);
group.Blocks += 1;
}
CheckGroup(x + 1, y, z, group);
CheckGroup(x - 1, y, z, group);
CheckGroup(x, y + 1, z, group);
CheckGroup(x, y - 1, z, group);
CheckGroup(x, y, z + 1, group);
CheckGroup(x, y, z - 1, group);
if (!groups.Contains(group))
{
groups.Add(group);
}
}
}
group - is simple class for cluster, that store data about elements count in this cluster and bounding box of this cluster.
reactorsChecked - is simple bool[,,] array, that store information about elements, that we have checked, to avoid doubles
reactor - simple bool[,,] array of random elements.
At first I insert random values to reactors array, and then call CheckGroup(x,y,z,null). If reactors array size less then 25x25x25, then all ok. In single thread size of array could be 100x100x100 and all would be ok. But if I try to use Parallel.For, then I got StackOverflow after near 9000 recursions...
Here is full code:
Parallel.For(0, Environment.ProcessorCount, (i) =>
{
Calculator calc = new Calculator(x, y, z, max, cycles);
calcs.Add(calc);
});
public class Calculator
{
Random rnd = new Random();
//List<Group> groups = new List<Group>();
HashSet<Group> groups = new HashSet<Group>();
bool[, ,] reactors;
public bool[, ,] reactorsMax;
bool[, ,] reactorsChecked;
public double maxEnergy = 0;
public string result = "";
public string resultPic = "";
int maxx, maxy, maxz;
public Calculator(int x, int y, int z, int max, int cycles)
{
maxx = x;
maxy = y;
maxz = z;
maxEnergy = max;
for (int i = 0; i < cycles; i++)//check few variants per thread
{
Calculate(x,y,z);
}
}
private void Calculate(int X, int Y, int Z)
{
//groups = new List<Group>();
groups = new HashSet<Group>();
reactors = new bool[X, Y, Z];
for (int x = 0; x < X; x++)
{
for (int y = 0; y < Y; y++)
{
for (int z = 0; z < Z; z++)
{
reactors[x, y, z] = rnd.Next(2)==1;//fill array with random values
}
}
}
reactorsChecked = new bool[X, Y, Z];
for (int x = 0; x < X; x++)
{
for (int y = 0; y < Y; y++)
{
for (int z = 0; z < Z; z++)
{
CheckGroup(x, y, z, null);//start calculations
}
}
}
double sum = 0;
int blocks = 0;
foreach(Group g in groups)
{
float dims = g.MaxX - g.MinX + g.MaxY - g.MinY + g.MaxZ - g.MinZ + 3;
sum += (2000000.0f / (1.0f + Math.Pow(1.000696f, (-0.333f * Math.Pow((dims / 3.0f), 1.7)))) - 1000000.0f + 25.0f * g.Blocks);
blocks += g.Blocks;
}
if (sum > maxEnergy)
{
maxEnergy = sum;
reactorsMax = reactors;
}
}
void CheckGroup(int x, int y, int z, Group group)
{
if(x >= maxz || x < 0 || y >= maxy || y < 0 || z >= maxz || z < 0)
{
return;
}
if (reactorsChecked[x, y, z])
{
return;
}
reactorsChecked[x, y, z] = true;
if (reactors[x, y, z])
{
if (group == null)
{
group = new Group();
group.MaxX = x;
group.MaxY = y;
group.MaxZ = z;
group.MinX = x;
group.MinY = y;
group.MinZ = z;
group.Blocks = 1;
}
else
{
group.MaxX = Math.Max(group.MaxX, x);
group.MaxY = Math.Max(group.MaxY, y);
group.MaxZ = Math.Max(group.MaxZ, z);
group.MinX = Math.Min(group.MinX, x);
group.MinY = Math.Min(group.MinY, y);
group.MinZ = Math.Min(group.MinZ, z);
group.Blocks += 1;
}
CheckGroup(x + 1, y, z, group);
CheckGroup(x - 1, y, z, group);
CheckGroup(x, y + 1, z, group);
CheckGroup(x, y - 1, z, group);
CheckGroup(x, y, z + 1, group);
CheckGroup(x, y, z - 1, group);
if (!groups.Contains(group))
{
groups.Add(group);
}
}
}
}
So the main question - is it possible to avoid stackOverflow in Parallel.For, or to rewrite it to iteration loop?
Parallel.For using default stackSize value even if you will use
Thread(()=>
{
Parallel.For(...);
},stackSize).Start()
it will use default values...
I don't like variant like this:
for(int i = 0; i < cpuCount; i++)
{
Thread t = new Thread(()=>{calculate();},stackSize).Start()
}
because I have to manage all threads, wait while all finishes, so it makes code very complicated... May be there are easier things?
There are two options:
to use recursion and try to increase the stack size (by using the Thread(ThreadStart, maxStackSize) constructor). The stack in applications is usually set to 1MB (see this link for details). Especially in DEBUG mode without optimizations (no inlining optimization done) this is a very limited value. Having a thread with separate stack for every Paralllel.For() statement
might help.
Use a iteration look instead of recursion to handle the stack depth by yourself.
I personally would go with option 1. (with or without separate stack) only in case I known the maximum depth of my recursion.
My preferred solution in most cases like yours will be the iteration approach.
Edit by #LordXaosa:
I tried this, and all works fine
int stackSize = 1024*1024*1024;//1GB limit
ManualResetEvent[] mre = new ManualResetEvent[Environment.ProcessorCount];
Parallel.For(0, Environment.ProcessorCount, (i) =>
{
mre[i] = new ManualResetEvent(false);
Thread t = new Thread((object reset) =>
{
Calculator calc = new Calculator(x, y, z, max, cycles);
calcs.Add(calc);
ManualResetEvent m = (ManualResetEvent)reset;
m.Set();
}, stackSize / (Environment.ProcessorCount * 4));
t.Start(mre[i]);
});
WaitHandle.WaitAll(mre);
But there also a limit... 50x50x50 array works fine, but more - stack overflow... In original game it can process 1000x1000x1000 sets, so may be there is another algorithm.
Thanks for your help!

C# Check for neighbours

I have a function to check neighbors of an array and if that element is equal with 1. X is for each neighbor found and v[l] is the position for each 0. I have a problem with this code each time gives me "Index was outside the bounds of the array" and i don't know what to do else.
public int modificari(int i,int j,int n,int m)
{
int x = 0;
v = new int[n];
l=0;
if (mat[i, j] == 1)
{
if (j++ < m)
{
if (mat[i, j++] == 1)
x++;
else
{
v[l] = i * n + j + 2;
l++;
}
}
if (j++ < m && i++ < n)
{
if (mat[i++, j++] == 1)
x++;
else
{
v[l] = (i + 1) * n + j + 2;
l++;
}
}
if (i++ < n)
{
if (mat[i++, j] == 1)
x++;
else
{
v[l] = (i + 1) * n + j + 1;
l++;
}
}
if (j-- >= 0 && i++ < n)
{
if (mat[i++, j--] == 1)
x++;
else
{
v[l] = (i + 1) * n + j;
l++;
}
}
if (j-- >= 0)
{
if (mat[i, j--] == 1)
x++;
else
{
v[l] = i * n + j;
l++;
}
}
if (j-- >= 0 && i-- >= 0)
{
if (mat[i--, j--] == 1)
x++;
else
{
v[l] = (i - 1) * n + j;
l++;
}
}
if (i-- >= 0)
{
if (mat[i--, j] == 1)
x++;
else
{
v[l] = (i - 1) * n + j + 1;
l++;
}
}
if (j < n && i-- >= 0)
{
if (mat[i--, j++] == 1)
x++;
else
{
v[l] = (i - 1) * n + j + 2;
l++;
}
}
if (x < 2 && x > 3)
return 1;
else
return random();
}
return x;
}
That is a total mess. It is very hard to follow, even for an experienced coder. Use of one letter variable names and inline ++ operators is usually discouraged for the sake of readability.
I've quickly tried to rewrite your function from my best guess of what you're trying to achieve. I'm hoping you can see a different way to approach the problem that suits you better.
NOTE: I did not test this code at all, it probably has compile errors.
public struct Point
{
public int X;
public int Y;
public Point( int x, int y )
{
X = x;
Y = y;
}
}
public class Whatever
{
// ...
// Here is a list of the positions of all the neighbours whose values are
// zero.
List<Point> zeroPositions = new List<Point>();
// ...
public int Modificari(int pointX, int pointY)
{
// Determine dimensions of array.
int height = mat.GetLength(0);
int width = mat.GetLength(1);
// Find the minimum and maximum positions bounded by array size. (So we
// don't try to look at cell (-1, -1) when considering the neighbours of
// cell (0, 0) for instance.
int left = Math.Max( pointX - 1, 0 );
int right = Math.Min( pointX + 1, width );
int top = Math.Max( pointY - 1, 0 );
int bottom = Math.Min( pointY + 1, height );
// This is the number of neighbours whose value is 1.
int oneCount = 0;
zeroPositions.Clear();
for( int y = top; y <= bottom; y++ )
{
for( int x = left; x <= right; x++ )
{
if( mat[x, y] == 1 )
{
oneCount++;
}
else if( mat[x, y] == 0 )
{
zeroPositions.Add( new Point( x, y ) );
}
}
}
return oneCount;
}
//...
}
Also I'd really advise you to try not to do too many things in a function. Try making a different function for getting positions of ones and for returning the number of zeros.

Categories

Resources