Detect and process only unique images - c#

The problem I'm having is that I have an image that appears on two pages in the same book.
I wish my program to react (trigger a side-effect) only when encountering new images and ignore duplicates.Once it has done that I want it to reset so the process is repeated.
namespace testpad
{
class Interaction: Scene
{
public override string Name => "Interaction";
public static RectMap imageone = new RectMap()
{
X = 239,
Y = 199,
Width = 125,
Height = 18
};
public static RectMap imagetwo = new RectMap()
{
X = 217,
Y = 317,
Width = 428,
Height = 12
public override bool Match(ScriptBase script)
{
return script.Match(imageone, 90),
|| script.Match(imagetwo, 90);
}
public override void OnMatched(ScriptBase script)
{
if (script.Match(imageone, 90))
{
script.PressKey() { A = true });
Thread.Sleep(100);
}
else if (script.Match(imagetwo, 90))
{
script.Press() { B = true });
Thread.Sleep(1000);
}
}
}

If you expect a collection of objects and you want to take actions based upon their frequency of apparition the best solution would be a Dictionary<[Key],int> where the Key is the identifier (in your case a String with the name of the image) and the value represents the frequency of your key.Whenever you encounter an object (in your case lets call it image)with a given Key you increment the value stored at that key.Afterwards you can take decisions based upon resulting frequencies.
However in your case you just need to react only once , the first time you encounter a new image , so a HashSet<String> would be your best bet.
So your code would look like:
public void Iterate(IEnumerable<(string,object)>images)
{
HashSet<string>set=new HashSet<string>();
foreach(var item in images)
{
if(!set.TryGetValue(item.item1,out object obj))
{
set.Add(item.item1);
//React(item.item2) ---do something the first time you encounter the image
}
}
}

Related

C# examining and replacing tuple values based on other tuple

