public MapSearchNode(MapNode mp) { mapNode = mp; }
public bool GetSuccessors(AStarPathfinder astarsearch, MapSearchNode parent_node) { MapSearchNode n; MapNode left = null; MapNode right = null; bool ret; if (parent_node != null && mapNode.floorNode != null) { // Start node which is also a floor node. // Find and add nearest transport nodes to the left/right (based on start_point, which should be populated) List <MapNode> nodesOnFloor = mapNode.nodesOnFloor; //assert(nodesOnFloor != NULL); foreach (var nodex in nodesOnFloor) //for (List<MapNode> const_iterator i = nodesOnFloor->begin(); i != nodesOnFloor->end(); i++) { //MapNode node = *i; if (nodex.position.X <= start_point.X && canTransfer(this, nodex, Direction.LEFT)) { left = nodex; } else if (canTransfer(this, nodex, Direction.RIGHT)) { right = nodex; break; } } if (left != null) { createNode(out n, left); ret = astarsearch.AddSuccessor(n); if (!ret) { return(false); } } if (right != null) { createNode(out n, right); ret = astarsearch.AddSuccessor(n); if (!ret) { return(false); } } return(true); } //if (mapNode.position.Y == end_point.Y && astarsearch.GetSolutionEnd().mapNode.floorNode != null) //{ // // Reached the same floor as end node, and end node is a floor node. // // Add destination floor node // if (mapNode.floorNode != null) return false; // ERROR: All transport nodes must contain pointer to their respective floor node. // createNode(out n, mapNode.floorNode); // ret = astarsearch.AddSuccessor(n); // if (!ret) return false; // else return true; //} MapNode node = mapNode.neighbours[(int)Direction.LEFT]; while (node != null && left == null) { if (!canTransfer(this, node, Direction.LEFT)) { node = node.neighbours[(int)Direction.LEFT]; continue; } left = node; } node = mapNode.neighbours[(int)Direction.RIGHT]; while (node != null && right == null) { if (!canTransfer(this, node, Direction.RIGHT)) { node = node.neighbours[(int)Direction.RIGHT]; continue; } right = node; } if (left != null) { createNode(out n, left); ret = astarsearch.AddSuccessor(n); if (!ret) { return(false); } } if (right != null) { createNode(out n, right); ret = astarsearch.AddSuccessor(n); if (!ret) { return(false); } } if (mapNode.neighbours[(int)Direction.UP] != null) { node = mapNode.neighbours[(int)Direction.UP]; if (mapNode.HasElevator) { while (node != null) { createNode(out n, node); ret = astarsearch.AddSuccessor(n); if (!ret) { return(false); } node = node.neighbours[(int)Direction.UP]; } } else if (canTransfer(this, node, Direction.UP)) { createNode(out n, node); ret = astarsearch.AddSuccessor(n); if (!ret) { return(false); } } } if (mapNode.neighbours[(int)Direction.DOWN] != null) { node = mapNode.neighbours[(int)Direction.DOWN]; if (mapNode.HasElevator) { while (node != null) { createNode(out n, node); ret = astarsearch.AddSuccessor(n); if (!ret) { return(false); } node = node.neighbours[(int)Direction.DOWN]; } } else if (canTransfer(this, node, Direction.DOWN)) { createNode(out n, node); ret = astarsearch.AddSuccessor(n); if (!ret) { return(false); } } } return(true); }
void createNode(out MapSearchNode n, MapNode node) { n = new MapSearchNode(node); n.end_point = end_point; n.serviceRoute = serviceRoute; }
bool canTransfer(MapSearchNode start, MapNode dest, Direction dir) { /* * Returns true if transfer to destination transport has not exceed transfer limits. * Returns false otherwise. * Maximum transfer limits are: * 2 elevators (no more than 1 elevator if journey has already used stairs or escalators) * 3 stairs * 6 escalators * 1 stair, 2 escalators OR 2 stairs, 1 escalator */ if ((dir == Direction.UP || dir == Direction.DOWN)) { // Once in an elevator node, travel is allowed for as many floors available in the elevator shaft if (start.mapNode.HasElevator) { return(true); } // Hence we only check limits for stairlike travel if (start.mapNode.transportItems[(int)dir].Icon == 2) { if (start.numStairs > 2 - start.numEscalators) { return(false); } } else { if (start.numEscalators > 5) { return(false); } if (start.numStairs > 0 && start.numEscalators > 2 - start.numStairs) { return(false); } } } else { if (dest.HasElevator) { if ((!start.serviceRoute && dest.HasServiceElevator) || (start.serviceRoute && !dest.HasServiceElevator)) { return(false); } if (start.numElevators > 1) { return(false); } if (start.numElevators == 1 && (start.mapNode.position.Y % 15 != 0 || start.numStairs > 0 || start.numEscalators > 0)) { return(false); } } // Transit to other stairlike nodes (moving left/right) has no limits. // Limit only applies when actually using (moving up/down) the stairlike. } return(true); }
public void removeNode(Slot slot, IPrototype item) { return; if (item is null) { return; } if (!(item is IHaulsPeople)) { return; } if (!peopleMovementMap.ContainsKey(slot.ToString())) { return; } MapNode n = peopleMovementMap[slot.ToString()]; // Update all neighour links if (item is IHaulsPeople && slot.Y == item.Position.Y) { n.neighbours[(int)Direction.UP].neighbours[(int)Direction.DOWN] = null; n.neighbours[(int)Direction.UP].transportItems[(int)Direction.DOWN] = null; n.neighbours[(int)Direction.UP] = null; n.transportItems[(int)Direction.UP] = null; } else if (item is Elevator) { n.HasElevator = false; if (item.Icon == (int)IconNumbers.ICON_ELEVATOR_SERVICE) { n.HasServiceElevator = false; } // Link upper & lower floor node to skip this node if (n.neighbours[(int)Direction.UP] != null) { n.neighbours[(int)Direction.UP].neighbours[(int)Direction.DOWN] = n.neighbours[(int)Direction.DOWN]; if (n.neighbours[(int)Direction.DOWN] == null) { n.neighbours[(int)Direction.UP].transportItems[(int)Direction.DOWN] = null; } } if (n.neighbours[(int)Direction.DOWN] != null) { n.neighbours[(int)Direction.DOWN].neighbours[(int)Direction.UP] = n.neighbours[(int)Direction.UP]; if (n.neighbours[(int)Direction.UP] == null) { n.neighbours[(int)Direction.DOWN].transportItems[(int)Direction.UP] = null; } } n.neighbours[(int)Direction.UP] = null; n.transportItems[(int)Direction.UP] = null; n.neighbours[(int)Direction.DOWN] = null; n.transportItems[(int)Direction.DOWN] = null; } // Delete and erase only if no other overlapping item if (!n.HasElevator && !n.HasServiceElevator && n.transportItems[(int)Direction.UP] == null && n.transportItems[(int)Direction.DOWN] == null) { if (n.neighbours[(int)MapNode.Direction.LEFT] != null) { n.neighbours[(int)MapNode.Direction.LEFT].neighbours[(int)MapNode.Direction.RIGHT] = n.neighbours[(int)MapNode.Direction.RIGHT]; } if (n.neighbours[(int)MapNode.Direction.RIGHT] != null) { n.neighbours[(int)MapNode.Direction.RIGHT].neighbours[(int)MapNode.Direction.LEFT] = n.neighbours[(int)MapNode.Direction.LEFT]; } peopleMovementMap.Remove(slot.ToString()); var mnl = mapNodesByFloor[slot.Y]; //mnl.Clear(); mnl.ForEach(x => { if (x == n) { x.Status = 1; // mark for deletion } }); mnl.RemoveAll(x => x.Status == 1); // using status lets delete } }
public MapNode extendNode(Slot slotBeforeExtending, Slot sizeBeforeExtending, IPrototype itemAfterExtending) { (FloorNode f, MapNode n)ret = createFloorAndNodeIfApplicable(slotBeforeExtending, itemAfterExtending); if (itemAfterExtending is Elevator) { // Link to upper/lower floor node var e = (Elevator)itemAfterExtending; var expandedUp = itemAfterExtending.Position.Y > slotBeforeExtending.Y; if (expandedUp) { var topIndex = itemAfterExtending.Position.Y; if (!e.ConnectsToFloor(topIndex, sizeBeforeExtending.Y)) { var ep = new Slot(itemAfterExtending.Position.X, topIndex); MapNode upper = peopleMovementMap.ContainsKey(ep.ToString()) ? peopleMovementMap[ep.ToString()] : addNode(ep, itemAfterExtending); ret.n.neighbours[(int)MapNode.Direction.UP] = upper; ret.n.transportItems[(int)MapNode.Direction.UP] = itemAfterExtending; //if (upper.neighbours[(int)MapNode.Direction.DOWN] != null) //{ // ret.n.neighbours[(int)MapNode.Direction.DOWN] = upper.neighbours[(int)MapNode.Direction.DOWN]; // ret.n.transportItems[(int)MapNode.Direction.DOWN] = itemAfterExtending; //} upper.neighbours[(int)MapNode.Direction.DOWN] = ret.n; upper.transportItems[(int)MapNode.Direction.DOWN] = itemAfterExtending; } } else { //expanded down var bottomIndex = itemAfterExtending.Position.Y - itemAfterExtending.Size.Y + 1; var topIndex = bottomIndex + 1; if (!e.ConnectsToFloor(bottomIndex, sizeBeforeExtending.Y)) { var epLower = new Slot(itemAfterExtending.Position.X, bottomIndex); var epUpper = new Slot(itemAfterExtending.Position.X, topIndex); MapNode lower = peopleMovementMap.ContainsKey(epLower.ToString()) ? peopleMovementMap[epLower.ToString()] : addNode(epLower, itemAfterExtending); MapNode upper = peopleMovementMap.ContainsKey(epUpper.ToString()) ? peopleMovementMap[epUpper.ToString()] : addNode(epUpper, itemAfterExtending); upper.neighbours[(int)MapNode.Direction.DOWN] = lower; upper.transportItems[(int)MapNode.Direction.DOWN] = itemAfterExtending; //ret.n.neighbours[(int)MapNode.Direction.DOWN] = lower; //ret.n.transportItems[(int)MapNode.Direction.DOWN] = itemAfterExtending; //if (lower.neighbours[(int)MapNode.Direction.UP] != null) //{ // ret.n.neighbours[(int)MapNode.Direction.UP] = lower.neighbours[(int)MapNode.Direction.UP]; // ret.n.transportItems[(int)MapNode.Direction.UP] = itemAfterExtending; //} lower.neighbours[(int)MapNode.Direction.UP] = upper; lower.transportItems[(int)MapNode.Direction.UP] = itemAfterExtending; } } } return(ret.n); }
public (FloorNode, MapNode) createFloorAndNodeIfApplicable(Slot slot, IPrototype item) { // Create corresponding FloorNode if not available FloorNode f; if (!floorNodes.ContainsKey(slot.Y)) { if (!mapNodesByFloor.ContainsKey(slot.Y)) { mapNodesByFloor[slot.Y] = new List <MapNode>(); } f = new FloorNode(mapNodesByFloor[slot.Y]); floorNodes[slot.Y] = f; f.position = new Slot(int.MinValue, slot.Y); } else { f = floorNodes[slot.Y]; } if (!(item is IHaulsPeople)) { return(f, null); // Building item, do not add into transport } // Create/Get MapNode for above created floor MapNode n; if (!peopleMovementMap.ContainsKey(slot.ToString())) { n = new MapNode(f); peopleMovementMap[slot.ToString()] = n; n.position = slot; // Just insert node if list is empty if (mapNodesByFloor[slot.Y].Count == 0) { mapNodesByFloor[slot.Y].Add(n); } else { // Look for nearby nodes on same floor to insert MapNode left = null; MapNode right = null; foreach (MapNode node in mapNodesByFloor[slot.Y]) { if (node.position.X < slot.X) { left = node; } else { right = node; var nodeIndex = mapNodesByFloor[slot.Y].IndexOf(node); mapNodesByFloor[slot.Y].Insert(nodeIndex, n); break; } } if (left != null) { if (right == null) { mapNodesByFloor[slot.Y].Add(n); // Insert node as last node in list } n.neighbours[(int)MapNode.Direction.LEFT] = left; left.neighbours[(int)MapNode.Direction.RIGHT] = n; } if (right != null) { n.neighbours[(int)MapNode.Direction.RIGHT] = right; right.neighbours[(int)MapNode.Direction.LEFT] = n; } } } else { n = peopleMovementMap[slot.ToString()]; } return(f, n); }