internal static TraversalNode MakeRoot(TrieNode currentNode) { var root = new TraversalNode(); root.IsRoot = true; root.Depth = -1; return(root); }
public IEnumerable <string> GetWordsByPrefix(string prefix) { if (!TryGetNodeByPrefix(prefix, out TrieNode currentNode)) { yield break; } var wordBuilder = new StringBuilder(100); if (prefix.Length > 0) { wordBuilder.Append(prefix, 0, prefix.Length - 1); } _traversalStack.Clear(); if (prefix.Length > 0) { char lastLetter = prefix[prefix.Length - 1]; _traversalStack.Push(new TraversalNode(currentNode, prefix.Length - 1, lastLetter)); } else { _traversalStack.Push(TraversalNode.MakeRoot(currentNode)); } while (_traversalStack.Count > 0) { var traversalNode = _traversalStack.Pop(); int currentDepth = traversalNode.Depth; if (!traversalNode.IsRoot) { currentNode = traversalNode.Node; if (wordBuilder.Length > currentDepth) { wordBuilder.Remove(currentDepth, wordBuilder.Length - currentDepth); } wordBuilder.Append(traversalNode.Letter); if (currentNode.IsEOW) { yield return(wordBuilder.ToString()); } } LoadChildren(currentDepth, currentNode); } }
/// <summary> /// Create a level element and recursively create elements for its children /// </summary> /// <param name="node"></param> /// <param name="grid"></param> private void CreateLevelElement(TraversalNode node, Grid2D <LevelElement> grid) { var split = node._split; var xOffset = split._rect.position.x; var yOffset = split._rect.position.y; for (var x = 1; x < split._rect.width; ++x) { for (var y = 1; y < split._rect.height; ++y) { grid[x + xOffset, y + yOffset]._id = LevelElementDefinitions.FloorTileIndex; } } // Draw some borders around the bottom and left part of the rect. We draw a wall on // two sides only so we draw a wall one thick in every room. A separate step // is required to draw the other walls iff necessary because children may surround this border var p1 = split._rect.position; var p2 = split._rect.position + new Vector2Int(split._rect.width, 0); var p3 = split._rect.position + new Vector2Int(0, split._rect.height); grid.TraceLine(p1, p2, (x, y, g) => grid[x, y]._id = LevelElementDefinitions.HorizontalWallIndex); grid.TraceLine(p1 + Vector2Int.up, p3, (x, y, g) => grid[x, y]._id = LevelElementDefinitions.VerticalWallIndex); if (node._parent != null) { // draw a doorway to the parent's room DrawDoorWay(node, node._parent, node._parentIntersection, grid); } // recursively draw the level element for each child node._children.ForEach((child) => { DrawDoorWay(node, child, child._parentIntersection, grid); CreateLevelElement(child, grid); }); // draw an exit if this is the last room on the primary path if (node._children.Count == 0 && node._isPrimaryPath) { var center = node._split._rect.center; grid[(int)center.x, (int)center.y]._id = LevelElementDefinitions.ExitIndex; } }
/// <summary> /// Last step of creating a grid, fill out the /// </summary> /// <param name="node"></param> /// <param name="grid"></param> private void TraceRoomBorders(TraversalNode node, Grid2D <LevelElement> grid) { var x1 = node._split._rect.min.x; var x2 = node._split._rect.max.x; var y1 = node._split._rect.min.y; var y2 = node._split._rect.max.y; // if we're at the top of the grid, slightly tweak the offset and adjust the condition for // drawing a wall var isAboveGrid = (y2 >= grid.Height); var offset = isAboveGrid ? -1 : 0; var condition = isAboveGrid ? LevelElementDefinitions.FloorTileIndex : LevelElementDefinitions.None; // trace the top left to the top right for (var x = x1; x <= x2; x++) { var y = y2 + offset; if (grid.IsOnGrid(x, y) && grid[x, y]._id == condition) { grid[x, y]._id = LevelElementDefinitions.HorizontalWallIndex; } } var isRightOfGrid = (x2 >= grid.Width); offset = isRightOfGrid ? -1 : 0; condition = isRightOfGrid ? LevelElementDefinitions.FloorTileIndex : LevelElementDefinitions.None; // trace the top right to the bottom right for (var y = y1; y < y2; y++) { var x = x2 + offset; if (grid.IsOnGrid(x, y) && grid[x, y]._id == condition) { grid[x, y]._id = LevelElementDefinitions.VerticalWallIndex; } } node._children.ForEach((c) => TraceRoomBorders(c, grid)); }
/// <summary> /// Draw a doorway between the parent and child /// </summary> /// <param name="parent"></param> /// <param name="child"></param> /// <param name="intersection"></param> /// <param name="grid"></param> private void DrawDoorWay(TraversalNode parent, TraversalNode child, Vector2Int[] intersection, Grid2D <LevelElement> grid) { var x1 = intersection[0].x; var x2 = intersection[1].x; var y1 = intersection[0].y; var y2 = intersection[1].y; // vertical intersection with child on the left side ? if (x1 == x2 && x1 <= parent._split._rect.min.x) { grid[x1, y1 + (y2 - y1) / 2]._id = LevelElementDefinitions.FloorTileIndex; } // horizontal intersection with child the bottom side ? else if (y1 == y2 && y1 <= parent._split._rect.min.y) { grid[x1 + (x2 - x1) / 2, y1]._id = LevelElementDefinitions.FloorTileIndex; } }
/// <summary> /// Build a 2d grid of level elements of the given dimensions and the traversal path /// </summary> /// <param name="width"></param> /// <param name="height"></param> /// <param name="pathRoot"></param> /// <returns></returns> public Grid2D <LevelElement> BuildLevelGrid(int width, int height, TraversalNode pathRoot) { // fill the grid with tiles var grid = new Grid2D <LevelElement>(width, height, () => new LevelElement() { _id = LevelElementDefinitions.None, // pre-select a randomized value so the sprite variations can easily pick a random sprite / color _randomRoll = UnityEngine.Random.Range(0, 256 * 256) }); // recursively build out the level starting from the root CreateLevelElement(pathRoot, grid); // draw an outline around the "rooms" (rects) in the level that do not have an outline TraceRoomBorders(pathRoot, grid); return(grid); }
public int NumBusesToDestination(int[][] routes, int S, int T) { if (routes == null || routes.Length == 0) { return(-1); } if (S == T) { return(0); } // First let's get our routes into a data structure that lets // us perform faster lookups on stops. // We need to know a few things: // (1) What stop numbers does a bus stop at? // (2) Is a bus route connected to another by a stop? // To answer (1) we have the routes array. // To answer (2) we will store a dictionary of stop numbers with a HashSet of bus numbers. Dictionary <int, HashSet <int> > stopsToBus = BuildStopsToBus(routes); // Now, perform a BFS on the graph, starting at the stop S, until we hit the stop T. Queue <TraversalNode> traversal = new Queue <TraversalNode>(); HashSet <int> visitedStops = new HashSet <int>(); // We can prune paths that have cycles. // We are starting at Stop S, and we can start at any bus that has a stop there. foreach (int busId in stopsToBus[S]) { traversal.Enqueue(new TraversalNode(S, busId, 1)); } TraversalNode currStop = null; // Now, start our BFS search in the graph... // Each time we take a node, we should investigate a few things: // (1) Is the stop what we want? If so we're done! // (2) Where can we go from this stop? // - For this we have to look at a few things... // (a) stopsToBus will tell us every bus that stops at this stop. // (b) From there, we can search each subarray in routes to find the next stop // (c) And then Enqueue all these stops/buses up! // !! Making sure to increase the NumBusesSoFar on the node if we switch a bus! while (traversal.Count > 0) { currStop = traversal.Dequeue(); // Check if this bus has the stop on its route. If so, we're done! int stopIdx = Array.BinarySearch(routes[currStop.BusId], T); if (stopIdx >= 0) { currStop.StopId = T; break; } visitedStops.Add(currStop.StopId); // Get every bus that stops at this stop HashSet <int> busesThatStopHere = stopsToBus[currStop.StopId]; bool found = false; // Add all of the stops that this bus can make to the Queue // except for this particular stop (and any we've already visited). foreach (int busId in busesThatStopHere) { for (int i = 0; i < routes[busId].Length; i++) { if (visitedStops.Contains(routes[busId][i])) { continue; } // Add this potential edge to the Queue. TraversalNode newRide = new TraversalNode( routes[busId][i], busId, busId == currStop.BusId ? currStop.NumBusesSoFar : currStop.NumBusesSoFar + 1); traversal.Enqueue(newRide); } } } return((currStop != null && currStop.StopId == T) ? currStop.NumBusesSoFar : -1); }