I'm starting with programming and C# and I have two tuples. One tuple is representing a list of points:
static List<(string, string, string)> PR { get; set; } = new List<(string, string, string)>()
{
("P1", "0", "0"),
("P2", "P1", "P1+Height"),
("P3", "P1+Width", "P2"),
("P4", "P3", "P3+Height")
};
where Item1 in the list of tuples stands for a Point name (P1, P2, P3, P4) and Item2 and Item3 represent a parametric formula for respectively the x- and y-value of a point.
"P1" in the second item in the above list should look for the tuple starting with "P1", and then for the second item in that tuple, in this case, 0.
I have a second list of tuples that represent the parameters that I need to calculate the above point values.
static List<(string, double)> PAR { get; set; } = new List<(string, double)>()
{
("Height", 500),
("Width", 1000)
};
Say I want to calculate the value of the parametric formula "P3+Height" as follows:
P3+Height --> P2 (+Height) --> P1+Height (+Height) --> 0 (+Height (+Height) --> 0 + Height + Height;
In the end I want to replace the parameter strings with the actual values (0 + 500 + 500 -> P3+Height = 1000) but thats of later concern.
Question: I'm trying to make a function that recursively evaluates the list of tuples and keeps the parameter names, but also looks for the corresponding tuple until we reach an end or exit situation. This is where I'm at now but I have a hard time getting my thought process in actual working code:
static void Main(string[] args)
{
//inputString = "P3+Height"
string inputString = PR[3].Item3;
string[] returnedString = GetParameterString(inputString);
#region READLINE
Console.ReadLine();
#endregion
}
private static string[] GetParameterString(string inputString)
{
string[] stringToEvaluate = SplitInputString(inputString);
for (int i = 0; i < stringToEvaluate.Length; i++)
{
//--EXIT CONDITION
if (stringToEvaluate[0] == "P1")
{
stringToEvaluate[i] = "0";
}
else
{
if (i % 2 == 0)
{
//Check if parameters[i] is point string
var value = PAR.Find(p => p.Item1.Equals(stringToEvaluate[i]));
//Check if parameters[i] is double string
if (double.TryParse(stringToEvaluate[i], out double result))
{
stringToEvaluate[i] = result.ToString();
}
else if (value == default)
{
//We have a point identifier
var relatingPR = PR.Find(val => val.Item1.Equals(stringToEvaluate[i])).Item2;
//stringToEvaluate[i] = PR.Find(val => val.Item1.Equals(pointId)).Item2;
stringToEvaluate = SearchParameterString(relatingPR);
}
else
{
//We have a parameter identifier
stringToEvaluate[i] = value.Item2.ToString();
}
}
}
}
return stringToEvaluate;
}
private static string[] SplitInputString(string inputString)
{
string[] splittedString;
splittedString = Regex.Split(inputString, Delimiters);
return splittedString;
}
Can anyone point me in the right direction of how this could be done with either recursion or some other, better, easier way?
In the end, I need to get a list of tuples like this:
("P1", "0", "0"),
("P2", "0", "500"),
("P3", "1000", "500"),
("P4", "1000", "1000")
Thanks in advance!
I wrote something that does this - I changed a bit of the structure to simplify the code and runtime, but it still returns the tuple you expect:
// first I used dictionaries so we can search for the corresponding value efftiantly:
static Dictionary<string, (string width, string height)> PR { get; set; } =
new Dictionary<string, (string width, string height)>()
{
{ "P1", ("0", "0") },
{ "P2", ("P1", "P1+Height")},
{ "P3", ("P1+Width", "P2") },
{ "P4", ("P3", "P3+Height") }
};
static Dictionary<string, double> PAR { get; set; } = new Dictionary<string, double>()
{
{ "Height", 500 },
{ "Width", 1000 }
};
static void Main(string[] args)
{
// we want to "translate" each of the values height and width values
List<(string, string, string)> res = new List<(string, string, string)>();
foreach (var curr in PR)
{
// To keep the code generic we want the same code to run for height and width-
// but for functionality reasons we need to know which it is - so sent it as a parameter.
res.Add((curr.Key,
GetParameterVal(curr.Value.width, false).ToString(),
GetParameterVal(curr.Value.height, true).ToString()));
}
#region READLINE
Console.ReadLine();
#endregion
}
private static double GetParameterVal(string inputString, bool isHeight)
{
// for now the only delimiter is + - adapt this and the code when \ as needed
// this will split string with the delimiter ("+height", "-500", etc..)
string[] delimiters = new string[] { "\\+", "\\-" };
string[] stringToEvaluate =
Regex.Split(inputString, string.Format("(?=[{0}])", string.Join("", delimiters)));
// now we want to sum up each "part" of the string
var sum = stringToEvaluate.Select(x =>
{
double result;
int factor = 1;
// this will split from the delimiter, we will use it as a factor,
// ["+", "height"], ["-", "500"] etc..
string[] splitFromDelimiter=
Regex.Split(x, string.Format("(?<=[{0}])", string.Join("|", delimiters)));
if (splitFromDelimiter.Length > 1) {
factor = int.Parse(string.Format($"{splitFromDelimiter[0]}1"));
x = splitFromDelimiter[1];
}
if (PR.ContainsKey(x))
{
// if we need to continue recursively translate
result = GetParameterVal(isHeight ? PR[x].height : PR[x].width, isHeight);
}
else if (PAR.ContainsKey(x))
{
// exit condition
result = PAR[x];
}
else
{
// just in case we didnt find something - we should get here
result = 0;
}
return factor * result;
}).Sum();
return sum;
}
}
}
I didnt add any validity checks, and if a value wasn't found it recieves a val of 0, but go ahead and adapt it to your needs..
Here a a working example for your question... It took me a lot of time so I hope you appreciate it: The whole code is comented line by line. If you have any question do not hesitate to ask me !
First of all we create a class named myEntry that will represent an entry. The name has to be unique e.g P1, P2, P3
public class myEntry
{
public string Name { get; private set; } //this field should be unique
public object Height { get; set; } //Can contain a reference to another entry or a value also as many combinations of those as you want.
// They have to be separated with a +
public object Width { get; set; } //same as for height here
public myEntry(string name, object height, object width)
{
//Set values
this.Name = name;
this.Height = height;
this.Width = width;
}
}
Now I create a dummy Exception class for an exception in a further class (you will see the use of this further on. Just ignore it for now)
public class UnknownEntry : Exception
{
//Create a new Class that represents an exception
}
Now we create the important class that will handle the entries and do all the work for us. This might look complicated but if you don't want to spend time understanding it you can just copy paste it, its a working solution!
public class EntryHolder
{
private Dictionary<string, double> _par = new Dictionary<string, double>(); //Dictionary holding our known variables
private List<myEntry> _entries; //List holding our entries
public EntryHolder()
{
_entries = new List<myEntry>(); //Create list
//Populate dictionary
_par.Add("Height", 500);
_par.Add("Width", 1000);
}
public bool Add(myEntry entry)
{
var otherEntry = _entries.FirstOrDefault(x => x.Name.Equals(entry.Name)); //Get entry with same name
if(otherEntry != null)
{
//Entry with the same name as another entry
//throw new DuplicateNameException(); //Throw an exception if you want
return false; //or just return false
}
//Entry to add is valid
_entries.Add(entry); //Add entry
return true; //return success
}
public void Add(List<myEntry> entries)
{
foreach (var entry in entries) //Loop through entries
{
Add(entry);
}
}
public myEntry GetEntry(string uniqueName)
{
var entry = GetRawEntry(uniqueName); //Get raw entry
var heightToCalculate = entry.Height.ToString(); //Height to calculate to string
var widthToCalculate = entry.Width.ToString(); //Width to calculate to string
entry.Height = Calculate(heightToCalculate, true); //Calculate height
entry.Width = Calculate(widthToCalculate, false); //Calculate width
return entry; //return entry
}
public List<myEntry> CalculateAllEntries()
{
List<myEntry> toReturn = new List<myEntry>(); //Create list that we will return after the calculation finished
foreach (var entryToCalculate in _entries) //Loop through all entries
{
toReturn.Add(GetEntry(entryToCalculate.Name)); //calculate entry values and add them to the list we will return after
}
return toReturn; //return list after the whole calculation finished
}
private double Calculate(string toCalculate, bool isHeight)
{
if (!toCalculate.Contains("+"))
{
//String doesn't contain a + that means it has to be a number or a key in our dictionary
object toConvert = toCalculate; //Set the object we want to convert to double
var entryCorrespondingToThisValue = _entries.FirstOrDefault(x => x.Name.Equals(toCalculate)); //Check if the string is a reference to another entry
if (entryCorrespondingToThisValue != null)
{
//It is the name of another object
toConvert = isHeight ? entryCorrespondingToThisValue.Height : entryCorrespondingToThisValue.Width; //Set object to convert to the height or width of the object in entries
}
try
{
return Convert.ToDouble(toConvert); //try to convert and return if success
}
catch (Exception e)
{
//the given height object has the wrong format
//Format: (x + Y + z ...)
throw new FormatException();
}
}
//Contains some +
var spitedString = toCalculate.Split(new char[] {'+'}); //Split
double sum = 0d; //Whole sum
foreach (var splited in spitedString) //Loop through all elements
{
double toAdd = 0; //To add default = 0
if (_par.ContainsKey(splited)) //Check if 'splited' is a key in the dictionary
{
//part of object is in the par dictionary so we get the value of it
toAdd = _par[splited]; //get value corresponding to key in dictionary
}
else
{
//'splited' is not a key in the dictionary
object toConvert = splited; //set object to convert
var entryCorrespondingToThisValue = _entries.FirstOrDefault(x => x.Name.Equals(splited)); //Does entries contain a reference to this value
if (entryCorrespondingToThisValue != null)
{
//It is a reference
toConvert = isHeight ? entryCorrespondingToThisValue.Height : entryCorrespondingToThisValue.Width; //Set to convert to references height or width
}
try
{
toAdd = Convert.ToDouble(toConvert); //Try to convert object
}
catch (Exception e)
{
//A part of the given height is not a number or is known in the par dictionary
throw new FormatException();
}
}
sum += toAdd; //Add after one iteration
}
return sum; //return whole sum
}
public myEntry GetRawEntry(string uniqueName)
{
var rawEntry = _entries.FirstOrDefault(x => x.Name.Equals(uniqueName)); //Check for entry in entries by name (unique)
if (rawEntry == null)
{
//Entry is not in the list holding all entries
throw new UnknownEntry(); //throw an exception
return null; //Or just return null
}
return rawEntry; //return entry
}
}
And here the end, the test and prove that it works:
public void TestIt()
{
List<myEntry> entries = new List<myEntry>()
{
new myEntry("P1", 0, 0),
new myEntry("P2", "P1", "P1+Height"),
new myEntry("P3", "P1+Height", "P2"),
new myEntry("P4", "P3", "P3+Height"),
};
EntryHolder myEntryHolder = new EntryHolder();
myEntryHolder.Add(entries);
var calculatedEntries = myEntryHolder.CalculateAllEntries();
}
Here an image of how it looks like:

