// PERF: If this ends up being slow, we can mark with a dirty bit /** * Returns a path from start to end, exclusive - that is, the start and end nodes are *not* listed in the path. Does a full * naive search every time. */ public static List <EncounterPosition> AStarWithNewGrid( EncounterPosition start, EncounterPosition end, EncounterState state, int maxAreaToExplore = 950 ) { SimplePriorityQueue <EncounterPosition> frontier = new SimplePriorityQueue <EncounterPosition>(); frontier.Enqueue(start, 0f); var cameFrom = new Dictionary <EncounterPosition, EncounterPosition>(); var costSoFar = new Dictionary <EncounterPosition, float>(); costSoFar[start] = 0f; while (frontier.Count > 0 && cameFrom.Count < maxAreaToExplore) { var currentPosition = frontier.Dequeue(); var adjacentPositions = state.AdjacentPositions(currentPosition); if (adjacentPositions.Contains(end)) { var path = new List <EncounterPosition>() { currentPosition }; EncounterPosition cameFromPos; while (cameFrom.TryGetValue(path[path.Count - 1], out cameFromPos) && (cameFromPos != start)) { path.Add(cameFromPos); } path.Reverse(); return(path); } var adjacentUnblocked = adjacentPositions.Where(adjacent => !state.IsPositionBlocked(adjacent)).ToList(); adjacentUnblocked.ForEach(adjacent => { var newNextPositionCost = costSoFar[currentPosition] + 1f; if (!costSoFar.ContainsKey(adjacent) || newNextPositionCost < costSoFar[adjacent]) { costSoFar[adjacent] = newNextPositionCost; // Uses straight-line distance as heuristic float priority = newNextPositionCost + adjacent.DistanceTo(end); frontier.Enqueue(adjacent, priority); cameFrom[adjacent] = currentPosition; } }); } return(null); }
public static EncounterPath BuildReverseLinePath(EncounterPosition start, EncounterPosition target, int overshoot) { var distance = (int)Math.Ceiling(start.DistanceTo(target)); var outwardPath = StraightLine(start, target, numSteps: distance + overshoot, endsAtTarget: false); var reversePath = StraightLine(outwardPath[outwardPath.Count - 2], start, numSteps: distance + overshoot, endsAtTarget: false); reversePath.RemoveAt(reversePath.Count - 1); outwardPath.AddRange(reversePath); return(new EncounterPath(outwardPath)); }
private static List <EncounterPosition> StraightLine(EncounterPosition start, EncounterPosition end, int numSteps, bool endsAtTarget) { List <EncounterPosition> acc = new List <EncounterPosition>(); acc.Add(start); bool isVertical = start.X == end.X; float dError = isVertical ? float.MaxValue : Math.Abs(((float)end.Y - (float)start.Y) / ((float)end.X - (float)start.X)); int yErr = end.Y - start.Y > 0 ? 1 : -1; int xDiff = end.X - start.X > 0 ? 1 : -1; float error = 0.0f; int cX = start.X; int cY = start.Y; int steps = 0; while (steps < numSteps) { EncounterPosition newPosition; if (isVertical) { cY += yErr; newPosition = new EncounterPosition(cX, cY); } else if (error >= 0.5f) { cY += yErr; error -= 1f; newPosition = new EncounterPosition(cX, cY); } else { cX += xDiff; error += dError; newPosition = new EncounterPosition(cX, cY); } acc.Add(newPosition); if (endsAtTarget && newPosition == end) { break; } steps += 1; } return(acc); }
public List <EncounterPosition> AStar(EncounterPosition start, EncounterPosition end, EncounterState state) { return(AStarWithNewGrid(start, end, state)); }
public static EncounterPath BuildStraightLinePath(EncounterPosition start, EncounterPosition target, int maxSteps = 100, bool endsAtTarget = false) { return(new EncounterPath(StraightLine(start, target, maxSteps, endsAtTarget))); }