public IEnumerable <Tile> Navigate(Tile from, Tile to)
        {
            var closed = new List <Tile>();
            var open   = new List <Tile>()
            {
                from
            };

            var path = new Dictionary <Tile, Tile>();

            var gScore = new Dictionary <Tile, double>();

            gScore[from] = 0;

            var fScore = new Dictionary <Tile, double>();

            fScore[from] = heuristicAlgorithm.Calculate(from, to);

            while (open.Any())
            {
                var current = open
                              .OrderBy(c => fScore[c])
                              .First();

                if (current == to)
                {
                    return(ReconstructPath(path, current));
                }

                open.Remove(current);
                closed.Add(current);

                foreach (Tile neighbor in neighborProvider.GetNeighbors(current))
                {
                    if (closed.Contains(neighbor) || blockedProvider.IsBlocked(neighbor))
                    {
                        continue;
                    }

                    var tentativeG = gScore[current] + distanceAlgorithm.Calculate(current, neighbor);

                    if (!open.Contains(neighbor))
                    {
                        open.Add(neighbor);
                    }
                    else if (tentativeG >= gScore[neighbor])
                    {
                        continue;
                    }

                    path[neighbor] = current;

                    gScore[neighbor] = tentativeG;
                    fScore[neighbor] = gScore[neighbor] + heuristicAlgorithm.Calculate(neighbor, to);
                }
            }

            return(null);
        }
        public IEnumerable <Tile> Navigate(Tile from, Tile to, int maxAttempts = int.MaxValue)
        {
            var closed = new HashSet <Tile>();
            var open   = new HashSet <Tile>()
            {
                from
            };
            var path = new Dictionary <Tile, Tile>();

            from.FScore = heuristicAlgorithm.Calculate(from, to);

            int noOfAttempts = 0;

            Tile highScore = from;
            Tile last      = from;

            while (open.Count != 0)
            {
                var current = last;
                if (last != highScore)
                {
                    current = open
                              .OrderBy(c => c.FScore)
                              .First();
                }

                last = null;

                if (++noOfAttempts > maxAttempts)
                {
                    return(ReconstructPath(path, highScore));
                }
                if (current.Equals(to))
                {
                    return(ReconstructPath(path, current));
                }

                open.Remove(current);
                closed.Add(current);

                foreach (Tile neighbor in neighborProvider.GetNeighbors(current))
                {
                    if (closed.Contains(neighbor) || blockedProvider.IsBlocked(neighbor))
                    {
                        continue;
                    }

                    var tentativeG = current.GScore + distanceAlgorithm.Calculate(current, neighbor);

                    if (!open.Add(neighbor) && tentativeG >= neighbor.GScore)
                    {
                        continue;
                    }

                    path[neighbor] = current;

                    neighbor.GScore = tentativeG;
                    neighbor.FScore = neighbor.GScore + heuristicAlgorithm.Calculate(neighbor, to);
                    if (neighbor.FScore <= highScore.FScore)
                    {
                        highScore = neighbor;
                        last      = neighbor;
                    }
                }
            }

            return(null);
        }