示例#1
0
    public override IEnumerator Search(List <Node> nodes, int size, Node start, Node goal, int framesPerSecond)
    {
        IsSearching = true;
        Debug.LogFormat("Searching path using A* algorythm");
        bool hasPath = false;

        bool[,] visited = new bool[size, size];
        cameFrom        = new Dictionary <Node, Node> ();
        List <NodeDistance> frontier = new List <NodeDistance> ();
        Node  current = new Node();
        float pathLength;

        frontier.Add(new NodeDistance(start, 0 + Mathf.Abs(Vector2.Distance(start.pos, goal.pos))));
        cameFrom[start] = null;
        visited[(int)start.pos.x, (int)start.pos.y] = true;


        while (frontier.Count > 0)
        {
            current    = frontier[0].node;
            pathLength = frontier[0].distance - Mathf.Abs(Vector2.Distance(current.pos, goal.pos));
            frontier.RemoveAt(0);

            UIUpdate(frontier.Count, pathLength, Mathf.Abs(Vector2.Distance(current.pos, goal.pos)) + pathLength);

            //visualize path to current
            GraphSearcher.VisualizePath(cameFrom, current, start);
            yield return(new WaitForSeconds(1f / framesPerSecond));

            if (current == goal)
            {
                hasPath = true;
                break;
            }

            //get the maxNodes nodes closest to the objective and keep them.
            for (int i = 0; i < current.links.Count; i++)
            {
                Node neighbour = current.links[i];

                if (!visited[(int)neighbour.pos.x, (int)neighbour.pos.y])
                {
                    visited[(int)neighbour.pos.x, (int)neighbour.pos.y] = true;

                    cameFrom[neighbour] = current;
                    float totalDistance = pathLength + Mathf.Abs(Vector2.Distance(neighbour.pos, current.pos)) + Mathf.Abs(Vector2.Distance(neighbour.pos, goal.pos));
                    frontier.Add(new NodeDistance(neighbour, totalDistance));
                    UIIncrementEnqueuings();
                }

                frontier.Sort();
            }
        }

        SearchComplete(hasPath);
        yield break;
    }
示例#2
0
    public override IEnumerator Search(List <Node> nodes, int size, Node start, Node goal, int framesPerSecond)
    {
        IsSearching = true;
        Debug.Log("Searching path using Breadth First Search algorythm.");
        bool hasPath = false;

        bool[,] visited = new bool[size, size];
        cameFrom        = new Dictionary <Node, Node> ();
        Queue <Node> frontier = new Queue <Node> ();
        Node         current  = new Node();

        frontier.Enqueue(start);
        cameFrom[start] = null;
        visited[(int)start.pos.x, (int)start.pos.y] = true;

        while (frontier.Count > 0)
        {
            current = frontier.Dequeue();

            UIUpdate(frontier.Count, CalculatePathLength(start, current));

            //visualize path to current
            GraphSearcher.VisualizePath(cameFrom, current, start);
            yield return(new WaitForSeconds(1f / framesPerSecond));

            if (current == goal)
            {
                hasPath = true;
                break;
            }

            for (int i = 0; i < current.links.Count; i++)
            {
                Node neighbour = current.links[i];

                if (neighbour == current)
                {
                    Debug.LogErrorFormat("node {0} has link to itself.", current);
                }

                if (!visited[(int)neighbour.pos.x, (int)neighbour.pos.y])
                {
                    visited[(int)neighbour.pos.x, (int)neighbour.pos.y] = true;

                    cameFrom[neighbour] = current;
                    frontier.Enqueue(neighbour);
                    UIIncrementEnqueuings();
                }
            }
        }

        SearchComplete(hasPath);
        yield break;
    }
示例#3
0
 private void Awake()
 {
     if (instance == null)
     {
         instance = FindObjectOfType <GraphSearcher> ();
     }
     if (instance != this)
     {
         Destroy(instance.gameObject);
     }
 }
        public void MemberWithConverterType_IsColumnMember()
        {
            var config = new ConversionConfiguration();

            config.AddConvertor(new ValueConverter <Id <SingleProperty>, int>(model => model.Value, provider => (Id <SingleProperty>)provider));
            var searcher = new GraphSearcher(config);
            var graph    = searcher.SearchGraph(typeof(SingleProperty));

            graph.Nodes.Should().ContainSingle()
            .Which.ColumnMembers.Should().ContainSingle(x => x.Name == nameof(SingleProperty.Id) && ((PropertyInfo)x).PropertyType == typeof(Id <SingleProperty>));
        }
