System.StackOverflowException error - c#

I am trying to create a 2D cave generation system. When I run the program I get "System.StackOverflowException" Exception, after I try to create new object from its own class.
My cave generator works like this:
I create a map that contains ID’s (integers) of the different types of cells(like wall, water or empty Space).
First off all my "Map" class creates a map filled with walls and after that in the centre of the map, it creates a "Miner" object. The Miner digs the map and makes caves. The problem is I want to create more miners. So, my Miner that is digging the map creates another Miner. However, when I do this, I get a "System.StackOverflowException" Exception.
How do I go about tracking down the cause of the StackOverflow in my program.
Here is my miner code:
Miner.cs
public class Miner
{
Random rand = new Random();
public string state { get; set; }
public int x { get; set; }
public int y { get; set; }
public Map map { get; set; }
public int minersCount;
public Miner(Map map, string state, int x, int y)
{
this.map = map;
this.state = state;
this.x = x;
this.y = y;
minersCount++;
if (state == "Active")
{
StartDigging();
}
}
bool IsOutOfBounds(int x, int y)
{
if (x == 0 || y == 0)
{
return true;
}
else if (x > map.mapWidth - 2 || y > map.mapHeight - 2)
{
return true;
}
return false;
}
bool IsLastMiner()
{
if (minersCount == 1)
{
return true;
}
else
{
return false;
}
}
public void StartDigging()
{
if (state == "Active")
{
int dir = 0;
bool needStop = false;
int ID = -1;
while (!needStop && !IsOutOfBounds(x, y))
{
while (dir == 0)
{
dir = ChooseDirection();
}
if (!AroundIsNothing())
{
while (ID == -1)
{
ID = GetIDFromDirection(dir);
}
}
else
{
if (!IsLastMiner())
{
needStop = true;
}
}
if (ID == 1)
{
DigToDirection(dir);
dir = 0;
}
if (ID == 0 && IsLastMiner())
{
MoveToDirection(dir);
dir = 0;
}
TryToCreateNewMiner();
}
if (needStop)
{
state = "Deactive";
}
}
}
public void TryToCreateNewMiner()
{
if (RandomPercent(8))
{
Miner newMiner = new Miner(map, "Active", x, y);
}
else
{
return;
}
}
bool AroundIsNothing()
{
if (map.map[x + 1, y] == 0 && map.map[x, y + 1] == 0 &&
map.map[x - 1, y] == 0 && map.map[x, y - 1] == 0)
{
return true;
}
else
{
return false;
}
}
void MoveToDirection(int dir)
{
if (dir == 1)
{
x = x + 1;
}
else if (dir == 2)
{
y = y + 1;
}
else if (dir == 3)
{
x = x - 1;
}
else if (dir == 4)
{
y = y - 1;
}
}
void DigToDirection(int dir)
{
if (dir == 1)
{
map.map[x + 1, y] = 0;
x = x + 1;
}
else if (dir == 2)
{
map.map[x, y + 1] = 0;
y = y + 1;
}
else if (dir == 3)
{
map.map[x - 1, y] = 0;
x = x - 1;
}
else if (dir == 4)
{
map.map[x, y - 1] = 0;
y = y - 1;
}
}
int GetIDFromDirection(int dir)
{
if (dir == 1)
{
return map.map[x + 1, y];
}
else if (dir == 2)
{
return map.map[x, y + 1];
}
else if (dir == 3)
{
return map.map[x - 1, y];
}
else if (dir == 4)
{
return map.map[x, y - 1];
}
else
{
return -1;
}
}
int ChooseDirection()
{
return rand.Next(1, 5);
}
bool RandomPercent(int percent)
{
if (percent >= rand.Next(1, 101))
{
return true;
}
return false;
}
}