List of numbers and goal -> closes sum

Regarding a question I got from one of my friends I want to ask the best possible solution
The situation is that I have a list of integers for example
2 5 6 8
And I want to get to the integers 17
I can only use each integers ones.
The closest you can get in this case is 16 because no combination leads up to 17.
public class Item
{
public int Weight { get; set; }
public int Value { get; set; }
}
public class Program
{
public static void Main()
{
var items = new[]
{
new Item {Value = 60, Weight = 10},
new Item {Value = 100, Weight = 20},
new Item {Value = 120, Weight = 30},
};
Console.WriteLine(KnapSackRecursive(items, 50));
}
public static int KnapSackRecursive(Item[] items, int capacity)
{
// keep track of the best value seen.
//TODO: Make it a list of numbers
int best = 0;
for (int i = 0; i < items.Length; i++)
{
// This is an array of the other items.
var otherItems = items.Take(i).Concat(items.Skip(i + 1)).ToArray();
// Calculate the best value without using the current item.
int without = KnapSackRecursive(otherItems, capacity);
int with = 0;
// If the current item fits then calculate the best value for
// a capacity less it's weight and with it removed from contention
// and add the current items value to that.
if (items[i].Weight <= capacity)
{
with = KnapSackRecursive(otherItems, capacity - items[i].Weight)
+ items[i].Value;
}
// The current best is the max of the with or without.
int currentBest = Math.Max(without, with);
// determine if the current best is the overall best.
if (currentBest > best)
best = currentBest;
}
return best;
}
}
Edit: It now finds the best possible weight based on the list. It'll result in finding that 20+30 = 50 so it returns 100+120 = 220 I want it to return ("Found best possible combination: 100 + 120 = 220") not just ("220")

