private void CreateSolution(IEnumerable<TsPoint> points, TspSolution solution, TsPoint firstPoint)
        {
            var notVisited = new List<TsPoint>(points.Where(p => p.Id != firstPoint.Id));
            var last = firstPoint;

            while (notVisited.Any())
            {
                var next = GetClosestPoint(last, notVisited);

                //check for potential orphans
                var pointsAbove = notVisited.Where(p => p != next && p.Y > last.Y).ToArray();
                var pointsBelow = notVisited.Where(p => p != next && p.Y < last.Y).ToArray();
                var pointsRight = notVisited.Where(p => p != next && p.X > last.X).ToArray();
                var pointsLeft = notVisited.Where(p => p != next && p.X < last.X).ToArray();

                TsPoint theAbove = null;
                TsPoint theBelow = null;
                TsPoint theRight = null;
                TsPoint theLeft = null;

                if (pointsAbove.Length == 1)
                {
                    theAbove = pointsAbove.Single();
                    if (next.DistanceFrom(last) / theAbove.DistanceFrom(last) < _threshold) theAbove = null;
                }
                if (pointsBelow.Length == 1)
                {
                    theBelow = pointsBelow.Single();
                    if (next.DistanceFrom(last) / theBelow.DistanceFrom(last) < _threshold) theBelow = null;
                }
                if (pointsRight.Length == 1)
                {
                    theRight = pointsRight.Single();
                    if (next.DistanceFrom(last) / theRight.DistanceFrom(last) < _threshold) theRight = null;
                }
                if (pointsLeft.Length == 1)
                {
                    theLeft = pointsLeft.Single();
                    if (next.DistanceFrom(last) / theLeft.DistanceFrom(last) < _threshold) theLeft = null;
                }

                var nextPoints = new[] { theAbove, theBelow, theRight, theLeft }.Where(p => p != null).ToList();

                if (nextPoints.Any())
                {
                    var unOrphaned = GetClosestPoint(last, nextPoints);
                    notVisited.Remove(unOrphaned);
                    last = unOrphaned;
                    solution.AddNext(unOrphaned);
                }
                else
                {
                    notVisited.Remove(next);
                    last = next;
                    solution.AddNext(next);
                }
            }
        }
        public TspSolution Execute(TsPoint[] points)
        {
            var sortedPoints = points.OrderBy(p => p.X).ThenBy(p => p.Y);

            var firstPoint = sortedPoints.First();
            var solution = new TspSolution(firstPoint);

            foreach (var point in sortedPoints.Skip(1))
                solution.AddNext(point);

            solution.Close();
            return solution;
        }
        public TspSolution Execute(TsPoint[] points)
        {
            TspSolution current = null;
            var sortedPoints = points.OrderBy(p => p.X + p.Y).ToArray();

            for (double ts = .5; ts < 1.00; ts = ts + .01)
            {
                var newSolution = new TspSolver01(ts).Execute(sortedPoints);
                if (current == null || newSolution.Distance < current.Distance) current = newSolution;
            }

            if (current != null) current.OutputToDebug();
            return current;
        }
        public TspSolution Execute(TsPoint[] points)
        {
            var minX = points.Min(p => p.X);
            var maxX = points.Max(p => p.X);
            var rangeMinX = 1.1*minX;
            var rangeMaxX = .9*maxX;

            TsPoint upperRight = null;
            TsPoint upperLeft = null;
            TsPoint lowerRight = null;
            TsPoint lowerLeft = null;

            foreach (var point in points.Skip(1))
            {
                if (point.X >= rangeMaxX)
                {
                    if (upperRight == null || point.Y >= upperRight.Y) upperRight = point;
                    if (lowerRight == null || point.Y <= lowerRight.Y) lowerRight = point;
                }
                else if(point.X <= rangeMinX)
                {
                    if (upperLeft == null || point.Y >= upperLeft.Y) upperLeft = point;
                    if (lowerLeft == null || point.Y <= lowerLeft.Y) lowerLeft = point;
                }
            }

            var solution1 = CreateSolution(points.Where(p => p != upperRight).ToArray(), upperRight);
            solution1.OutputToDebug();

            var solution2 = CreateSolution(points.Where(p => p != upperRight).ToArray(), lowerRight);
            solution2.OutputToDebug();
            if (solution2.Distance < solution1.Distance) solution1 = solution2;

            var solution3 = CreateSolution(points.Where(p => p != upperRight).ToArray(), upperLeft);
            solution3.OutputToDebug();
            if (solution3.Distance < solution1.Distance) solution1 = solution3;

            var solution4 = CreateSolution(points.Where(p => p != upperRight).ToArray(), lowerLeft);
            solution4.OutputToDebug();
            if (solution4.Distance < solution1.Distance) solution1 = solution4;

            return solution1;
        }
        private TspSolution CreateSolution(TsPoint[] points, TsPoint firstPoint)
        {
            var solution = new TspSolution(firstPoint);

            var alreadyVisited = new List<int> { firstPoint.Id };

            var last = firstPoint;

            while (alreadyVisited.Count != points.Length)
            {
                var notVisited = points.Where(p => !alreadyVisited.Contains(p.Id)).ToArray();
                var next = notVisited.Aggregate(notVisited.First(),
                                                (min, curr) =>
                                                curr.DistanceFrom(last) < min.DistanceFrom(last) ? curr : min);

                alreadyVisited.Add(next.Id);
                last = next;
                solution.AddNext(next);
            }
            solution.Close();
            return solution;
        }
        public TspSolution Execute(TsPoint[] points)
        {
            var minX = points.Min(p => p.X);
            var maxX = points.Max(p => p.X);
            var increment = (maxX - minX) / _steps;

            TspSolution solution = null;

            for (int i = 1; i <= _steps; i++)
            {
                var range = minX + increment;
                if (i == _steps) ++range;
                var thesePoints = points.Where(p => p.X >= minX && p.X < range).ToList();

                TsPoint firstPoint;
                if (solution == null)
                {
                    firstPoint = thesePoints.OrderBy(p => p.Y).First();
                    solution = new TspSolution(firstPoint);
                }
                else
                {
                    firstPoint = GetClosestPoint(solution.LastItem, thesePoints);
                    solution.AddNext(firstPoint);
                }

                CreateSolution(thesePoints, solution, firstPoint);
                minX = range;
            }

            if (solution != null)
            {
                solution.Close();
                solution.OutputToDebug();
            }
            return solution;
        }
        public TspSolution Execute(TsPoint[] points)
        {
            var minX = points.Min(p => p.X);
            var maxX = points.Max(p => p.X);
            var minY = points.Min(p => p.Y);
            var maxY = points.Max(p => p.Y);

            const int pageSize = 7;
            var stepX = (maxX - minX) / pageSize;
            var stepY = (maxY - minY) / pageSize;

            var groups = new List<TspGroup>();

            var goingDown = false;
            var sortNumber = 0;

            for (var x = minX; x < maxX; x = x + stepX)
            {
                if (goingDown)
                    sortNumber += pageSize-1;
                else if (sortNumber > 0)
                    sortNumber += pageSize+1;

                for (var y = minY; y < maxY; y = y + stepY)
                {
                    var sort = goingDown ? sortNumber-- : sortNumber++;
                    //Console.WriteLine(sort);

                    var group = new TspGroup {SortNumber = sort, MinX = x, MaxX = x+stepX, MinY = y, MaxY = y+stepY};
                    groups.Add(group);

                    if ((y + stepY) > (maxY - (stepY / pageSize)))
                    {
                        group.MaxY = maxY + 1;
                        y = maxY;
                    }
                    if ((x + stepX) > (maxX - (stepX / pageSize)))
                    {
                        group.MaxX = maxX + 1;
                    }
                }

                if ((x + stepX) > (maxX - (stepX / pageSize)))
                {
                    x = maxX;
                }

                goingDown = !goingDown;
            }

            var sortedGroups = groups.OrderBy(g => g.SortNumber).ToArray();

            for (var i = 0; i < sortedGroups.Length; i++)
            {
                var group = sortedGroups[i];
                bool goingUp = ((group.SortNumber / pageSize) % 2) == 0;
                TsPoint[] pointsPage;

                var pointsPage1 = points.Where(p =>
                                          p.X >= group.MinX && p.X < group.MaxX &&
                                          p.Y >= group.MinY && p.Y < group.MaxY);

                if (goingUp) pointsPage = pointsPage1.OrderBy(p => p.X).ThenBy(p => p.Y).ToArray();
                else pointsPage = pointsPage1.OrderBy(p => p.X).ThenByDescending(p => p.Y).ToArray();

                var firstPoint = pointsPage.First();
                if (_solution == null)
                {
                    _solution = new TspSolution(firstPoint);
                }
                else
                {
                    var lastItem = _solution.LastItem;
                    firstPoint = pointsPage.Aggregate(firstPoint,
                                                    (min, curr) =>
                                                    curr.DistanceFrom(lastItem) < min.DistanceFrom(lastItem) ? curr : min);
                    _solution.AddNext(firstPoint);
                }

                var alreadyVisited = new List<int> { firstPoint.Id };
                var last = firstPoint;

                while (alreadyVisited.Count != pointsPage.Length)
                {
                    var notVisited = pointsPage.Where(p => !alreadyVisited.Contains(p.Id)).ToArray();
                    var next = notVisited.Aggregate(notVisited.First(),
                                                    (min, curr) =>
                                                    curr.DistanceFrom(last) < min.DistanceFrom(last) ? curr : min);

                    alreadyVisited.Add(next.Id);
                    last = next;
                    _solution.AddNext(next);
                }
            }
            _solution.Close();
            return _solution;
        }
        private TsPoint GetClosestPoint(TsPoint referencePoint, List<TsPoint> points)
        {
            var result = points.Aggregate(points.First(),
                    (min, curr) =>
                    curr.DistanceFrom(referencePoint) < min.DistanceFrom(referencePoint) ? curr : min);

            return result;
        }
        private void CreateSolutionOld(TsPoint[] points, TspSolution solution, TsPoint firstPoint)
        {
            var alreadyVisited = new List<int> { firstPoint.Id };

            var last = firstPoint;

            while (alreadyVisited.Count != points.Length)
            {
                var notVisited = points.Where(p => !alreadyVisited.Contains(p.Id)).ToArray();
                var next = notVisited.Aggregate(notVisited.First(),
                                                (min, curr) =>
                                                curr.DistanceFrom(last) < min.DistanceFrom(last) ? curr : min);

                if (next.Y < solution.LastItem.Y)
                {
                    //i went down, so is there only 1 left above me?
                    var above = points.Where(p => !alreadyVisited.Contains(p.Id) && p != next && p.Y > next.Y).ToArray();
                    if (above.Length == 1)
                    {
                        var theAbove = above.Single();
                        if (next.DistanceFrom(last) / theAbove.DistanceFrom(last) > .95)
                            next = theAbove;
                    }
                }
                else
                {
                    //i went up, so is there only 1 left below me?
                    var below = points.Where(p => !alreadyVisited.Contains(p.Id) && p != next && p.Y < next.Y).ToArray();
                    if (below.Length == 1)
                    {
                        var theBelow = below.Single();
                        if (next.DistanceFrom(last) / theBelow.DistanceFrom(last) > .95)
                            next = theBelow;
                    }
                }

                alreadyVisited.Add(next.Id);
                last = next;
                solution.AddNext(next);
            }
        }
 protected bool Equals(TsPoint other)
 {
     return Id == other.Id;
 }
 public double DistanceFrom(TsPoint point)
 {
     return Math.Sqrt(Math.Pow(point.X - X, 2) + Math.Pow(point.Y - Y, 2));
 }
        public TspSolution Execute(TsPoint[] points)
        {
            var firstPoint = points.First();
            var solution = new TspSolution(firstPoint);

            //var alreadyVisited = new List<int> { firstPoint.Id };
            var notVisited = new List<TsPoint>(points.Where(p => p.Id != firstPoint.Id));

            var last = firstPoint;

            //while (alreadyVisited.Count != points.Length)
            while(notVisited.Any())
            {
                //var notVisited = points.Where(p => !alreadyVisited.Contains(p.Id)).ToArray();
                var next = GetClosestPoint(last, notVisited);

                //var nextNotVisited = points.Where(p => !alreadyVisited.Contains(p.Id) && p != next).ToArray();

                //check for potential orphans
                var pointsAbove = notVisited.Where(p => p != next && p.Y > last.Y).ToArray();
                var pointsBelow = notVisited.Where(p => p != next && p.Y < last.Y).ToArray();
                var pointsRight = notVisited.Where(p => p != next && p.X > last.X).ToArray();
                var pointsLeft = notVisited.Where(p => p != next && p.X < last.X).ToArray();

                TsPoint theAbove = null;
                TsPoint theBelow = null;
                TsPoint theRight = null;
                TsPoint theLeft = null;

                if (pointsAbove.Length == 1)
                {
                    theAbove = pointsAbove.Single();
                    if (next.DistanceFrom(last) / theAbove.DistanceFrom(last) < _threshold) theAbove = null;
                }
                if (pointsBelow.Length == 1)
                {
                    theBelow = pointsBelow.Single();
                    if (next.DistanceFrom(last) / theBelow.DistanceFrom(last) < _threshold) theBelow = null;
                }
                if (pointsRight.Length == 1)
                {
                    theRight = pointsRight.Single();
                    if (next.DistanceFrom(last) / theRight.DistanceFrom(last) < _threshold) theRight = null;
                }
                if (pointsLeft.Length == 1)
                {
                    theLeft = pointsLeft.Single();
                    if (next.DistanceFrom(last) / theLeft.DistanceFrom(last) < _threshold) theLeft = null;
                }

                var nextPoints = new[] {theAbove, theBelow, theRight, theLeft}.Where(p => p != null).ToList();

                if (nextPoints.Any())
                {
                    var unOrphaned = GetClosestPoint(last, nextPoints);
                    //alreadyVisited.Add(unOrphaned.Id);
                    notVisited.Remove(unOrphaned);
                    last = unOrphaned;
                    solution.AddNext(unOrphaned);
                }
                else
                {
                    //alreadyVisited.Add(next.Id);
                    notVisited.Remove(next);
                    last = next;
                    solution.AddNext(next);
                }
            }
            solution.Close();
            //solution.OutputToDebug();
            return solution;
        }
 public void AddNext(TsPoint point)
 {
     var distanceFromLast = point.DistanceFrom(_points.Last());
     Distance += distanceFromLast;
     _points.Add(point);
 }
 public void AddLast(TsPoint point)
 {
     AddNext(point);
     var distanceToBeginning = point.DistanceFrom(_points.First());
     Distance += distanceToBeginning;
 }
 public TspSolution(TsPoint firstPoint)
 {
     _points = new List<TsPoint> { firstPoint };
 }