示例#5
0
    private void ClearPreviousMap()
    {
        GraphSearcher.ResetAllPaths();

        foreach (Transform child in transform)
        {
            GameObject.Destroy(child.gameObject);
        }

        Node.ResetIDs();
    }
示例#6
0
        public void PrimitiveTypeAsRoot_WillBeEmptyGraph()
        {
            var primitiveType = typeof(int);
            var config        = new ConversionConfiguration
            {
                IsAllowedForColumn = x => x == primitiveType,
            };
            var searcher = new GraphSearcher(config);
            var graph    = searcher.SearchGraph(primitiveType);

            graph.Nodes.Should().BeEmpty();
        }
示例#7
0
        public void CyclicGraphs_DontCauseEndlessRecursion()
        {
            var primitiveType = typeof(int);
            var config        = new ConversionConfiguration
            {
                IsAllowedForColumn          = x => false,
                ShouldMediateTargetProperty = x => true,
            };
            var searcher = new GraphSearcher(config);
            var graph    = searcher.SearchGraph(typeof(CycleLink1));

            graph.Nodes.Select(_ => _.Type).Should().Contain(new[] { typeof(CycleLink1), typeof(CycleLink2) });
        }
示例#8
0
        public void TryingToSearchMoreThanMaxLevelDeep_ThrowsSanityException()
        {
            var primitiveType = typeof(int);
            var config        = new ConversionConfiguration
            {
                IsAllowedForColumn          = x => false,
                ShouldMediateTargetProperty = x => true,
                MaxRecursion = 0,
            };
            var searcher = new GraphSearcher(config);

            searcher.Invoking(x => x.SearchGraph(typeof(Outer)))
            .Should().Throw <SanityException>().WithMessage("*recursion limit*");
        }
示例#9
0
        internal void AddGoalNodes(GraphSearchData gsData, Level level, Entity exceptThisGoal, HashSet <Goal> solvedGoals)
        {
            foreach (var node in Nodes)
            {
                if (node is BoxConflictNode boxNode)
                {
                    level.AddWall(boxNode.Value.Ent.Pos);
                }
            }

            var goalCondition = new Func <(Point pos, int distance), GraphSearcher.GoalFound <(Point pos, int distance)> >(x =>
            {
                return(new GraphSearcher.GoalFound <(Point, int)>(x, PositionHasNode(x.pos)));
            });

            foreach (var goal in level.Goals)
            {
                if (solvedGoals.Contains(goal))
                {
                    continue;
                }
                if (goal.Ent == exceptThisGoal)
                {
                    continue;
                }

                BoxConflictNode node = new BoxConflictNode(new EntityNodeInfo(goal.Ent, goal.EntType));

                List <(Point pos, int distance)> edges = GraphSearcher.GetReachedGoalsBFS(gsData, level, goal.Ent.Pos, goalCondition);
                foreach (var edge in edges.Distinct())
                {
                    if (GetNodeFromPosition(edge.pos) is BoxConflictNode boxEnd)
                    {
                        node.AddEdge(new Edge <DistanceEdgeInfo>(boxEnd, new DistanceEdgeInfo(edge.distance)));
                        boxEnd.AddEdge(new Edge <DistanceEdgeInfo>(node, new DistanceEdgeInfo(edge.distance)));
                    }
                    else if (GetNodeFromPosition(edge.pos) is FreeSpaceNode freeEnd)
                    {
                        node.AddEdge(new Edge <DistanceEdgeInfo>(freeEnd, new DistanceEdgeInfo()));
                        freeEnd.AddEdge(new Edge <DistanceEdgeInfo>(node, new DistanceEdgeInfo()));
                    }
                }

                Nodes.Add(node);
            }

            level.ResetWalls();
        }
