import java.util.Random;

public class TSP {
  public static void main(String[] args) {
	double totalClosest = 0;
	double totalRandom = 0;
	double totalDiagonal = 0;
	double totalClusteredness = 0;
	for (int i = 0; i < 10; i++) {
	  Point[] points = generatePoints();
	  sortByClosest(points);
	  totalClosest += totalDist(points);
	  sortByRandom(points);
	  totalRandom += totalDist(points);
	  sortByDiagonal(points);
	  totalDiagonal += totalDist(points);
	  sortByClusteredness(points);
	  totalClusteredness += totalDist(points);
	}
	System.out.println("Closest: " + (int) totalClosest);
	System.out.println("Random: " + (int) totalRandom);
	System.out.println("Diagonal: " + (int) totalDiagonal);
	System.out.println("Clusteredness: " + (int) totalClusteredness);
  }



  public static void printPoints(Point[] points) {
	for (int i = 0; i < points.length - 1; i++) {
	  System.out.println(points[i]);
	  System.out.println(points[i+1]);
	  System.out.println(points[i].Dist(points[i+1]));
	} System.out.println(points[points.length - 1]);
	System.out.println(points[0]);
	System.out.println(points[points.length - 1].Dist(points[0]));
  }
  public static Point newPoint() {
	Random r = new Random();
	Point p = new Point(r.nextInt(100), r.nextInt(100));
	return p;
  }

  public static Point[] generatePoints() {
	Point[] points = new Point[100];
	for (int i = 0; i < points.length; i++)
	  points[i] = newPoint();
	return points;
  }

  public static void swap(Point[] points, int i, int j) {
	Point temp = points[i];
	points[i] = points[j];
	points[j] = temp;
  }

  public static void swap(double[] points, int i, int j) {
	double temp = points[i];
	points[i] = points[j];
	points[j] = temp;
  }


  public static void sortByClosest(Point[] points) {
	Random r = new Random();
	swap(points, 0, r.nextInt(points.length));
	for (int i = 1; i < points.length; i++)
	  swap(points, i, indexofClosest(points, i - 1));
  }

  public static int indexofClosest(Point[] points, int i) {
	double closest = points[i].Dist(points[i + 1]);
	int ret = i + 1;
	for (int j = i + 2; j < points.length; j++) {
	  if (points[i].Dist(points[j]) < closest) {
		ret = j;
		closest = points[i].Dist(points[j]);
	  }
	} return ret;
  }

  public static void sortByRandom(Point[] points) {
	Random r = new Random();
	for (int i = points.length - 1; i > 0; i--)
	  swap(points, i, r.nextInt(i));
  }

  public static void sortByDiagonal(Point[] points) {
	for (int i = 0; i < points.length; i++)
	  swap(points, i, indexOfNextDiagonal(points, i));
  }

  public static void sortByClusteredness(Point[] points) {
	double[] pointsDists = new double[points.length];
	int s;
	for (int i = 0; i < points.length; i++)
	  pointsDists[i] = averageDist(points, i);
	for (int j = 0; j < points.length; j++) {
	  s = indexOfNextMostClustered(pointsDists, j);
	  swap(points, j, s);
	  swap(pointsDists, j, s);
	}
  }

  public static int indexOfNextMostClustered(double[] pointDists, int i) {
	double highest = pointDists[i];
	int ret = i;
	for (int j = i + 1; j < pointDists.length; j++) {
	  if (pointDists[j] < highest) {
		highest = pointDists[j];
		ret = j;
	  }
	} return ret;
  }

  public static double averageDist(Point[] points, int i) {
	double ret = 0;
	for (int j = 0; j < points.length; j++) {
	  ret += points[i].Dist(points[j]);
	} return ret;
  }

  public static int indexOfNextDiagonal(Point[] points, int i) {
	int closest = points[i].MDist(new Point(0, 100));
	int ret = i;
	for (int j = i + 1; j < points.length; j++) {
	  if (points[j].MDist(new Point(0, 100)) == closest) {
		if (points[j].getX()>points[ret].getX()) {
		  ret = j;
		}
	  }	if (points[j].MDist(new Point(0, 100)) < closest) {
		closest = points[j].MDist(new Point(0, 100));
		ret = j;
	  }
	} return ret;
  }

  public static double totalDist(Point[] points) {
	double ret = 0;
	for (int i = 0; i < points.length; i++)
	  ret += points[i].Dist(points[(i+1)%points.length]);
	return ret;
  }
}

