Exemple #1
0
            internal static TraversalNode MakeRoot(TrieNode currentNode)
            {
                var root = new TraversalNode();

                root.IsRoot = true;
                root.Depth  = -1;
                return(root);
            }
Exemple #2
0
        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);
    }