示例#10
0
        public void SelectWithMultiplePropertyChain_IsProperlyMaterialized()
        {
            using (var connection = new SQLiteConnection("data source=:memory:"))
            {
                connection.Open();
                using (var ctx = new OrderContext(connection))
                {
                    var order = new Order
                    {
                        Items = new List <OrderItem>
                        {
                            new OrderItem
                            {
                                Product = new Product {
                                    Name = "Diapers", Cost = 10.0m
                                },
                                Quantity = 5,
                            },
                            new OrderItem
                            {
                                Product = new Product {
                                    Name = "Baby formula", Cost = 50m
                                },
                                Quantity = 3,
                            },
                        },
                    };
                    ctx.Orders.Add(order);
                    ctx.SaveChanges();

                    var config = new ConversionConfiguration()
                    {
                        IsAllowedForColumn = x => x.IsValueType || x == typeof(string),
                    };
                    var searcher       = new GraphSearcher(config);
                    var graph          = searcher.SearchGraph(typeof(B));
                    var mediatorMapper = new MediatorTypeBuilder().CreateMediatorTypes(graph);
                    var result         = ctx.OrderItems.ProjectToList(
                        x => new B
                    {
                        ProductCost = x.Product.Cost,
                    },
                        mediatorMapper);
                    result.Select(x => x.ProductCost).Should().BeEquivalentTo(10m, 50m);
                }
            }
        }
示例#11
0
        public void PropertiesMaterializedFromDbColumnAreAlwaysAllowed()
        {
            var originType    = typeof(Outer);
            var primitiveType = new Outer().Primitive.GetType();
            var config        = new ConversionConfiguration
            {
                IsAllowedForColumn          = x => x == primitiveType,
                ShouldMediateTargetProperty = x => false,
            };
            var searcher = new GraphSearcher(config);
            var graph    = searcher.SearchGraph(originType);

            graph.Nodes.Should().ContainSingle()
            .Which.Type.Should().Be(originType);
            graph.Nodes.Single().ColumnMembers
            .Should().Equal(typeof(Outer).GetProperty(nameof(Outer.Primitive)));
        }
示例#12
0
        private void AssertTargetToMediator <TParameter, TResult>(
            Expression <Func <TParameter, TResult> > projection,
            string resultTargetToMediator)
        {
            var config = new ConversionConfiguration()
            {
                IsAllowedForColumn = x => x.IsValueType || x == typeof(string),
            };
            var searcher = new GraphSearcher(config);
            var graph    = searcher.SearchGraph(typeof(TResult));

            var mediatorMapper = new MediatorTypeBuilder().CreateMediatorTypes(graph);

            var targetToMediatorVisitor = new TargetToMediatorVisitor(mediatorMapper);
            var result = targetToMediatorVisitor.Visit(projection);

            result.ToString("C#").Should().Be(resultTargetToMediator.Trim());
        }
示例#13
0
        public void GraphHasMultipleLevels_AllAreFound()
        {
            var originType = typeof(Outer);
            var config     = new ConversionConfiguration
            {
                IsAllowedForColumn          = x => x.IsPrimitive,
                ShouldMediateTargetProperty = x => true,
            };
            var searcher = new GraphSearcher(config);
            var graph    = searcher.SearchGraph(originType);

            graph.Nodes.Select(x => x.Type).Should().BeEquivalentTo(typeof(Outer), typeof(Inner), typeof(Innermost));
            var outerNode     = graph.Nodes.Single(x => x.Type == typeof(Outer));
            var innerNode     = graph.Nodes.Single(x => x.Type == typeof(Inner));
            var innermostNode = graph.Nodes.Single(x => x.Type == typeof(Innermost));

            graph.Edges.Should().BeEquivalentTo(
                new Edge(outerNode, innerNode, typeof(Outer).GetProperty(nameof(Outer.Inner))),
                new Edge(innerNode, innermostNode, typeof(Inner).GetProperty(nameof(Inner.Innermost))));
        }
