public GraphResult FindPath(Node sourceNode, Node destinationNode, bool exhaustiveSearch = false, List <Item> startingItems = null, List <Requirement> requirements = null) { this.ResetState(); // reset our nodes and edges (really just edges unless something changes on nodes) var orderedVisit = new LinkedList <Node>(); var obtainedItems = new List <Item>(); if (startingItems != null) { obtainedItems.AddRange(startingItems); } var retryQueue = new Queue <Edge>(); //var startingEdges = Edges.Where(x => x.SourceNode == sourceNode); var visitedNodes = new LinkedList <Node>(); //visitedNodes.AddLast(sourceNode); //orderedVisit.AddLast(sourceNode); var nextToVisit = new Queue <Node>(); //foreach(var se in startingEdges) //{ // nextToVisit.Enqueue(se.DestinationNode); //} nextToVisit.Enqueue(sourceNode); // TODO: is there a better way to do this for exhaustiveSearches? bool foundDestination = false; while (nextToVisit.Count > 0) { var next = nextToVisit.Dequeue(); if (visitedNodes.Contains(next) && nextToVisit.Count > 0) { // already visited continue; } visitedNodes.AddLast(next); orderedVisit.AddLast(next); if (next is ItemLocation) { var item = ((ItemLocation)next).Item; if (item is ConsumableItem) { ((ConsumableItem)item).IncreaseCount(); } obtainedItems.Add(item); } if (next is LogicalBoss) { obtainedItems.Add(((LogicalBoss)next).Boss); } if (next == destinationNode && (requirements == null || requirements.Count == 0 || (requirements.Count > 0 && requirements.Any(x => x.RequirementsMet(obtainedItems))))) { foundDestination = true; if (!exhaustiveSearch || (exhaustiveSearch && nextToVisit.Count == 0 && retryQueue.Count == 0)) { // found it var result = new GraphResult(); result.Success = true; result.ItemsObtained.AddRange(obtainedItems); result.OrderedNodesVisited.AddRange(orderedVisit.ToList()); result.NodesVisited.AddRange(visitedNodes.ToList()); result.EdgesNotRetried.AddRange(retryQueue.ToList()); return(result); } } var nextEdges = Edges.Where(x => x.SourceNode == next) .Where(x => x.SourceNode != destinationNode) // don't go past the node we are looking for .Where(x => !exhaustiveSearch || (exhaustiveSearch && x.SourceNode != destinationNode)) .Where(x => x.MeetsRequirements(obtainedItems)) .Where(x => !visitedNodes.Contains(x.DestinationNode)); foreach (var e in nextEdges) { nextToVisit.Enqueue(e.DestinationNode); } var retryEdges = Edges.Where(x => x.SourceNode == next) .Where(x => x.SourceNode != destinationNode) .Where(x => !exhaustiveSearch || (exhaustiveSearch && x.SourceNode != destinationNode)) .Where(x => !x.MeetsRequirements(obtainedItems)); foreach (var e in retryEdges) { retryQueue.Enqueue(e); } // if we run out - retry all our retry queue items if (nextToVisit.Count == 0) { var tempRetry = new Queue <Edge>(); while (retryQueue.Count > 0) { var e = retryQueue.Dequeue(); if (e.MeetsRequirements(obtainedItems)) { nextToVisit.Enqueue(e.SourceNode); visitedNodes.Remove(e.SourceNode); } else { tempRetry.Enqueue(e); } } retryQueue = tempRetry; } } GraphResult ret = new GraphResult(); ret.Success = foundDestination; ret.ItemsObtained.AddRange(obtainedItems); ret.OrderedNodesVisited.AddRange(orderedVisit.ToList()); ret.NodesVisited.AddRange(visitedNodes.ToList()); ret.EdgesNotRetried.AddRange(retryQueue.ToList()); return(ret); }
protected bool CanGetBossRoomAndDefeat(Dungeon dungeon, GraphResult result) { bool bossRoom = false; bool bossWin = false; switch (dungeon.BossRoomId) { case RoomIdConstants.R200_EasternPalace_ArmosKnights: bossRoom = result.NodesVisited.Any(x => x.LogicalId == "eastern-armos"); bossWin = result.ItemsObtained.Any(x => x.LogicalId == "[Eastern Boss]"); break; case RoomIdConstants.R51_DesertPalace_Lanmolas: bossRoom = result.NodesVisited.Any(x => x.LogicalId == "desert-lanmolas"); bossWin = result.ItemsObtained.Any(x => x.LogicalId == "[Desert Boss]"); break; case RoomIdConstants.R7_TowerofHera_Moldorm: bossRoom = result.NodesVisited.Any(x => x.LogicalId == "hera-moldorm"); bossWin = result.ItemsObtained.Any(x => x.LogicalId == "[Hera Boss]"); break; case RoomIdConstants.R90_PalaceofDarkness_HelmasaurKing: bossRoom = result.NodesVisited.Any(x => x.LogicalId == "pod-helmasaur"); bossWin = result.ItemsObtained.Any(x => x.LogicalId == "[PoD Boss]"); break; case RoomIdConstants.R6_SwampPalace_Arrghus: bossRoom = result.NodesVisited.Any(x => x.LogicalId == "swamp-arrghus"); bossWin = result.ItemsObtained.Any(x => x.LogicalId == "[Swamp Boss]"); break; case RoomIdConstants.R41_SkullWoods_Mothula: bossRoom = result.NodesVisited.Any(x => x.LogicalId == "skull-mothula"); bossWin = result.ItemsObtained.Any(x => x.LogicalId == "[Skull Boss]"); break; case RoomIdConstants.R172_ThievesTown_BlindTheThief: bossRoom = result.NodesVisited.Any(x => x.LogicalId == "thieves-blind"); bossWin = result.ItemsObtained.Any(x => x.LogicalId == "[Thieves Boss]"); break; case RoomIdConstants.R222_IcePalace_Kholdstare: bossRoom = result.NodesVisited.Any(x => x.LogicalId == "ice-kholdstare"); bossWin = result.ItemsObtained.Any(x => x.LogicalId == "[Ice Boss]"); break; case RoomIdConstants.R144_MiseryMire_Vitreous: bossRoom = result.NodesVisited.Any(x => x.LogicalId == "mire-vitreous"); bossWin = result.ItemsObtained.Any(x => x.LogicalId == "[Mire Boss]"); break; case RoomIdConstants.R164_TurtleRock_Trinexx: bossRoom = result.NodesVisited.Any(x => x.LogicalId == "turtle-trinexx"); bossWin = result.ItemsObtained.Any(x => x.LogicalId == "[Turtle Boss]"); break; case RoomIdConstants.R28_GanonsTower_IceArmos: bossRoom = result.NodesVisited.Any(x => x.LogicalId == "gt-armos"); bossWin = result.ItemsObtained.Any(x => x.LogicalId == "[GT Armos Boss]"); break; case RoomIdConstants.R108_GanonsTower_LanmolasRoom: bossRoom = result.NodesVisited.Any(x => x.LogicalId == "gt-lanmolas"); bossWin = result.ItemsObtained.Any(x => x.LogicalId == "[GT Lanmolas Boss]"); break; case RoomIdConstants.R77_GanonsTower_MoldormRoom: bossRoom = result.NodesVisited.Any(x => x.LogicalId == "gt-moldorm"); bossWin = result.ItemsObtained.Any(x => x.LogicalId == "[GT Moldorm Boss]"); break; } // if we can't even get to the room no need to switch it, because something else is blocking the seed return(!bossRoom || bossWin); }