//TODO: @herman, check at the examples. /// <summary> /// Returns a list containing lines connected to the given points. A line is a list of points. /// Only returns correct results for square or hex grids. /// </summary> /// <example> /// <code> /// private bool IsSameColour(point1, point2) /// { /// return grid[point1].Color == grid[point2].Color; /// } /// /// private SomeMethod() /// { /// ... /// var rays = GetConnectedRays<ColourCell, PointyHexPoint, PointyHexNeighborIndex>( /// grid, point, IsSameColour); /// ... /// } /// </code> /// You can of course also use a lambda expression, like this: /// <code> /// //The following code returns all lines that radiate from the given point /// GetConnectedRays<ColourCell, PointyHexPoint, PointyHexNeighborIndex>( /// grid, point, (x, y) => grid[x].Color == grid[y].Color); /// </code> /// </example> /// <typeparam name="TPoint">The type of point of the grid that this algorithm takes.</typeparam> /// <param name="grid">Grid in which the calculations are made.</param> /// <param name="point">Point where the calculations start.</param> /// <param name="rayGenerators"></param> //TODO: Remove this argument? Make that as part of the rayGenerator? /// <param name="isNeighborsConnected"> /// A functions that returns true or false, depending on whether /// two points can be considered connected when they are neighbors.For example, if you want /// rays of points that refer to cells of the same color, you can pass in a functions that /// compares the DefaultColors of cells. /// </param> public static IEnumerable <IEnumerable <TPoint> > GetConnectedRays <TPoint>( IImplicitShape <TPoint> grid, TPoint point, IEnumerable <IForwardMap <TPoint, TPoint> > rayGenerators, Func <TPoint, TPoint, bool> isNeighborsConnected) { var lines = new List <IEnumerable <TPoint> >(); foreach (var rayGenertor in rayGenerators) { var line = new StructList <TPoint>(); var rayEnd = point; while (grid.Contains(rayEnd) && isNeighborsConnected(point, rayEnd)) { line.Add(rayEnd); rayEnd = rayGenertor.Forward(rayEnd); } if (line.Count > 1) { lines.Add(line); } } return(lines); }
//TODO remove construction of list! /// <summary> /// It construct a list of Points that represent a path by using a Dictionary that hold the information from where the point came from. /// </summary> /// <typeparam name="TPoint">The type of the point.</typeparam> /// <param name="cameFrom">Dictionary holding the information from where the point came from.</param> /// <param name="currentNode">Node that start the path.</param> private static IList <TPoint> ReconstructPath <TPoint>( Dictionary <TPoint, TPoint> cameFrom, TPoint currentNode) { IList <TPoint> path = new StructList <TPoint>(); ReconstructPath(cameFrom, currentNode, path); return(path); }
/// <summary> /// Gets the longest line of connected points that contains this point. /// <see cref="GetConnectedRays{TPoint}"/> /// </summary> /// <typeparam name="TPoint">The type of point of the grid that this algorithm takes.</typeparam> /// <param name="grid">Grid in which the calculations are made.</param> /// <param name="point">Point where the calculations start.</param> /// <param name="lineGenerators">List of line generators.</param> //TODO is Generator the right word? /// <param name="isNeighborsConnected"> /// A functions that returns true or false, depending on whether /// two points can be considered connected when they are neighbors.For example, if you want /// rays of points that refer to cells of the same color, you can pass in a functions that /// compares the DefaultColors of cells. /// </param> public static IEnumerable <IEnumerable <TPoint> > GetConnectedLines <TPoint>( IImplicitShape <TPoint> grid, TPoint point, IEnumerable <IMap <TPoint, TPoint> > lineGenerators, Func <TPoint, TPoint, bool> isNeighborsConnected) { var lines = new List <IEnumerable <TPoint> >(); foreach (var lineGenerator in lineGenerators) { var line = new StructList <TPoint>(); var edge = point; //go forwards while (grid.Contains(edge) && isNeighborsConnected(point, edge)) { edge = lineGenerator.Forward(edge); } //TPoint oppositeNeighbor = point.MoveBy(direction.Negate()); edge = lineGenerator.Reverse(edge); //go backwards while (grid.Contains(edge) && isNeighborsConnected(point, edge)) { line.Add(edge); edge = lineGenerator.Reverse(edge); } if (line.Count > 1) { lines.Add(line); } } return(lines); }
/// <summary> /// Gets all the points (and their costs) from a given point in a given range. This result is stored and returned /// in a dictionary. /// </summary> /// <typeparam name="TPoint">The type of the point used on the grid.</typeparam> /// <param name="grid">The grid used to make the calculations.</param> /// <param name="start">Point where the calculations will start.</param> /// <param name="getConnectedPoints">This function is used to get the connected points to a given point.</param> /// <param name="isAccessible">This function is used to know if a point is acessible within the grid.</param> /// <param name="getCellMoveCost">This function is used to get the movement cost from moving to a cell.</param> /// <param name="moveRange">Range of movement where make the calculations.</param> /// <returns></returns> public static Dictionary <TPoint, int> GetPointsInRangeCost <TPoint>( IGrid <TPoint> grid, TPoint start, Func <TPoint, IEnumerable <TPoint> > getConnectedPoints, Func <TPoint, bool> isAccessible, Func <TPoint, TPoint, int> getCellMoveCost, int moveRange) { // Nodes in range var closedSet = new HashSet <TPoint>(); var costToReach = new Dictionary <TPoint, int>(); var openSet = new StructList <TPoint> { start }; // Cost from start along best known path up to current point var costToReachContains = grid.CloneStructure(false); costToReach[start] = 0; var currentNeighbors = new List <TPoint>(); while (!openSet.IsEmpty()) { // Process current node var current = FindNodeWithLowestScore(openSet, costToReach); openSet.Remove(current); closedSet.Add(current); CheckGridNeighbors(getConnectedPoints(current), grid, currentNeighbors); for (int i = 0; i < currentNeighbors.Count; i++) { var neighbor = currentNeighbors[i]; if (!closedSet.Contains(neighbor) && !openSet.Contains(neighbor) && isAccessible(neighbor) && (costToReach[current] + getCellMoveCost(current, neighbor) <= moveRange) ) { // Cost of current node + neighbor's move cost int newCost = costToReach[current] + getCellMoveCost(current, neighbor); if (costToReachContains[neighbor]) { if (costToReach[neighbor] > newCost) { costToReach[neighbor] = newCost; } } else { costToReach[neighbor] = newCost; costToReachContains[neighbor] = true; } openSet.Add(neighbor); } } } return(costToReach); }