private static IEnumerable <Transition> NullNeighborToTransitionMap(RoomVertex r)
 {
     return(r.Neighbors
            .Select((x, i) => x == null ? new int?(i) : null)
            .OfType <int>()
            .Select(x => r.room.Transitions[x]));
 }
        private void MakeGraph()
        {
            var root = new RoomVertex(_rooms.RemoveFirst(x => x.Name == "Tutorial_01"), "top1");

            PopulateTransitions(root);

            List <RoomVertex> neighborless = _vertices.Where(x => x != null && x.Neighbors.Any(n => n == null)).ToList();
            List <RoomVertex> leftover     = new List <RoomVertex>();

            while (neighborless.Count != 0)
            {
                RoomVertex node = neighborless.RandomRemove(_rand);

                for (int i = 0; i < node.Neighbors.Count; i++)
                {
                    if (node.Neighbors[i] != null)
                    {
                        continue;
                    }

                    Transition t = node.room.Transitions[i];

                    List <RoomVertex> validNeighbors = neighborless.Where(x => HasValidNullTransition(x, t.To)).ToList();

                    if (validNeighbors.Count == 0)
                    {
                        leftover.Add(node);

                        // Continuing only the inner loop because it's possible that some of the other transitions have valid neighbors
                        // This way we can still fill those and handle the leftovers.
                        continue;
                    }

                    RoomVertex neighbor = validNeighbors.Random(_rand);

                    Transition to = NullNeighborToTransitionMap(neighbor).First();

                    node.Neighbors.Add(new RoomVertex(neighbor.room, GetGate(neighbor.room, to.To)));
                }
            }

            // Left-overs with non-matching gates get redirected to kp
            foreach (RoomVertex rv in leftover)
            {
                for (int i = 0; i < rv.Neighbors.Count; i++)
                {
                    if (rv.Neighbors[i] != null)
                    {
                        continue;
                    }

                    string to = rv.room.Transitions[i].To;

                    if (to.StartsWith("left") || to.StartsWith("right"))
                    {
                        rv.Neighbors[i] = new RoomVertex(root.room, "right1");
                    }
                    else if (to.StartsWith("bot") || to.StartsWith("top"))
                    {
                        rv.Neighbors[i] = new RoomVertex(root.room, "top1");
                    }
                }
            }

            foreach (RoomVertex rv in _vertices)
            {
                foreach (RoomVertex neighbor in rv.Neighbors)
                {
                    if (neighbor == null)
                    {
                        Modding.Logger.LogError($"Neighbor for rv is null with rv {rv}");
                        continue;
                    }

                    Modding.Logger.Log($"Vertex {rv} to {neighbor}");
                }
            }

            /*
             * plan
             * Return bool
             * Check if any transition is available
             * Fill first transition which is available (or maybe use Random)?
             * Grab items at beginning of check like current method does
             * After all rooms have been connected (which are able to connect to the last point on the line **)
             * (**) Matching gates, use HasValidTransition
             * Link remains + all rooms on the line to each other creating 3d directed graph
             * Instead of checking for nulls, check for length of transitions != length of neighbors
             */
        }
 private static bool HasValidNullTransition(RoomVertex r, string from)
 {
     return(HasValidTransition(NullNeighborToTransitionMap(r), from));
 }
        private bool PopulateTransitions(RoomVertex node)
        {
            _vertices.Add(node);

            RefreshItems();

            _player.HasVisited(new TransitionInfo(node.Name, node.Entrance));

            bool foundTrans = false;

            foreach (Transition trans in node.room.Transitions)
            {
                Modding.Logger.Log($"Checking transition {trans.To} from entrance {node.Entrance}");

                if (!trans.IsAccessible(node.Entrance, _player) || _rooms.Count == 0)
                {
                    node.Neighbors.Add(null);
                    continue;
                }

getRoom:

                Modding.Logger.Log($"Transition {trans.To} is accessible!");

                /*
                 * TODO: In addition to a valid transition, room has to have *at least* 1 accessible transition
                 * TODO: otherwise "player" will softlock.
                 * TODO: Use of N-queens esque going back recursive method might be good
                 * This would entail returning bool instead of void if at least 1 transition is satisfied
                 * We may want to require or at least emphasize more than 1 transition as it could lead to a map where king's pass
                 * is the dominant reciever of most transitions.
                 */
                List <Room> validRooms = _rooms.Where(x => HasValidTransition(x, trans)).ToList();

                if (validRooms.Count == 0)
                {
                    node.Neighbors.Add(null);
                    continue;
                }

                Room random = validRooms.Random(_rand);

                var vertex = new RoomVertex(random, GetGate(random, trans.To));

                node.Neighbors.Add(vertex);

                if (PopulateTransitions(vertex))
                {
                    foundTrans = true;
                }
                else
                {
                    goto getRoom;
                }
            }

            // TODO: Move this into inner loop so that we can handle fake player "softlocks"
            // foreach (RoomVertex neighbor in node.Neighbors)
            // {
            //     if (neighbor == null) continue;

            //     Modding.Logger.LogWarn($"Populating neighbor {neighbor.Name} from entrance {neighbor.Entrance}");

            //     PopulateTransitions(neighbor);
            // }

            return(foundTrans);
        }