private static bool ValidateTransitionRandomization() { if (randomizationError) { return(false); } Log("Beginning transition placement validation..."); ProgressionManager pm = new ProgressionManager( RandomizerState.Validating ); pm.Add(startProgression); pm.Add(LogicManager.ItemNames.Where(i => LogicManager.GetItemDef(i).progression)); tm.ResetReachableTransitions(); tm.UpdateReachableTransitions(_pm: pm); bool validated = tm.reachableTransitions.SetEquals(LogicManager.TransitionNames()); if (!validated) { Log("Transition placements failed to validate!"); foreach (string t in LogicManager.TransitionNames().Except(tm.reachableTransitions)) { Log($"{t} --> {(TransitionManager.transitionPlacements.TryGetValue(t, out string target) ? target : "???")}"); } } else { Log("Validation successful."); } return(validated); }
private static void PlaceOneWayTransitions() { if (randomizationError) { return; } List <string> oneWayEntrances = LogicManager.TransitionNames().Where(transition => LogicManager.GetTransitionDef(transition).oneWay == 1).ToList(); List <string> oneWayExits = LogicManager.TransitionNames().Where(transition => LogicManager.GetTransitionDef(transition).oneWay == 2).ToList(); List <string> horizontalOneWays = oneWayEntrances.Where(t => !LogicManager.GetTransitionDef(t).doorName.StartsWith("b")).ToList(); while (horizontalOneWays.Any()) { string horizontalEntrance = horizontalOneWays.First(); string downExit = oneWayExits[rand.Next(oneWayExits.Count)]; tm.PlaceOneWayPair(horizontalEntrance, downExit); oneWayEntrances.Remove(horizontalEntrance); horizontalOneWays.Remove(horizontalEntrance); oneWayExits.Remove(downExit); } DirectedTransitions directed = new DirectedTransitions(rand); directed.Add(oneWayExits); while (oneWayEntrances.Any()) { string entrance = oneWayEntrances[rand.Next(oneWayEntrances.Count)]; string exit = directed.GetNextTransition(entrance); tm.PlaceOneWayPair(entrance, exit); oneWayEntrances.Remove(entrance); oneWayExits.Remove(exit); directed.Remove(exit); } }
public TransitionManager(Random rnd) { rand = rnd; dt = new DirectedTransitions(rnd); pm = new ProgressionManager( RandomizerState.InProgress ); transitionPlacements = new Dictionary <string, string>(); List <string> iterate = LogicManager.TransitionNames().ToList(); unplacedTransitions = new List <string>(); while (iterate.Any()) { string t = iterate[rand.Next(iterate.Count)]; unplacedTransitions.Add(t); iterate.Remove(t); } standbyTransitions = new Dictionary <string, string>(); reachableTransitions = new HashSet <string>(); recentProgression = new HashSet <string>(); dt.Add(unplacedTransitions); }
// useful for debugging public string ListObtainedProgression() { string progression = string.Empty; foreach (string item in LogicManager.ItemNames) { if (LogicManager.GetItemDef(item).progression&& Has(item)) { progression += item + ", "; } } if (RandomizerMod.Instance.Settings.RandomizeTransitions) { foreach (string transition in LogicManager.TransitionNames()) { if (Has(transition)) { progression += transition + ", "; } } } return(progression); }
public TransitionManager(Random rnd) { rand = rnd; dt = new DirectedTransitions(rnd); pm = new ProgressionManager( RandomizerState.InProgress ); // start items added to pm in Connect Start to Graph in Randomizer transitionPlacements = new Dictionary <string, string>(); List <string> iterate = LogicManager.TransitionNames().ToList(); unplacedTransitions = new List <string>(); while (iterate.Any()) { string t = iterate[rand.Next(iterate.Count)]; unplacedTransitions.Add(t); iterate.Remove(t); } standbyTransitions = new Dictionary <string, string>(); reachableTransitions = new HashSet <string>(); recentProgression = new HashSet <string>(); vanillaProgression = VanillaManager.GetVanillaProgression(); checkProgression = new HashSet <string>(); dt.Add(unplacedTransitions); }
public static void BuildRoomSpanningTree() { List <string> rooms = new List <string>(); Dictionary <string, List <string> > roomTransitions = new Dictionary <string, List <string> >(); foreach (string transition in LogicManager.TransitionNames()) { if (transition == startTransition) { continue; } TransitionDef def = LogicManager.GetTransitionDef(transition); string roomName = def.sceneName; if (new List <string> { "Crossroads_46", "Crossroads_46b" }.Contains(roomName)) { roomName = "Crossroads_46"; } if (new List <string> { "Abyss_03", "Abyss_03_b", "Abyss_03_c" }.Contains(roomName)) { roomName = "Abyss_03"; } if (new List <string> { "Ruins2_10", "Ruins2_10b" }.Contains(roomName)) { roomName = "Ruins2_10"; } if (!rooms.Contains(roomName) && !def.deadEnd && !def.isolated) { rooms.Add(roomName); roomTransitions.Add(roomName, new List <string>()); } } foreach (string transition in LogicManager.TransitionNames()) { if (transition == startTransition) { continue; } TransitionDef def = LogicManager.GetTransitionDef(transition); string roomName = def.sceneName; if (def.oneWay == 0 && rooms.Contains(roomName)) { roomTransitions[roomName].Add(transition); } } BuildSpanningTree(roomTransitions); }
private List <string> GetReachableTransitions(ProgressionManager _pm = null) // essentially the same as the method in transitionManager, using that class's static placement dictionary { if (_pm != null) { pm = _pm; } bool done = false; bool updated = false; List <string> reachableTransitions = new List <string>(); List <string> unreachableTransitions = LogicManager.TransitionNames().ToList(); while (!done) { foreach (string transition in unreachableTransitions) { if (pm.Has(transition)) { reachableTransitions.Add(transition); } else if (LogicManager.GetTransitionDef(transition).oneWay == 2) { string entrance = TransitionManager.transitionPlacements.FirstOrDefault(exit => exit.Value == transition).Key; if (entrance != null && pm.CanGet(entrance)) { reachableTransitions.Add(transition); updated = true; } } else if (!LogicManager.GetTransitionDef(transition).isolated&& pm.CanGet(transition)) { reachableTransitions.Add(transition); updated = true; } else if (TransitionManager.transitionPlacements.TryGetValue(transition, out string altTransition) && LogicManager.GetTransitionDef(altTransition).oneWay != 2 && !LogicManager.GetTransitionDef(altTransition).isolated&& pm.CanGet(altTransition)) { reachableTransitions.Add(transition); updated = true; } } foreach (string transition in reachableTransitions) { unreachableTransitions.Remove(transition); pm.Add(transition); } done = !updated; updated = false; } return(reachableTransitions); }
public static void BuildAreaSpanningTree() { List <string> areas = new List <string>(); Dictionary <string, List <string> > areaTransitions = new Dictionary <string, List <string> >(); foreach (string transition in LogicManager.TransitionNames()) { if (transition == startTransition) { continue; } TransitionDef def = LogicManager.GetTransitionDef(transition); string areaName = def.areaName; if (new List <string> { "City_of_Tears", "Forgotten_Crossroads", "Resting_Grounds" }.Contains(areaName)) { areaName = "Kings_Station"; } if (new List <string> { "Ancient_Basin", "Kingdoms_Edge" }.Contains(areaName)) { areaName = "Deepnest"; } if (!areas.Contains(areaName) && !def.deadEnd && !def.isolated) { areas.Add(areaName); areaTransitions.Add(areaName, new List <string>()); } } foreach (string transition in LogicManager.TransitionNames()) { if (transition == startTransition) { continue; } TransitionDef def = LogicManager.GetTransitionDef(transition); string areaName = def.areaName; if (def.oneWay == 0 && areas.Contains(areaName)) { areaTransitions[areaName].Add(transition); } } BuildSpanningTree(areaTransitions); }
// useful for debugging public string ListObtainedProgression() { string progression = string.Empty; foreach (string item in LogicManager.ItemNames) { if (LogicManager.GetItemDef(item).progression&& Has(item)) { progression += item + ", "; } } foreach (string transition in LogicManager.TransitionNames()) { if (Has(transition)) { progression += transition + ", "; } } return(progression); }
private static bool ValidateItemRandomization() { RandomizerMod.Instance.Log("Beginning item placement validation..."); List <string> unfilledLocations; if (im.normalFillShops) { unfilledLocations = im.randomizedLocations.Except(ItemManager.nonShopItems.Keys).Except(ItemManager.shopItems.Keys).ToList(); } else { unfilledLocations = im.randomizedLocations.Except(ItemManager.nonShopItems.Keys).Except(LogicManager.ShopNames).ToList(); } if (unfilledLocations.Any()) { Log("Unable to validate!"); string m = "The following locations were not filled: "; foreach (string l in unfilledLocations) { m += l + ", "; } Log(m); return(false); } HashSet <(string, string)> LIpairs = new HashSet <(string, string)>(ItemManager.nonShopItems.Select(kvp => (kvp.Key, kvp.Value))); foreach (var kvp in ItemManager.shopItems) { LIpairs.UnionWith(kvp.Value.Select(i => (kvp.Key, i))); } var lookup = LIpairs.ToLookup(pair => pair.Item2, pair => pair.Item1).Where(x => x.Count() > 1); if (lookup.Any()) { Log("Unable to validate!"); string m = "The following items were placed multiple times: "; foreach (var x in lookup) { m += x.Key + ", "; } Log(m); string l = "The following locations were filled by these items: "; foreach (var x in lookup) { foreach (string k in x) { l += k + ", "; } } Log(l); return(false); } /* * // Potentially useful debug logs * foreach (string item in ItemManager.GetRandomizedItems()) * { * if (ItemManager.nonShopItems.Any(kvp => kvp.Value == item)) * { * Log($"Placed {item} at {ItemManager.nonShopItems.First(kvp => kvp.Value == item).Key}"); * } * else if (ItemManager.shopItems.Any(kvp => kvp.Value.Contains(item))) * { * Log($"Placed {item} at {ItemManager.shopItems.First(kvp => kvp.Value.Contains(item)).Key}"); * } * else LogError($"Unable to find where {item} was placed."); * } * foreach (string location in ItemManager.GetRandomizedLocations()) * { * if (ItemManager.nonShopItems.TryGetValue(location, out string item)) * { * Log($"Filled {location} with {item}"); * } * else if (ItemManager.shopItems.ContainsKey(location)) * { * Log($"Filled {location}"); * } * else LogError($"{location} was not filled."); * } */ ProgressionManager pm = new ProgressionManager( RandomizerState.Validating ); pm.Add(startProgression); HashSet <string> locations = new HashSet <string>(im.randomizedLocations.Union(vm.progressionLocations)); HashSet <string> transitions = new HashSet <string>(); HashSet <string> items = im.randomizedItems; items.ExceptWith(startItems); if (RandomizerMod.Instance.Settings.RandomizeTransitions) { transitions.UnionWith(LogicManager.TransitionNames()); tm.ResetReachableTransitions(); tm.UpdateReachableTransitions(_pm: pm); } vm.ResetReachableLocations(false, pm); int passes = 0; while (locations.Any() || items.Any() || transitions.Any()) { if (RandomizerMod.Instance.Settings.RandomizeTransitions) { transitions.ExceptWith(tm.reachableTransitions); } foreach (string location in locations.Where(loc => pm.CanGet(loc)).ToList()) { locations.Remove(location); if (vm.progressionLocations.Contains(location)) { vm.UpdateVanillaLocations(location, false, pm); if (RandomizerMod.Instance.Settings.RandomizeTransitions && !LogicManager.ShopNames.Contains(location)) { tm.UpdateReachableTransitions(location, true, pm); } else if (RandomizerMod.Instance.Settings.RandomizeTransitions) { foreach (string i in vm.progressionShopItems[location]) { tm.UpdateReachableTransitions(i, true, pm); } } // It is possible for a shop to be both a vanilla progression location and contain randomized items, if // Charms or Keys are unrandomized if (ItemManager.shopItems.TryGetValue(location, out List <string> shopItems)) { foreach (string newItem in shopItems) { items.Remove(newItem); if (LogicManager.GetItemDef(newItem).progression) { pm.Add(newItem); if (RandomizerMod.Instance.Settings.RandomizeTransitions) { tm.UpdateReachableTransitions(newItem, true, pm); } } } } } else if (ItemManager.nonShopItems.TryGetValue(location, out string item)) { items.Remove(item); if (LogicManager.GetItemDef(item).progression) { pm.Add(item); if (RandomizerMod.Instance.Settings.RandomizeTransitions) { tm.UpdateReachableTransitions(item, true, pm); } } } else if (ItemManager.shopItems.TryGetValue(location, out List <string> shopItems)) { foreach (string newItem in shopItems) { items.Remove(newItem); if (LogicManager.GetItemDef(newItem).progression) { pm.Add(newItem); if (RandomizerMod.Instance.Settings.RandomizeTransitions) { tm.UpdateReachableTransitions(newItem, true, pm); } } } } else { Log("Unable to validate!"); Log($"Location {location} did not correspond to any known placement."); return(false); } } passes++; if (passes > 400) { Log("Unable to validate!"); Log("Progression: " + pm.ListObtainedProgression() + Environment.NewLine + "Grubs: " + pm.obtained[LogicManager.grubIndex] + Environment.NewLine + "Essence: " + pm.obtained[LogicManager.essenceIndex] + Environment.NewLine + "Flames: " + pm.obtained[LogicManager.flameIndex]); string m = string.Empty; foreach (string s in items) { m += s + ", "; } Log("Unable to get items: " + m); m = string.Empty; foreach (string s in locations) { m += s + ", "; } Log("Unable to get locations: " + m); m = string.Empty; foreach (string s in transitions) { m += s + ","; } Log("Unable to get transitions: " + m); LogItemPlacements(pm); return(false); } } //LogItemPlacements(pm); Log("Validation successful."); return(true); }
private static void CompleteTransitionGraph() { if (randomizationError) { return; } // IDK if this is the right fix but the line is correct and the algo is being rewritten so w/e foreach (string item in startProgression) { im.UpdateReachableLocations(item); } int failsafe = 0; Log("Beginning full placement of transitions..."); while (tm.unplacedTransitions.Any()) { failsafe++; if (failsafe > 120) { Log("Aborted randomization on too many passes. At the time, there were:"); Log("Unplaced transitions: " + tm.unplacedTransitions.Count); Log("Reachable transitions: " + tm.reachableTransitions.Count); Log("Reachable unplaced transitions, directionally compatible: " + tm.placeableCount); Log("Reachable item locations: " + im.availableCount); foreach (string t in tm.unplacedTransitions) { Log(t + ", in reachable: " + tm.reachableTransitions.Contains(t) + ", is reachable: " + tm.pm.CanGet(t)); } randomizationError = true; return; } if (im.canGuess && im.availableCount > 1) // give randomized progression as locations are available { if (im.FindNextLocation(tm.pm) is string placeLocation) { string placeItem = im.GuessItem(); im.PlaceItem(placeItem, placeLocation); tm.UpdateReachableTransitions(placeItem, true); } } int placeableCount = tm.placeableCount; if (placeableCount < 4) { tm.UpdateReachableTransitions(); } if (placeableCount == 0 && im.availableCount == 0) { Log("Ran out of locations?!?"); randomizationError = true; return; } else if (placeableCount > 2) { tm.UnloadReachableStandby(); string transition1 = tm.NextTransition(); string transition2 = tm.dt.GetNextTransition(transition1); tm.PlaceTransitionPair(transition1, transition2); //Log($">2 place: {transition1}, {transition2}"); continue; } else if (tm.unplacedTransitions.Count == 2) { string transition1 = tm.unplacedTransitions[0]; string transition2 = tm.unplacedTransitions[1]; tm.PlaceTransitionPair(transition1, transition2); //Log($"last place: {transition1}, {transition2}"); continue; } else if (placeableCount != 0) { if (tm.ForceTransition() is string transition1) { string transition2 = tm.dt.GetNextTransition(transition1); tm.PlaceTransitionPair(transition1, transition2); //Log($"force place: {transition1}, {transition2}"); continue; } } // Last ditch effort to save the seed. The list is ordered by which items are heuristically likely to unlock transitions at this point. if (im.FindNextLocation(tm.pm) is string lastLocation) { IEnumerable <string> progressionCandidates = new List <string> { "Mantis_Claw", "Monarch_Wings", "Left_Mantis_Claw", "Right_Mantis_Claw", "Desolate_Dive", "Isma's_Tear", "Crystal_Heart", "Mothwing_Cloak", "Shade_Cloak", "Right_Mothwing_Cloak", "Right_Shade_Cloak", "Left_Mothwing_Cloak", "Left_Shade_Cloak" } .Where(item => im.randomizedItems.Contains(item)); foreach (string item in progressionCandidates) { if (!tm.pm.Has(item)) { im.PlaceItem(item, lastLocation); tm.UpdateReachableTransitions(item, true); break; } } continue; } } Log("Placing last reserved transitions..."); tm.UnloadStandby(); Log("All transitions placed? " + (TransitionManager.transitionPlacements.Count == LogicManager.TransitionNames().Count(t => LogicManager.GetTransitionDef(t).oneWay != 2))); }
private static bool ValidateItemRandomization() { RandomizerMod.Instance.Log("Beginning item placement validation..."); if (im.randomizedLocations.Except(ItemManager.nonShopItems.Keys).Except(ItemManager.shopItems.Keys).Any()) { Log("Unable to validate!"); string m = "The following locations were not filled: "; foreach (string l in im.randomizedLocations.Except(ItemManager.nonShopItems.Keys).Except(ItemManager.shopItems.Keys)) { m += l + ", "; } Log(m); return(false); } ProgressionManager pm = new ProgressionManager( RandomizerState.Validating ); pm.Add(startProgression); HashSet <string> everything = new HashSet <string>(im.randomizedLocations.Union(vm.progressionLocations)); if (RandomizerMod.Instance.Settings.RandomizeTransitions) { everything.UnionWith(LogicManager.TransitionNames()); tm.ResetReachableTransitions(); tm.UpdateReachableTransitions(_pm: pm); } vm.ResetReachableLocations(false, pm); int passes = 0; while (everything.Any()) { if (RandomizerMod.Instance.Settings.RandomizeTransitions) { everything.ExceptWith(tm.reachableTransitions); } foreach (string location in im.randomizedLocations.Union(vm.progressionLocations).Where(loc => everything.Contains(loc) && pm.CanGet(loc))) { everything.Remove(location); if (LogicManager.ShopNames.Contains(location)) { if (ItemManager.shopItems.Keys.Contains(location)) { foreach (string newItem in ItemManager.shopItems[location]) { if (LogicManager.GetItemDef(newItem).progression) { pm.Add(newItem); if (RandomizerMod.Instance.Settings.RandomizeTransitions) { tm.UpdateReachableTransitions(newItem, true, pm); } } } } if (vm.progressionLocations.Contains(location)) { vm.UpdateVanillaLocations(location, false, pm); } } else if (vm.progressionLocations.Contains(location)) { vm.UpdateVanillaLocations(location, false, pm); } else if (LogicManager.GetItemDef(ItemManager.nonShopItems[location]).progression) { pm.Add(ItemManager.nonShopItems[location]); if (RandomizerMod.Instance.Settings.RandomizeTransitions) { tm.UpdateReachableTransitions(ItemManager.nonShopItems[location], true, pm); } } } passes++; if (passes > 400) { Log("Unable to validate!"); Log("Able to get items: " + pm.ListObtainedProgression() + Environment.NewLine + "Grubs: " + pm.obtained[LogicManager.grubIndex] + Environment.NewLine + "Essence: " + pm.obtained[LogicManager.essenceIndex]); string m = string.Empty; foreach (string s in everything) { m += s + ", "; } Log("Unable to get locations: " + m); LogItemPlacements(pm); return(false); } } //LogItemPlacements(pm); Log("Validation successful."); return(true); }
private static bool ValidateItemRandomization() { RandomizerMod.Instance.Log("Beginning item placement validation..."); if (im.randomizedLocations.Except(ItemManager.nonShopItems.Keys).Except(ItemManager.shopItems.Keys).Any()) { Log("Unable to validate!"); string m = "The following locations were not filled: "; foreach (string l in im.randomizedLocations.Except(ItemManager.nonShopItems.Keys).Except(ItemManager.shopItems.Keys)) { m += l + ", "; } Log(m); return(false); } /* * // Potentially useful debug logs * foreach (string item in ItemManager.GetRandomizedItems()) * { * if (ItemManager.nonShopItems.Any(kvp => kvp.Value == item)) * { * Log($"Placed {item} at {ItemManager.nonShopItems.First(kvp => kvp.Value == item).Key}"); * } * else if (ItemManager.shopItems.Any(kvp => kvp.Value.Contains(item))) * { * Log($"Placed {item} at {ItemManager.shopItems.First(kvp => kvp.Value.Contains(item)).Key}"); * } * else LogError($"Unable to find where {item} was placed."); * } * foreach (string location in ItemManager.GetRandomizedLocations()) * { * if (ItemManager.nonShopItems.TryGetValue(location, out string item)) * { * Log($"Filled {location} with {item}"); * } * else if (ItemManager.shopItems.ContainsKey(location)) * { * Log($"Filled {location}"); * } * else LogError($"{location} was not filled."); * } */ ProgressionManager pm = new ProgressionManager( RandomizerState.Validating ); pm.Add(startProgression); HashSet <string> locations = new HashSet <string>(im.randomizedLocations.Union(vm.progressionLocations)); HashSet <string> transitions = new HashSet <string>(); HashSet <string> items = ItemManager.GetRandomizedItems(); items.ExceptWith(startItems); if (RandomizerMod.Instance.Settings.RandomizeTransitions) { transitions.UnionWith(LogicManager.TransitionNames()); tm.ResetReachableTransitions(); tm.UpdateReachableTransitions(_pm: pm); } vm.ResetReachableLocations(false, pm); int passes = 0; while (locations.Any() || items.Any() || transitions.Any()) { if (RandomizerMod.Instance.Settings.RandomizeTransitions) { transitions.ExceptWith(tm.reachableTransitions); } foreach (string location in locations.Where(loc => pm.CanGet(loc)).ToList()) { locations.Remove(location); if (vm.progressionLocations.Contains(location)) { vm.UpdateVanillaLocations(location, false, pm); } if (ItemManager.nonShopItems.TryGetValue(location, out string item)) { items.Remove(item); if (LogicManager.GetItemDef(item).progression) { pm.Add(item); if (RandomizerMod.Instance.Settings.RandomizeTransitions) { tm.UpdateReachableTransitions(item, true, pm); } } } else if (ItemManager.shopItems.TryGetValue(location, out List <string> shopItems)) { foreach (string newItem in shopItems) { items.Remove(newItem); if (LogicManager.GetItemDef(newItem).progression) { pm.Add(newItem); if (RandomizerMod.Instance.Settings.RandomizeTransitions) { tm.UpdateReachableTransitions(newItem, true, pm); } } } } else if (!vm.progressionLocations.Contains(location)) { Log("Unable to validate!"); Log($"Location {location} did not correspond to any known placement."); return(false); } } passes++; if (passes > 400) { Log("Unable to validate!"); Log("Progression: " + pm.ListObtainedProgression() + Environment.NewLine + "Grubs: " + pm.obtained[LogicManager.grubIndex] + Environment.NewLine + "Essence: " + pm.obtained[LogicManager.essenceIndex]); string m = string.Empty; foreach (string s in items) { m += s + ", "; } Log("Unable to get items: " + m); m = string.Empty; foreach (string s in locations) { m += s + ", "; } Log("Unable to get locations: " + m); m = string.Empty; foreach (string s in transitions) { m += s + ","; } Log("Unable to get transitions: " + m); LogItemPlacements(pm); return(false); } } //LogItemPlacements(pm); Log("Validation successful."); return(true); }