Frame/Assets/Scripts/BFS/BFS.cs

315 lines
8.2 KiB
C#
Raw Normal View History

2024-04-04 23:51:14 +08:00
using System;
using System.Collections.Generic;
2024-04-08 18:20:55 +08:00
using Cysharp.Threading.Tasks;
2024-04-04 23:51:14 +08:00
using JetBrains.Annotations;
using UnityEngine;
namespace Game.Pathfinding;
public class Node<T>
2024-04-08 18:20:55 +08:00
{
public int index { get; private set; }
public T data { get; private set; }
public Node(int index, T data)
2024-04-04 23:51:14 +08:00
{
2024-04-08 18:20:55 +08:00
this.index = index;
this.data = data;
}
}
2024-04-04 23:51:14 +08:00
2024-04-08 18:20:55 +08:00
class Edge<T>
{
public Node<T> from { get; private set; }
public Node<T> to { get; private set; }
public bool canTranslate { get; private set; }
public Edge(Node<T> from, Node<T> to, bool canTranslate = true)
{
this.from = from;
this.to = to;
this.canTranslate = canTranslate;
2024-04-04 23:51:14 +08:00
}
2024-04-08 18:20:55 +08:00
public Node<T> GetAnotherNode(Node<T> node)
2024-04-04 23:51:14 +08:00
{
2024-04-08 18:20:55 +08:00
return node == this.from ? to : to == node ? from : throw new InvalidOperationException();
}
}
2024-04-04 23:51:14 +08:00
2024-04-08 18:20:55 +08:00
public class WayPointGraph : Graph<WayPoint>
{
readonly struct UniqueWayPoint : IEquatable<UniqueWayPoint>
{
private readonly WayPoint _wayPoint;
public UniqueWayPoint(WayPoint wayPoint)
2024-04-04 23:51:14 +08:00
{
2024-04-08 18:20:55 +08:00
this._wayPoint = wayPoint;
2024-04-04 23:51:14 +08:00
}
2024-04-08 18:20:55 +08:00
public bool Equals(UniqueWayPoint other)
2024-04-04 23:51:14 +08:00
{
2024-04-08 18:20:55 +08:00
return _wayPoint.position == other._wayPoint.position;
2024-04-04 23:51:14 +08:00
}
2024-04-08 18:20:55 +08:00
public override bool Equals(object obj)
2024-04-04 23:51:14 +08:00
{
2024-04-08 18:20:55 +08:00
return obj is UniqueWayPoint other && Equals(other);
}
2024-04-08 18:20:55 +08:00
public override int GetHashCode()
{
return _wayPoint.position.GetHashCode();
}
2024-04-08 18:20:55 +08:00
public static implicit operator WayPoint(UniqueWayPoint uniqueWayPoint)
{
return uniqueWayPoint._wayPoint;
}
2024-04-08 18:20:55 +08:00
public static implicit operator UniqueWayPoint(WayPoint wayPoint)
{
return new UniqueWayPoint(wayPoint);
2024-04-04 23:51:14 +08:00
}
2024-04-08 18:20:55 +08:00
}
2024-04-04 23:51:14 +08:00
2024-04-08 18:20:55 +08:00
public void Initialize(GameGlobalConfig.NodeMap[] nodeMaps)
{
HashSet<UniqueWayPoint> wayPoints = new HashSet<UniqueWayPoint>();
foreach (var nodeMap in nodeMaps)
2024-04-04 23:51:14 +08:00
{
2024-04-08 18:20:55 +08:00
wayPoints.Add(new WayPoint(nodeMap.node1));
wayPoints.Add(new WayPoint(nodeMap.node2));
}
2024-04-08 18:20:55 +08:00
Dictionary<Vector3, Node<WayPoint>> position2NodeMap = new Dictionary<Vector3, Node<WayPoint>>();
_nodes = new Node<WayPoint>[wayPoints.Count];
using var enumerator = wayPoints.GetEnumerator();
int index = 0;
while (enumerator.MoveNext())
{
var enumeratorCurrent = (WayPoint)enumerator.Current;
var node = new Node<WayPoint>(index, enumeratorCurrent);
this._nodes[index] = node;
position2NodeMap[enumeratorCurrent.position] = node;
index++;
}
2024-04-08 18:20:55 +08:00
_edges = new List<Edge<WayPoint>>(nodeMaps.Length);
this._connection = new Dictionary<Node<WayPoint>, List<Edge<WayPoint>>>(_edges.Count);
2024-04-08 18:20:55 +08:00
foreach (var nodeMap in nodeMaps)
{
if (position2NodeMap.TryGetValue(nodeMap.node1, out var node1))
{
2024-04-08 18:20:55 +08:00
if (position2NodeMap.TryGetValue(nodeMap.node2, out var node2))
2024-04-04 23:51:14 +08:00
{
2024-04-08 18:20:55 +08:00
var edge = new Edge<WayPoint>(node1, node2);
_edges.Add(edge);
if (!this._connection.TryGetValue(node1, out var list1))
2024-04-04 23:51:14 +08:00
{
2024-04-08 18:20:55 +08:00
this._connection[node1] = list1 = new List<Edge<WayPoint>>();
2024-04-04 23:51:14 +08:00
}
2024-04-08 18:20:55 +08:00
list1.Add(edge);
if (!this._connection.TryGetValue(node2, out var list2))
{
this._connection[node2] = list2 = new List<Edge<WayPoint>>();
}
list2.Add(edge);
2024-04-04 23:51:14 +08:00
}
}
}
}
2024-04-08 18:20:55 +08:00
}
2024-04-04 23:51:14 +08:00
2024-04-08 18:20:55 +08:00
public class Graph<T>
{
private protected Node<T>[] _nodes;
private protected List<Edge<T>> _edges;
private protected Dictionary<Node<T>, List<Edge<T>>> _connection;
2024-04-04 23:51:14 +08:00
2024-04-08 18:20:55 +08:00
internal Node<T> GetNode(int index)
{
if (index < 0 || index >= this._nodes.Length)
2024-04-04 23:51:14 +08:00
{
2024-04-08 18:20:55 +08:00
throw new IndexOutOfRangeException($"Index is {index}");
}
2024-04-04 23:51:14 +08:00
2024-04-08 18:20:55 +08:00
return this._nodes[index];
}
[CanBeNull]
internal Node<T> GetNode(Predicate<Node<T>> predicate)
{
foreach (var node in this._nodes)
{
2024-04-08 18:20:55 +08:00
if (predicate(node))
{
2024-04-08 18:20:55 +08:00
return node;
}
}
2024-04-04 23:51:14 +08:00
2024-04-08 18:20:55 +08:00
return null;
}
internal IReadOnlyList<Edge<T>> GetNeighbours(Node<T> node)
{
if (this._connection.TryGetValue(node, out var edges))
{
return edges;
}
2024-04-08 18:20:55 +08:00
throw new ArgumentException($"GetNeighbours have error ! the id is {node.index}");
2024-04-04 23:51:14 +08:00
}
2024-04-08 18:20:55 +08:00
}
public class BFS<T>
{
private Graph<T> _graph;
private List<int> _closeList = new List<int>();
private Queue<int> _openList = new Queue<int>();
private Dictionary<Node<T>, Node<T>> _nodeMap = new Dictionary<Node<T>, Node<T>>();
2024-04-09 14:19:54 +08:00
private List<int> ids = new List<int>();
2024-04-04 23:51:14 +08:00
2024-04-08 18:20:55 +08:00
public BFS(Graph<T> graph)
2024-04-04 23:51:14 +08:00
{
2024-04-08 18:20:55 +08:00
this._graph = graph;
}
2024-04-04 23:51:14 +08:00
2024-04-08 18:20:55 +08:00
[CanBeNull]
public Node<T> GetNode(Predicate<Node<T>> predicate)
{
return _graph.GetNode(predicate);
}
public Path<T> FindPath(Node<T> begin, Node<T> end)
{
2024-04-09 14:19:54 +08:00
if (begin == null)
throw new NullReferenceException("begin");
if (end == null)
throw new NullReferenceException("end");
2024-04-08 18:20:55 +08:00
_openList.Clear();
_closeList.Clear();
_nodeMap.Clear();
2024-04-04 23:51:14 +08:00
2024-04-08 18:20:55 +08:00
_openList.Enqueue(begin.index);
while (this._openList.Count > 0)
2024-04-04 23:51:14 +08:00
{
2024-04-08 18:20:55 +08:00
var nodeIndex = this._openList.Dequeue();
var currNode = this._graph.GetNode(nodeIndex);
if (currNode.index == end.index)
break;
_closeList.Add(currNode.index);
Search(currNode);
2024-04-04 23:51:14 +08:00
}
2024-04-08 18:20:55 +08:00
Path<T> path = new Path<T>();
path.AddNode(new PathNode<T>(end.index, end.data));
this.ids.Clear();
2024-04-08 18:20:55 +08:00
bool isTrue = true;
UniTask.Create(async () =>
{
await UniTask.Delay(5000);
if (isTrue)
2024-04-04 23:51:14 +08:00
{
2024-04-08 18:20:55 +08:00
isTrue = false;
Debug.LogError("没找到路径卡死了,强制跳出的");
2024-04-04 23:51:14 +08:00
}
2024-04-09 14:05:45 +08:00
}).Forget();
2024-04-08 18:20:55 +08:00
Node<T> node = end;
while (isTrue)
{
if (this._nodeMap.TryGetValue(node, out node))
2024-04-04 23:51:14 +08:00
{
2024-04-09 14:05:45 +08:00
2024-04-08 18:20:55 +08:00
if (!this.ids.Contains(node.index))
{
2024-04-09 14:05:45 +08:00
Debug.Log($"正在查询的点{node.index}");
2024-04-08 18:20:55 +08:00
this.ids.Add(node.index);
path.AddNode(new PathNode<T>(node.index, node.data));
}
2024-04-04 23:51:14 +08:00
}
2024-04-09 14:19:54 +08:00
if (node==null || node == begin)
2024-04-08 18:20:55 +08:00
{
Debug.Log("结束了");
break;
}
2024-04-04 23:51:14 +08:00
}
2024-04-08 18:20:55 +08:00
path.Reverse();
return path;
}
private void Search(Node<T> node)
{
var readOnlyList = this._graph.GetNeighbours(node);
foreach (var edge in readOnlyList)
{
2024-04-08 18:20:55 +08:00
if (!edge.canTranslate)
continue;
Node<T> another = edge.GetAnotherNode(node);
if (!this._nodeMap.ContainsKey(another))
{
2024-04-08 18:20:55 +08:00
_nodeMap[another] = node;
}
2024-04-04 23:51:14 +08:00
2024-04-08 18:20:55 +08:00
if (!this._closeList.Contains(another.index))
{
if (!this._openList.Contains(another.index))
{
_openList.Enqueue(another.index);
}
}
}
2024-04-04 23:51:14 +08:00
}
2024-04-08 18:20:55 +08:00
}
2024-04-04 23:51:14 +08:00
2024-04-08 18:20:55 +08:00
public class Path<T>
{
private readonly List<PathNode<T>> _pathNodes = new List<PathNode<T>>();
public void Reverse()
2024-04-04 23:51:14 +08:00
{
2024-04-08 18:20:55 +08:00
this._pathNodes.Reverse();
}
2024-04-04 23:51:14 +08:00
2024-04-08 18:20:55 +08:00
public void AddNode(PathNode<T> node)
{
if (this._pathNodes.Contains(node))
2024-04-04 23:51:14 +08:00
{
2024-04-08 18:20:55 +08:00
throw new ArgumentException($"{node.index}");
}
2024-04-08 18:20:55 +08:00
this._pathNodes.Add(node);
}
2024-04-04 23:51:14 +08:00
2024-04-08 18:20:55 +08:00
public IReadOnlyList<PathNode<T>> GetNodes()
{
return this._pathNodes;
}
2024-04-04 23:51:14 +08:00
2024-04-08 18:20:55 +08:00
public void GetDatas(IList<T> result)
{
foreach (var pathNode in this._pathNodes)
{
2024-04-08 18:20:55 +08:00
result.Add(pathNode.data);
}
2024-04-04 23:51:14 +08:00
}
2024-04-08 18:20:55 +08:00
}
2024-04-08 18:20:55 +08:00
public class PathNode<T>
{
public int index { get; private set; }
public T data { get; private set; }
2024-04-08 18:20:55 +08:00
public PathNode(int index, T data)
{
this.index = index;
this.data = data;
}
}