示例#14
0
        // A bit of explanation on the convert method
        // It is using a simple dijkstra algorithm to find the shortest path
        // The set of conversion rates being represented as a graph
        // It is using decimals for representing the numbers, which limits funny behaviors regarding float/double precision
        // Finally, it's converting the rates into integer so that it makes it much easier to round to the 4th decimal
        // You just need to always keep in mind to divide by 10 000 when necessary
        // But rounding to the nearest integer gives you automatically the proper adjustment (in particular for the inverse of rates)
        private static string convert(string toConvert, List<string> rates)
        {
            string[] splitConvertTo = toConvert.Split(SEPARATOR);
            if(splitConvertTo.Length != 3) {
                return "Invalid line describing the conversion to be done";
            }
            string fromCurrency = splitConvertTo[FROM_CURRENCY_POSITION];
            decimal originalAmount = 0;
            // Code is running on a French server, so numbers with . were probably creating a problem since, my guess is that it was using a French CultureInfo
            if (!decimal.TryParse(splitConvertTo[ORIGINAL_AMOUNT_POSITION], System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture.NumberFormat, out originalAmount))
            {
                return "Invalid line describing the conversion to be done";
            }
            string toCurrency = splitConvertTo[TO_CURRENCY_POSITION];
            GraphSearcher helper = new GraphSearcher();
            foreach (string rateDescription in rates)
            {
                string[] splitRateDescription = rateDescription.Split(SEPARATOR);
                string fromRateCurrency = splitRateDescription[RATE_FROM_CURRENCY_POSITION];
                string toRateCurrency = splitRateDescription[RATE_TO_CURRENCY_POSITION];
                string rateAsString = splitRateDescription[RATE_POSITION];
                // Code is running on a French server, so numbers with . were probably creating a problem since, my guess is that it was using a French CultureInfo
                decimal rateAsDouble = decimal.Parse(rateAsString, System.Globalization.CultureInfo.InvariantCulture.NumberFormat);

                decimal rate = decimal.Round(rateAsDouble * PRECISION);
                //We make sure our inverse rate is rounded to the 4th decimal
                decimal inverseRate = decimal.Round((PRECISION / rateAsDouble));

                helper.addEdge(fromRateCurrency, toRateCurrency, rate);
                helper.addEdge(toRateCurrency, fromRateCurrency, inverseRate);
            }

            decimal convertedValue = originalAmount;
            foreach (decimal rate in helper.getShortestPath(fromCurrency, toCurrency))
            {
                convertedValue = convertedValue * (rate / PRECISION);
            }
            convertedValue = decimal.Round(convertedValue);
            return string.Format("{0:0}",convertedValue);
        }
示例#15
0
        public Maze(FPseudoRandom random,
                    FVec3 scale, FVec3 offset, int row, int col,
                    int startIndex, int endIndex, FVec2 startPointPlace)
        {
            this.startPointPlace = startPointPlace;
            if (this.row < ( int )this.startPointPlace.y + 3 ||
                this.col < ( int )this.startPointPlace.x + 3)
            {
                throw new Exception("The row or col invaild");
            }

            this.scale  = scale;
            this.offset = offset;
            this.row    = row;
            this.col    = col;

            this._localToWorld = FMat4.FromTRS(this.offset, FQuat.identity, this.scale);
            this._worldToLocal = FMat4.NonhomogeneousInverse(this._localToWorld);

            //创建二维图
            Graph2D graph2 = this.CreateFullDigraph(random);

            //创建格子
            this.CreateTiles(graph2);

            //是否随机起点和终点
            this.startIndex = startIndex < 0 ? this.RandomIndexWithinBorder(random) : startIndex;
            if (endIndex < 0)
            {
                int[] candidate = new int[5];
                for (int i = 0; i < 5; i++)
                {
                    candidate[i] = this.RandomIndexWithinBorder(random);
                }
                endIndex = this.GetFarthestToStartIndex(this.startIndex, candidate);
            }
            this.endIndex = endIndex;

            //初始化起点范围
            HashSet <int> walkablesHs = new HashSet <int>();

            this.SetStart(graph2, this.startIndex, walkablesHs);

            //创建起点和终点
            int[]            coord       = graph2.IndexToCoord(this.startIndex);
            Delaunay.DVertex startVertex = new Delaunay.DVertex(coord[0], coord[1]);
            coord = graph2.IndexToCoord(this.endIndex);
            Delaunay.DVertex endVertex = new Delaunay.DVertex(coord[0], coord[1]);
            //创建外圆周附近的顶点
            List <Delaunay.DVertex> vertices1 = this.GenVertices(24, 1f, 0.8f, 24, random);
            //创建内圆周附近的顶点
            List <Delaunay.DVertex> vertices2 = this.GenVertices(12, 0.2f, 0.6f, 12, random);
            //合并所有顶点
            List <Delaunay.DVertex> vertices = new List <Delaunay.DVertex> {
                startVertex, endVertex
            };

            vertices.AddRange(vertices1);
            vertices.AddRange(vertices2);

            //点集合的三角化
            List <Delaunay.DTriangle> triangles = Delaunay.Triangulate(vertices);

            //从三角形集合创建图
            GraphBase graph = Tools.TrianglesToGraph(triangles, random.NextFloat);
            //Prim算法创建最小生成树
            List <GraphEdge> edges = GraphSearcher.PrimSearch(graph, triangles[0].v0);

            //每条边用A*算法生成路径
            int count = edges.Count;

            for (int i = 0; i < count; i++)
            {
                GraphEdge        edge = edges[i];
                Delaunay.DVertex v0   = vertices[edge.from];
                Delaunay.DVertex v1   = vertices[edge.to];
                int[]            path = GraphSearcher.AStarSearch(graph2, graph2.CoordToIndex(( int )v0.x, ( int )v0.y),
                                                                  graph2.CoordToIndex(( int )v1.x, ( int )v1.y));
                this.SetPathWalkable(path, walkablesHs);

                //把顶点扩展成房间
                if (i == 0)
                {
                    this.SetIndexToWalkable(graph2, ( int )v0.x, ( int )v0.y, random.Next(1, 3), random.Next(1, 3), walkablesHs);
                }
                this.SetIndexToWalkable(graph2, ( int )v1.x, ( int )v1.y, random.Next(1, 3), random.Next(1, 3), walkablesHs);
            }

            this.walkables = walkablesHs.ToArray();
        }
