/// <summary> /// Performs the path discovery on the specified path. The path costs of this path /// are determined and it is checked whether the target router can be reached with /// less path costs using this path. If the target router can be reached with less /// path costs via this path, the distance (priority) of the router is adjusted and /// the previous router on this path stored in the predecessorRouter data structure. /// Finally, the path is set to discovered. /// </summary> /// <param name="path">The path for which the path discovery is performed.</param> public void PerformPathDiscovery(PathScript path) { RouterScript from = path.from.GetComponent <RouterScript>(); RouterScript to = path.to.GetComponent <RouterScript>(); RouterScript previousRouter = null; RouterScript discoveredRouter = null; // Check which router will be discovered. if (from == routerScriptCurrentPlayerPosition) { // Player discovers 'to' router. discoveredRouter = to; previousRouter = routerScriptCurrentPlayerPosition; } else if (bidirectional && to == routerScriptCurrentPlayerPosition) { // Player discovers 'from' router. discoveredRouter = from; previousRouter = routerScriptCurrentPlayerPosition; } // Update the current distance if we have found a shorter path to the discovered router. // This only needs to be done when the discovered router has not already been handled by the dijkstra algorithm. if (priorityQueue.IsContained(discoveredRouter)) { // Path costs to the discovered router are the path cost to the previous router + the path costs of this path. int pathCost = previousRouter.GetPriority() + graphRepresentation2[previousRouter.GetRouterIndex(), discoveredRouter.GetRouterIndex()].GetPathCosts(); // Are the new path costs lower than the currently stored lowest path costs. if (pathCost < discoveredRouter.GetPriority()) { // Update the path costs of the router. priorityQueue.DecreasePriority(discoveredRouter, pathCost); // Set the new predecessor for this router. predecessorRouter[discoveredRouter] = previousRouter; } } // Set path to discovered. graphRepresentation2[previousRouter.GetRouterIndex(), discoveredRouter.GetRouterIndex()].SetDiscovered(true); //graphRepresentation2[previousRouter.GetRouterIndex(), discoveredRouter.GetRouterIndex()].DisplayPathCosts(); // If there is a path back with the same costs, discover this path as well. PathScript backPath = graphRepresentation2[discoveredRouter.GetRouterIndex(), previousRouter.GetRouterIndex()]; if (backPath != null && backPath.GetPathCosts() == path.GetPathCosts()) { backPath.SetDiscovered(true); //backPath.DisplayPathCosts(); } // Test: Output the current priority queue. // Debug.Log(priorityQueue.ToString()); }
/// <summary> /// Determines whether this hop is a valid uniform cost hop for the specified targetRouter. /// </summary> /// <returns><c>true</c> if this instance is a valid uniform cost hop for the specified targetRouter; otherwise, <c>false</c>.</returns> /// <param name="targetRouter">Target router.</param> private bool IsValidUniformCostHop(RouterScript targetRouter) { if (!prioQueue.IsContained(targetRouter)) { // Valid hop. return(true); } // Is the target the first element in the priority queue? if (prioQueue.Peek() == targetRouter) { return(true); } else { // Target is not the first element in the priority Queue. // But it is still a valid hop if there are more elements with // the same costs. bool isValidHop = false; // To check this, we need to remove the elements before this router from the queue and later put them back in. RouterScript headOfQueue = prioQueue.PullHighest(); // Check the following routers. Stop if they have a higher priority than the original head. List <RouterScript> nextRouterCandidates = new List <RouterScript>(); while (prioQueue.Count() > 0 && prioQueue.Peek().GetPriority() == headOfQueue.GetPriority()) { RouterScript candidateRouter = prioQueue.PullHighest(); nextRouterCandidates.Add(candidateRouter); if (candidateRouter == targetRouter) { isValidHop = true; break; } } // Store the candidate routers and the original headOfQueue back into the priority queue. prioQueue.Enqueue(headOfQueue); for (int i = 0; i < nextRouterCandidates.Count; i++) { prioQueue.Enqueue(nextRouterCandidates[i]); } if (!isValidHop) { return(false); } } return(true); }
void GameManagerInterface.PerformHop(PathScript path) { GameObject hopTarget = null; //to=active --> goto from if (path.to.gameObject == activeRouter.gameObject) { hopTarget = path.from.gameObject; } else //from=active --> goto to if (path.from.gameObject == activeRouter.gameObject) { hopTarget = path.to.gameObject; } // Update the active router and the neighbours of the active router. activeRouter = hopTarget; currentPath.Add(hopTarget.GetComponent <RouterScript>()); neighboursOfActiveRouter = ExpandNode(activeRouter.GetComponent <RouterScript>()); // Remove the hop target from the priortiy queue. RemoveRouterFromPrioQueue(hopTarget.GetComponent <RouterScript>()); for (int i = 0; i < neighboursOfActiveRouter.Count; i++) { RouterScript neighborRouter = neighboursOfActiveRouter[i].GetComponent <RouterScript>(); // Path costs to the target router are the path cost to the currently active router + the path costs of this path. int pathCost = activeRouter.GetComponent <RouterScript>().GetPriority() + graphRepresentation2[ activeRouter.GetComponent <RouterScript>().GetRouterIndex(), neighborRouter.GetRouterIndex() ].GetPathCosts(); if (currentPath.Contains(neighborRouter)) { continue; } if (prioQueue.IsContained(neighborRouter)) { if (pathCost < neighborRouter.GetPriority()) { // Update the path costs of the router. prioQueue.DecreasePriority(neighborRouter, pathCost); if (isLogEnabled) { Debug.Log(string.Format("Updated path costs of router {0}, new path costs are {1}.", neighborRouter.GetRouterName(), neighborRouter.GetPriority())); } } } else { neighborRouter.SetPriority(pathCost); if (isLogEnabled) { Debug.Log(string.Format("Inserted neighbor into prio queue. Neighbor is {0}, path costs are {1}.", neighborRouter.GetRouterName(), pathCost)); } // Insert neighbor into priority queue. prioQueue.Enqueue(neighborRouter); } } if (isLogEnabled) { Debug.Log("Prio Queue after hop: " + prioQueue.ToString()); } }
/// <summary> /// Checks whether the attempted hop by the player is a valid hop which fulfills the conditions of the dijkstra algorithm. /// First, it is checked whether the path is connecting the router on which the player is currently located and an adjacent router. /// If not, it is an invalid hop. Second, it is checked whether the path is already discovered. If not, it is a valid hop, but a /// hop in discovery mode. If the path it is not discovered and there are still undiscovered paths connected to the router on which the player is /// located, it is an invalid hop due to undiscovered neighbors. Third, if the target router of this path has already been handled, the user /// can move back to this router, so its a valid hop. Finally, if non of the cases mentioned before has applied, the player wants to perform an /// actual movement towards an router which should be handled by the dijkstra algorithm next. It is checked whether the target router determined by /// the path is actually a router that the dijkstra algorithm would handle next. If it is, it is a valid hop, otherwise it is an invalid hop concerning /// the dijkstra algorithm. /// </summary> /// <param name="path">The path between the two routers which should be passed in this hop.</param> /// <returns>The result of the dijkstra path check.</returns> public DijkstraStatus IsValidHop(PathScript path) { RouterScript from; RouterScript to; DijkstraMove dijkstraMove = new DijkstraMove(); // Get path script. //PathScript currentPath = graphRepresentation2[from.GetRouterIndex(), to.GetRouterIndex()]; PathScript currentPath = path; if (currentPath == null) { // Invalid hop, no path found between these routers. return(DijkstraStatus.HOP_UNREACHABLE); } // Check on which of the routers the player is located. if (path.from.GetComponent <RouterScript>() == routerScriptCurrentPlayerPosition) { to = path.to.GetComponent <RouterScript>(); from = path.from.GetComponent <RouterScript>(); } else if (bidirectional && path.to.GetComponent <RouterScript>() == routerScriptCurrentPlayerPosition) { to = path.from.GetComponent <RouterScript>(); from = path.to.GetComponent <RouterScript>(); } else { dijkstraMove.Source = routerScriptCurrentPlayerPosition; dijkstraMove.Destination = currentPath.from.GetComponent <RouterScript>(); dijkstraMove.Status = DijkstraStatus.HOP_UNREACHABLE; listOfMoves.Add(dijkstraMove); // Invalid hop if player is not located on one of these routers. return(DijkstraStatus.HOP_UNREACHABLE); } // Store the routers in the DijkstraMove object. dijkstraMove.Source = from; dijkstraMove.Destination = to; // Check if player is in error recovery mode. if (errorRecovery) { dijkstraMove.Status = DijkstraStatus.ERROR_RECOVERY; listOfMoves.Add(dijkstraMove); return(DijkstraStatus.ERROR_RECOVERY); } // Check whether the path is already discovered. if (!currentPath.IsDiscovered()) { dijkstraMove.Status = DijkstraStatus.VALID_HOP_DISCOVERY; listOfMoves.Add(dijkstraMove); // It is a valid hop. It is a path discovery move. return(DijkstraStatus.VALID_HOP_DISCOVERY); } // Check if all paths to the adjacent routers have already been discovered. for (int i = 0; i < graphRepresentation2.GetLength(1); i++) { PathScript pathToNeighbor = graphRepresentation2[from.GetRouterIndex(), i]; if (pathToNeighbor != null && !pathToNeighbor.IsDiscovered()) { dijkstraMove.Status = DijkstraStatus.UNDISCOVERED_PATHS; listOfMoves.Add(dijkstraMove); // Not a valid move. The player needs to perform path discovery on all paths of this router first. return(DijkstraStatus.UNDISCOVERED_PATHS); } } // Check if the router has already been handled by the dijkstra algorithm. // If the router has already been handled, the player can perform a hop to this router. // Perform this check after the 'all paths discovered' check to make sure the player has handled the current working router completely before moving back to a already handled router. if (!priorityQueue.IsContained(to)) { dijkstraMove.Status = DijkstraStatus.NOP; listOfMoves.Add(dijkstraMove); // Valid hop. return(DijkstraStatus.NOP); } // Check if the hop conforms to the hop which will be performed by the Dijkstra algorithm. // To do this, get the next hop from the priority queue, i.e. the router with the currently shortest distance. if (priorityQueue.Peek() == to) { dijkstraMove.Status = DijkstraStatus.VALID_HOP; listOfMoves.Add(dijkstraMove); // All conditions are met. It is a valid move. return(DijkstraStatus.VALID_HOP); } else { // It is still possible that there is another router which has the same distance and is thus a valid next hop. bool isValidHop = false; // To check this, we need to remove the elements before this router from the queue and later put them back in. RouterScript headOfQueue = priorityQueue.PullHighest(); // Check the following routers. Stop if they have a higher priority than the original head. List <RouterScript> nextRouterCandidates = new List <RouterScript>(); while (priorityQueue.Count() > 0 && priorityQueue.Peek().GetPriority() == headOfQueue.GetPriority()) { RouterScript candidateRouter = priorityQueue.PullHighest(); nextRouterCandidates.Add(candidateRouter); if (candidateRouter == to) { isValidHop = true; break; } } // Store the candidate routers and the original headOfQueue back into the priority queue. priorityQueue.Enqueue(headOfQueue); for (int i = 0; i < nextRouterCandidates.Count; i++) { priorityQueue.Enqueue(nextRouterCandidates[i]); } // Break if it isn't a valid hop. if (!isValidHop) { dijkstraMove.Status = DijkstraStatus.WRONG_HOP; listOfMoves.Add(dijkstraMove); return(DijkstraStatus.WRONG_HOP); } } dijkstraMove.Status = DijkstraStatus.VALID_HOP; listOfMoves.Add(dijkstraMove); // All conditions are met. It is a valid move. return(DijkstraStatus.VALID_HOP); }
/// <summary> /// Finds the optimal between the source and the destination router using the metric hop count. /// </summary> /// <returns>The optimal path as a list.</returns> /// <param name="source">Source.</param> /// <param name="destination">Destination.</param> protected List <GameObject> findOptimalHopCountPath(GameObject source, GameObject destination) { if (isLogEnabled) { Debug.Log("Finding best path!"); } prioQueue = new PriorityQueue <RouterScript>(); RouterScript current = source.GetComponent <RouterScript>(); current.SetPriority(0); Dictionary <RouterScript, RouterScript> parentRelationship = new Dictionary <RouterScript, RouterScript>(); List <RouterScript> closed = new List <RouterScript>(); List <RouterScript> children = new List <RouterScript>(); if (isLogEnabled) { Debug.Log("Starting findOptimalHopCountPath from " + current.name + " to " + destination.name); } while (current.gameObject != destination) { if (!closed.Contains(current)) // Don't need to check this node again. { children = ExpandNode(current); foreach (RouterScript tmp in children) { // Check whether the router has already been handled. If this is the case, // we don't need to add them to the priority queue again. if (closed.Contains(tmp)) { continue; } // Increase the priority. One more hop. tmp.SetPriority(current.GetPriority() + 1); // Store parent (predecessor router of current router) for child. // Only do this if no router has already been defined as the predecessor router. if (parentRelationship.ContainsKey(tmp)) { // do nothing. if (isLogEnabled) { Debug.Log("There is already a predecessor for the router " + tmp.name + "defined."); } } else { parentRelationship.Add(tmp, current); if (isLogEnabled) { Debug.Log("Setting predecessor for router: " + tmp.name + ", the predecessor is: " + current.name); } } if (isLogEnabled) { Debug.Log("Adding to prioQueue: router: " + tmp.name + " | with priority: " + tmp.GetPriority()); } prioQueue.Enqueue(tmp); } // Mark router as handled. closed.Add(current); } if (isLogEnabled) { Debug.Log("Handling of router: " + current.name + " is done. Taking the next one."); } // Continue with node that has the lowest priority at that time. current = prioQueue.PullHighest(); } // Calculate optimal path. List <GameObject> optimalPath = new List <GameObject>(); optimalPath.Insert(0, current.gameObject); while (parentRelationship[current].gameObject != source) { current = parentRelationship[current]; optimalPath.Insert(0, current.gameObject); } optimalPath.Insert(0, source); if (isLogEnabled) { string logString = "Optimal Path: "; foreach (GameObject go in optimalPath) { logString += go.GetComponent <RouterScript>().GetRouterName() + " -> "; } Debug.Log(logString.Substring(0, logString.Length - 3)); } return(optimalPath); }