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;
        }
        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;
        }