Example #1
0
        private async Task <IEnumerable <byte[]> > GetUniqueNodeCountsAsync(Shape shape)
        {
            const int ThreadCount = 1;

            var tableau = shape.CreateTableau();

            var terminalNodePairs = tableau.TerminalNodeUniqueCombinations()
                                    .GroupBy(nodePair => (TerminalNode)nodePair.Node1)
                                    .Select(grp => (
                                                startNode: grp.Key,
                                                endNodes: grp.Select(node => (TerminalNode)node.Node2).ToList()))
                                    .ToList();

            var jobSpecs = terminalNodePairs.Select(nodePair =>
                                                    new PathFinderJobSpec
            {
                Tableau     = tableau,
                Name        = nodePair.startNode.Index.ToString(),
                StartPoint  = nodePair.startNode,
                EndPoints   = nodePair.endNodes.ToList(),
                ThreadCount = ThreadCount
            }).ToList();

            var combinedNodeCounts = new Dictionary <byte[], int>(new ByteSequenceEqualEqualityComparer());
            var tokenSource        = new CancellationTokenSource();
            var tasks = new List <Task <(IDictionary <byte[], int>, PathFinderState)> >();

            foreach (var jobSpec in jobSpecs)
            {
                var pathFinderJob = new PathFinderJob(jobSpec);

                var pathFinderState = new PathFinderState
                {
                    Name     = jobSpec.Name,
                    Steps    = jobSpec.StartPoint.Links.Select(link => new Step(link.Value, link.Key)).ToList(),
                    Progress = new Progress()
                };

                tasks.Add(pathFinderJob.ExploreAsync(pathFinderState, tokenSource.Token));
            }

            await Task.WhenAll(tasks);

            foreach (var task in tasks)
            {
                var(nodeCounts, pathFinderState) = task.Result;

                foreach (var nodeCount in nodeCounts)
                {
                    if (!combinedNodeCounts.TryAdd(nodeCount.Key, nodeCount.Value))
                    {
                        combinedNodeCounts[nodeCount.Key] += nodeCount.Value;
                    }
                }
            }

            return(combinedNodeCounts
                   .Where(kv => kv.Value == 1)
                   .Select(kv => kv.Key));
        }
Example #2
0
    //TODO: Make this a Job
    private void Awake()
    {
        CurrentState = PathFinderState.StateIdle;

        PathNodeOpen   = new List <PathNode>();
        PathNodeClosed = new List <PathNode>();
        PathNodeFinal  = new List <PathNode>();
        AdjacentNodes  = new List <Tile>();
    }
