LINQ List<> Moving Elements up and down - c#

Would it be possible to tell me the best way of moving elements in a List<> up and down.
For example I have a class called Building and Building has a list of Rooms objects List<Room>. The rooms are added to the building by name, but I am using this structure to generate a tree view. The user has the option to move a room up and down within a building.
I was trying to use .Reverse(index, count) but this didn't seem to do anything:
// can this item actually be moved up (is it at the first position in it's current parent?)
if (moveDirection == MoveDirection.UP)
{
int roomIndex = parentBuilding.Rooms.IndexOf(room);
if (roomIndex == 0)
{
return;
}
else
{
// move this room up.
parentBuilding.Rooms.Reverse(roomIndex, 1);
}
}

Create a list extension. Call as List<T>.Move(1, MoveDirection.Up).
public static class ListExtensions
{
public static void Move<T>(this IList<T> list, int iIndexToMove,
MoveDirection direction)
{
if (direction == MoveDirection.Up)
{
var old = list[iIndexToMove - 1];
list[iIndexToMove - 1] = list[iIndexToMove];
list[iIndexToMove] = old;
}
else
{
var old = list[iIndexToMove + 1];
list[iIndexToMove + 1] = list[iIndexToMove];
list[iIndexToMove] = old;
}
}
}
public enum MoveDirection
{
Up,
Down
}
Things to consider
Exception handling - what if you are trying to move the bottom
element down or top element up? You will get an index out of range
because you can't move these up or down.
You could improve this and prevent handling exception by extending
functionality to moving the top element to the bottom element and
bottom element down to the top element etc.

Just do a swap:
int roomIndex = parentBuilding.Rooms.IndexOf(room);
if (roomIndex == 0)
{
return;
}
else
{
// move this room up.
var temp = parentBuilding.Rooms[index-1];
parentBuilding.Rooms[index-1] = parentBuilding.Rooms[index];
parentBuilding.Rooms[index] = temp;
}

Personally, I'd make extension method:
static void Swap<TSource>(this IList<TSource> source, int fromIndex, int toIndex)
{
if (source == null)
throw new ArgumentNullExcpetion("source");
TSource tmp = source[toIndex];
source[toIndex] = source[fromIndex];
source[fromIndex] = tmp;
}
Usage:
if (moveDirection == MoveDirection.UP)
{
int roomIndex = parentBuilding.Rooms.IndexOf(room);
if (roomIndex == 0)
{
return;
}
else
{
// move this room up.
parentBuilding.Rooms.Swap(roomIndex, roomIndex - 1);
}
}

How about using SortedDictionary<int, Room> instead of a list. You could store an index in as a Key of the Dictionary and just swap the values when needed.

Swapping places with the room that used to be above should do it:
int roomIndex = parentBuilding.Rooms.IndexOf(room);
if (roomIndex == 0)
{
return;
}
var wasAbove = parentBuilding.Rooms[roomIndex - 1];
parentBuilding.Rooms[roomIndex - 1] = room;
parentBuilding.Rooms[roomIndex] = wasAbove;
That said, I 'm not sure that this is the best object model for the situation; it's not clear that the order of rooms in the list plays a role, and it's also not clear how a room can be "moved up" -- what does that mean?
It might be better to have a RoomPlacement class that aggregates a room and enough information to locate it, and work with that instead.

try this:
int newIndex = whateverIndexYouWantItAt;
int oldIndex = parentBuilding.Rooms.IndexOf(room);
var item = parentBuilding.Rooms[oldIndex];
list.RemoveAt(oldIndex);
if (newIndex > oldIndex) newIndex--;
parentBuilding.Rooms.Insert(newIndex, item);

Related

Need help modifying my A* on a (hex) grid that's mostly "obstacles", but the actor can jump over X tiles

