[Question]
  [
> 
> Given a list of points, find the shortest path that visits all points and returns to the starting point.
> 
> 
> 
The [Travelling Salesman Problem](http://en.wikipedia.org/wiki/Travelling_salesman_problem) is well-known in the computer science field, as are many ways to calculate/approximate it. It's been solved for very large groups of points, but some of the largest take many CPU-years to finish.
> 
> Don't get burned by the potato.
> 
> 
> 
[Hot Potato](http://en.wikipedia.org/wiki/Hot_potato_%28game%29) is a game where 2+ players pass a "potato" around in a circle while music plays. The object is to pass it to the next player quickly. If you are holding the potato when the music stops, you're out.
---
The object of **Hot Potato Salesman** is:
> 
> Given a set of **100 unique points**, return those points in a better order (*shorter total distance as defined further down*). This will "pass" the problem to the next player. They have to improve it and pass it to the next, etc. If a player cannot improve it, they are out and play continues until one player is left.
> 
> 
> 
To keep this from being a "brute-force-me-a-path" competition, there are these stipulations:
* You cannot take more than **one minute** to pass the potato. If you haven't found and passed a shorter solution by the time one minute is up, you're out.
* You cannot change the position of more than **25** points. To be exact, `>= 75` points must be in the same position as you received them. It does not matter *which* ones you decide to change, just the *amount* you change.
When only one player is left, he is the winner of that game, and receives one point. A tourney consists of `5*n` games, where `n` is the number of players. Each game, the starting player will be *rotated*, and the remaining player order will be *shuffled*. The player with the most points at the end is the winner of the tourney. If the tourney ends with a tie for first place, a new tourney will be played with only those contestants. This will continue until there is no tie.
The starting player for each game will receive a set of pseudorandomly selected points in no particular order.
Points are defined as a pair of integer `x,y` coordinates on a cartesian grid. Distance is measured using [Manhattan distance](http://en.wikipedia.org/wiki/Taxicab_geometry), `|x1-x2| + |y1-y2|`. All coordinates will lie in the `[0..199]` range.
## Input
Input is given with a single string argument. It will consist of 201 comma-separated integers representing the number of current players(`m`) and 100 points:
```
m,x0,y0,x1,y1,x2,y2,...,x99,y99
```
The order of these points is the current path. The total distance is obtained by adding the distance from each point to the next (`dist(0,1) + dist(1,2) + ... + dist(99,0)`). *Don't forget to return to start when calculating total distance!*
Note that `m` is *not* the number of players that started the game, it is the number that are still in.
## Output
Output is given in the same way as input, minus `m`; a single string containing comma-separated integers representing the points in their new order.
```
x0,y0,x1,y1,x2,y2,...,x99,y99
```
The control program will wait for output for one minute only. When output is received, it will verify that:
* the output is well-formed
* the output consists of *only* and *all* the 100 points present in the input
* `>=75` points are in their original positions
* the path length is less than the previous path
If any of these checks fail (or there is no output), you are out and the game will proceed to the next player.
## Control Program
You can find the control program [at this link](https://bitbucket.org/Geobits/hotpotatosalesman/src). The control program itself is deterministic, and is posted with a dummy seed of `1`. The seed used during scoring will be different, so don't bother trying to analyze the turn order/point lists it spits out.
The main class is `Tourney`. Running this will do a full tournament with contestants given as arguments. It spits out the winner of each game and a tally at the end. A sample tourney with two SwapBots looks like:
```
Starting tournament with seed 1
(0) SwapBot wins a game! Current score: 1
(1) SwapBot wins a game! Current score: 1
(1) SwapBot wins a game! Current score: 2
(1) SwapBot wins a game! Current score: 3
(0) SwapBot wins a game! Current score: 2
(1) SwapBot wins a game! Current score: 4
(1) SwapBot wins a game! Current score: 5
(1) SwapBot wins a game! Current score: 6
(1) SwapBot wins a game! Current score: 7
(1) SwapBot wins a game! Current score: 8
Final Results:
Wins        Contestant
2       (0) SwapBot
8       (1) SwapBot
```
If you want to test just one game at a time, you can run the `Game` class instead. This will run one game with players in the order given as arguments. By default, it will also print a play-by-play showing the current player and path length.
Also included are a few test players: `SwapBot`, `BlockPermuter`, and `TwoSwapBot`. The first two will not be included in scoring runs, so feel free to use and abuse them during testing. `TwoSwapBot` **will** be included in judging, and he's no slouch, so bring your A-game.
## Miscellany
* You cannot save state information, and each turn is a separate run of your program. The only information you will receive each turn is the set of points.
* You cannot use external resources. This includes network calls and file access.
* You cannot use library functions designed to solve/assist with the TSP problem or its variants.
* You cannot manipulate or interfere with other players in any way.
* You cannot manipulate or interfere with the control program or any included classes or files in any way.
* Multi-threading is allowed.
* One submission per user. If you submit more than one entry, I will only enter the first one submitted. If you want to change your submission, edit/delete the original.
* The tournament will be running on Ubuntu 13.04, on a computer with an [i7-3770K CPU](http://ark.intel.com/products/65523/Intel-Core-i7-3770K-Processor-8M-Cache-up-to-3_90-GHz) and 16GB RAM. It will not be run in a VM. Anything I perceive as malicious will immediately disqualify the current **and** any future entry you submit.
* All entries must be runnable from the command line with free ([*as in beer*](http://en.wikipedia.org/wiki/Gratis_versus_libre#.22Free_beer.22_vs_.22free_speech.22_distinction)) software. If I have problems compiling/running your entry, I will request aid in the comments. If you do not respond or I cannot ultimately get it running, it will be disqualified.
## Results (22 May 2014)
New results are in! UntangleBot has beaten the competition quite soundly. TwoSwapBot managed seven wins, and SANNbot snuck a victory in as well. Here's a scoreboard, and a [link to the raw output](http://pastebin.com/wFePpbiU):
```
Wins        Contestant
22      (2) ./UntangleBot
7       (0) TwoSwapBot
1       (5) SANNbot.R
0       (1) BozoBot
0       (3) Threader
0       (4) DivideAndConquer
```
As it stands *now*, **UntangleBot** has won the checkmark. Don't let that discourage you from entering, though, since I'll run the tournament as more contestants appear and change the accepted answer accordingly.
  
[Answer]
# UntangleBot (formerly NiceBot)
A C++11 bot that uses two strategies.  
At first it will try to "untangle" the path if possible, by detecting intersections between paths that are closer than 25 points (since untangling implies modifying all points in-between).  
If the first strategy fails, it randomly swaps points to find better distances until a better path has been found.
This bot consistently beats TwoSwapBot with an approximate ratio of five victories for one loss in my test tourneys.
```
// g++ -std=c++11 -O3 -o UntangleBot UntangleBot.cpp
#include <algorithm>
#include <chrono>
#include <cmath>
#include <iostream>
#include <iterator>
#include <random>
#include <set>
#include <sstream>
const int NPOINTS = 100;
struct Point {
    int x, y;
    Point():x(0),y(0) {}    
    Point(int x, int y):x(x),y(y) {}
    int distance_to(const Point & pt) const {
        return std::abs(x - pt.x) + std::abs(y - pt.y);
    }
};
std::ostream & operator<<(std::ostream & out, const Point & point) {
    return out << point.x << ',' << point.y;
}
int total_distance(const Point points[NPOINTS]) {
    int distance = 0;
    for (int i = 0; i < NPOINTS; ++i) {
        distance += points[i].distance_to(points[(i+1)%NPOINTS]);
    }
    return distance;
}
bool intersects(const Point & p1, const Point & p2, const Point & p3, const Point & p4) {
    double s1_x, s1_y, s2_x, s2_y;
    s1_x = p2.x - p1.x;
    s1_y = p2.y - p1.y;
    s2_x = p4.x - p3.x;
    s2_y = p4.y - p3.y;
    double s, t;
    s = (-s1_y * (p1.x - p3.x) + s1_x * (p1.y - p3.y)) / (-s2_x * s1_y + s1_x * s2_y);
    t = ( s2_x * (p1.y - p3.y) - s2_y * (p1.x - p3.x)) / (-s2_x * s1_y + s1_x * s2_y);
    return s >= 0 && s <= 1 && t >= 0 && t <= 1;
}
int main(int argc, char ** argv) {
    Point points[NPOINTS];
    using Clock = std::chrono::system_clock;
    const Clock::time_point start_time = Clock::now();
    // initialize points
    if (argc < 2) {
        std::cerr << "Point list is missing" << std::endl;
        return 1;
    }
    std::stringstream in(argv[1]);
    int players;
    char v;
    in >> players >> v;
    for (int i = 0; i < NPOINTS; ++i) {
        in >> points[i].x >> v >> points[i].y >> v;
    }
    int original_distance = total_distance(points);
    // detect intersection between any 4 points
    for (int i = 0; i < NPOINTS; ++i) {
        for (int j = i+1; j < NPOINTS; ++j) {
            Point & p1 = points[i];
            Point & p2 = points[(i+1)%NPOINTS];
            Point & p3 = points[j];
            Point & p4 = points[(j+1)%NPOINTS];
            // points must all be distinct
            if (p1.distance_to(p3) == 0 || p1.distance_to(p4) == 0 || p2.distance_to(p3) == 0 || p2.distance_to(p4) == 0) {
                continue;
            }
            // do they intersect ?
            if (!intersects(p1, p2, p3, p4)) {
                continue;
            }
            // can modify less than 25 points ?
            if (std::abs(j-i) > 25) {
                continue;
            }
            // swap points
            for (int m = 0; m < std::abs(j-i)/2; ++m) {
                if (i+1+m != j-m) {
                    std::swap(points[i+1+m], points[j-m]);
                    //std::cerr << "untangle " << i+1+m << " <=> " << j-m << '\n';
                }
            }
            int new_distance = total_distance(points);
            if (new_distance < original_distance) {
                std::copy(std::begin(points), std::end(points)-1, std::ostream_iterator<Point>(std::cout, ","));
                std::cout << points[NPOINTS-1];
                return 0;
            }
            else {
                // swap points back
                for (int m = 0; m < std::abs(j-i)/2; m++) {
                    if (i+1+m != j-m) {
                        std::swap(points[i+1+m], points[j-m]);
                    }
                }
            }
        }
    }
    // more traditional approach if the first fails
    std::mt19937 rng(std::chrono::duration_cast<std::chrono::seconds>(start_time.time_since_epoch()).count());
    std::uniform_int_distribution<> distr(0, NPOINTS-1);
    while (true) {
        // try all possible swaps from a random permutation
        int p1 = distr(rng);
        int p2 = distr(rng);
        std::swap(points[p1], points[p2]);
        for (int i = 0; i < NPOINTS; ++i) {
            for (int j = i+1; j < NPOINTS; ++j) {
                std::swap(points[i], points[j]);
                if (total_distance(points) < original_distance) {
                    std::copy(std::begin(points), std::end(points)-1, std::ostream_iterator<Point>(std::cout, ","));
                    std::cout << points[NPOINTS-1];
                    return 0;
                }
                else {
                    std::swap(points[i], points[j]);
                }
            }
        }
        // they didn't yield a shorter path, swap the points back and try again
        std::swap(points[p1], points[p2]);
    }
    return 0;
}
```
[Answer]
### SANNbot
(a simulated annealing bot in **R**)
Should be called with `Rscript SANNbot.R`.
```
input <- strsplit(commandArgs(TRUE),split=",")[[1]]
n <- as.integer(input[1])                            # Number of players
init_s <- s <- matrix(as.integer(input[-1]),ncol=2,byrow=TRUE) # Sequence of points
totdist <- function(s){                              # Distance function
    d <- 0
    for(i in 1:99){d <- d + (abs(s[i,1]-s[i+1,1])+abs(s[i,2]-s[i+1,2]))}
    d
    }
gr <- function(s){                                   # Permutation function
    changepoints <- sample(1:100,size=2, replace=FALSE)
    tmp <- s[changepoints[1],]
    s[changepoints[1],] <- s[changepoints[2],]
    s[changepoints[2],] <- tmp
    s
    }
d <- init_d <- totdist(s)                            # Initial distance
k <- 1                                               # Number of iterations
v <- 0
t <- n*(init_d/12000)                                 # Temperature
repeat{
    si <- gr(s)                                      # New sequence
    di <- totdist(si)                                # New distance
    dd <- di - d                                     # Difference of distances
    if(dd <= 0 | runif(1) < exp(-dd/t)){             # Allow small uphill changes
        d <- di
        s <- si
        v <- v+2
        }
    k <- k+1
    if(k > 10000){break}
    if(d > init_d & v>20){s <- init_s; d <- init_d; v <- 0}
    if(v>23){break}
}
cat(paste(apply(s,1,paste,collapse=","),collapse=","))
```
The idea is relatively simple: each turn is one "cooling step" of a [simulated annealing](http://en.wikipedia.org/wiki/Simulated_annealing) with the number of players still in the game as "temperature" (modified by the current distance over 12000, i.e. roughly the initial distance). Only difference with a proper simulated annealing is that I checked that i don't permute more than 25 elements and if i used up 20 moves but the resulting sequence is worth than the initial then it start over again.
[Answer]
# BozoBot
Utilizes the complex logic behind [Bozosort](http://projecteuler.net/problem=367) to find a better path. It looks like this.
* Swap random points
* If we improved
	+ Return the answer
* Otherwise
	+ Try again
~~BozoBot has now been improved with **Multithreading**! Four minions now aimlessly juggle points until they stumble upon an improvement. The first one to find a solution gets a cookie!~~
Apparently I fail at multithreading.
```
import java.util.Random;
public class BozoBot {
    public static String[] input;
    public static void main(String[] args) {
        input = args;
        for(int i = 0; i < 4; i++) new Minion().run();
    }
}
class Minion implements Runnable {
    public static boolean completed = false;
    public static synchronized void output(int[] x, int[] y) {
        if(!completed) {
            completed = true;
            String result = x[0]+","+y[0];
            for (int i = 1; i < 100; i++)
                result+=","+x[i]+","+y[i];
            System.out.print(result);
            // receiveCookie(); // Commented out to save money
        }
    }
    public void run() {
        String[] args = BozoBot.input[0].split(",");
        int[] x = new int[100];
        int[] y = new int[100];
        for (int i = 1; i < 201; i+=2) {
            x[(i-1)/2] = Integer.parseInt(args[i]);
            y[i/2] = Integer.parseInt(args[i+1]);
        }
        int startDistance = 0;
        for (int i = 1; i < 100; i++)
            startDistance += Math.abs(x[i-1]-x[i]) + Math.abs(y[i-1]-y[i]);
        int r1, r2, r3, r4, tX, tY, newDistance;
        Random gen = new java.util.Random();
        while (true) {
            r1 = gen.nextInt(100);
            r2 = gen.nextInt(100);
            r3 = gen.nextInt(100);
            r4 = gen.nextInt(100);
            tX = x[r1];
            x[r1] = x[r2];
            x[r2] = tX;
            tY = y[r1];
            y[r1] = y[r2];
            y[r2] = tY;
            tX = x[r3];
            x[r3] = x[r4];
            x[r4] = tX;
            tY = y[r3];
            y[r3] = y[r4];
            y[r4] = tY;
            newDistance = 0;
            for (int i=1; i < 100; i++)
                newDistance += Math.abs(x[i-1]-x[i]) + Math.abs(y[i-1]-y[i]);
            if(newDistance < startDistance)
                break;
            tX = x[r1];
            x[r1] = x[r2];
            x[r2] = tX;
            tY = y[r1];
            y[r1] = y[r2];
            y[r2] = tY;
            tX = x[r3];
            x[r3] = x[r4];
            x[r4] = tX;
            tY = y[r3];
            y[r3] = y[r4];
            y[r4] = tY;
        }
        output(x,y);
    }
}
```
[Answer]
# TwoSwapBot
An upgrade to `SwapBot`, this guy checks for every pair of swaps. First, he checks if any single swap will shorten the path. If it does, it returns immediately. If not, he checks each to see if *another* swap will shorten it. If not, he just dies.
While the path is still semi-random, it normally returns in about 100ms. If he has to check each and every 2-swap (roughly 25M), it takes about 20 seconds.
At the time of submission, this beat all other competitors in test rounds.
```
public class TwoSwapBot {
    static int numPoints = 100;
    
    String run(String input){
        String[] tokens = input.split(",");
        if(tokens.length < numPoints*2)
            return "bad input? nope. no way. bye.";
        
        Point[] points = new Point[numPoints];  
        for(int i=0;i<numPoints;i++)
            points[i] = new Point(Integer.valueOf(tokens[i*2+1]), Integer.valueOf(tokens[i*2+2]));
        int startDist = totalDistance(points);
        Point[][] swapped = new Point[(numPoints*(numPoints+1))/2][];       
        int idx = 0;
        for(int i=0;i<numPoints;i++){
            for(int j=i+1;j<numPoints;j++){
                Point[] test = copyPoints(points);
                swapPoints(test,i,j);
                int testDist = totalDistance(test);
                if( testDist < startDist)
                    return getPathString(test);
                else
                    swapped[idx++] = test;
            }
        }
        
        for(int i=0;i<idx;i++){
            for(int k=0;k<numPoints;k++){
                for(int l=k+1;l<numPoints;l++){
                    swapPoints(swapped[i],k,l);
                    if(totalDistance(swapped[i]) < startDist)
                        return getPathString(swapped[i]);
                    swapPoints(swapped[i],k,l);
                }
            }
        }
        return "well damn";
    }
    
    void swapPoints(Point[] in, int a, int b){
        Point tmp = in[a];
        in[a] = in[b];
        in[b] = tmp;
    }
    
    String getPathString(Point[] in){
        String path = "";
        for(int i=0;i<numPoints;i++)
            path += in[i].x + "," + in[i].y + ",";
        return path.substring(0,path.length()-1);
    }
    Point[] copyPoints(Point[] in){
        Point[] out = new Point[in.length];
        for(int i=0;i<out.length;i++)
            out[i] = new Point(in[i].x, in[i].y);
        return out;
    }
    
    static int totalDistance(Point[] in){
        int dist = 0;
        for(int i=0;i<numPoints-1;i++)
            dist += in[i].distance(in[i+1]);
        return dist + in[numPoints-1].distance(in[0]);
    }
    public static void main(String[] args) {
        if(args.length < 1)
            return;
        System.out.print(new TwoSwapBot().run(args[0]));
    }
    
    class Point{
        final int x; final int y;
        Point(int x, int y){this.x = x; this.y = y;}
        int distance(Point other){return Math.abs(x-other.x) + Math.abs(y-other.y);}
    }
}
```
[Answer]
# Threader
This bot
1. Splits the 100 points up in ~~4~~**10** pieces of ~~25~~**10** points
2. Starts a thread for each piece
3. In the thread, randomly shuffle the array, while keeping the start- and endpoint fixed
4. If distance of new array is shorter, keep it
5. After 59s, the main thread collects the results and prints it out
The idea is to find the best improvement to the path, so that the other bots will fail with their logic.
  
```
import java.util.Arrays;
import java.util.Collections;
public class Threader {
    public static final int THREAD_COUNT = 10;
    public static final int DOT_COUNT = 100;
    private final Dot[] startDots = new Dot[THREAD_COUNT];
    private final Dot[] endDots = new Dot[THREAD_COUNT];
    private final Dot[][] middleDots = new Dot[THREAD_COUNT][DOT_COUNT/THREAD_COUNT-2];
    private final Worker worker[] = new Worker[THREAD_COUNT];
    private final static long TIME = 59000; 
    public static void main(String[] args) {
        Threader threader = new Threader();
        //remove unnecessary player count to make calculation easier
        threader.letWorkersWork(args[0].replaceFirst("^[0-9]{1,3},", "").split(","));
    }
    public void letWorkersWork(String[] args) {
        readArgs(args);
        startWorkers();
        waitForWorkers();
        printOutput();
    }
    private void readArgs(String[] args) {
        final int magigNumber = DOT_COUNT*2/THREAD_COUNT;
        for (int i = 0; i < args.length; i += 2) {
            Dot dot = new Dot(Integer.parseInt(args[i]), Integer.parseInt(args[i + 1]));
            if (i % magigNumber == 0) {
                startDots[i / magigNumber] = dot;
            } else if (i % magigNumber == magigNumber - 2) {
                endDots[i / magigNumber] = dot;
            } else {
                middleDots[i / magigNumber][(i % magigNumber) / 2 - 1] = dot;
            }
        }
    }
    private void startWorkers() {
        for (int i = 0; i < THREAD_COUNT; i++) {
            worker[i] = new Worker(startDots[i], endDots[i], middleDots[i]);
            Thread thread = new Thread(worker[i]);
            thread.setDaemon(true);
            thread.start();
        }
    }
    private void waitForWorkers() {
        try {
            Thread.sleep(TIME);
        } catch (InterruptedException e) {
        }
    }
    private void printOutput() {
        //get results
        Worker.stopWriting = true;
        int workerOfTheYear = 0;
        int bestDiff = 0;
        for (int i = 0; i < THREAD_COUNT; i++) {
            if (worker[i].diff() > bestDiff) {
                bestDiff = worker[i].diff();
                workerOfTheYear = i;
            }
        }
        //build output
        StringBuilder result = new StringBuilder(1000);
        for (int i = 0; i < THREAD_COUNT; i++) {
            result.append(startDots[i]);
            Dot middle[] = middleDots[i];
            if (i == workerOfTheYear) {
                middle = worker[i].bestMiddle;
            }
            for (int j = 0; j < middle.length; j++) {
                result.append(middle[j]);
            }
            result.append(endDots[i]);
        }
        result.replace(0, 1, ""); //replace first comma
        System.out.print(result);
    }
}
class Worker implements Runnable {
    public Dot start;
    public Dot end;
    private Dot[] middle = new Dot[Threader.DOT_COUNT/Threader.THREAD_COUNT-2];
    public Dot[] bestMiddle = new Dot[Threader.DOT_COUNT/Threader.THREAD_COUNT-2];
    public static boolean stopWriting = false;
    private int bestDist = Integer.MAX_VALUE;
    private final int startDist;
    public Worker(Dot start, Dot end, Dot[] middle) {
        this.start = start;
        this.end = end;
        System.arraycopy(middle, 0, this.middle, 0, middle.length);
        System.arraycopy(middle, 0, this.bestMiddle, 0, middle.length);
        startDist = Dot.totalDist(start, middle, end);
    }
    @Override
    public void run() {
        while (true) {
            shuffleArray(middle);
            int newDist = Dot.totalDist(start, middle, end);
            if (!stopWriting && newDist < bestDist) {
                System.arraycopy(middle, 0, bestMiddle, 0, middle.length);
                bestDist = newDist;
            }
        }
    }
    public int diff() {
        return startDist - bestDist;
    }
    private void shuffleArray(Dot[] ar) {
        Collections.shuffle(Arrays.asList(ar));
    }
}
class Dot {
    public final int x;
    public final int y;
    public Dot(int x, int y) {
        this.x = x;
        this.y = y;
    }
    public int distTo(Dot other) {
        return Math.abs(x - other.x) + Math.abs(y - other.y);
    }
    public static int totalDist(Dot start, Dot[] dots, Dot end) {
        int distance = end.distTo(start);
        distance += start.distTo(dots[0]);
        distance += end.distTo(dots[dots.length - 1]);
        for (int i = 1; i < dots.length; i++) {
            distance += dots[i].distTo(dots[i - 1]);
        }
        return distance;
    }
    @Override
    public String toString() {
        return "," + x + "," + y;
    }
}
```
[Answer]
# Divide And Conquer + Greedy Bot
**NOTE:** I looked at your code for `Game` which includes the following in Game.parsePath:
```
for(int i=0;i<numPoints;i++){
        test[i] = new Point(Integer.valueOf(tokens[i*2]), Integer.valueOf(tokens[i*2+1]));
        if(test[i].equals(currentPath[i]))
            same++;
```
However, there is no `catch(NumberFormatException)` block, so your program will likely crash when a player program outputs a string (as demonstrated at the end of my program's `main` method). I advise you fix this, because programs could output exceptions, stack traces, or the like. Otherwise, comment out that line in my program before you run it.
## Back to the topic
This implementation (in Java) splits the list of points into chunks of 25, randomly spaced on the list. Then, it creates threads to shorten the path between the points in each chunk (Hence, "Divide and Conquer"). The main thread monitors the others and makes sure to present the shortest solution within the time limit. If a thread dies with or without a solution, it starts another thread off again on a different chunk.
Each thread uses the "greedy" algorithm, which starts off on a random point, goes to the closest point, and repeats until all the points are covered (Hence, "greedy").
### Notes
* This will run through the full 1 minute (I gave 3 seconds for program startup/shutdown and JVM startup - you never know what the JVM startup routines get caught up on next...)
* Even if it has found solutions, it will keep searching and after the 1 minute is up it presents the best solution it found.
* I'm not sure if this implementation is actually any good. I had some fun coding it though :)
* Since a lot of things are random, this
may not give the same output for the same input.
Just compile and use `java DivideAndConquer.class` to run.
```
public class DivideAndConquer extends Thread {
    static LinkedList<Point> original;
    static Solution best;
    static LinkedList<DivideAndConquer> bots;
    static final Object _lock=new Object();
    public static void main(String[] args){
        if(args.length != 1) {
            System.err.println("Bad input!");
            System.exit(-1);
        }
        // make sure we don't sleep too long... get the start time
        long startTime = System.currentTimeMillis();
        // parse input
        String[] input=args[0].split(",");
        int numPlayers=Integer.parseInt(input[0]);
        original=new LinkedList<Point>();
        for(int i=1;i<input.length;i+=2){
            original.add(new Point(Integer.parseInt(input[i]), Integer.parseInt(input[i+1])));
        }
        // start threads
        bots=new LinkedList<DivideAndConquer>();
        for(int i=0;i<6;i++)
            bots.add(new DivideAndConquer(i));
        // sleep
        try {
            Thread.sleep(57000 - (System.currentTimeMillis() - startTime));
        } catch(Exception e){} // should never happen, so ignore
        // time to collect the results!
        Solution best=getBestSolution();
        if(best!=null){
            best.apply(original);
            String printStr="";
            for(int i=0;i<original.size();i++){
                Point printPoint=original.get(i);
                printStr+=printPoint.x+","+printPoint.y+",";
            }
            printStr=printStr.substring(0, printStr.length()-1);
            System.out.print(printStr);
        } else {
            System.out.println("Hey, I wonder if the tournament program crashes on NumberFormatExceptions... Anyway, we failed");
        }
    }
    // check the distance
    public static int calculateDistance(List<Point> points){
        int distance = 0;
        for(int i=0;i<points.size();i++){
            int next=i+1;
            if(next>=points.size())next=0;
            distance+=points.get(i).distance(points.get(next));
        }
        return distance;
    }
    public static void solutionFound(Solution s){
        // thanks to Java for having thread safety features built in
        synchronized(_lock){
            // thanks to Java again for short-circuit evaluation
            // saves lazy programmers lines of code all the time
            if(best==null || best.distDifference < s.distDifference){
                best=s;
            }
        }
    }
    public static Solution getBestSolution(){
        // make sure we don't accidentally return
        // the best Solution before it's even
        // done constructing
        synchronized(_lock){
            return best;
        }
    }
    List<Point> myPoints;
    int start;
    int length;
    int id;
    public DivideAndConquer(int id){
        super("DivideAndConquer-Processor-"+(id));
        this.id=id;
        myPoints=new LinkedList<Point>();
        start=(int) (Math.random()*75);
        length=25;
        for(int i=start;i<start+length;i++){
            myPoints.add(original.get(i));
        }
        start();
    }
    public void run(){
        // copy yet again so we can delete from it
        List<Point> copied=new LinkedList<Point>(myPoints);
        int originalDistance=calculateDistance(copied);
        // this is our solution list
        List<Point> solution=new LinkedList<Point>();
        int randomIdx=new Random().nextInt(copied.size());
        Point prev=copied.get(randomIdx);
        copied.remove(randomIdx);
        solution.add(prev);
        while(copied.size()>0){
           int idx=-1;
           int len = -1;
           for(int i=0;i<copied.size();i++){
               Point currentPoint=copied.get(i);
               int dist=prev.distance(currentPoint);
               if(len==-1 || dist<len){
                   len=dist;
                   idx=i;
               }
           }
           prev=copied.get(idx);
           copied.remove(idx);
           solution.add(prev);
        }
        // aaaand check our distance
        int finalDistance=calculateDistance(solution);
        if(finalDistance<originalDistance){
            // yes! solution
            Solution aSolution=new Solution(start, length, solution, originalDistance-finalDistance);
            solutionFound(aSolution);
        }
        // start over regardless
        bots.set(id, new DivideAndConquer(id));
    }
    // represents a solution
    static class Solution {
        int start;
        int length;
        int distDifference;
        List<Point> region;
        public Solution(int start, int length, List<Point> region, int distDifference){
            this.region=new LinkedList<Point>(region);
            this.start=start;
            this.length=length;
            this.distDifference=distDifference;
        }
        public void apply(List<Point> points){
            for(int i=0;i<length;i++){
                points.set(i+start, region.get(i));
            }
        }
    }
    // copied your Point class, sorry but it's useful...
    // just added public to each method for aesthetics
    static class Point{
        int x;
        int y;
        Point(int x, int y){
            this.x = x;
            this.y = y;
        }
        Point(Point other){
            this.x = other.x;
            this.y = other.y;
        }
        public boolean equals(Point other){
            if(this.x==other.x && this.y==other.y)
                return true;
            return false;
        }
        public int distance(Point other){
            return Math.abs(x-other.x) + Math.abs(y-other.y);
        }
    }
}
```
]