Whilst you can get StackOverflowExceptions by creating too many really large objects on the stack, it usually happens because your code has got into a state where it is calling the same chain of functions over and over again. So, to track down the cause in your code, the best starting point is to determine where your code calls itself.
Your code consists of several functions that are called by the Miner class itself, most of which are trivial
Trivial functions that don't call anything else in the class. Whilst these functions may contribute to the state that triggers the problem, they aren't part of the terminal function loop:
IsOutOfBounds(int x, int y)
bool IsLastMiner()
bool AroundIsNothing()
void MoveToDirection(int dir)
void DigToDirection(int dir)
int GetIDFromDirection(int dir)
int ChooseDirection()
bool RandomPercent(int percent)
This leaves your remaining three functions
public Miner(Map map, string state, int x, int y) // Called by TryToCreateNewMiner
public void StartDigging() // Called by constructor
// Contains main digging loop
public void TryToCreateNewMiner() // Called by StartDigging
These three functions form a calling loop, so if the branching logic in the functions is incorrect it could cause a non-terminating loop and hence a stack overflow.
So, looking at the branching logic in the functions
Miner
The constructor only has one branch, based on if the state is "Active". It is always active, since that's the way the object is always being created, so the constructor will always call StartDigging. This feels like the state isn't being handled correctly, although it's possible that you're going to use it for something else in the future...
As an aside, it's generally considered to be bad practice to do a lot of processing, not required to create the object in an objects constructor. All of your processing happens in the constructor which feels wrong.
TryToCreateNewMiner
This has one branch, 8% of the time, it will create a new miner and call the constructor. So for every 10 times TryToCreateNewMiner is called, we stand a good chance that it will have succeeded at least once. The new miner is initially started in the same position as the parent object (x and y aren't changed).
StartDigging
There's a fair bit of branching in this method. The main bit we are interested in are the conditions around calls to TryToCreateNewMiner. Lets look at the branches:
if(state=="Active")
This is currently a redundant check (it's always active).
while (!needStop && !IsOutOfBounds(x, y)) {
The first part of this termination clause is never triggered. needStop is only ever set to true if(!IsLastMiner). Since minersCount is always 1, it's always the last miner, so needStop is never triggered. The way you are using minersCount suggests that you think it is shared between instances of Miner, which it isn't. If that is your intention you may want to read up on static variables.
The second part of the termination clause is the only way out of the loop and that is triggered if either x or y reaches the edge of the map.
while(dir==0)
This is a pointless check, dir can only be a number between 1 and 5, since that's what is returned by ChooseDirection.
if(!AroundIsNothing())
This is checking if the positions that the Miner can move into are all set to 0. If they are not, then GetIDFromDirection is called. This is key. If the Miner is currently surrounded by 0, ID will not be set, it will remain at it's previous value. In a situation where a Miner has just been created, this will be -1 (we know this could happen because all Miners are created at the location of the Miner creating it).
The last two checksif(ID==1) and if(ID==0 && IsLastMiner()) guard the code that moves the Miner (either by calling dig, or move). So, if ID is not 0, or 1 at this point the Miner will not move. This could cause a problem because it is immediately before the call to TryToCreateNewMiner, so if the program ever gets into this situation it will be stuck in a loop where the Miner isn't moving and it's constantly trying to create new Miners in the same position. 8% of the time this will work, creating a new miner in the same position, which will perform the same checks and get into the same loop, again not moving and trying to create a new miner and so it goes until the stack runs out of space and the program crashes.
You need to take a look at your termination clauses and the way you're handling ID, you probably don't want the Miner to just stop doing anything if it gets completely surround by 0.

Related

I need to reset y inside the loop before the if statements, then check the count

Hello im trying to make this loop count when it finds a certain object then once it finds all 3 it executes the final line. However when i run the code as is the game does not start. Im assuming this is because once it cant find one object it counts that 3 times. So i believe the best way to fix this would be to reset y inside the loop before the if statements, then check the count. Im not exactly sure how to go about this. Any ideas of how i can make this happen. any help would be greatly appreciate it.
void Start() {
y = 0;
StartCoroutine(checkTurrets());
}
IEnumerator checkTurrets() {
while (true) {
y = 0;
if (GameObject.Find("right") != null) {} else {
y++;
}
y = 0;
if (GameObject.Find("left") != null) {} else {
y++;
}
y = 0;
if (GameObject.Find("bottom") != null) {} else {
y++;
}
if (y == 3) {
y++;
SphereCollider sc = gameObject.AddComponent(typeof (SphereCollider)) as SphereCollider;
}
}
}
Try This
IEnumerator checkTurrets() {
while (true) {
if (GameObject.Find("right") != null && GameObject.Find("left") != null && GameObject.Find("bottom") != null)
{
SphereCollider sc = gameObject.AddComponent(typeof (SphereCollider)) as SphereCollider;
}
}
}
I am assuming you want to execute the statement when you find all three objects.

Depth-first search never reaching goal state

I was studying search algorithms and wanted to solve the missionaries and cannibals problem in order to practice. However, my code never provides a solution. At first, I thought this was because I had recurring states, causing an infinite loop, so I added a state history to make sure states weren't being repeated. However, this still has not worked.
Below is the code I have written. I am using vectors to represent the states of the missionaries, cannibals and the boat and the children of the nodes get added if they pass a check that checks if the move is within the range (0,0,0) and (3,3,1).
I have tried stepping through the code but since the tree is fairly large I can only keep track of so many things, so I have a hard time seeing the fault in my code.
This was written in Visual Studio as a console program.
Vector3 class
public class Vector3
{
public int m;
public int c;
public int b;
public Vector3(int M, int C, int B)
{
m = M;
c = C;
b = B;
}
public override bool Equals(System.Object obj)
{
if (obj == null)
return false;
Vector3 p = obj as Vector3;
if ((System.Object)p == null)
return false;
return (m == p.m) && (c == p.c) && (b == p.b);
}
}
Node class
public class Node
{
public Vector3 State;
public Node(Vector3 st)
{
State = st;
}
}
My Program.cs
class Program
{
static void Main(string[] args)
{
Program p = new Program();
p.DFS(new Node(new Vector3(3, 3, 1)));
Console.ReadKey();
}
List<Vector3> History = new List<Vector3>();
Vector3[] Operators = new Vector3[]
{
new Vector3(1,0,1),
new Vector3(2,0,1),
new Vector3(0,1,1),
new Vector3(0,2,1),
new Vector3(1,1,1),
};
public bool TryMove(Vector3 current, Vector3 toApply, bool substract)
{
if (substract)
{
if (current.c - toApply.c < 0 || current.m - toApply.m < 0 || current.b - toApply.b < 0 || (current.c - toApply.c) > (current.m - toApply.m))
{
return false;
}
else return true;
}
else
{
if (current.c + toApply.c > 3 || current.m + toApply.m > 3 || current.b + toApply.b > 1 || (current.c + toApply.c) > (current.m + toApply.m))
{
return false;
}
else return true;
}
}
public void DFS(Node n)
{
Stack<Node> stack = new Stack<Node>();
stack.Push(n);
while (stack.Count > 0)
{
Node curNode = stack.Pop();
if (History.Contains(curNode.State))
{
}
else
{
History.Add(curNode.State);
if (curNode.State == new Vector3(0, 0, 0))
{
Console.WriteLine("Solution found.");
return;
}
else
{
if (curNode.State.b == 0) //Boat is across the river
{
for (int x = 0; x < 5; x++)
{
if (TryMove(curNode.State, Operators[x], false))
{
stack.Push(new Node(new Vector3(curNode.State.m + Operators[x].m, curNode.State.c + Operators[x].c, curNode.State.b + Operators[x].b)));
}
}
}
else //Boat == 1
{
for (int x = 0; x < 5; x++)
{
if (TryMove(curNode.State, Operators[x], true))
{
stack.Push(new Node(new Vector3(curNode.State.m - Operators[x].m, curNode.State.c - Operators[x].c, curNode.State.b - Operators[x].b)));
}
}
}
}
}
}
Console.WriteLine("No solution found.");
return;
}
}
My code keeps hitting the 'No solution found' block. When I remove the history I keep infinite looping between states (3,3,1) and (2,2,1) and get an OutOfMemoryException at the 2 gigabyte mark, so I'm not even sure about keeping track of history anymore.
What steps should I take in order to implement the DFS in the context of the problem correctly, given the code I provided above?
Your algorithm is fine. The problem is that you used == operator in curNode.State == new Vector3(0, 0, 0); line. In C#, by default, == compares objects by reference, so this condition will always return false. Either use node.State.Equals(new Vector3(0, 0, 0)) or override == operator to use your Equals method.
See MSDN Guidelines on custom comparison in C#.

C# Possible.NullReferenceExcpetion

i'm learning C# at the moment and i'm learning all those new concepts and stuff.
I was working on a program for school on which it consists of creating an aquarium that has fish on it and these fish has positions.
The class is initialized:
int z = 0,x,y,max;
Peixe[] peixes;
Posicao[] posicoes;
Random rng = new Random();
public Aquario(string nome, int x, int y, int max)
{
this.nome = nome;
this.x = x;
this.y = y;
peixes = new Peixe[max];
posicoes = new Posicao[max];
}
So, in my aquarium there must be a method to shuffle the fish's positions and I did that as follows:
public bool AbanarAquario()
{
for (int i = 0; i < z; i++)
{
int x = rng.Next(0, this.x);
int y = rng.Next(0, this.y);
if (!peixes[i].emagrecer())
{
return false;
}
else
{
posicoes[i].ChangeX(x);
posicoes[i].ChangeY(y);
}
}
if (z > 0)
{
for (int i = 0; i < z; i++)
{
for (int j = 0; j < z; j++)
{
if (posicoes[i].comparePos(posicoes[j]))
{
if (peixes[i].mostraPeso() > peixes[j].mostraPeso())
{
if (!peixes[j].eliminarPeixe())
{
return false;
}
else
{
posicoes[j] = null;
z--;
}
}
else
{
if (!peixes[i].eliminarPeixe())
{
return false;
}
else
{
posicoes[i] = null;
z--;
}
}
}
}
}
}
return true;
}
So, that uses a method that my position class has and again, is as follows:
public bool comparePos(Posicao outro)
{
if (this.x == outro.x && this.y == outro.y)
{
return true;
}
return false;
}
So, visual studio warns me that there will probably be a null reference exception in the line if (posicoes[i].comparePos(posicoes[j])) and I can't figure out why!
Not only this the program actually does crash when I try to shuffle the positions, tried to debug it but i'm not very experienced in the matter so no luck there.
EDIT
Initializing position:
public bool adicionarPeixe(string nome, string cor, float peso)
{
if (z >= peixes.Length)
{
return false;
}
else
{
int x = rng.Next(0, this.x);
int y = rng.Next(0, this.y);
peixes[z] = new Peixe(z, nome, cor, peso);
peixes[z].Aquario(0);
posicoes[z] = new Posicao(x,y);
z++;
}
return true;
}
I think it's a fair warning.
The z variable looks like it could be anything. Consider:
Dividing this up into different methods.
Using a foreach() loop instead of a for() loop. (Failing that you use int z = posicoes.Count())
I think the compiler is worried about z=999 when the collection only goes up to 99 or something like that.
Unless I'm completely missing it, I don't see where you're defining posicoes. But it sounds like you aren't initializing it.
If you're doing something like,
Posicao posicoes;
then using it, then the compiler is assuming it's going to be null and warning you.
You need to do something like,
Posicao posicoes = new Posicao();
So the object exists for you to manipulate. But again, I'm not sure where you're defining it, so this could be off base. Can you update your question with where and how you're defining posicoes.
Also if you are defining it, you can put a simple check in right before you use it, or if you just want to back out of the method if for some reason it is null at the top of the method you can just do,
if(posicoes == null)
{
return false;
}
EDIT
Per information about the constructor, your loop is going outside the size of the list. I don't see where Z is being defined, but are you by chance not accounting for 0 based indexing and going over the length of the array by 1?
Put a break point on where you're setting Z and see if it's bigger than the amount of items in your list.

Recursive edge search

I'm trying to write an algorithm that will take a list of points visited along an edge, and a list of unvisited edges (made up of pairs of points) which make up the rest of the object and search through them for a path that completes the edge (that is, connects the start to the end). I currently have:
public static int PolygonSearch(Point start, Point end, List<Point> visitedPoints, List<Point[]> unvisitedEdges)
{
int count = 0;
for (int i = unvisitedEdges.Count - 1; i > -1; i--)
{
Point[] line = unvisitedEdges[i];
if (((Equal(line[0], start) && Equal(line[1], end))
|| (Equal(line[1], start) && Equal(line[0], end)))
&& visitedPoints.Count > 2)
{
return count + 1;
}
else if (Equal(start, line[0]))
{
unvisitedEdges.RemoveAt(i);
count += PolygonSearch(line[1], end, visitedPoints, unvisitedEdges);
}
else if (Equal(start, line[1]))
{
unvisitedEdges.RemoveAt(i);
count += PolygonSearch(line[0], end, visitedPoints, unvisitedEdges);
}
}
return count;
}
(start and end being the current start and end points of the line)
The obvious problem here is the removal, which messes up the outer loops, but I'm not sure how to correct for it, I tried creating a new list each time but that didn't work (I've not even implemented a way to return the path yet, just to count the valid ones).
Any help fixing this would be greatly appreciated.
To avoid removing an object, you can set it as 'removed', then ignore it if it is so set.
The following uses a flag called Visited. If it is 'removed', Visited is set to true.
I haven't tested this obviously, but it should give you a general idea of what to do:
public struct Edge
{
public Edge()
{
this.Visited = false;
}
public Point[] Points;
public bool Visited;
}
public static int PolygonSearch(Point start, Point end, List<Point> visitedPoints, List<Edge> unvisitedEdges)
{
int count = 0;
for (int i = unvisitedEdges.Count - 1; i > -1; i--)
{
Edge line = unvisitedEdges[i];
if (((Equal(line.Points[0], start) && Equal(line.Points[1], end))
|| (Equal(line.Points[1], start) && Equal(line.Points[0], end)))
&& visitedPoints.Count > 2
&& line.Visited == false)
{
return count + 1;
}
else if (Equal(start, line[0]))
{
unvisitedEdges[i].Visited = true;
count += PolygonSearch(line.Points[1], end, visitedPoints, unvisitedEdges);
}
else if (Equal(start, line[0]))
{
unvisitedEdges[i].Visited = true;
count += PolygonSearch(line.Points[1], end, visitedPoints, unvisitedEdges);
}
}
return count;
}

Multithreading and passing data to new threads

I have some issues with an application I'm coding. It's job is to solve a maze using threads. One thread begins, and for each bifurcation it calls a static method in another class, passing parameters that the other thread needs, and then starts threads for each path. My outputs are all messed up, and I'm not sure if it's a Multithreading problem or maybe a problem with the references. Here's some of the code (Each thread is given a new instance of an Explorer class):
This is the Run() method for each thread:
public void Explore()
{
while (ImDone == false)
{
Move();
if (ActualPosition[0] != Labyrinth.ExitPoint[0] ||
ActualPosition[1] != Labyrinth.ExitPoint[1]) //I'm not at the end..
continue;
PrintMyStatus(); //Print in the console my parents and my complete route..
break;
}
This is the Move() method:
List<int[]> validPaths = CheckSurroundings(); //returns a list of paths
switch (validPaths.Count)
{
case 0:
ImDone = true; //No more routes available
break;
case 1:
MarkMyPosition(validPaths); //Change internal variables to the only new path
break;
default:
lock(this) //As this involves thread creating I locked it..
{
//Creating deep copies of my "History" so my childs can have them..
List<int[]> DCValidPaths = DeepCopy(validPaths);
List<string> DCMyParents = DeepCopy(MyParents);
string[,] DCMyExplorationMap = DeepCopy(MyExplorationMap);
List<int[]> DCMyPositions = DeepCopy(MyPositions);
foreach (var path in validPaths)
{
DCMyParents.Add(Thread.CurrentThread.Name); //Adding myself as a parent
ExplorationManager.ExplorerMaker(
DCValidPaths,
DCMyParents,
DCMyExplorationMap,
DCMyPositions,
ID); //Threads are created in the static class
}
}
break;
}
My DeepCopy() method is using is the one in the accepted answer of this question. Any other info needed I'll be more than happy to provide in order to solve the problem. Thanks in advance for your help.
EDITS: My problem consists basically in: I'm having an OutOfMemoryException in the Thread.Start() clause and the Path displayed by the threads contain corrupted data (incorrect positions). I tested the CheckSurroundings() method and by far only returns correct positions (The labyrinth is contained in a two-dimensional string array).
This is the constructor of the Explorer class:
public Explorer(List<string> myParents, int[] actualPosition, string[,] myExplorationMap,
List<int[]> myPositions, int ID)
{
//Here I pass the data specified in Move();
MyParents = myParents;
ActualPosition = actualPosition;
MyExplorationMap = myExplorationMap;
MyPositions = myPositions;
this.ID = ID + 1; //An ID for reference
//Marking position in my map with "1" so I know I've been here already,
//and adding the position given to my list of positions
MyExplorationMap[ActualPosition[0], ActualPosition[1]] = "1";
MyPositions.Add(DeepCopy(ActualPosition));
}
And this is the class creating the threads:
public static class ExplorationManager
{
public static void ExplorerMaker(List<int[]> validPaths, List<string> myParents, string[,] myExplorationMap, List<int[]> myPositions, int ID)
{
foreach (var thread in validPaths.Select
(path => new Explorer(myParents, path, myExplorationMap, myPositions,ID)).
Select(explorer => new Thread(explorer.Explore)))
{
thread.Name = "Thread of " + ID + " generation";
thread.Start(); //For each Path in Valid paths, create a new instance of Explorer and assign a thread to it.
}
}
}
And the method returning the ValidPaths
private List<int[]> CheckSurroundings()
{
var validPaths = new List<int[]>();
var posX = ActualPosition[0];
var posY = ActualPosition[1];
for (var dx = -1; dx <= 1; dx++)
{
if (dx == 0 || (posX + dx) < 0 || (posX + dx) >= Labyrinth.Size ||
MyExplorationMap[posX + dx, posY] == "1") continue;
var tempPos = new int[2];
tempPos[0] = posX + dx;
tempPos[1] = posY;
validPaths.Add(tempPos);
}
for (var dy = -1; dy <= 1; dy++)
{
if (dy == 0 || (posY + dy) < 0 || (posY + dy) >= Labyrinth.Size ||
MyExplorationMap[posX, posY + dy] == "1") continue;
var tempPos = new int[2];
tempPos[0] = posX;
tempPos[1] = posY + dy;
validPaths.Add(tempPos);
}
//This method checks up, down, left, right and returns the posible routes as `int[]` for each one
return validPaths;
}
CheckSurroundings uses the deep copy passed to the child (via the constructor) to validate the routes he can take. It is NOT intended to alterate the parent's copy, because he is now in ANOTHER path of the labyrinth. The child only needs the information updated (passed via the constructor) UNTIL the point they "separate". And also EACH child must be independent from the other childs. That's what I'm trying to do. But I'm not sure what's wrong, maybe concurrency problem? Please help. If you need anything else let me know. –
EDIT for your updates:
myExplorationMap is a deep copy of the original exploration map. You set the position to 1 in the Explorer constructor, which updates the copy that is shared by all of the child threads, but it does not update the original MyExplorationMap property in the parent thread. Only the child threads will know this position was visited. I assume this is used somewhere in the CheckSurroundings method?

Categories