I am writing a pathfinding script in Unity, and I have been trying to figure out IEnumerables, and I feel I am not wording my internet searches correct, because it is not at all what I want.
I have 3 scripts, 1 find nodes and it adds to the OpenNodes list which is it's own script with constructor. I have An IEnumerable and it is still saying it can't access, or it needs to be static if just public. So my codes as follows:
public class OpenNodes: IEnumerator, IEnumerable {
public static Vector3 node;
public static int g;
public static IEnumerator GetEnumerator()
{
return (IEnumerator)this;
}
public OpenNodes(Vector3 newNode, int newGscore)
{
node = newNode;
g = newGscore;
}
so what I am trying to do in a different "FinderScript" is along these lines:
foreach(Vector3 node in OpenNodes)
I have been trying my hardest to figure it out, but I have never worked in constructor lists like this. This is new to me, so any help, would be SO greatly appreciated.. Thanks
EDIT:
This for each needs to take node in as a vector3 as it is using .x,.y, and .z values for comparison and changes..
As you need to store a score per node you could simply use a Dictionary<Vector3, int> to store the values.
e.g.
var nodes = new Dictionary<Vector3, int>();
nodes.add(node, gScore);
And then either access them directly
nodes[node] = ...
Or loop through them
foreach (var node in nodes.Keys) {
...
}
Alternatively, perhaps you can create an object that maps the score and the node together (or simply use a Pair and then just use a list?
var nodes = new List<Vector3>();
var map = new Pair(node, gScore);
nodes.add(map);
Then loop through them as per usual:
foreach (var node in nodes) {
...
}
Not sure if i have understood you correctly, and i haven't run this code. HTH.
The problem I was facing was actually more simple that I realized. Below is the code of my constructor list:
public class OpenNodes {
public Vector3 node;
public int g;
public OpenNodes(Vector3 newNode, int newGscore)
{
node = newNode;
g = newGscore;
}
}
The code for the foreach is as follow:
foreach(OpenNodes list in OpenNode)
to populate the list looks like:
OpenNode.Add(new OpenNodes(nodeLocation, 0 ));
to remove an item looks like:
OpenNode.RemoveAll(OpenNodes => nodeLocation == OpenNodes.node && 0 == OpenNodes.g);
and to access my node it is simply:
list.node.x
list.node
list.node.z
ect.
This is iterating through each item in the list as list, and then you call upon each variable after that. I hope this code will help someone in the future!
Related
I have a tree that can have the same node.
If it found the node explored, then I want to skip the node.
Of course, this is a simple topic but I am curious if there is a simpler way.
The code that comes to mind is something like this:
void Explore(Tree tree, HashSet<Tree> exploredTrees)
{
if (exploredTrees.Contains(tree))
continue;
foreach(var childTree in tree.ChildTree)
{
Explore(childTree);
exploredTrees.Add(childTree);
}
}
void static Program()
{
// it assumes there is data in the tree.
Tree tree = new Tree();
Explore(tree, new HashSet());
}
I've been using the code above so far but the second parameter getting on my nerves (new HashSet() for the above example).
As you know to achieve this purpose it must need a data structure to store the data explored.
However, I'm not satisfied because the data structure has to pass from the external. (ex: Explore(tree, new HashSet()))
Is there a way to achieve this purpose without the second parameter in C#?
I don't want to use static keyword because it has to remember to clear the data structure at external.
Thank you for reading.
The general approach is correct, but you could simply add a helper method that creates the hashSet for you: void Explore(Tree tree) => Explore(tree, new HashSet<Tree>())
Or you could use an iterative solution that lets you keep the HashSet as a local variable:
public static IEnumerable<T> DepthFirstLoopSafe<T>(T self, Func<T, IEnumerable<T>> selector, IEqualityComparer<T> equalityComparer = default)
{
var stack = new Stack<T>();
var visited = new HashSet<T>(equalityComparer ?? EqualityComparer<T>.Default);
stack.Push(self);
while (stack.Count > 0)
{
var current = stack.Pop();
visited.Add(current);
yield return current;
foreach (var child in selector(current))
{
if (!visited.Contains(child))
{
stack.Push(child);
}
}
}
}
Called like DepthFirstLoopSafe(tree, t => t.ChildTree). I like to use generics to describe the iteration of trees, since it allows reuse of code for all kinds of trees, regardless of type or how the tree is described.
I am working on a project in C# where I have an object with properties, one of which is called Children which is the same as the parent object. For example:
public class ObjectInformation
{
public string FullName {get; set;}
public string FriendlyName {get; set;}
public List<ObjectInformation> Children {get;}
}
And I already have a method which flattens a root object into a simple list:
public static IEnumerable<ObjectInformation> Flatten(List<ObjectInformation> objs)
{
var localCopy = Helpers.General.DeepCopy(objs);
var finalList = new List<ObjectInformation>();
foreach(var obj in localCopy)
{
if(obj.Children.Count > 0)
{
finalList.AddRange(Flatten(obj.Children));
obj.Children.Clear();
}
obj.Parent = null;
finalList.Add(obj);
}
return finalList;
}
I know the above method could probably be improved, but it works right now. However, what I'm trying to do now is traverse the nested list and output the data, while indenting lines depending on the nesting level.
So, as an example, say the root object has two objects, the first one which has one child, and the second which has a child, which also has a child. I would want the output to be something like this:
FullName of Root Object 1
FullName of Child 1 of Root Object 1
FullName of Root Object 2
FullName of Child 1 of Root Object 2
FullName of Child 1 of Child 1 of Root Object 2
To do the indenting, I need some kind of counter to determine how deep the level is nested. I keep running into an issue using a recursive method though because on each call, the variable is reset. I was thinking, maybe I need to use a static variable to track the nesting level. The issue I see with that though is that as it travels back up, the static variable will still have the value of the deepest level its reached.
I'm kind of at a lost of how to proceed with this, albeit I'm sure it is probably a simple solution I just can't picture at the moment; I generally don't use/need recursion so I don't have a lot of experience actually using it.
Any help/suggestions you an provide would be greatly apprecated.
Thank You
I would recommend a method that takes the object and prints each with a defined space. Recursive call would add x amount of spaces each time you would go in deeper within the objects.
public static void Print(this ObjectInformation parent, int spacing = 2)
{
Console.WriteLine($"{new string(' ', spacing)}{parent.FullName}");
foreach (ObjectInformation child in parent.Children)
{
child.Print(spacing + 2);
}
}
I tried this same as an exercise and got a working result.
public void PrintInfoList(IEnumerable<ObjectInformation> list)
{
var result = string.Join("\n", list.Select(item => GetPrintedFormat(item)));
Console.WriteLine(result);
}
public string GetPrintedFormat(ObjectInformation info)
{
string printedFormat = string.Empty;
printedFormat = $"Fullname of {info.FriendlyName} - {info.FullName}";
if (info.Children != null && info.Children.Any())
{
childCount++;
_formatter = $"\n{string.Empty.PadRight(childCount, '\t')}";
printedFormat += $"{_formatter}{string.Join(_formatter, info.Children.Select(child => GetPrintedFormat(child)))}";
}
else
if (childCount > 0) childCount--;
return printedFormat;
}
this is tested working solution. Let me know what you think of this.
But i like to vote #Jawad's simplest way too. (clap)
I'm trying to implement AI's A star algorithm in C#. As all of you may know, there is some place in my code where I want to check if a Node object (which I've defined in my code) is in my List<Node> nodes or not. But since the Node object in the List<Node> nodes has different reference with the one I've created to see if exists in the list, the output I get is False. (You can see this in the code below) :
class Node
{
bool[,] state;
Node parent;
String action;
int path_cost=0;
public int Cost
{
get
{
return path_cost;
}
}
public Node (bool[,] map)
{
this.state = map;
}
public double Heuristic()
{
return 0;
}
}
static void Main(string[] args)
{
bool[,] a = new bool[,] { { false, false }, { true, true } };
bool[,] a1 = new bool[,] { { false, false }, { true, true } };
Node temp = new Node(a);
Node n = new Node(a);
Node n1 = new Node(a1);
List<Node> nodes = new List<Node>();
nodes.Add(n);
Console.WriteLine(nodes.Contains(n1));
Console.ReadLine();
}
I've read about it and I know I should use LINQ and it's WHERE function. As you can see in my code, I want to check for n1's existence based on Node's state property which is a 2-dimensional array of booleans. Is using WHERE function best practice we can have here? I mean isn't there any problems with using it in my case?
Instead of Where(), I'd use Any(), like this:
Console.WriteLine(nodes.Any(n => ... ));
The trick here is the .... You mentioned comparing based on a 2D state array, but not what that comparison should look like. Does every item need to match? That seems... expensive. Is there a faster comparison? Have you thought about overriding .Equals()/GetHashCode()?
Additionally, depending on the size and nature of your List, you might do better with either a Dictionary or HashSet, both of which can potentially do much better than Any().
Finally, pay attention to the comments on your question from Eric Lippert. He's worked on a the C# team at Microsoft, and has a blog where he's already implemented A*. That ought to be a great reference for you.
I'm trying to create a function that will add each visible node in a tree to a node array and then return it.
This is the code I have so far, but struggling to figure out how to add them.
Note: The tree has a maximum of 8 nodes.
private Node[] activeClients(AdvTree tree)
{
Node[] activeClients = new Node[8];
foreach (Node client in tree.Nodes)
{
if (client.IsVisible)
{
//Add Visible Node to activeClients Node Array
}
}
return activeClients;
}
May be something like:
var visibleNodes = tree.Nodes.Where(client=>client.IsVisible)
especially if you are talking about small numbers (8 elements) and not compute intensive function, dynamic array (or vector) like List<T>, IEnumerable<T> is a right choice.
And in this way, your code also scales better in the future.
I actually figured out I didn't need a Node Array, but thanks for the help guys.
I used NodeCollection instead and it worked perfect for my needs.
private NodeCollection activeClients(AdvTree tree)
{
NodeCollection activeClients = new NodeCollection();
foreach (Node client in tree.Nodes)
{
if (client.IsVisible)
{
//Add Visible Node to activeClients Node Array
activeClients.Add(client, eTreeAction.Code);
}
}
return activeClients;
}
I have this class
class Node
{
public bool is_end;
public int prefix_count;
public Node[] child = new Node[26];
}
My problem is, the class only creates Nodes if it is necessary, but later in the program, i need to check all the created Nodes, though since i don't know which ones are created, i can't use a cycle for it.
Is there a way for me to know which Nodes are created, is there a code to check if this Node exists or not.
Try using a List<Node> instead of a fixed length array. Then you can use methods such as
var nodeList = new List<Node>();
nodeList.Add(someRandomNode);
if (nodeList.Contains(someRandomNode))
{
// your logic
}
You may also iterate over your Node collection.
foreach(var node in nodeList) { }
In this case, your child array is pre-created, but each individual node is not allocated. You can check for null to see if a Node has been created:
bool ChildCreated(Node parent, int childIndex)
{
return parent.child[childIndex] != null;
}
I have to find out which child nodes are created, for example a cycle from 0 to 25, and it has to give a message like node[2] and node[11] are created, others aren't.
Using this method, you could easily do:
var created = Enumerable.Range(0, node.child.Length).Where(i => ChildCreated(node, i)).ToList();
if (!created.Any())
{
Console.WriteLine("No children created.");
}
else
{
Console.WriteLine("Children {0} created, all others aren't.", string.Join(", ", created));
}
All you need to do is to check if Node[] element is null:
int nodeIndex = 0;
if(child[nodeIndex] == null)
{
// node doesn't exist
}
else
{
// node exists
}