Example #3
0
        public static async Task Main(string[] args)
        {
            Trace.Listeners.Add(new TextWriterTraceListener(Console.Out));

            if (!Directory.Exists(Configuration.FolderName))
            {
                Directory.CreateDirectory(Configuration.FolderName);
            }

            var shape           = GetShape(args);
            var tableau         = shape.CreateTableau();
            var concurrency     = GetConcurrency(args);
            var persistInterval = GetPersistInterval(args);

            var terminalNodePairs = tableau.TerminalNodeUniqueCombinations()
                                    .GroupBy(nodePair => (TerminalNode)nodePair.Node1)
                                    .Select(grp => (
                                                startNode: grp.Key,
                                                endNodes: grp.Select(node => (TerminalNode)node.Node2).ToList()))
                                    .ToList();

            foreach (var(startNode, endNodes) in terminalNodePairs)
            {
                Trace.WriteLine($"{startNode.Index}: {string.Join(", ", endNodes.Select(node => node.Index))}");
            }

            var jobs = new List <(PathFinderJob, PathFinderState)>();

            foreach (var(startNode, endNodes) in terminalNodePairs)
            {
                var jobAdded = false;
                var jobSpec  = new PathFinderJobSpec
                {
                    Name            = startNode.Index.ToString(),
                    Tableau         = tableau,
                    StartPoint      = startNode,
                    EndPoints       = endNodes,
                    ThreadCount     = concurrency,
                    MonitorInterval = persistInterval
                };

                if (persistInterval > TimeSpan.Zero)
                {
                    var saveFilePath = Configuration.Filename(shape, jobSpec.Name);
                    Trace.WriteLine($"Save file path: {saveFilePath}");

                    if (File.Exists(saveFilePath))
                    {
                        var savedState = RouteStateReaderWriter.ReadFromFile(saveFilePath);

                        if (savedState.Shape != shape.Name)
                        {
                            throw new Exception($"The shape {savedState.Shape} specfied in file '{saveFilePath}' does not match the expected value {shape.Name}.");
                        }

                        if (savedState.Size != shape.Size)
                        {
                            throw new Exception($"The size {savedState.Size} specfied in file '{saveFilePath}' does not match the expected value {shape.Size}.");
                        }

                        var endPoints = savedState.TerminalNodes
                                        .Select(index => tableau.TerminalNodes[index])
                                        .ToList();

                        var steps = new List <Step>();
                        var queue = new Queue <(Step step, int id)>();
                        var items = savedState.Steps.Where(x => x.PreviousId == 0).ToList();

                        foreach (var item in items)
                        {
                            var step = new Step(
                                node: tableau.Nodes[item.Position],
                                direction: new Direction(item.Direction));

                            queue.Enqueue((step, item.Id));
                        }

                        while (queue.Any())
                        {
                            var(previousStep, id) = queue.Dequeue();
                            items = savedState.Steps.Where(x => x.PreviousId == id).ToList();

                            if (items.Count == 0)
                            {
                                steps.Add(previousStep);
                                continue;
                            }

                            foreach (var item in items)
                            {
                                var direction = new Direction(item.Direction);
                                var twist     = direction - previousStep.Direction;

                                var step = new Step(
                                    node: tableau.Nodes[item.Position],
                                    direction: direction,
                                    twist: twist,
                                    previous: previousStep);

                                queue.Enqueue((step, item.Id));
                            }
                        }

                        var pathFinderJob   = new PathFinderJob(jobSpec); //TODO: paths
                        var pathFinderState = new PathFinderState
                        {
                            Name     = jobSpec.Name,
                            Steps    = steps,
                            Progress = savedState.Progress
                        };

                        jobs.Add((pathFinderJob, pathFinderState));
                        jobAdded = true;
                    }
                }

                if (!jobAdded)
                {
                    var pathFinderJob   = new PathFinderJob(jobSpec);
                    var pathFinderState = new PathFinderState
                    {
                        Name     = jobSpec.Name,
                        Steps    = startNode.Links.Select(link => new Step(link.Value, link.Key)).ToList(),
                        Progress = new Progress()
                    };

                    jobs.Add((pathFinderJob, pathFinderState));
                }
            }

            var tokenSource = new CancellationTokenSource();
            var tasks       = new List <Task <(IDictionary <byte[], int>, PathFinderState)> >();

            foreach (var(pathFinderJob, pathFinderState) in jobs)
            {
                tasks.Add(pathFinderJob.ExploreAsync(pathFinderState, tokenSource.Token));
            }

            await Task.WhenAll(tasks);

            var combinedElapsedTime = TimeSpan.Zero;
            var combinedRouteCount  = 0L;

            var combinedNodeCounts = new Dictionary <byte[], int>(new ByteSequenceEqualEqualityComparer());

            foreach (var task in tasks)
            {
                var(nodeCounts, pathFinderState) = task.Result;

                foreach (var nodeCount in nodeCounts)
                {
                    if (!combinedNodeCounts.ContainsKey(nodeCount.Key))
                    {
                        combinedNodeCounts.Add(nodeCount.Key, 0);
                    }

                    combinedNodeCounts[nodeCount.Key] += nodeCount.Value;
                }

                var uniqueSolutionCount = nodeCounts.Count(item => item.Value == 1);

                combinedRouteCount += pathFinderState.Progress.RouteCount;
                if (pathFinderState.Progress.ElapsedTime > combinedElapsedTime)
                {
                    combinedElapsedTime = pathFinderState.Progress.ElapsedTime;
                }

                Trace.WriteLine($"Result for job {pathFinderState.Name}: routes = {pathFinderState.Progress.RouteCount}, distinct solutions = {nodeCounts.Count}, unique solutions = {uniqueSolutionCount}, elapsed time = {pathFinderState.Progress.ElapsedTime}");
            }

            var combinedUniqueSolutionCount = combinedNodeCounts.Count(item => item.Value == 1);

            Trace.WriteLine($"Overall result: routes = {combinedRouteCount}, distinct solutions = {combinedNodeCounts.Count}, unique solutions = {combinedUniqueSolutionCount}, elapsed time = {combinedElapsedTime}");
        }