Solved! See my own answer.
I'm creating an app in which there is a hex based map. It takes a certain amount of time to travel between hexes and I'm trying to implement a way to press on any valid hex and get the optimal path (If possible) from the players current position.
Here comes the tricky part, only a few of the hexes are valid travel locations, so I need my path finding to be able to skip over empty hexes. Depending on the players "reach" they are allowed to skip otherwise invalid spaces. So if the players reach was f ex. 3, they are allowed to move 1, 2, or 3 spaces in one "move", even if hexes in between are invalid (Empty), but they are not allowed to "stop" on invalid hexes.
Example:
So far, I've implemented an A* pathfinding script with the help of these references:
https://www.redblobgames.com/grids/hexagons/
https://www.redblobgames.com/pathfinding/a-star/introduction.html
https://gist.github.com/keithcollins/307c3335308fea62db2731265ab44c06
But I'm not sure how to implement the "Skipping" or "Jumping" funcitonality I'm looking for. I've specifically avoided using "edge" cost, because it would require a lot of changes to my current implementation, and direction doesn't matter at all.
My version of the A* function in the third reference link:
public void AStarSearch(MapHex startHex, MapHex goalHex)
{
if (goalHex.empty)
{
Debug.Log("Goal empty.");
return;
}
SimplePriorityQueue<MapHex> frontier =
new SimplePriorityQueue<MapHex>();
frontier.Enqueue(startHex, 0);
cameFrom.Add(startHex, startHex);
costSoFar.Add(startHex, 0);
while (frontier.Count > 0)
{
MapHex current = frontier.Dequeue();
if (current.Equals(goalHex)) break;
foreach (MapHex neighbor in GetNeighbors(current))
{
float newCost = costSoFar[current] + 1;
if (!costSoFar.ContainsKey(neighbor) ||
newCost < costSoFar[neighbor])
{
if (costSoFar.ContainsKey(neighbor))
{
costSoFar.Remove(neighbor);
cameFrom.Remove(neighbor);
}
costSoFar.Add(neighbor, newCost);
cameFrom.Add(neighbor, current);
float priority = newCost +
HexHeuristicDistance(neighbor, goalHex);
frontier.Enqueue(neighbor, priority);
}
}
}
}
I just don't know how to expand the search past otherwise impassable hexes, or similar. I need the final output to be the shortest route to the end hex (If any is possible), to display the route, and the distance travelled.
Any help appreciated :)
Edit:
Okay as per Ruzihm's suggestion I'm trying to expand my "GetNeighbors" function to achieve my goal.
To get all "neighbors" in range of the max speed, I'm trying to implement the code from the "Movement range" section of Red Blob Games's hexgrid guide: https://www.redblobgames.com/grids/hexagons/#range (Second code snip)
Converting from python is proving to be a challenge though and I seem to have created an inefficient monster that may or may not work:
public IEnumerable<MapHex> GetNeighbors(MapHex hex, int distanceOffset)
{
if (distanceOffset == 0)
{
foreach (Vector2 dir in oddQDirections)
{
MapHex next = allMapHexes.Find(item => item.coordinate == new Vector2(hex.coordinate.x + dir.x, hex.coordinate.y + dir.y));
if (next != null)
{
yield return next;
}
}
}
else
{
List<MapHex> neighbors = new List<MapHex>();
List<MapHex> closeHexesX = new List<MapHex>();
Vector3 hexCubeCoord = OddQToCube(hex.coordinate);
foreach (MapHex closeHex in allMapHexes.FindAll(item => !item.empty && -(distanceOffset + 1) <= -OddQToCube(item.coordinate).x && -OddQToCube(item.coordinate).x <= distanceOffset + 1))
{
closeHexesX.Add(closeHex);
}
foreach (MapHex closeHex in closeHexesX.FindAll(item => Mathf.Max(-(distanceOffset + 1), -OddQToCube(item.coordinate).x - (distanceOffset + 1)) <= -OddQToCube(item.coordinate).y && -OddQToCube(item.coordinate).x <= Mathf.Min((distanceOffset + 1), -OddQToCube(item.coordinate).x + (distanceOffset + 1))))
{
Vector3 cubeCoord = OddQToCube(closeHex.coordinate);
cubeCoord.z = -cubeCoord.x - cubeCoord.y;
neighbors.Add(closeHexesX.Find(item => item.coordinate == CubeToOddQ(hexCubeCoord + cubeCoord)));
}
}
}
Maybe I'm better off just running GetDistance for each hex and return those that have a distance <= to "reach"..?
Alright so I ended up solving my problem (Thanks to some pointers from Ruzihm that made me rethink my problem) by simply checking all valid hexes in range, for each pathfinding node. I'm not sure this is the fastest method, but I already have a list of valid hexes, so I don't have iterate through all the empty hexes each loop and it seems to be fast enough.
Here's the "GetNeighbours" code I ended up using each path finding loop:
public List<MapHex> GetNeighborsInRange(MapHex hex, int distance)
{
List<MapHex> neighbors = new List<MapHex>();
if (distance == 0)
{
foreach (Vector2 dir in oddQDirections)
{
MapHex next = allMapHexes.Find(item => item.coordinate == new Vector2(hex.coordinate.x + dir.x, hex.coordinate.y + dir.y));
if (next != null)
{
neighbors.Add(next);
}
}
}
else
{
foreach (MapHex closeHex in nonEmptyMapHexes)
{
if (HexHeuristicDistance(hex, closeHex) <= distance)
{
neighbors.Add(closeHex);
}
}
}
return neighbors;
}
Oh also, here's the method I use to convert my pathfinding data into useful data in the form of an object I call "Journey":
public Journey GetLatestPath()
{
if (cameFrom == null || cameFrom.Count == 0 || costSoFar == null || costSoFar.Count == 0)
{
//Trying to run this before running an A* search.
return null;
}
int pathTravelTime = 0;
List<MapHex> path = new List<MapHex>();
MapHex current = aStarLatestGoal;
while (!current.Equals(aStarLatestStart))
{
if (!cameFrom.ContainsKey(current))
{
//A* was unable to find a valid path.
return null;
}
path.Add(current);
current = cameFrom[current];
pathTravelTime += HexHeuristicDistance(current, path[path.Count - 1]);
}
path.Reverse();
return new Journey(path, aStarLatestStart, pathTravelTime);
}
If you are using a cube or axial hex grid, check out this question for a possible solution to "Get all in range": https://gamedev.stackexchange.com/questions/116035/finding-cells-within-range-on-hexagonal-grid?rq=1