How to get all values from a JSON object for a highscore system

I've been looking around trying to find a half decent way of getting this done.
Essentially I have a JSON object called BeginnerNicknameScores. It contains string keys of nickname and the associated values score.
I am using the SimpleJSON namespace, because it was used in a tutorial but I can of course change the namespace and adjust my code according.
Essentially my goal here is to get all the score values from the JSON object, sort into the top 5 scores and display them as text.
public void DisplayBeginnerHighscores()
{
//declare top 5 interger variables
int one = 0;
int two = 0;
int three = 0;
int four = 0;
int five = 0;
//BeginnerNicknameScores is the JSON Object
//BeginnerNicknameScores.Values is an emerator contraining all the [scores] value
//Thus I use MoveNext() to check all the values, then sort them into top five using the if statements
while (Highscore.BeginnerNicknameScores.Values.MoveNext())
{
if(Highscore.BeginnerNicknameScores.Values.Current > one)
{
one = Highscore.BeginnerNicknameScores.Values.Current;
BegNum1.text = one.ToString();
}
else if(Highscore.BeginnerNicknameScores.Values.Current > two)
{
two = Highscore.BeginnerNicknameScores.Values.Current;
BegNum2.text = two.ToString();
}
else if (Highscore.BeginnerNicknameScores.Values.Current > three)
{
three = Highscore.BeginnerNicknameScores.Values.Current;
BegNum3.text = three.ToString();
}
else if (Highscore.BeginnerNicknameScores.Values.Current > four)
{
four = Highscore.BeginnerNicknameScores.Values.Current;
BegNum4.text = four.ToString();
}
else if (Highscore.BeginnerNicknameScores.Values.Current > five)
{
five = Highscore.BeginnerNicknameScores.Values.Current;
BegNum5.text = five.ToString();
}
}
}
Thing is, I must be doing something wrong because whenever I load the object containing this script, and thus calling this function, my Unity Engine crashes.
If anyone has any suggestions as to another way to go about this problem I would definitely appreciate it. It might be worth noting that one the scores are separated into top five, I will also need to display the associate nicknames of each score, in my Highscore menu.
What about the following ?
using System;
using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using UnityEngine;
public class NewBehaviourScript : MonoBehaviour
{
private void Start()
{
var scores = new List<Score>
{
new Score("Bart", 100),
new Score("Maggie", 75),
new Score("Lisa", 50),
new Score("Marge", 25),
new Score("Homer", 0)
};
var table = new ScoreTable(scores);
// save to JSON
var json = JsonUtility.ToJson(table, true);
// load from JSON
var fromJson = JsonUtility.FromJson<ScoreTable>(json);
// print the top 3 players
var take = fromJson.Scores.OrderByDescending(s => s.Points).Take(3);
foreach (var score in take)
Debug.Log($"{score.Name}: {score.Points}");
}
}
[Serializable]
public class ScoreTable
{
public List<Score> Scores = new List<Score>();
public ScoreTable()
{
// for serializer
}
public ScoreTable([NotNull] List<Score> scores)
{
if (scores == null)
throw new ArgumentNullException(nameof(scores));
Scores = scores;
}
}
[Serializable]
public class Score
{
public string Name;
public int Points;
public Score()
{
// for serializer
}
public Score(string name, int points)
{
Name = name;
Points = points;
}
}
Generated JSON:
{
"Scores": [
{
"Name": "Bart",
"Points": 100
},
{
"Name": "Maggie",
"Points": 75
},
{
"Name": "Lisa",
"Points": 50
},
{
"Name": "Marge",
"Points": 25
},
{
"Name": "Homer",
"Points": 0
}
]
}
The top 3 players:
No need for fancy external library, just Unity's one :)

