1
0
Fork 0
mirror of https://github.com/Ellpeck/MLEM.git synced 2024-11-29 23:58:34 +01:00

use dictionaries in favor of lists for AStar to speed up pathfinding

This commit is contained in:
Ell 2020-09-10 02:12:53 +02:00
parent a5c1b6c2b4
commit 4f63770de0

View file

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace MLEM.Pathfinding { namespace MLEM.Pathfinding {
@ -91,25 +92,23 @@ namespace MLEM.Pathfinding {
var tries = maxTries ?? this.DefaultMaxTries; var tries = maxTries ?? this.DefaultMaxTries;
var defCost = defaultCost ?? this.DefaultCost; var defCost = defaultCost ?? this.DefaultCost;
var open = new List<PathPoint<T>>(); var open = new Dictionary<T, PathPoint<T>>();
var closed = new List<PathPoint<T>>(); var closed = new Dictionary<T, PathPoint<T>>();
open.Add(new PathPoint<T>(start, this.GetManhattanDistance(start, goal), null, 0, defCost)); open.Add(start, new PathPoint<T>(start, this.GetManhattanDistance(start, goal), null, 0, defCost));
var count = 0; var count = 0;
Stack<T> ret = null; Stack<T> ret = null;
while (open.Count > 0) { while (open.Count > 0) {
PathPoint<T> current = null; PathPoint<T> current = null;
var lowestF = float.MaxValue; foreach (var point in open.Values) {
foreach (var point in open) if (current == null || point.F < current.F)
if (point.F < lowestF) {
current = point; current = point;
lowestF = point.F; }
}
if (current == null) if (current == null)
break; break;
open.Remove(current); open.Remove(current.Pos);
closed.Add(current); closed.Add(current.Pos, current);
if (current.Pos.Equals(goal)) { if (current.Pos.Equals(goal)) {
ret = CompilePath(current); ret = CompilePath(current);
@ -120,20 +119,19 @@ namespace MLEM.Pathfinding {
foreach (var dir in dirsUsed) { foreach (var dir in dirsUsed) {
var neighborPos = this.AddPositions(current.Pos, dir); var neighborPos = this.AddPositions(current.Pos, dir);
var cost = getCost(current.Pos, neighborPos); var cost = getCost(current.Pos, neighborPos);
if (!float.IsInfinity(cost) && cost < float.MaxValue) { if (!float.IsInfinity(cost) && cost < float.MaxValue && !closed.ContainsKey(neighborPos)) {
var neighbor = new PathPoint<T>(neighborPos, this.GetManhattanDistance(neighborPos, goal), current, cost, defCost); var neighbor = new PathPoint<T>(neighborPos, this.GetManhattanDistance(neighborPos, goal), current, cost, defCost);
if (!closed.Contains(neighbor)) { // check if we already have a waypoint at this location with a worse path
var alreadyIndex = open.IndexOf(neighbor); if (open.TryGetValue(neighborPos, out var alreadyNeighbor)) {
if (alreadyIndex < 0) { if (neighbor.G < alreadyNeighbor.G) {
open.Add(neighbor); open.Remove(neighborPos);
} else { } else {
var alreadyNeighbor = open[alreadyIndex]; // if the old waypoint is better, we don't add ours
if (neighbor.G < alreadyNeighbor.G) { continue;
open.Remove(alreadyNeighbor);
open.Add(neighbor);
}
} }
} }
// add the new neighbor as a possible waypoint
open.Add(neighborPos, neighbor);
} }
} }