//Some basic operations. public bool BoundedBy(IVector3 min, IVector3 max) { if (X >= min.X && Y >= min.Y && Z >= min.Z && X < max.X && Y < max.Y && Z < max.Z) { return true; } return false; }
TileType GetTileType( IVector3 xyz ) { if ( xyz.Z == 0 ) return TileType.Grass; return TileType.Air; }
public static double Distance(IVector3 a, IVector3 b) { double d = Dot(a, b); return Math.Sqrt(d); }
public static int Dot(IVector3 a, IVector3 b) { return a.X * b.X + a.Y * b.Y + a.Z * b.Z; }
private void Reconstruct(Dictionary<IVector3, IVector3> camefrom, IVector3 current, List<IVector3> result) { if (camefrom.ContainsKey(current)) { Reconstruct(camefrom, camefrom[current], result); } result.Add(current); }
private List<IVector3> PassableNodes(IVector3 node) { var result = new List<IVector3>(); Tile currentTile = this[node]; TileDeclaration decl = currentTile.Declaration; if (decl.StairType != StairType.None) { if ((decl.StairType & StairType.Up) != 0) { IVector3 target = node; target.Z += 1; if (this[target].IsPassable) { result.Add(target); } } if ((decl.StairType & StairType.Down) != 0) { IVector3 target = node; target.Z -= 1; if (this[target].IsPassable) { result.Add(target); } } } for (int x = -1; x <= 1; ++x) { for (int y = -1; y <= 1; ++y) { if (y == 0 && x == 0) { continue; } IVector3 target = node; target.X += x; target.Y += y; if (target.BoundedBy(IVector3.Zero, Dimensions)) { Tile tile = this[target]; if (tile.IsPassable) { result.Add(target); } } } } return result; }
private double Cost(IVector3 node, IVector3 end) { return IVector3.Dot(node, end); }
// Basic A* implementation. public List<IVector3> Path(IVector3 start, IVector3 end) { Debug.Assert(start.BoundedBy(IVector3.Zero, Dimensions)); Debug.Assert(end.BoundedBy(IVector3.Zero, Dimensions)); List<IVector3> result = new List<IVector3>(); HashSet<IVector3> closed = new HashSet<IVector3>(); HashSet<IVector3> open = new HashSet<IVector3>(); open.Add(start); var cameFrom = new Dictionary<IVector3, IVector3>(); var goalScore = new Dictionary<IVector3, double>(); goalScore.Add(start, 0); var guessScore = new Dictionary<IVector3, double>(); guessScore.Add(start, Cost(start, end)); var finalScore = new Dictionary<IVector3, double>(); finalScore.Add(start, guessScore[start]); while(open.Count != 0) { double minscore = finalScore[open.First()]; IVector3 node = open.First(); foreach (var n in open) { if (finalScore[n] < minscore) { minscore = finalScore[n]; node = n; } } if (node == end) { Reconstruct(cameFrom, cameFrom[end], result); result.Add(end); return result; } open.Remove(node); closed.Add(node); foreach (var t in PassableNodes(node)) { if (closed.Contains(t)) { continue; } bool isBetter = false; double score = goalScore[node] + IVector3.Distance(node, t); if (!open.Contains(t)) { open.Add(t); isBetter = true; } else if (score < goalScore[t]) { isBetter = true; } else { isBetter = false; } if (isBetter) { cameFrom[t] = node; goalScore[t] = score; guessScore[t] = Cost(t, end); finalScore[t] = score + Cost(t, end); } } } //No path! return null; }
public Tile this[IVector3 i] { get { return this[i.X, i.Y, i.Z]; } set { this[i.X, i.Y, i.Z] = value; } }