mirror of
https://github.com/Xevion/Paths.git
synced 2026-01-31 02:25:06 -06:00
implement GridState code with accompanying refactoring, general fixes and cleanup, GetNode, IsValid, RecordState, GetStates etc.
This commit is contained in:
@@ -1,68 +1,99 @@
|
|||||||
using System;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using Algorithms;
|
|
||||||
|
|
||||||
public class AStar : IPathfinding {
|
namespace Algorithms {
|
||||||
private NodeGrid _nodeGrid;
|
public class AStar : IPathfinding {
|
||||||
|
private NodeGrid _nodeGrid;
|
||||||
|
|
||||||
private Stack<Node> _path;
|
private Stack<Node> _path;
|
||||||
private List<Node> _openList;
|
private List<Node> _openList;
|
||||||
private List<Node> _closedList;
|
private List<Node> _closedList;
|
||||||
|
private List<GridState> _states;
|
||||||
public AStar(NodeGrid nodeGrid) {
|
|
||||||
this._nodeGrid = nodeGrid;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Tuple<List<NodeGrid>, Stack<Node>> FindPath(Vector2 Start, Vector2 End) {
|
private Vector2 _start;
|
||||||
var start = new Node(Start, true);
|
private Vector2 _end;
|
||||||
var end = new Node(End, true);
|
|
||||||
|
|
||||||
_path = new Stack<Node>();
|
public AStar(NodeGrid nodeGrid) {
|
||||||
_openList = new List<Node>();
|
this._nodeGrid = nodeGrid;
|
||||||
_closedList = new List<Node>();
|
_states = new List<GridState>();
|
||||||
Node current = start;
|
}
|
||||||
|
|
||||||
// add start node to Open List
|
public Stack<Node> FindPath(Vector2 Start, Vector2 End) {
|
||||||
_openList.Add(start);
|
this._start = Start;
|
||||||
|
this._end = End;
|
||||||
|
|
||||||
while (_openList.Count != 0 && !_closedList.Exists(x => x.Position == end.Position)) {
|
var start = new Node(Start, true);
|
||||||
current = _openList[0];
|
var end = new Node(End, true);
|
||||||
_openList.Remove(current);
|
|
||||||
_closedList.Add(current);
|
RecordState();
|
||||||
List<Node> adjacentNodes = this._nodeGrid.GetAdjacentNodes(current);
|
|
||||||
|
|
||||||
|
_path = new Stack<Node>();
|
||||||
|
_openList = new List<Node>();
|
||||||
|
_closedList = new List<Node>();
|
||||||
|
Node current = start;
|
||||||
|
|
||||||
foreach (Node n in adjacentNodes) {
|
// add start node to Open List
|
||||||
if (!_closedList.Contains(n) && n.Walkable) {
|
_openList.Add(start);
|
||||||
if (!_openList.Contains(n)) {
|
|
||||||
n.Parent = current;
|
while (_openList.Count != 0 && !_closedList.Exists(x => x.Position == end.Position)) {
|
||||||
n.DistanceToTarget = NodeGrid.Manhattan(n, end);
|
current = _openList[0];
|
||||||
n.Cost = n.Weight + n.Parent.Cost;
|
_openList.Remove(current);
|
||||||
_openList.Add(n);
|
_closedList.Add(current);
|
||||||
_openList = _openList.OrderBy(node => node.F).ToList<Node>();
|
RecordState();
|
||||||
|
|
||||||
|
IEnumerable<Node> adjacentNodes = this._nodeGrid.GetAdjacentNodes(current);
|
||||||
|
|
||||||
|
foreach (Node n in adjacentNodes) {
|
||||||
|
if (!_closedList.Contains(n) && n.Walkable) {
|
||||||
|
if (!_openList.Contains(n)) {
|
||||||
|
n.Parent = current;
|
||||||
|
n.DistanceToTarget = NodeGrid.Manhattan(n, end);
|
||||||
|
n.Cost = n.Weight + n.Parent.Cost;
|
||||||
|
|
||||||
|
_openList.Add(n);
|
||||||
|
_openList = _openList.OrderBy(node => node.F).ToList();
|
||||||
|
|
||||||
|
RecordState();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// construct path, if end was not closed return null
|
||||||
|
if (!_closedList.Exists(x => x.Position == end.Position)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if all good, return path
|
||||||
|
Node temp = _closedList[_closedList.IndexOf(current)];
|
||||||
|
if (temp == null) return null;
|
||||||
|
do {
|
||||||
|
_path.Push(temp);
|
||||||
|
temp = temp.Parent;
|
||||||
|
} while (temp != start && temp != null);
|
||||||
|
|
||||||
|
return _path;
|
||||||
}
|
}
|
||||||
|
|
||||||
// construct path, if end was not closed return null
|
/// <summary>
|
||||||
if (!_closedList.Exists(x => x.Position == end.Position)) {
|
/// Records the current state of the pathfinding algorithm in the grid.
|
||||||
return null;
|
/// </summary>
|
||||||
|
public void RecordState() {
|
||||||
|
// TODO: Record basic grid node types
|
||||||
|
// TODO: Record timing information
|
||||||
|
// TODO: Record pathfinding state information (stages, heuristic, statistical info)
|
||||||
|
this._states.Add(
|
||||||
|
new GridState(this._nodeGrid, this._openList, this._closedList, _start, _end, _path)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if all good, return path
|
/// <summary>
|
||||||
Node temp = _closedList[_closedList.IndexOf(current)];
|
/// Returns the current list of grid states of the pathfinding algorithm.
|
||||||
if (temp == null) return null;
|
/// </summary>
|
||||||
do {
|
/// <returns>A list of GridState objects representing the pathfinding algorithm's progress</returns>
|
||||||
_path.Push(temp);
|
public List<GridState> GetStates() {
|
||||||
temp = temp.Parent;
|
return this._states;
|
||||||
} while (temp != start && temp != null);
|
}
|
||||||
|
|
||||||
return _path;
|
|
||||||
}
|
|
||||||
|
|
||||||
private StateGrid compileState() {
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,59 +2,76 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using Algorithms;
|
|
||||||
using NUnit.Framework.Constraints;
|
|
||||||
using UnityEngine.SocialPlatforms;
|
|
||||||
|
|
||||||
public class NodeGrid {
|
namespace Algorithms {
|
||||||
private List<List<Node>> grid;
|
public class NodeGrid {
|
||||||
private readonly int _width;
|
private List<List<Node>> grid;
|
||||||
private readonly int _height;
|
public readonly int Width;
|
||||||
|
public readonly int Height;
|
||||||
|
|
||||||
public NodeGrid(int width, int height) {
|
public NodeGrid(int width, int height) {
|
||||||
if (width <= 0)
|
if (width <= 0)
|
||||||
throw new ArgumentOutOfRangeException(nameof(width),
|
throw new ArgumentOutOfRangeException(nameof(width),
|
||||||
$"The width of the grid must be a positive non-zero integer.");
|
$"The width of the grid must be a positive non-zero integer.");
|
||||||
if (height <= 0)
|
if (height <= 0)
|
||||||
throw new ArgumentOutOfRangeException(nameof(height),
|
throw new ArgumentOutOfRangeException(nameof(height),
|
||||||
$"The height of the grid must be a positive non-zero integer.");
|
$"The height of the grid must be a positive non-zero integer.");
|
||||||
|
|
||||||
this.grid = new List<List<Node>>(width);
|
this.grid = new List<List<Node>>(width);
|
||||||
// Fill grid with width*height nodes, zero-indexed
|
// Fill grid with width*height nodes, zero-indexed
|
||||||
foreach (int x in Enumerable.Range(0, width - 1)) {
|
foreach (int x in Enumerable.Range(0, width - 1)) {
|
||||||
List<Node> list = new List<Node>(height);
|
List<Node> list = new List<Node>(height);
|
||||||
foreach (int y in Enumerable.Range(0, height))
|
foreach (int y in Enumerable.Range(0, height))
|
||||||
list.Add(new Node(new Vector2(x, y), true));
|
list.Add(new Node(new Vector2(x, y), true));
|
||||||
|
|
||||||
this.grid.Add(list);
|
this.grid.Add(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Width = width;
|
||||||
|
this.Height = height;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._width = width;
|
public NodeGrid(List<List<Node>> grid) {
|
||||||
this._height = height;
|
this.grid = grid;
|
||||||
}
|
|
||||||
|
|
||||||
public NodeGrid(List<List<Node>> grid) {
|
this.Height = this.grid[0].Count;
|
||||||
this.grid = grid;
|
this.Width = this.grid.Count;
|
||||||
|
}
|
||||||
|
|
||||||
this._height = this.grid[0].Count;
|
public IEnumerable<Node> GetAdjacentNodes(Node node) {
|
||||||
this._width = this.grid.Count;
|
List<Node> temp = new List<Node>();
|
||||||
}
|
|
||||||
|
|
||||||
public List<Node> GetAdjacentNodes(Node node) {
|
int row = (int) node.Position.Y;
|
||||||
List<Node> temp = new List<Node>();
|
int col = (int) node.Position.X;
|
||||||
|
|
||||||
int row = (int) node.Position.Y;
|
if (row + 1 < Height) temp.Add(this.grid[col][row + 1]);
|
||||||
int col = (int) node.Position.X;
|
if (row - 1 >= 0) temp.Add(this.grid[col][row - 1]);
|
||||||
|
if (col - 1 >= 0) temp.Add(this.grid[col - 1][row]);
|
||||||
|
if (col + 1 < Width) temp.Add(this.grid[col + 1][row]);
|
||||||
|
|
||||||
if (row + 1 < _height) temp.Add(this.grid[col][row + 1]);
|
return temp;
|
||||||
if (row - 1 >= 0) temp.Add(this.grid[col][row - 1]);
|
}
|
||||||
if (col - 1 >= 0) temp.Add(this.grid[col - 1][row]);
|
|
||||||
if (col + 1 < _width) temp.Add(this.grid[col + 1][row]);
|
|
||||||
|
|
||||||
return temp;
|
public bool IsValid(int x, int y) {
|
||||||
}
|
return x > 0 && x < this.Width && y > 0 && y < this.Height;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves a node at a given coordinate.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="x">the X (column) coordinate</param>
|
||||||
|
/// <param name="y">the Y (row) coordinate</param>
|
||||||
|
/// <returns>A Node object</returns>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException">when the coordinate given does not exist on the grid</exception>
|
||||||
|
public Node GetNode(int x, int y) {
|
||||||
|
if(!IsValid(x, y))
|
||||||
|
throw new ArgumentOutOfRangeException();
|
||||||
|
|
||||||
|
return this.grid[x][y];
|
||||||
|
}
|
||||||
|
|
||||||
public static float Manhattan(Node first, Node second) {
|
public static float Manhattan(Node first, Node second) {
|
||||||
return Math.Abs(first.Position.X - second.Position.X) + Math.Abs(first.Position.Y - second.Position.Y);
|
return Math.Abs(first.Position.X - second.Position.X) + Math.Abs(first.Position.Y - second.Position.Y);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Numerics;
|
||||||
|
using Algorithms;
|
||||||
|
|
||||||
|
public class GridState {
|
||||||
|
private List<List<GridNodeType>> _grid;
|
||||||
|
|
||||||
|
public GridState(NodeGrid grid, IEnumerable<Node> seen, IEnumerable<Node> expanded, Vector2 start, Vector2 end, IReadOnlyCollection<Node> path) {
|
||||||
|
this._grid = new List<List<GridNodeType>>(grid.Width);
|
||||||
|
|
||||||
|
// Add walls and empty tiles
|
||||||
|
foreach (var x in Enumerable.Range(0, grid.Width - 1)) {
|
||||||
|
this._grid.Add(new List<GridNodeType>(grid.Height));
|
||||||
|
foreach (var y in Enumerable.Range(0, grid.Height - 1)) {
|
||||||
|
Node node = grid.GetNode(x, y);
|
||||||
|
this._grid[x].Add(!node.Walkable ? GridNodeType.Wall : GridNodeType.Empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add 'seen' tiles
|
||||||
|
foreach (Node seenNode in seen) {
|
||||||
|
this._grid[(int) seenNode.Position.X][(int) seenNode.Position.Y] = GridNodeType.Seen;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add 'expanded' tiles
|
||||||
|
foreach (Node expandedNode in expanded) {
|
||||||
|
this._grid[(int) expandedNode.Position.X][(int) expandedNode.Position.Y] = GridNodeType.Expanded;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set start and end tiles
|
||||||
|
this._grid[(int) start.X][(int) start.Y] = GridNodeType.Start;
|
||||||
|
this._grid[(int) end.X][(int) end.Y] = GridNodeType.End;
|
||||||
|
|
||||||
|
// Add 'path' tiles
|
||||||
|
if (path != null)
|
||||||
|
foreach (Node pathNode in path)
|
||||||
|
this._grid[(int) pathNode.Position.X][(int) pathNode.Position.Y] = GridNodeType.Path;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 1a26aa7e514043e8911382088176258b
|
||||||
|
timeCreated: 1604887099
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
using System;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using Algorithms;
|
using Algorithms;
|
||||||
|
|
||||||
@@ -13,5 +12,12 @@ public interface IPathfinding {
|
|||||||
/// <param name="start">The position from which pathfinding begins</param>
|
/// <param name="start">The position from which pathfinding begins</param>
|
||||||
/// <param name="end">The position trying to be found via pathfinding</param>
|
/// <param name="end">The position trying to be found via pathfinding</param>
|
||||||
/// <returns>A List of NodeGridGrid objects representing the timeline of Pathfinding</returns>
|
/// <returns>A List of NodeGridGrid objects representing the timeline of Pathfinding</returns>
|
||||||
Tuple<List<NodeGrid>, Stack<Node>> FindPath(Vector2 start, Vector2 end);
|
Stack<Node> FindPath(Vector2 start, Vector2 end);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Records the current state of the pathfinding algorithm. Internal usage only.
|
||||||
|
/// </summary>
|
||||||
|
void RecordState();
|
||||||
|
|
||||||
|
List<GridState> GetStates();
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user