示例#16
0
    public override IEnumerator Search(List <Node> nodes, int size, Node start, Node goal, int framesPerSecond)
    {
        IsSearching = true;
        Debug.Log("Searching path using Hill Climbing algorythm.");
        bool hasPath = false;

        bool[,] visited = new bool[size, size];
        cameFrom        = new Dictionary <Node, Node> ();
        Stack <Node> frontier = new Stack <Node> ();
        Node         current  = new Node();

        frontier.Push(start);
        cameFrom[start] = null;

        while (frontier.Count > 0)
        {
            current = frontier.Pop();

            UIUpdate(frontier.Count, CalculatePathLength(start, current));

            //visualize path to current
            GraphSearcher.VisualizePath(cameFrom, current, start);
            yield return(new WaitForSeconds(1f / framesPerSecond));

            if (current == goal)
            {
                hasPath = true;
                break;
            }

            float closestDistance  = Vector2.Distance(current.pos, goal.pos);
            Node  closestNeighbour = null;
            for (int i = 0; i < current.links.Count; i++)
            {
                Node neighbour = current.links[i];

                // test shortest path
                float neighbourDist = Vector2.Distance(neighbour.pos, goal.pos);
                if (neighbourDist < closestDistance || closestDistance == float.MaxValue)
                {
                    closestNeighbour = neighbour;
                    closestDistance  = neighbourDist;
                }
            }

            // extend path
            if (closestNeighbour != null)
            {
                if (!visited[(int)closestNeighbour.pos.x, (int)closestNeighbour.pos.y])
                {
                    visited[(int)closestNeighbour.pos.x, (int)closestNeighbour.pos.y] = true;

                    cameFrom[closestNeighbour] = current;
                    frontier.Push(closestNeighbour);
                    UIIncrementEnqueuings();
                }
            }
            else
            {
                Debug.LogFormat("Stuck in local maxima. node {0}", current.ID);
            }
        }

        SearchComplete(hasPath);
        yield break;
    }
