switched GridState operations from List to 2d array, attempting to fix off-by-one mistakes, fix unwalkable start after nodeGrid.AddRandomWall

This commit is contained in:
Xevion
2020-11-09 10:20:28 -06:00
parent bca7e1f33f
commit 21c666bd60
6 changed files with 82 additions and 59 deletions

View File

@@ -145,7 +145,7 @@ AudioListener:
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 519420028}
m_Enabled: 1
m_Enabled: 0
--- !u!20 &519420031
Camera:
m_ObjectHideFlags: 0
@@ -575,7 +575,7 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
gridMaterial: {fileID: 2100000, guid: 780d53bea4df7b0418e9c8ed8afd6410, type: 2}
size: 31
size: 32
--- !u!23 &2092623186
MeshRenderer:
m_ObjectHideFlags: 0

View File

@@ -11,11 +11,8 @@ namespace Algorithms {
private List<Node> _closedList;
private List<GridState> _states;
private Vector2Int _start;
private Vector2Int _end;
public Vector2Int Start { get => _start; }
public Vector2Int End { get => _end; }
public Vector2Int Start { get; private set; }
public Vector2Int End { get; private set; }
public AStar(NodeGrid nodeGrid) {
this._nodeGrid = nodeGrid;
@@ -23,17 +20,17 @@ namespace Algorithms {
}
public Stack<Node> FindPath(Vector2Int start, Vector2Int end) {
this._start = start;
this._end = end;
this.Start = start;
this.End = end;
var startNode = new Node(start, true);
var endNode = new Node(end, true);
_path = new Stack<Node>();
_openList = new List<Node>();
_closedList = new List<Node>();
RecordState();
Node current = startNode;
@@ -58,16 +55,16 @@ namespace Algorithms {
_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 == endNode.Position)) {
if (!_closedList.Exists(node => node.Position == endNode.Position)) {
return null;
}
@@ -89,7 +86,7 @@ namespace Algorithms {
public void RecordState() {
// TODO: Record pathfinding state information (stages, heuristic, statistical info)
this._states.Add(
new GridState(this._nodeGrid, this._openList, this._closedList, _start, _end, _path)
new GridState(this._nodeGrid, this._openList, this._closedList, Start, End, _path)
);
}

View File

@@ -22,14 +22,14 @@ namespace Algorithms {
// Fill grid with width*height nodes, zero-indexed
foreach (int x in Enumerable.Range(0, width - 1)) {
List<Node> list = new List<Node>(height);
foreach (int y in Enumerable.Range(0, height))
foreach (int y in Enumerable.Range(0, height - 1))
list.Add(new Node(new Vector2Int(x, y), true));
grid.Add(list);
}
Width = width;
Height = height;
Width = this.grid.Count;
Height = this.grid[0].Count;
}
public NodeGrid(List<List<Node>> grid) {
@@ -42,8 +42,8 @@ namespace Algorithms {
public List<Node> GetAdjacentNodes(Node node) {
List<Node> temp = new List<Node>();
int row = node.Position.y;
int col = node.Position.x;
int row = node.Position.y;
if (row + 1 < Height) temp.Add(grid[col][row + 1]);
if (row - 1 >= 0) temp.Add(grid[col][row - 1]);
@@ -71,16 +71,31 @@ namespace Algorithms {
return grid[x][y];
}
public void FlipRandomWall() {
grid[Random.Range(0, Width - 1)][Random.Range(0, Height - 1)].Walkable = false;
public Node GetNode(Vector2Int position) {
return GetNode(position.x, position.y);
}
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);
/// <summary>
/// Finds one random walkable cell and turns it into a wall.
/// </summary>
public void AddRandomWall() {
while (true) {
int x = Random.Range(0, Width - 1);
int y = Random.Range(0, Height - 1);
if (grid[x][y].Walkable) {
grid[x][y].Walkable = false;
return;
}
}
}
public static float Manhattan(Vector2Int algorithmStart, Vector2Int algorithmEnd) {
return Manhattan(new Node(algorithmStart, false), new Node(algorithmEnd, false));
public static float Manhattan(Node a, Node b) {
return Math.Abs(a.Position.x - b.Position.x) + Math.Abs(a.Position.y - b.Position.y);
}
public static float Manhattan(Vector2Int a, Vector2Int b) {
return Manhattan(new Node(a, false), new Node(b, false));
}
/// <summary>

View File

@@ -14,7 +14,7 @@ public enum PropertyName {
public class GridController : MonoBehaviour {
public Material gridMaterial; // Maintain reference to the Grid Material the Shader is implanted upon
public int size = 32; // Size of the grid, width and height
// Value management
private int[] _values;
private ComputeBuffer _buffer;
@@ -54,7 +54,7 @@ public class GridController : MonoBehaviour {
throw new ArgumentOutOfRangeException(nameof(property), property, null);
}
}
private void OnApplicationQuit() {
// Release ComputeBuffer memory
_buffer.Release();
@@ -66,12 +66,14 @@ public class GridController : MonoBehaviour {
/// <param name="gridState"></param>
public void LoadGridState(GridState gridState) {
// Loop over matrix and set values via cast Enum to int
foreach(int x in Enumerable.Range(0, gridState.Grid.Count - 1))
foreach(int y in Enumerable.Range(0, gridState.Grid[0].Count - 1))
this.SetValue(x, y, (int) gridState.Grid[x][y]);
for (int x = 0; x < gridState.Grid.GetLength(0); x++) {
for (int y = 0; y < gridState.Grid.GetLength(1); y++)
this.SetValue(x, y, (int) gridState.Grid[x, y]);
}
UpdateShader(PropertyName.Values);
}
/// <summary>
/// Sets a value in the 1D array at a particular 2D coordinate
/// </summary>
@@ -81,7 +83,7 @@ public class GridController : MonoBehaviour {
public void SetValue(int x, int y, int value) {
_values[size * y + x] = value;
}
/// <summary>
/// Returns the value at a 2D coordinate within the 1D array
/// </summary>

View File

@@ -1,55 +1,58 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using Algorithms;
using UnityEngine;
public class GridState {
public List<List<GridNodeType>> Grid;
public readonly GridNodeType[,] Grid;
// public List<List<GridNodeType>> Grid;
public float time;
public GridState(NodeGrid grid, IEnumerable<Node> seen, IEnumerable<Node> expanded, Vector2Int start,
Vector2Int end, IReadOnlyCollection<Node> path) {
time = Time.realtimeSinceStartup;
Grid = new List<List<GridNodeType>>(grid.Width);
Grid = new GridNodeType[grid.Width, grid.Height];
// Add walls and empty tiles
foreach (var x in Enumerable.Range(0, grid.Width - 1)) {
Grid.Add(new List<GridNodeType>(grid.Height));
foreach (var y in Enumerable.Range(0, grid.Height - 1)) {
for (int x = 0; x < grid.Width; x++) {
for (int y = 0; y < grid.Height; y++) {
Node node = grid.GetNode(x, y);
Grid[x].Add(!node.Walkable ? GridNodeType.Wall : GridNodeType.Empty);
Grid[x, y] = node.Walkable ? GridNodeType.Empty : GridNodeType.Wall;
}
}
// Add 'seen' tiles
foreach (Node seenNode in seen)
Grid[seenNode.Position.x][seenNode.Position.y] = GridNodeType.Seen;
Grid[seenNode.Position.x, seenNode.Position.y] = GridNodeType.Seen;
// Add 'expanded' tiles
foreach (Node expandedNode in expanded)
Grid[expandedNode.Position.x][expandedNode.Position.y] = GridNodeType.Expanded;
Grid[expandedNode.Position.x, expandedNode.Position.y] = GridNodeType.Expanded;
// Add 'path' tiles
if (path != null)
foreach (Node pathNode in path)
Grid[pathNode.Position.y][pathNode.Position.y] = GridNodeType.Path;
Grid[pathNode.Position.x, pathNode.Position.y] = GridNodeType.Path;
// Set start and end tiles
Grid[start.x][start.y] = GridNodeType.Start;
Grid[end.x][end.y] = GridNodeType.End;
Grid[start.x, start.y] = GridNodeType.Start;
Grid[end.x, end.y] = GridNodeType.End;
}
public IEnumerable<GridNodeType> GetNodes() {
return Grid.SelectMany(nodeList => nodeList).ToList();
}
// public IEnumerable<GridNodeType> GetNodes() {
// return Grid.SelectMany(nodeList => nodeList).ToList();
// }
public string RenderGrid() {
string result = "";
foreach (List<GridNodeType> nodeTypes in Grid) {
result = nodeTypes.Aggregate(result, (current, nodeType) => current + $"{(int) nodeType}") + "\n";
}
// public string RenderGrid() {
// string result = "";
// foreach (List<GridNodeType> nodeTypes in Grid) {
// result = nodeTypes.Aggregate(result, (current, nodeType) => current + $"{(int) nodeType}") + "\n";
// }
return result;
}
// return result;
// }
}

View File

@@ -23,7 +23,8 @@ public class Manager : MonoBehaviour {
}
public void OnDrawGizmos() {
Gizmos.DrawSphere(transform.position, 1);
float size = (float) (10.0 / gridController.size);
Gizmos.DrawWireCube(transform.position, new Vector3(size, size, size));
}
public void Update() {
@@ -48,10 +49,14 @@ public class Manager : MonoBehaviour {
// Vector2 start = nodeGrid.RandomPosition();
Vector2Int start = new Vector2Int(30, 30);
Vector2Int end = nodeGrid.RandomPosition();
int wallCount = (int) (gridController.size * gridController.size * 0.5);
foreach (int unused in Enumerable.Range(0, wallCount))
nodeGrid.FlipRandomWall();
int wallCount = (int) (gridController.size * gridController.size * 0.25);
for (int unused = 0; unused < wallCount; unused++)
nodeGrid.AddRandomWall();
nodeGrid.GetNode(start).Walkable = true;
nodeGrid.GetNode(end).Walkable = true;
path = _algorithm.FindPath(start, end);
@@ -64,7 +69,8 @@ public class Manager : MonoBehaviour {
float change = state.time - lastStart;
string pathCount = path != null ? $"{path.Count}" : "N/A";
debugText.text = $"{change * 1000.0:F1}ms\n{this._curIndex:000} / {this._states.Count:000}\nPath: {pathCount} tiles";
_curIndex += 1;
debugText.text =
$"{change * 1000.0:F1}ms\n{this._curIndex:000} / {this._states.Count:000}\nPath: {pathCount} tiles";
_curIndex += 3;
}
}