Example #4
0
        public async Task <(IDictionary <byte[], int> nodeCounts, PathFinderState state)> ExploreAsync(
            PathFinderState state,
            CancellationToken cancellationToken)
        {
            var routeCount = state.Progress.RouteCount;
            var stopwatch  = Stopwatch.StartNew();
            var routes     = new BlockingCollection <Step>(new ConcurrentStack <Step>());

            foreach (var step in state.Steps)
            {
                routes.Add(step);
            }

            var latch = new ManualResetEventSlim(initialState: true);

            void StartWalkAction() => Interlocked.Add(ref routeCount, StartWalk(routes, latch));

            while (routes.Any())
            {
                var tasks = Enumerable.Range(0, _threadCount)
                            .Select(index => Task.Run(StartWalkAction, cancellationToken))
                            .ToList();

                if (_monitorInterval > TimeSpan.Zero)
                {
                    var persistTask = Task.Delay(_monitorInterval, cancellationToken)
                                      .ContinueWith(_ => latch.Reset(), TaskContinuationOptions.ExecuteSynchronously);

                    tasks.Add(persistTask);
                }

                await Task.WhenAll(tasks);

                if (_monitorInterval > TimeSpan.Zero)
                {
                    //TODO: export paths
                    var routeLog = RouteLogFactory.CreateRouteLog(
                        _tableau,
                        _endPoints,
                        routes.ToArray(),
                        new Progress
                    {
                        RouteCount  = routeCount,
                        ElapsedTime = state.Progress.ElapsedTime + stopwatch.Elapsed
                    });

                    RouteStateReaderWriter.WriteToFile(routeLog, _saveFilePath);
                }

                latch.Set();
            }

            stopwatch.Stop();


            return(
                nodeCounts : _nodeCounts,
                state : state with
            {
                Steps = routes.ToList(),
                Progress = new Progress
                {
                    RouteCount = routeCount,
                    ElapsedTime = state.Progress.ElapsedTime + stopwatch.Elapsed
                }
            });
Example #5
0
    public List <PathNode> FindPath(Tile startingTile, Tile destinationTile)//TODO: Refactor?
    {
        Reset();

        var startingIndex    = GetTileIndex(startingTile);
        var destinationIndex = GetTileIndex(destinationTile);

        if (startingIndex == destinationIndex)
        {
            return(null);
        }

        CurrentState = PathFinderState.StateSearchingPath;

        var hScore = GetManhattanDistanceCost(startingTile, destinationTile);

        var startingNode = startingTile.GetPathNode();

        startingNode.SetScore(hScore);
        AddPathNodeToOpenList(startingNode);

        while (IsSearchingForPath())
        {
            if (PathNodeOpen.Count == 0)
            {
                CurrentState = PathFinderState.StateError;
                return(null);
            }

            var currentNode = PathNodeOpen[0];
            MoveNodeToClosedList(currentNode);

            if (GetTileIndex(currentNode.GetTile()) == destinationIndex)
            {
                BuildFinalNodePath(currentNode);
                CurrentState = PathFinderState.StateFoundPath;
                return(PathNodeFinal);
            }

            FindAjacentTiles(currentNode.GetTile());

            for (int i = 0; i < AdjacentNodes.Count; i++)
            {
                var tile = AdjacentNodes[i];
                if (tile == null)
                {
                    continue;
                }

                if (DoesTileExistInClosedList(tile))
                {
                    continue;
                }

                if (!DoesTileExistInOpenList(tile))
                {
                    hScore = GetManhattanDistanceCost(tile, destinationTile);

                    var node = tile.GetPathNode();
                    node.SetParent(currentNode);
                    node.SetScore(hScore);
                    AddPathNodeToOpenList(node);
                }
                else
                {
                    var node = GetOpenPathNodeForTile(tile);

                    if (currentNode.GetGScore() + 1 < node.GetGScore())
                    {
                        node.SetParent(currentNode);
                        SortOpenList();
                    }
                }
            }
        }

        return(null);
    }
Example #6
0
 public void Reset()
 {
     CurrentState = PathFinderState.StateIdle;
     ClearPathNodes();
 }