示例#17
0
        internal void AddFreeSpaceNodes(GraphSearchData gsData, Level level)
        {
            //
            //All entities need to be made into walls so the only freepsace is space
            //that won't block the path or be on top of other entities.
            //

            HashSet <Point> agentPositions = new HashSet <Point>();

            foreach (var inode in Nodes)
            {
                if (inode is BoxConflictNode boxNode)
                {
                    level.Walls[boxNode.Value.Ent.Pos.X, boxNode.Value.Ent.Pos.Y] = true;
                    if (boxNode.Value.EntType == EntityType.AGENT)
                    {
                        agentPositions.Add(boxNode.Value.Ent.Pos);
                    }
                }
            }


            //
            //Now go through the map and and find all empty spaces. When an empty space is found, bfs is used to
            //find all connecting spaces which makes up the free space node.
            //

            var foundFreeSpace = new Func <(Point pos, int distance), GraphSearcher.GoalFound <Point> >(x =>
            {
                return(new GraphSearcher.GoalFound <Point>(x.pos, !level.IsWall(x.pos)));
            });
            HashSet <Point>      alreadySeenSpaces = new HashSet <Point>();
            List <FreeSpaceNode> freeSpaceNodes    = new List <FreeSpaceNode>();

            for (int y = 0; y < level.Height; y++)
            {
                for (int x = 0; x < level.Width; x++)
                {
                    if (!level.Walls[x, y] && !alreadySeenSpaces.Contains(new Point(x, y)))
                    {
                        //There is an issue here.
                        //The list has a duplicate in it.
                        //It's currently handled by inserting it
                        //into a hashset.
                        var freeSpacesFound = GraphSearcher.GetReachedGoalsBFS(gsData, level, new Point(x, y), foundFreeSpace);

                        //A single free space can't be part of multiple nodes
                        alreadySeenSpaces.UnionWith(freeSpacesFound);

                        //Create node and add it to the graph.
                        //keep a list of the freespace nodes so edges can be added later
                        var newFreeSpaceNode = new FreeSpaceNode(new FreeSpaceNodeInfo(freeSpacesFound));
                        AddNode(newFreeSpaceNode);
                        freeSpaceNodes.Add(newFreeSpaceNode);
                    }
                }
            }


            //
            //Now it's time to add edges between the free spaces nodes and the rest of the graph.
            //To do that the original map has to be restored as the path may block pathways from
            //a freespace to any other node on the map. Agents and boxes still have to be walls
            //as there is no direct path through them. This excludes goals as only goals with
            //boxes on them should be walls and the boxes on top of them will makes them walls.
            //Go through all free space nodes and use bfs to check which other nodes it can reach,
            //then add edges to those nodes.
            //

            level.ResetWalls();
            foreach (var inode in Nodes)
            {
                if (inode is BoxConflictNode boxNode && !boxNode.Value.EntType.IsGoal())
                {
                    level.Walls[boxNode.Value.Ent.Pos.X, boxNode.Value.Ent.Pos.Y] = true;
                }
            }

            var foundNode = new Func <(Point pos, int distance), GraphSearcher.GoalFound <INode> >(x =>
            {
                if (PositionToNode.TryGetValue(x.pos, out INode node))
                {
                    return(new GraphSearcher.GoalFound <INode>(node, true));
                }
                return(new GraphSearcher.GoalFound <INode>(null, false));
            });

            foreach (var freeSpaceNode in freeSpaceNodes)
            {
                var nodesFound = GraphSearcher.GetReachedGoalsBFS(gsData, level, freeSpaceNode.Value.FreeSpaces.First(), foundNode);
                foreach (var neighbour in nodesFound.ToHashSet())
                {
                    //The search may find itself and such edges are not necessary
                    if (neighbour != freeSpaceNode)
                    {
                        //Bidirectional edges
                        freeSpaceNode.AddEdge(new Edge <DistanceEdgeInfo>(neighbour, new DistanceEdgeInfo()));
                        if (neighbour is BoxConflictNode boxNode)
                        {
                            boxNode.AddEdge(new Edge <DistanceEdgeInfo>(freeSpaceNode, new DistanceEdgeInfo()));
                        }
                        else if (neighbour is FreeSpaceNode freeNode)
                        {
                            freeNode.AddEdge(new Edge <DistanceEdgeInfo>(freeSpaceNode, new DistanceEdgeInfo()));
                        }
                    }
                }
            }
            level.ResetWalls();

            foreach (var agentPos in agentPositions)
            {
                foreach (var dirDelta in Direction.NONE.DirectionDeltas())
                {
                    Point nextToAgent = agentPos + dirDelta;
                    if (PositionHasNode(nextToAgent))
                    {
                        INode node = GetNodeFromPosition(nextToAgent);
                        if (node is FreeSpaceNode freeSpaceNode)
                        {
                            freeSpaceNode.Value.FreeSpaces.Add(agentPos);
                            continue;
                        }
                    }
                }
            }
        }