public Path(string identifier, IMapNode from, IMapNode to) { From = from; To = to; Identifier = identifier; Description = "A path."; }
/// <summary> /// Generic path finding. Works on any map type. /// </summary> /// <returns>A list of paths to take to move from the start node to the goal node using the minimum number of paths, or null if no such list exists.</returns> public static List<Path> Find(IGameMap map, IMapNode start, IMapNode goal) { if (start == goal) return new List<Path>(); Dictionary<IMapNode, int> distance = new Dictionary<IMapNode, int>(); Dictionary<IMapNode, Path> previous = new Dictionary<IMapNode, Path>(); ICollection<IMapNode> unvisited = new HashSet<IMapNode>(); foreach (IMapNode node in map.Nodes) { distance.Add(node, Int32.MaxValue); previous.Add(node, null); unvisited.Add(node); } distance[start] = 0; while (unvisited.Count > 0) { IMapNode currentNode = unvisited.First(x => distance[x] == unvisited.Min(y => distance[y])); unvisited.Remove(currentNode); if (currentNode == goal) break; foreach (Path p in map.GetPathsFrom(currentNode)) { IMapNode neighbor = p.To; int alternateDistance = distance[currentNode] + 1; if (alternateDistance < distance[neighbor]) { distance[neighbor] = alternateDistance; previous[neighbor] = p; } } } List<Path> path = new List<Path>(); Path prevPath = previous[goal]; do { path.Insert(0, prevPath); prevPath = previous[prevPath.From]; } while (prevPath != null); return path; }
public Point GetPosition(IMapNode node) { Point nodePos = new Point(-1, -1); for (int y = 0; y < Height; y++) { for (int x = 0; x < Width; x++) { if (Tiles[x, y] == node) { nodePos = new Point(x, y); break; } } if (nodePos.X >= 0) break; } return nodePos; }
/// <summary> /// Добавляет новый узел графа. /// </summary> /// <param name="node"></param> public abstract void AddNode(IMapNode node);
public int DistanceBetween(IMapNode currentNode, IMapNode targetNode) { return(0); }
public override bool TestCross(IMapNode other) { return(true); }
public List<Path> FindPath(IMapNode from, IMapNode to) { return Path.Find(this, from, to); }
public MoveIntention(IMapNode targetNode, IMap map) { TargetNode = targetNode; _map = map; }
public void MoveToNode(IMapNode targetNode) { Node = targetNode; Moved?.Invoke(this, new EventArgs()); }
private void CreateBoard(int size, string data) { //check to see if the Board list is already created, if it is, we just overwrite its values if (Board == null || Board.Length != size) { Board = new IMapNode[size][]; for (var index = 0; index < Board.Length; index++) { Board[index] = new IMapNode[size]; } } var x = 0; var y = 0; var charData = data.ToCharArray(); for (var i = 0; i < charData.Length; i += 2) { switch (charData[i]) { case '#': Board[x][y] = new MapNode(Tile.IMPASSABLE_WOOD, x, y) { Id = i, Passable = false }; break; case ' ': Board[x][y] = new MapNode(Tile.FREE, x, y) { Id = i, Passable = true, Type = Tile.FREE }; break; case '@': switch (charData[i + 1]) { case '1': Board[x][y] = AllCharacters.First(h => h.Type == Tile.HERO_1); break; case '2': Board[x][y] = AllCharacters.First(h => h.Type == Tile.HERO_2); break; case '3': Board[x][y] = AllCharacters.First(h => h.Type == Tile.HERO_3); break; case '4': Board[x][y] = AllCharacters.First(h => h.Type == Tile.HERO_4); break; } break; case '[': Board[x][y] = new MapNode(Tile.TAVERN, x, y); break; case '$': switch (charData[i + 1]) { case '-': Board[x][y] = new MapNode(Tile.GOLD_MINE_NEUTRAL, x, y); break; case '1': Board[x][y] = new MapNode(Tile.GOLD_MINE_1, x, y); break; case '2': Board[x][y] = new MapNode(Tile.GOLD_MINE_2, x, y); break; case '3': Board[x][y] = new MapNode(Tile.GOLD_MINE_3, x, y); break; case '4': Board[x][y] = new MapNode(Tile.GOLD_MINE_4, x, y); break; } break; } //time to increment X and Y x++; if (x == size) { x = 0; y++; } } }
private static bool IsZoomedInOn(IMapController controller, IMapNode node) => controller.ZoomedNode == node;
/// <summary>Возвращает узлы, напрямую соединённые с указанным узлом.</summary> /// <param name="node">Опорный узел, относительно которого выбираются соседние узлы.</param> /// <returns>Возвращает набор соседних узлов.</returns> public override IEnumerable <IMapNode> GetNext(IMapNode node) { var hexCurrent = (HexNode)node; var offsetCoords = new OffsetCoords(hexCurrent.OffsetX, hexCurrent.OffsetY); var segmentX = offsetCoords.X / _segmentSize; if (offsetCoords.X < 0) { segmentX--; } var segmentY = offsetCoords.Y / _segmentSize; if (offsetCoords.Y < 0) { segmentY--; } var localOffsetX = NormalizeNeighborCoord(offsetCoords.X % _segmentSize); var localOffsetY = NormalizeNeighborCoord(offsetCoords.Y % _segmentSize); var segmentKey = new SegmentKey(segmentX, segmentY); var matrix = _segmentDict[segmentKey]; var directions = HexHelper.GetOffsetClockwise(); var currentCubeCoords = HexHelper.ConvertToCube(localOffsetX, localOffsetY); for (var i = 0; i < 6; i++) { var dir = directions[i]; var neighborLocalCube = new CubeCoords(dir.X + currentCubeCoords.X, dir.Y + currentCubeCoords.Y, dir.Z + currentCubeCoords.Z); var neighborLocalOffset = HexHelper.ConvertToOffset(neighborLocalCube); var neighborSegmentX = segmentX; var neighborSegmentY = segmentY; if (neighborLocalOffset.X < 0) { neighborSegmentX--; } else if (neighborLocalOffset.X >= _segmentSize) { neighborSegmentX++; } if (neighborLocalOffset.Y < 0) { neighborSegmentY--; } else if (neighborLocalOffset.Y >= _segmentSize) { neighborSegmentY++; } IMapNode currentNeibour; if (neighborSegmentX == segmentX && neighborSegmentY == segmentY) { currentNeibour = matrix[neighborLocalOffset.X, neighborLocalOffset.Y]; if (currentNeibour == null) { continue; } yield return(currentNeibour); } } }
/// <summary>Создаёт ребро между двумя узлами графа карты.</summary> /// <param name="node1">Узел графа карты.</param> /// <param name="node2">Узел графа карты.</param> public override void AddEdge(IMapNode node1, IMapNode node2) { // Эта возможность не нужна. Пока не будет сделан метод удаления ребра. // Сейчас ребра есть между всеми соседями в сетке шестиугольников. }
/// <summary>Удаляет ребро между двумя узлами графа карты.</summary> /// <param name="node1">Узел графа карты.</param> /// <param name="node2">Узел графа карты.</param> /// <exception cref="NotImplementedException"></exception> public override void RemoveEdge(IMapNode node1, IMapNode node2) { throw new NotImplementedException(); }
public Actor([NotNull] IPerson person, [NotNull] IPlayer owner, [NotNull] IMapNode node, [CanBeNull] IPerkResolver perkResolver) : this(person, owner, node) { _perkResolver = perkResolver; }
public DropTablePropChest(IMapNode node, IDropTableScheme[] dropTables, IDropResolver dropResolver, int id) : base(node, new DropTableChestStore(dropTables, dropResolver), id) { }
public void GetCurrentTask_StartOnFirstPoint_ActorWalkThroughRount() { // ARRANGE _factActorNode = _map.Nodes.OfType <HexNode>().SelectBy(1, 1); _map.HoldNode(_factActorNode, _actor); var expectedActorPositions = new IMapNode[] { _map.Nodes.OfType <HexNode>().SelectBy(2, 2), _map.Nodes.OfType <HexNode>().SelectBy(2, 3), _map.Nodes.OfType <HexNode>().SelectBy(3, 3), _map.Nodes.OfType <HexNode>().SelectBy(4, 3), _map.Nodes.OfType <HexNode>().SelectBy(5, 3), _map.Nodes.OfType <HexNode>().SelectBy(5, 3), _map.Nodes.OfType <HexNode>().SelectBy(4, 3), _map.Nodes.OfType <HexNode>().SelectBy(4, 4), _map.Nodes.OfType <HexNode>().SelectBy(3, 5), _map.Nodes.OfType <HexNode>().SelectBy(3, 5), _map.Nodes.OfType <HexNode>().SelectBy(3, 4), _map.Nodes.OfType <HexNode>().SelectBy(2, 3), _map.Nodes.OfType <HexNode>().SelectBy(2, 2), _map.Nodes.OfType <HexNode>().SelectBy(1, 1), _map.Nodes.OfType <HexNode>().SelectBy(1, 1), }; var tacticalActUsageService = CreateTacticalActUsageService(); var logic = new PatrolLogic(_actor, _patrolRoute3Points, _map, _actorList, _decisionSource, tacticalActUsageService); // ACT for (var round = 0; round < expectedActorPositions.Count() + 1; round++) { var task = logic.GetCurrentTask(); // ASSERT task.Should().NotBeNull(); switch (round) { case 5: case 9: case 14: task.Should().BeOfType <IdleTask>($"На {round} итерации ожидается задача на простой."); break; default: task.Should().BeOfType <MoveTask>($"На {round} итерации ожидается задача на перемещение."); break; } task.Execute(); if (round < expectedActorPositions.Count()) { _factActorNode.Should().Be(expectedActorPositions[round], $"На {round} итерации неожиданные координаты актёра."); } else { _factActorNode.Should().Be(expectedActorPositions[0], $"На {round} итерации актёр должен начать маршрут заново."); } } }
protected ChestBase(IMapNode node, IPropStore content) : this(node, content, 0) { }
public int DistanceBetween(IMapNode currentNode, IMapNode targetNode) { var distance = _nodeDistanceCalculator.GetDistance((TNode)currentNode, (TNode)targetNode); return(distance); }
private static bool IsHighlighted(IMapNode node) => node.Focused || node.IsMouseOver;
public Actor([NotNull] IPerson person, [NotNull] IPlayer owner, [NotNull] IMapNode node) { Person = person ?? throw new ArgumentNullException(nameof(person)); Owner = owner ?? throw new ArgumentNullException(nameof(owner)); Node = node ?? throw new ArgumentNullException(nameof(node)); }
private void OnZoomedIn(IMapNode zoomedNode) => Bind();
/// <summary> /// Moves the AStar algorithm forward one step. /// </summary> /// <returns>Returns the state the alorithm is in after the step, either Failed, GoalFound or still Searching.</returns> private State Step() { while (true) { // There are no more nodes to search, return failure. if (_openList.IsEmpty()) { return(State.Failed); } // Check the next best node in the graph by TotalCost. CurrentNode = _openList.Pop(); // This node has already been searched, check the next one. if (_closedList.ContainsValue(CurrentNode)) { continue; } // An unsearched node has been found, search it. break; } // Remove from the open list and place on the closed list // since this node is now being searched. var currentData = GetData(CurrentNode); _openList.Remove(AStarData.TotalCost); _closedList.Add(CurrentNode, currentData); // Found the goal, stop searching. if (CurrentNode == _goal) { return(State.GoalFound); } // Node was not the goal so add all children nodes to the open list. // Each child needs to have its movement cost set and estimated cost. var neighbors = GetAvailableNeighbors(CurrentNode, _map); foreach (var child in neighbors) { // If the child has already been searched (closed list) or is on // the open list to be searched then do not modify its movement cost // or estimated cost since they have already been set previously. if (_openList.ContainsValue(child) || _closedList.ContainsValue(child)) { continue; } var childData = GetData(child); currentData = GetData(CurrentNode); childData.Parent = CurrentNode; childData.MovementCost = currentData.MovementCost + 1; _openList.Add(child, childData); } // This step did not find the goal so return status of still searching. return(State.Searching); }
private void OnNodeClicked(IMapNode clickedNode) => Bind();
public List<Path> GetPathsFrom(IMapNode node) { if (node == null || !(node is GridTile)) throw new ArgumentException("Node is not a tile."); Point nodePos = GetPosition(node); if (nodePos.X < 0) throw new ArgumentException("Node not part of this map."); List<Path> pathsFrom = new List<Path>(); if (nodePos.Y > 0) pathsFrom.Add(new Path("north", node, Tiles[nodePos.X, nodePos.Y - 1])); if (nodePos.Y < Height - 1) pathsFrom.Add(new Path("south", node, Tiles[nodePos.X, nodePos.Y + 1])); if (nodePos.X > 0) pathsFrom.Add(new Path("west", node, Tiles[nodePos.X - 1, nodePos.Y])); if (nodePos.X < Width - 1) pathsFrom.Add(new Path("east", node, Tiles[nodePos.X + 1, nodePos.Y])); pathsFrom.RemoveAll(x => !((GridTile)x.To).Travelable); return pathsFrom; }
private void OnNodeStateChanged(IMapNode node) => Bind();
public override float GetTargetH(IMapNode father) { var ft = father as ClientMapNode; return(Vector3.Distance(Position, ft.Position)); }
/// <summary> /// Создаёт ребро между двумя узлами графа карты. /// </summary> /// <param name="node1">Узел графа карты.</param> /// <param name="node2">Узел графа карты.</param> public abstract void AddEdge(IMapNode node1, IMapNode node2);
public override float GetFatherG(IMapNode target) { var tt = target as ClientMapNode; return(Vector3.Distance(Position, tt.Position)); }
protected ChestBase(IMapNode node, IPropStore content, int id) { Id = id; Node = node ?? throw new ArgumentNullException(nameof(node)); Content = content ?? throw new ArgumentNullException(nameof(content)); }
/// <summary> /// Возвращает узлы, напрямую соединённые с указанным узлом. /// </summary> /// <param name="node">Опорный узел, относительно которого выбираются соседние узлы.</param> /// <returns> /// Возвращает набор соседних узлов. /// </returns> public abstract IEnumerable <IMapNode> GetNext(IMapNode node);
protected ChestBase(IMapNode node, IPropStore content) : this(node, content, default(int)) { }
/// <summary> /// Удаляет ребро между двумя узлами графа карты. /// </summary> /// <param name="node1">Узел графа карты.</param> /// <param name="node2">Узел графа карты.</param> public abstract void RemoveEdge(IMapNode node1, IMapNode node2);
public abstract void OnNodeClicked(IMapNode node);
public abstract bool IsPositionAvailableForContainer(IMapNode targetNode);
public void Mark(IMapNode tile) { Point position = GridMap.GetPosition(tile); IEnumerable<Path> paths = GridMap.GetPathsFrom(tile); Map[position.X, position.Y] = 'x'; if (paths.FirstOrDefault(x => x.Identifier.Equals("north")) != null && Map[position.X, position.Y - 1] == ' ') { Map[position.X, position.Y - 1] = '?'; } if (paths.FirstOrDefault(x => x.Identifier.Equals("east")) != null && Map[position.X + 1, position.Y] == ' ') { Map[position.X + 1, position.Y] = '?'; } if (paths.FirstOrDefault(x => x.Identifier.Equals("west")) != null && Map[position.X - 1, position.Y] == ' ') { Map[position.X - 1, position.Y] = '?'; } if (paths.FirstOrDefault(x => x.Identifier.Equals("south")) != null && Map[position.X, position.Y + 1] == ' ') { Map[position.X, position.Y + 1] = '?'; } }