namespace Application.Domain;
// ===================== 核心定义:全局坐标体系 =====================
///
/// 全局坐标结构体(所有城市共享唯一坐标)
///
public struct Point
{
public int X; // 全局X坐标
public int Y; // 全局Y坐标
public Point(int x, int y)
{
X = x;
Y = y;
}
public override bool Equals(object obj)
{
return obj is Point point && X == point.X && Y == point.Y;
}
public override int GetHashCode()
{
return HashCode.Combine(X, Y);
}
public static bool operator ==(Point a, Point b) => a.X == b.X && a.Y == b.Y;
public static bool operator !=(Point a, Point b) => !(a == b);
public override string ToString() => $"({X},{Y})";
}
///
/// 城市节点(全局坐标管辖范围)
///
public class CityNode
{
public int CityId { get; set; } // 城市ID
public string CityName { get; set; } // 城市名称
public Point CoreAnchor { get; set; } // 核心锚点(全局坐标)
public string CoreAnchorName { get; set; } // 核心锚点名称
public int MinX { get; set; } // 城市管辖范围-最小X(全局)
public int MaxX { get; set; } // 城市管辖范围-最大X(全局)
public int MinY { get; set; } // 城市管辖范围-最小Y(全局)
public int MaxY { get; set; } // 城市管辖范围-最大Y(全局)
public List Portals { get; set; } // 所属传送点(全局坐标)
public CityNode(int cityId, string cityName, Point coreAnchor, string coreAnchorName,
int minX, int maxX, int minY, int maxY)
{
CityId = cityId;
CityName = cityName;
CoreAnchor = coreAnchor;
CoreAnchorName = coreAnchorName;
MinX = minX;
MaxX = maxX;
MinY = minY;
MaxY = maxY;
Portals = new List();
}
///
/// 校验全局坐标是否属于当前城市管辖范围
///
public bool IsPointInCity(Point point)
{
return point.X >= MinX && point.X <= MaxX && point.Y >= MinY && point.Y <= MaxY;
}
public void AddPortal(InterCityPortal portal)
{
if (!Portals.Any(p => p.PortalId == portal.PortalId))
Portals.Add(portal);
}
}
///
/// 城际传送点(全局坐标,PortalId改为字符串)
///
public class InterCityPortal
{
public string PortalId { get; set; } // 1. 改为字符串类型
public int BelongCityId { get; set; } // 所属城市ID
public Point Position { get; set; } // 传送点全局坐标
public int TargetCityId { get; set; } // 目标城市ID
public string PortalName { get; set; } // 传送点名称
public int Priority { get; set; } = 1; // 优先级
public string? ReversePortalId { get; set; } // 反向传送点ID(字符串)
public InterCityPortal(string portalId, int belongCityId, Point pos, int targetCityId, string name,
int priority = 1, string? reversePortalId = null)
{
PortalId = portalId;
BelongCityId = belongCityId;
Position = pos;
TargetCityId = targetCityId;
PortalName = name;
Priority = priority;
ReversePortalId = reversePortalId;
}
}
///
/// 全局路网(基于全局坐标管理城市+传送点)
///
public class GlobalRoadNetwork
{
public Dictionary CityDict { get; private set; }
public Dictionary PortalDict { get; private set; } // 适配字符串PortalId
public GlobalRoadNetwork()
{
CityDict = new Dictionary();
PortalDict = new Dictionary(); // 改为字符串Key
}
public void AddCity(CityNode city)
{
if (!CityDict.ContainsKey(city.CityId))
CityDict.Add(city.CityId, city);
}
public void AddPortal(InterCityPortal portal)
{
if (!PortalDict.ContainsKey(portal.PortalId))
{
PortalDict.Add(portal.PortalId, portal);
if (CityDict.ContainsKey(portal.BelongCityId))
CityDict[portal.BelongCityId].AddPortal(portal);
}
}
///
/// 根据全局坐标获取所属城市
///
public CityNode GetCityByGlobalPoint(Point point)
{
return CityDict.Values.FirstOrDefault(city => city.IsPointInCity(point));
}
///
/// 获取最优传送点(修复反向寻路筛选逻辑)
///
public InterCityPortal GetOptimalPortal(int startCityId, int targetCityId, Point startPos,
Dictionary cityNetworks, bool isReverse = false)
{
if (!CityDict.ContainsKey(startCityId) || !cityNetworks.ContainsKey(startCityId))
return null;
var startCity = CityDict[startCityId];
var startCityNetwork = cityNetworks[startCityId];
// 修复反向寻路筛选逻辑:
// - 正向:当前城市传送点 → 目标城市
// - 反向:目标城市传送点 → 当前城市(但从当前城市视角找)
var candidatePortals = isReverse
? CityDict.Values
.Where(c => c.CityId == targetCityId)
.SelectMany(c => c.Portals)
.Where(p => p.TargetCityId == startCityId)
.Where(p => startCityNetwork.IsPointWalkable(p.Position))
.Where(p => startCityNetwork.FindPathInCity(startPos, p.Position) != null)
: startCity.Portals
.Where(p => p.TargetCityId == targetCityId)
.Where(p => startCityNetwork.IsPointWalkable(p.Position))
.Where(p => startCityNetwork.FindPathInCity(startPos, p.Position) != null);
// 计算距离并排序
var sortedPortals = candidatePortals
.Select(p => new
{
Portal = p,
Distance = GetManhattanDistance(startPos, p.Position)
})
.OrderBy(p => p.Portal.Priority)
.ThenBy(p => p.Distance);
return sortedPortals.FirstOrDefault()?.Portal;
}
///
/// 获取反向传送点(适配字符串PortalId)
///
public InterCityPortal GetReversePortal(InterCityPortal portal)
{
if (!string.IsNullOrEmpty(portal.ReversePortalId) && PortalDict.ContainsKey(portal.ReversePortalId))
return PortalDict[portal.ReversePortalId];
return null;
}
///
/// 校验全局坐标合法性(属于某城市+该城市内可通行)
///
public bool IsPointValid(Point point, Dictionary cityNetworks)
{
var city = GetCityByGlobalPoint(point);
if (city == null || !cityNetworks.ContainsKey(city.CityId))
return false;
return cityNetworks[city.CityId].IsPointWalkable(point);
}
///
/// 修复:使用BFS获取所有连通的城市链(支持多中转)
///
public List GetConnectedCityChain(int startCityId, int endCityId)
{
if (startCityId == endCityId)
return new List { startCityId };
// BFS队列:存储(当前城市ID, 路径)
var queue = new Queue>>();
var visited = new HashSet();
queue.Enqueue(Tuple.Create(startCityId, new List { startCityId }));
visited.Add(startCityId);
while (queue.Count > 0)
{
var current = queue.Dequeue();
int currCityId = current.Item1;
List path = current.Item2;
// 获取当前城市所有可达的传送点目标城市
var reachableCities = CityDict[currCityId].Portals
.Select(p => p.TargetCityId)
.Distinct()
.Where(c => !visited.Contains(c));
foreach (int nextCityId in reachableCities)
{
var newPath = new List(path) { nextCityId };
// 找到终点,返回路径
if (nextCityId == endCityId)
return newPath;
visited.Add(nextCityId);
queue.Enqueue(Tuple.Create(nextCityId, newPath));
}
}
return null; // 无可达路线
}
private int GetManhattanDistance(Point a, Point b)
{
return Math.Abs(a.X - b.X) + Math.Abs(a.Y - b.Y);
}
}
public class AStarNode : IComparable
{
public Point Position { get; set; }
public AStarNode Parent { get; set; }
public int G { get; set; } // 起点到当前节点的代价
public int H { get; set; } // 当前节点到终点的预估代价
public int F => G + H; // 总代价
// 实现IComparable接口,解决SortedSet重复元素问题
public int CompareTo(AStarNode other)
{
if (other == null) return 1;
// 先按F值排序,再按H值,最后按坐标(避免重复)
int fCompare = F.CompareTo(other.F);
if (fCompare != 0) return fCompare;
int hCompare = H.CompareTo(other.H);
if (hCompare != 0) return hCompare;
int xCompare = Position.X.CompareTo(other.Position.X);
return xCompare != 0 ? xCompare : Position.Y.CompareTo(other.Position.Y);
}
}
///
/// 单城市路网(基于全局坐标管理可通行区域)
///
public class CityRoadNetwork
{
public int CityId { get; set; }
public Dictionary WalkablePoints { get; private set; } // 全局坐标可通行列表
public CityRoadNetwork(int cityId)
{
CityId = cityId;
WalkablePoints = new Dictionary();
}
///
/// 添加全局坐标可通行点
///
public void AddWalkablePoint(int x, int y, bool walkable = true)
{
var point = new Point(x, y);
WalkablePoints[point] = walkable;
}
///
/// 批量添加全局坐标可通行区域
///
public void AddWalkableRect(int minX, int maxX, int minY, int maxY, bool walkable = true)
{
if (minX > maxX || minY > maxY)
throw new ArgumentException("矩形范围不合法:min不能大于max");
for (int x = minX; x <= maxX; x++)
for (int y = minY; y <= maxY; y++)
AddWalkablePoint(x, y, walkable);
}
///
/// 校验全局坐标是否可走
///
public bool IsPointWalkable(Point point)
{
return WalkablePoints.TryGetValue(point, out bool walkable) && walkable;
}
///
/// 修复后的A*寻路(基于全局坐标)
///
public List FindPathInCity(Point start, Point end)
{
// 基础校验
if (!WalkablePoints.ContainsKey(start) || !WalkablePoints.ContainsKey(end))
return null;
if (!IsPointWalkable(start) || !IsPointWalkable(end))
return null;
if (start == end)
return new List { start };
// 开放列表(排序集合)和关闭列表
var openSet = new SortedSet();
var openDict = new Dictionary(); // 快速查找
var closeDict = new Dictionary();
// 初始化起点
var startNode = new AStarNode
{
Position = start,
Parent = null,
G = 0,
H = GetManhattanDistance(start, end)
};
openSet.Add(startNode);
openDict[start] = startNode;
// 四方向移动
var dirs = new[] { new Point(0, 1), new Point(0, -1), new Point(1, 0), new Point(-1, 0) };
while (openSet.Count > 0)
{
// 获取F值最小的节点
var currentNode = openSet.Min;
openSet.Remove(currentNode);
openDict.Remove(currentNode.Position);
closeDict[currentNode.Position] = currentNode;
// 到达终点,回溯路径
if (currentNode.Position == end)
{
var path = new List();
var node = currentNode;
while (node != null)
{
path.Add(node.Position);
node = node.Parent;
}
path.Reverse();
return path;
}
// 遍历邻接节点
foreach (var dir in dirs)
{
var neighborPos = new Point(currentNode.Position.X + dir.X, currentNode.Position.Y + dir.Y);
// 跳过不可通行或已关闭的节点
if (!IsPointWalkable(neighborPos) || closeDict.ContainsKey(neighborPos))
continue;
// 计算新的G值
int newG = currentNode.G + 1;
// 邻接节点不存在或找到更优路径
if (!openDict.TryGetValue(neighborPos, out var neighborNode) || newG < neighborNode.G)
{
// 如果节点已存在,先移除
if (neighborNode != null)
{
openSet.Remove(neighborNode);
openDict.Remove(neighborPos);
}
// 创建/更新节点
neighborNode = new AStarNode
{
Position = neighborPos,
Parent = currentNode,
G = newG,
H = GetManhattanDistance(neighborPos, end)
};
openSet.Add(neighborNode);
openDict[neighborPos] = neighborNode;
}
}
}
// 无路径
return null;
}
private int GetManhattanDistance(Point a, Point b)
{
return Math.Abs(a.X - b.X) + Math.Abs(a.Y - b.Y);
}
}
// ===================== 路径步骤定义 =====================
public enum PathStepType
{
Move,
Teleport
}
public class PathStep
{
public int CityId { get; set; }
public Point Position { get; set; } // 全局坐标
public PathStepType StepType { get; set; }
public int? TargetCityId { get; set; }
public Point? TargetAnchor { get; set; } // 目标锚点全局坐标
public string? TargetAnchorName { get; set; }
public string ToWapDesc(GlobalRoadNetwork globalNetwork)
{
var cityName = globalNetwork?.CityDict?.ContainsKey(CityId) == true
? globalNetwork.CityDict[CityId].CityName
: "未知城市";
return StepType switch
{
PathStepType.Move => $"【{cityName}】移动到全局坐标{Position}",
PathStepType.Teleport => GetTeleportDesc(globalNetwork, cityName),
_ => string.Empty
};
}
private string GetTeleportDesc(GlobalRoadNetwork globalNetwork, string currentCityName)
{
if (globalNetwork == null || !TargetCityId.HasValue)
return $"【{currentCityName}】通过传送阵→【未知城市】未知锚点";
var targetCityName = globalNetwork.CityDict.ContainsKey(TargetCityId.Value)
? globalNetwork.CityDict[TargetCityId.Value].CityName
: "未知城市";
var anchorName = string.IsNullOrEmpty(TargetAnchorName) ? "未知锚点" : TargetAnchorName;
var anchorPos = TargetAnchor.HasValue ? $"(全局坐标{TargetAnchor})" : "";
return $"【{currentCityName}】通过传送阵→【{targetCityName}】{anchorName}{anchorPos}";
}
}
// ===================== 跨城寻路核心服务(全自动适配) =====================
public class CrossCityPathFinder
{
private readonly GlobalRoadNetwork _globalNetwork;
private readonly Dictionary _cityNetworks;
public CrossCityPathFinder(GlobalRoadNetwork globalNetwork)
{
_globalNetwork = globalNetwork;
_cityNetworks = new Dictionary();
}
public void AddCityRoadNetwork(CityRoadNetwork cityNetwork)
{
if (!_cityNetworks.ContainsKey(cityNetwork.CityId))
_cityNetworks.Add(cityNetwork.CityId, cityNetwork);
}
///
/// 核心方法:输入起止点,全自动判定同城/跨城/多城市,自动适配正向/反向
///
public List FindCrossCityPath(Point startPos, Point endPos)
{
// 1. 基础校验:识别起止点所属城市
var startCity = _globalNetwork.GetCityByGlobalPoint(startPos);
var endCity = _globalNetwork.GetCityByGlobalPoint(endPos);
if (startCity == null || endCity == null)
{
return null;
}
// 2. 同城寻路
if (startCity.CityId == endCity.CityId)
{
return FindSameCityPath(startCity.CityId, startPos, endPos);
}
// 3. 跨城/多城市寻路(使用修复后的BFS路径链)
var cityChain = _globalNetwork.GetConnectedCityChain(startCity.CityId, endCity.CityId);
if (cityChain == null || cityChain.Count < 2)
{
return null;
}
// 自动适配正向/反向
var cityStartPoints = new Dictionary
{
{ startCity.CityId, startPos },
{ endCity.CityId, endPos }
};
// 自动判断是否需要反向寻路
var isReverse = IsNeedReverseRoute(startCity.CityId, endCity.CityId);
return FindMultiCityPath(cityChain, cityStartPoints, isReverse);
}
///
/// 同城寻路
///
private List FindSameCityPath(int cityId, Point startPos, Point endPos)
{
if (!_globalNetwork.IsPointValid(startPos, _cityNetworks) ||
!_globalNetwork.IsPointValid(endPos, _cityNetworks))
{
return null;
}
var cityPath = _cityNetworks[cityId].FindPathInCity(startPos, endPos);
return cityPath?.Select(p => new PathStep
{
CityId = cityId,
Position = p,
StepType = PathStepType.Move
}).ToList();
}
///
/// 多城市寻路(自动适配正向/反向)
///
private List FindMultiCityPath(List cityChain, Dictionary cityStartPoints,
bool isReverse)
{
var finalPath = new List();
var actualChain = isReverse ? cityChain.AsEnumerable().Reverse().ToList() : cityChain;
for (int i = 0; i < actualChain.Count - 1; i++)
{
int currCityId = actualChain[i];
int nextCityId = actualChain[i + 1];
Point currStartPoint = cityStartPoints.ContainsKey(currCityId)
? cityStartPoints[currCityId]
: _globalNetwork.CityDict[currCityId].CoreAnchor;
// 校验起点坐标归属
var currCity = _globalNetwork.CityDict[currCityId];
if (!currCity.IsPointInCity(currStartPoint))
{
return null;
}
if (!_globalNetwork.IsPointValid(currStartPoint, _cityNetworks))
return null;
// 获取最优传送点(自动传入反向标识)
var optimalPortal =
_globalNetwork.GetOptimalPortal(currCityId, nextCityId, currStartPoint, _cityNetworks, isReverse);
if (optimalPortal == null)
{
return null;
}
// 当前城市内:起点 → 传送点
var currToPortal = _cityNetworks[currCityId].FindPathInCity(currStartPoint, optimalPortal.Position);
if (currToPortal == null)
return null;
finalPath.AddRange(currToPortal.Select(p => new PathStep
{
CityId = currCityId,
Position = p,
StepType = PathStepType.Move
}));
// 跨城传送
var nextCity = _globalNetwork.CityDict[nextCityId];
finalPath.Add(new PathStep
{
CityId = currCityId,
Position = optimalPortal.Position,
StepType = PathStepType.Teleport,
TargetCityId = nextCityId,
TargetAnchor = nextCity.CoreAnchor,
TargetAnchorName = nextCity.CoreAnchorName
});
// 更新下一个城市的起点
if (!cityStartPoints.ContainsKey(nextCityId))
cityStartPoints.Add(nextCityId, nextCity.CoreAnchor);
// 最后一段:核心锚点→终点
if (i == actualChain.Count - 2)
{
Point nextEndPoint = cityStartPoints[nextCityId];
var anchorToEnd = _cityNetworks[nextCityId].FindPathInCity(nextCity.CoreAnchor, nextEndPoint);
if (anchorToEnd == null)
return null;
finalPath.AddRange(anchorToEnd.Select(p => new PathStep
{
CityId = nextCityId,
Position = p,
StepType = PathStepType.Move
}));
}
}
return finalPath;
}
///
/// 自动判断是否需要反向寻路
///
private bool IsNeedReverseRoute(int startCityId, int endCityId)
{
// 检查正向传送点
var startCity = _globalNetwork.CityDict[startCityId];
var hasForward = startCity.Portals.Any(p => p.TargetCityId == endCityId);
// 正向无则反向
if (!hasForward)
{
var endCity = _globalNetwork.CityDict[endCityId];
var hasReverse = endCity.Portals.Any(p => p.TargetCityId == startCityId);
return hasReverse;
}
return false;
}
///
/// 辅助方法:获取城市名称
///
private string GetCityName(CityNode city)
{
return city?.CityName ?? "未知城市";
}
///
/// 简化路径描述(用于展示)
///
public List SimplifyPathForWap(List fullPath)
{
if (fullPath == null || fullPath.Count == 0)
return new List();
var simplified = new List();
PathStep? lastTeleport = null;
foreach (var step in fullPath)
{
if (step.StepType == PathStepType.Teleport)
{
simplified.Add(step.ToWapDesc(_globalNetwork));
lastTeleport = step;
}
else if (lastTeleport == null && step == fullPath.First())
{
var cityName = _globalNetwork.CityDict.ContainsKey(step.CityId)
? _globalNetwork.CityDict[step.CityId].CityName
: "未知城市";
simplified.Add($"【{cityName}】从起点(全局坐标{step.Position})出发");
}
else if (step == fullPath.Last())
{
var cityName = _globalNetwork.CityDict.ContainsKey(step.CityId)
? _globalNetwork.CityDict[step.CityId].CityName
: "未知城市";
simplified.Add($"【{cityName}】到达终点(全局坐标{step.Position})");
}
}
return simplified;
}
}