swapping nodes in doubly linked list

Trying to swap the second and third nodes from a doubly linked list in c# with the following method:-
public static void swapNodes(List dblLinkList)
{
Node tempnodeTwo = dblLinkList.firstNode.next; //node two in list
Node tempnodeThree = dblLinkList.firstNode.next.next; //node three in list
Node tempnodeFive = tempnodeTwo.previous;
Node tempnodeSix = tempnodeThree.next;
tempnodeThree.previous = tempnodeFive;
tempnodeThree.next = tempnodeThree;
tempnodeTwo.previous = tempnodeTwo;
tempnodeTwo.next = tempnodeSix;
}
The following shows the output: The first is the original list and the second is the result of the method.
N:19:16 19:16:9 16:9:15 9:15:15 15:15:N
N:19:16 16:16:15 9:15:15 15:15:N
Where am I going wrong?? I have already studied previous questions about this topic which gave me the idea for the code but now stuck!
It seems that you assume tempnodeThree is the third and tempnodeTwo is the second node
of the linked list regardless of the changes you make but this is not the case.
After the initializations what you get is:
tempnodeFive <--> tempnodeTwo <--> tempnodeThree <--> tempnodeSix
And you need is:
tempnodeFive <--> tempnodeThree <--> tempnodeTwo <--> tempnodeSix
So what you have to change from left to right are:
tempNodeFive.next, tempNodeTwo.previous, tempNodeTwo.next, tempNodeThree.previous, tempNodeThree.next, tempNodeSix.previous
Let's go over them following the 2nd linked list representation:
tempNodeFive.next = tempNodeThree;
tempNodeTwo.previous = tempnodeThree;
tempNodeTwo.next = tempnodeSix;
tempNodeThree.previous = tempnodeFive;
tempNodeThree.next = tempnodeTwo;
tempNodeSix.previous = tempnodeTwo;
These six lines are what you need.
PS: You can reconsider variable names for a readable and maintainable code, esp. tempNodeFive and tempnodeSix because five and six does not make any sense as an index and it arises confusion while reading the code.
well here in these lines
tempnodeThree.next = tempnodeThree;
tempnodeTwo.previous = tempnodeTwo;
you are setting the next of a node to itself and the previous of another to itself.
don't you mean
tempnodeThree.next = tempnodeTwo;
tempnodeTwo.previous = tempnodeThree;
I think you would have an easier time if you used better names.
I also would not implement this function like this -- I'd make the function suit it's name like this:
public static void swapNodes(Node a, Node b)
{
if (a == null) return;
if (b == null) return;
Node afterA = a.next;
Node beforeA = a.previous;
a.previous = b.previous;
if (b.previous != null) b.previous.next = a;
a.next = b.next;
if (b.next != null) b.next.previous = a;
b.next = afterA;
if (afterA != null) afterA.previous = b;
b.previous = beforeA;
if (beforeA != null) beforeA.next = b;
}
// call it like this
swapNodes(dblLinkList.firstNode.next, dblLinkList.firstNode.next.next);
Are you sure it's c#? Looks like java. C# has LinkedListNode<T> class, not Node. And LinkedListNode<T> has Next and Previous properties. With capitals. And they are read only.
Any way c# implementation looks like this:
using System;
using System.Collections.Generic;
namespace LinkedListSwap
{
class Program
{
static void Main(string[] args)
{
var list = new LinkedList<string>(new[] { "1st", "2nd", "3rd", "4th", "5th", "6th", "7th" });
Console.WriteLine(list.ToDisplayString());
list.Swap(2, 3);
Console.WriteLine(list.ToDisplayString());
}
}
static class LinkedListExtensions
{
public static void Swap<T>(this LinkedList<T> list, int firstIndex, int secondIndex)
{
if (firstIndex < 1 || firstIndex > list.Count)
throw new IndexOutOfRangeException($"Index out of range: {nameof(firstIndex)}");
if (secondIndex < 1 || secondIndex > list.Count)
throw new IndexOutOfRangeException($"Index out of range: {nameof(secondIndex)}");
if (firstIndex == secondIndex)
return;
if (firstIndex > secondIndex)
(firstIndex, secondIndex) = (secondIndex, firstIndex);
int i = 0;
var leftNode = list.First;
while (++i < firstIndex)
leftNode = leftNode.Next;
var rightNode = leftNode.Next;
while (++i < secondIndex)
rightNode = rightNode.Next;
list.Replace(leftNode, rightNode);
list.Replace(rightNode, leftNode);
}
public static void Replace<T>(this LinkedList<T> list, LinkedListNode<T> oldNode, LinkedListNode<T> newNode)
{
list.AddAfter(oldNode, new LinkedListNode<T>(newNode.Value));
list.Remove(oldNode);
}
public static string ToDisplayString<T>(this LinkedList<T> list) => string.Join(" ", list);
}
}
Output is:
1st 2nd 3rd 4th 5th 6th 7th
1st 3rd 2nd 4th 5th 6th 7th

