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); }