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; } }