How to move stack list in other list c#?

I'm working on a solitaire game.
I need help for move several cards from one pile to another.
I can just move one card to an other pile and I don't know how to change that because I use stack list.
So How can check another index apart the first index ?
// valid card at to pile
public bool TryPushCardsOnPile(Card card, int index)
{
Stack<Card> pile = piles[index];
if (pile.Count() == 0)
{
return (card.getRank() == CardRank.King);
}
Card topPile = piles[index].Peek();
if (!topPile.IsVisible())
{
return false;
}
return (card.IsRed() != topPile.IsRed()) && (card.getRank() == topPile.getRank() - 1);
}
in Form Class
public void PileClicked(int index)
{
if (IsDeckDisplaySelected())
{
Card temp = game.deckDisplay.Last();
if (game.TryPushCardsOnPile(temp, index))
{
game.piles[index].Push(temp);
game.deckDisplay.Remove(temp);
move++;
}
Unselect();
SelectPile(index);
}
else if (IsPileSelected())
{
int oldPile = SelectedPile();
if (index != oldPile)
{
Card temp = game.piles[oldPile].Peek();
if (game.TryPushCardsOnPile (temp, index))
{
game.piles[index].Push(temp);
game.piles[oldPile].Pop();
if (game.piles[oldPile].FirstOrDefault() != null)
{
game.piles[oldPile].FirstOrDefault().IsVisible();
}
move++;
Unselect();
}
else
{
// game.piles[oldPile].Push(temp);
// game.AddToPile(temp, oldPile);
Unselect();
SelectPile(index);
}
}
else Unselect();
}
else
{
SelectPile(index);
game.piles[index].Peek().TurnCardUp();
}
}
thank you
While using List or even custom linked list would be probably better choice, it is easy to move block of items from one stack to another: pop all, reverse, push to other stack:
var items = sourceStack.Take(4).Reverse().ToList();
items.ForEach(x => destinationStack.Push(x));