Google OR-Tools TSP returning several solution

I've been recently working on finding more than just the optimal route using Google's OR-Tools. I have found an example in the repo, but this only solves for the optimal route, any idea how to generate more than just one solution for a set of points? I'm currently working with the DotNet version of the tool, any solution with any other language would be helpful!
public class tspParams : NodeEvaluator2
{
public static int[,] distanceMatrix =
{
{ 0, 20, 40, 10 },
{ 20, 0, 4, 55 },
{ 40, 4, 0, 2 },
{ 10, 55, 2, 0 }
};
public static int tsp_size
{
get { return distanceMatrix.GetUpperBound(0) + 1; }
}
public static int num_routes
{
get { return 1; }
}
public static int depot
{
get { return 0; }
}
public override long Run(int FromNode, int ToNode)
{
return distanceMatrix[FromNode, ToNode];
}
}
public class TSP
{
public static void PrintSolution(RoutingModel routing, Assignment solution)
{
Console.WriteLine("Distance of the route: {0}", solution.ObjectiveValue());
var index = routing.Start(0);
Console.WriteLine("Route for Vehicle 0:");
while (!routing.IsEnd(index))
{
Console.Write("{0} -> ", routing.IndexToNode(index));
var previousIndex = index;
index = solution.Value(routing.NextVar(index));
}
Console.WriteLine("{0}", routing.IndexToNode(index));
//Console.WriteLine("Calculated optimal route!");
}
public static void Solve()
{
// Create Routing Model
RoutingModel routing = new RoutingModel(
tspParams.tsp_size,
tspParams.num_routes,
tspParams.depot);
// Define weight of each edge
NodeEvaluator2 distanceEvaluator = new tspParams();
//protect callbacks from the GC
GC.KeepAlive(distanceEvaluator);
routing.SetArcCostEvaluatorOfAllVehicles(distanceEvaluator);
// Setting first solution heuristic (cheapest addition).
RoutingSearchParameters searchParameters = RoutingModel.DefaultSearchParameters();
searchParameters.FirstSolutionStrategy = FirstSolutionStrategy.Types.Value.PathCheapestArc;
Assignment solution = routing.SolveWithParameters(searchParameters);
PrintSolution(routing, solution);
}
}
Use AllSolutionCollector from the underlying CP solver. python code:
solver = routing.solver()
collector = solver.AllSolutionCollector()
for location_idx in range(len(data['time_windows'])):
index = manager.NodeToIndex(location_idx)
time_var = time_dimension.CumulVar(index)
next_var = routing.NextVar(index)
collector.Add(time_var)
collector.Add(next_var)
for v in range(data['num_vehicles']):
index = routing.Start(v)
time_var = time_dimension.CumulVar(index)
next_var = routing.NextVar(index)
collector.Add(time_var)
collector.Add(next_var)
index = routing.End(v)
time_var = time_dimension.CumulVar(index)
collector.Add(time_var)
routing.AddSearchMonitor(collector)
assignment = routing.SolveFromAssignmentWithParameters(initial_solution, search_parameters)
if assignment:
logger.info("solution count: %d", collector.SolutionCount())
for index in range(collector.SolutionCount()):
logger.info("solution index: %d", index)
self.print_solution(data, manager, routing, collector.Solution(index))
logger.info('final solution:')
self.print_solution(data, manager, routing, assignment)
else:
raise OptimizationInternalException("no solution found")

