Esempio n. 1
0
        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);
        }
Esempio n. 2
0
        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);
        }
Esempio n. 4
0
        // 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);
        }
Esempio n. 5
0
        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);
        }
Esempio n. 7
0
        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);
        }
Esempio n. 9
0
        // 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);
        }
Esempio n. 10
0
        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);
        }
Esempio n. 11
0
        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);
        }
Esempio n. 13
0
        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);
        }