C# increment decrement List values

So sorry for this vague question... its doing my head in...
Basically just a test project, use the [+] key to add a bunch of values into the List.... The arrow keys need to go up and down the List values...
When a new value is added to the list the "historySelected" is reset, so that the 'Up Arrow'.. always selects the last item added in the List first, and then if you keep pressing it, it goes back through the List values. At anytime if the 'Down Arrow' key is pressed it needs to go back to the previous value in the List of values. At no point should a Up Arrow key followed by a Down Arrow key show the same List value, and vice versa..
The behavior I'm looking for is much like a developer console with a command history, where Up arrow goes further back in history, and Down arrow the opposite.
Again apologies for the code, its been through so many test changes, currently this works going Up arrow to the start of the List value, and then using the Down arrow to go all the back to the highest List index... but the problem is if you go half way through the List (or inbetween anyway), and switch from Up arrow.. to Down arrow.. the values increment/decrement don't act accordingly... I can't seem to get the right codelogic for it.
Any help or suggestions thanks.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ArrowKeys {
class Program {
//public static List<string> cmdHistory = new List<string>() { "1", "2", "3", "4", "5" };
public static List<string> cmdHistory = new List<string>();
public static int cmdHistoryCount = 0;
public static int historySelected = 0;
public static int num = 0;
public static string current = "";
public enum UpDown {
reset,
up,
down
};
public static UpDown LastUpDown;
static void Main(string[] args) {
bool running = true;
while (running) {
ConsoleKeyInfo kb = Console.ReadKey();
switch (kb.Key) {
case ConsoleKey.Escape:
Console.WriteLine("Exit");
running = false;
return;
case ConsoleKey.Add:
cmdHistory.Add(num.ToString());
cmdHistoryCount++;
historySelected= cmdHistoryCount;
LastUpDown = UpDown.reset;
Console.WriteLine(string.Join(" ", cmdHistory.Cast<string>().ToArray()));
num++;
break;
case ConsoleKey.UpArrow:
UpArrow();
LastUpDown = UpDown.up;
Console.WriteLine("UpArrow pressed");
Console.WriteLine(current);
break;
case ConsoleKey.DownArrow:
DownArrow();
LastUpDown = UpDown.down;
Console.WriteLine("DownArrow pressed");
Console.WriteLine(current);
break;
}
}
}
public static int Clamp(int value, int min, int max) {
return (value < min) ? min : (value > max) ? max : value;
}
public static void UpArrow() {
if (cmdHistoryCount != 0) {
if (LastUpDown == UpDown.down) {
if (historySelected - 1 == 0) {
return;
}
}
current = cmdHistory[historySelected - 1];
if (historySelected - 1 == 0) {
return;
}
historySelected--;
}
}
public static void DownArrow() {
if (cmdHistoryCount != 0) {
if (LastUpDown == UpDown.up) {
if (historySelected + 1 > cmdHistoryCount) {
return;
}
}
current = cmdHistory[historySelected - 1];
if (historySelected + 1 > cmdHistoryCount) {
return;
}
historySelected++;
}
}
}
}
It sounds like you simply need to stop your index going out of range. It's not clear what the existing code was intended to do, but your clarification seems to imply it's not necessary. Try this:
public static void UpArrow()
{
historySelected = Math.Max(0, historySelected - 1);
current = cmdHistory[historySelected];
}
public static void DownArrow()
{
var maxIndex = cmdHistory.Count - 1;
historySelected = Math.Min(maxIndex, historySelected + 1);
current = cmdHistory[historySelected];
}
If I'm understanding what you're looking for correctly, a pair of dueling stacks might work for your case. They're going to give you the FILO/LIFO style item access you're looking for. Drop the List and do something like:
var UpStack = new Stack<string>();
var DownStack = new Stack<string>();
On "new item"
UpStack.Push(newItem);
On "Up"
DownStack.Push(UpStack.Pop());
On "Down"
UpStack.Push(DownStack.Pop());
If you wanted a "buffer" item that isn't in either of the stacks, that's easy enough to do by just Popping into the buffer item. It's a little more management, because you'd have to push it onto one stack, then pop the other each time, but it's whatever. There's also the Peek() method, which gets the item on top of a Stack without Popping it, so you use that for your display item, as well.