Cycle enumeration of a directed graph with multi edges [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
How can I find all cyles in a directed graph with multi edges?
Graph example 1:
Cycles:
1-2-6
1-2-3-4
1-2-3-4-5-6
1-2-6-5-3-4
3-4-5
5-6
Graph example 2 (multi-edge 4/5):
Cycles:
1-2-3
1-4
1-5
Notes:
I don't want to detect a cycle (boolean result), I want to list all cycles.
Any Strongly connected component algorithm is not sufficient for my problem (it would find only one component in both examples).
I'm using the QuickGraph implementation in C#, but I would be happy to see an algorithm in any language.
I had fun with this question, thanks! :P
I have a solution in C#. The algorithm to find the cycles is very short(~10 lines), but there is a lot of clutter around it(implementations of the classes Node and Edge for instance).
I've used the variable naming convention that the letter "e" represents an edge, the letter "a" the node where the edge start, and "b" the node it links to. With those conventions, this is the algorithm:
public static IEnumerable<Cycle> FindAllCycles()
{
HashSet<Node> alreadyVisited = new HashSet<Node>();
alreadyVisited.Add(Node.AllNodes[0]);
return FindAllCycles(alreadyVisited, Node.AllNodes[0]);
}
private static IEnumerable<Cycle> FindAllCycles(HashSet<Node> alreadyVisited, Node a)
{
for (int i = 0; i < a.Edges.Count; i++)
{
Edge e = a.Edges[i];
if (alreadyVisited.Contains(e.B))
{
yield return new Cycle(e);
}
else
{
HashSet<Node> newSet = i == a.Edges.Count - 1 ? alreadyVisited : new HashSet<Node>(alreadyVisited);
newSet.Add(e.B);
foreach (Cycle c in FindAllCycles(newSet, e.B))
{
c.Build(e);
yield return c;
}
}
}
}
It has an optimization to reuse some Hashsets, and that might be confusing. I've included the following code, which produces exactly the same results, but this implementation doesn't have optimizations, so you can figure out more easily how it works.
private static IEnumerable<Cycle> FindAllCyclesUnoptimized(HashSet<Node> alreadyVisited, Node a)
{
foreach (Edge e in a.Edges)
if (alreadyVisited.Contains(e.B))
yield return new Cycle(e);
else
{
HashSet<Node> newSet = new HashSet<Node>(alreadyVisited);
newSet.Add(e.B);//EDIT: thnx dhsto
foreach (Cycle c in FindAllCyclesUnoptimized(newSet, e.B))
{
c.Build(e);
yield return c;
}
}
}
This uses the following implementations of Node, Edge and Cycle. They're pretty straightforward, although I did put a lot of thought in making everything immutable and members as least accessible as possible.
public sealed class Node
{
public static readonly ReadOnlyCollection<Node> AllNodes;
internal static readonly List<Node> allNodes;
static Node()
{
allNodes = new List<Node>();
AllNodes = new ReadOnlyCollection<Node>(allNodes);
}
public static void SetReferences()
{//call this method after all nodes have been created
foreach (Edge e in Edge.AllEdges)
e.A.edge.Add(e);
}
//All edges linking *from* this node, not to it.
//The variablename "Edges" it quite unsatisfactory, but I couldn't come up with anything better.
public ReadOnlyCollection<Edge> Edges { get; private set; }
internal List<Edge> edge;
public int Index { get; private set; }
public Node(params int[] nodesIndicesConnectedTo)
{
this.edge = new List<Edge>(nodesIndicesConnectedTo.Length);
this.Edges = new ReadOnlyCollection<Edge>(edge);
this.Index = allNodes.Count;
allNodes.Add(this);
foreach (int nodeIndex in nodesIndicesConnectedTo)
new Edge(this, nodeIndex);
}
public override string ToString()
{
return this.Index.ToString();
}
}
public sealed class Edge
{
public static readonly ReadOnlyCollection<Edge> AllEdges;
static readonly List<Edge> allEdges;
static Edge()
{
allEdges = new List<Edge>();
AllEdges = new ReadOnlyCollection<Edge>(allEdges);
}
public int Index { get; private set; }
public Node A { get; private set; }
public Node B { get { return Node.allNodes[this.bIndex]; } }
private readonly int bIndex;
internal Edge(Node a, int bIndex)
{
this.Index = allEdges.Count;
this.A = a;
this.bIndex = bIndex;
allEdges.Add(this);
}
public override string ToString()
{
return this.Index.ToString();
}
}
public sealed class Cycle
{
public readonly ReadOnlyCollection<Edge> Members;
private List<Edge> members;
private bool IsComplete;
internal void Build(Edge member)
{
if (!IsComplete)
{
this.IsComplete = member.A == members[0].B;
this.members.Add(member);
}
}
internal Cycle(Edge firstMember)
{
this.members = new List<Edge>();
this.members.Add(firstMember);
this.Members = new ReadOnlyCollection<Edge>(this.members);
}
public override string ToString()
{
StringBuilder result = new StringBuilder();
foreach (var member in this.members)
{
result.Append(member.Index.ToString());
if (member != members[members.Count - 1])
result.Append(", ");
}
return result.ToString();
}
}
Then to illustrate how you might use this small API, I have implemented your two examples.
Basically it comes down to, create all the nodes by specifying to which nodes they link, then call SetReferences() to, well.... set some references. After that, calling the publicly accessible FindAllCycles() should return all cycles. I've excluded any code to reset the static members, but that is easily implemented. It should just clear all static lists.
static void Main(string[] args)
{
InitializeExampleGraph1();//or: InitializeExampleGraph2();
Node.SetReferences();
var allCycles = FindAllCycles().ToList();
}
static void InitializeExampleGraph1()
{
new Node(1, 2);//says that the first node(node a) links to b and c.
new Node(2);//says that the second node(node b) links to c.
new Node(0, 3);//says that the third node(node c) links to a and d.
new Node(0);//etc
}
static void InitializeExampleGraph2()
{
new Node(1);
new Node(0, 0, 2);
new Node(0);
}
I must note that the indices of the edges in these examples do NOT correspond to the indices in your images, but that is avoidable with a simple lookup.
The results: allCycles is for the first example:
{3, 2, 0}
{5, 4, 2, 0}
{3, 1}
{5, 4, 1}
allCycles is for the second example:
{1, 0}
{2, 0}
{4, 3, 0}
I hope you are satisfied with this solution and that you use it. I've barely commented on the code, so I know it might be hard to understand. In that case, please ask and I'll comment on it!
What about using Breadth-first search to find all paths between nodes A and B - lets call that function get_all_paths
To find all cycles you just need to:
cycles = []
for x in nodes:
cycles += get_all_paths(x,x)
get_all_paths(x,x) because a cycle is just a path that starts and ends in the same node.
Just an alternative solution - I hope it gives new ideas.
Edit
Another option is to compute all the posible paths and check every time that the first edge starts where the last edge finishes - a cycle.
Here you can see the Python code for it.
def paths_rec(path,edges):
if len(path) > 0 and path[0][0] == path[-1][1]:
print "cycle", path
return #cut processing when find a cycle
if len(edges) == 0:
return
if len(path) == 0:
#path is empty so all edges are candidates for next step
next_edges = edges
else:
#only edges starting where the last one finishes are candidates
next_edges = filter(lambda x: path[-1][1] == x[0], edges)
for edge in next_edges:
edges_recursive = list(edges)
edges_recursive.remove(edge)
#recursive call to keep on permuting possible path combinations
paths_rec(list(path) + [edge], edges_recursive)
def all_paths(edges):
paths_rec(list(),edges)
if __name__ == "__main__":
#edges are represented as (node,node)
# so (1,2) represents 1->2 the edge from node 1 to node 2.
edges = [(1,2),(2,3),(3,4),(4,2),(2,1)]
all_paths(edges)
JBSnorro gave an awesome answer, but still it might seem a little too hardcore. Starting from his solution, i present an easier to follow example, that does not need the definitions of Node, Edge and Cycle, and also works on adjacency matrices. My solution though, repeats some cycles if they are started from a different node.
int[,] Adjacency = new int[6, 6] {
{ 0,1,0,1,0,0 },
{ 0,0,0,1,0,0 },
{ 0,0,0,0,1,0 },
{ 0,1,1,0,0,0 },
{ 0,1,0,0,0,1 },
{ 0,0,1,1,0,0 }};
public void Start()
{
List<List<int>> Out = new List<List<int>>();
FindAllCycles(new List<int>(), Out, 0);
Console.WriteLine("");
foreach (List<int> CurrCycle in Out)
{
string CurrString = "";
foreach (int Currint in CurrCycle) CurrString += Currint + ", ";
Console.WriteLine(CurrString);
}
}
private void FindAllCycles(List<int> CurrentCycleVisited, List<List<int>> Cycles, int CurrNode)
{
CurrentCycleVisited.Add(CurrNode);
for (int OutEdgeCnt = 0; OutEdgeCnt < Adjacency.GetLength(0); OutEdgeCnt++)
{
if (Adjacency[CurrNode, OutEdgeCnt] == 1)//CurrNode Is connected with OutEdgeCnt
{
if (CurrentCycleVisited.Contains(OutEdgeCnt))
{
int StartIndex = CurrentCycleVisited.IndexOf(OutEdgeCnt);
int EndIndex = CurrentCycleVisited.IndexOf(CurrNode);
Cycles.Add(CurrentCycleVisited.GetRange(StartIndex, EndIndex - StartIndex + 1));
}
else
{
FindAllCycles(new List<int>(CurrentCycleVisited), Cycles, OutEdgeCnt);
}
}
}
}

Categories

Resources