Algorithm for detecting cycles finds far to few cycles

I have the following algorithm:
class CycleData : List<IntPoint>{
public IntPoint startPoint;
public Boolean ended=false;
public CycleData(IntPoint startpoint) { startPoint = startpoint; base.Add(startpoint); }
}
class GeoDataGraphPoint
{
private IntPoint point;
private List<GeoDataGraphPoint> connected = new List<GeoDataGraphPoint>();
private int generation=-9999;
public void AddConnection(GeoDataGraphPoint c)
{
connected.Add(c);
c.connected.Add(this);
}
public GeoDataGraphPoint(IntPoint point)
{
this.point = point;
}
public List<CycleData> GetCycles(int gen)
{
if (generation != -9999)
{
var r = new CycleData(point);
return new List<CycleData> { r };
}
generation = gen;
List<CycleData> res = new List<CycleData>();
foreach (GeoDataGraphPoint p in connected)
{
if (p.generation != gen-1)
{
res.AddRange(p.GetCycles(gen + 1));
}
}
foreach (CycleData list in res)
{
if (list.ended == false)
{
list.Add(point);
if (list.startPoint == this.point)
{
list.ended = false;
}
}
}
gen = -9999;
return res;
}
}
Now in principle this should return every cycle in the graph (for polygon detection). However it seems to fail to return anything in some occasions, I suspect that there is some kind of memory problem as removing parts of the graph sometimes causes new cycles to be found.
Here is a part of the input where it fails:
connection:(2282,3) to (2282,-192)
connection:(2282,3) to (2085,3)
connection:(2282,-192) to (2282,3)
connection:(2282,-192) to (2466,-192)
connection:(2466,-192) to (2282,-192)
connection:(2466,-192) to (2466,581)
connection:(2466,581) to (2466,-192)
connection:(2466,581) to (1494,581)
connection:(1494,581) to (2466,581)
connection:(1494,581) to (1494,397)
connection:(1494,397) to (1494,581)
connection:(1494,397) to (2282,397)
connection:(2282,397) to (1494,397)
connection:(2282,397) to (2282,187)
connection:(2282,187) to (2282,397)
connection:(2282,187) to (2085,187)
connection:(2085,187) to (2282,187)
connection:(2085,187) to (2085,3)
connection:(2085,3) to (2085,187)
connection:(2085,3) to (2282,3)
connection:(2085,3) to (2085,187)
connection:(2085,3) to (2282,3)
connection:(2085,187) to (2282,187)
connection:(2085,187) to (2085,3)
connection:(2282,187) to (2282,397)
connection:(2282,187) to (2085,187)
connection:(2282,397) to (1494,397)
The above code is for two triangles arranged to form a square (in coordinates) where both sides touch one another so like this:
Where I can the function as following:
class GeoDataGraph : Dictionary<IntPoint, GeoDataGraphPoint>
{
public void resetGens()
{
foreach(var v in base.Values)
{
v.generation = -9999;
}
}
public static Island GetHolesInIsland(Island input)
{
GeoDataGraph graph = new GeoDataGraph();
for (int i = 0; i < input.area.Count-1; i = i + 2)
{
var p1 = new IntPoint(input.area[i].X, input.area[i].Y);
var p2 = new IntPoint(input.area[i + 1].X, input.area[i + 1].Y);
if (!graph.ContainsKey(p1)) graph.Add(p1, new GeoDataGraphPoint(p1));
if (!graph.ContainsKey(p2)) graph.Add(p2, new GeoDataGraphPoint(p2));
graph[p1].AddConnection(graph[p2]);
}
IntPoint min = new IntPoint(int.MaxValue, int.MaxValue);
List<IntPoint> minCycle = null;
List<List<IntPoint>> cycles = new List<List<IntPoint>>();
while (graph.Count != 0)
{
var first = graph.First();
var NewCycles = first.Value.GetCycles(1);
graph.resetGens();
if (NewCycles.Count == 0)
{
graph.Remove(first.Key);
Console.WriteLine("point" + first.Key + "is uncycled");
}
cycles.AddRange(NewCycles);
foreach (var cycle in NewCycles)
{
foreach (var cycleNode in cycle)
{
graph.Remove(cycleNode);
if (min.X > cycleNode.X || min.Y > cycleNode.Y)
{
minCycle = cycle;
min = cycleNode;
}
}
}
}
cycles.Remove(minCycle);
if (minCycle == null) { minCycle = new List<IntPoint>();
foreach(IntPoint a in input.area) {
Console.Write(a);
} }
input.holes = cycles;
input.area = minCycle;
return input;
}
}
}
where Island contains.area contains a list of points ordered by connected pairs.
The basic algorithm is simple: take a node recursively visit every node connected to it until you detect a cycle, then return that node and append any node on the way out until you find the start of the cycle again. Once you have found every node connected to the start node remove the cycles (they since we checked every node connected to the cycle we shouldn't be deleting the once we already did) and start again on the next node, if a node contains no cycles remove it. I suspect something might be going wrong at this step but am unsure.
Any idea what I'm doing wrong that causes a weird interdependence that causes seemingly unrelated polygons to go wrong?
I think that one problem is the way you ignore connected nodes using p.generation != gen-1. As you use depth first search you will tag all the nodes until the most depth and when backtracking I think it can miss some nodes or explore nodes twice.
As a general advise I can say: Don't reinvent the wheel yourself but use a known algorithm.
First ask yourself what you want to do. The number of cycles can be exponential. So the question is if you really need all the cycles.
If the answer is yes and you want to find all the cycles in a undirected graph you can get more information here.
If you don't really need all the cyles maybe what your are looking for is to find strongly connected components.

Categories