xxxxxxxxxx
111
// 2-opt for solving travelling salesman problem
// (I tried to make it do less unnecessary checks and not drop the framerate to snail speeds, so the code is quite kludgy. Sorry. At least works well.)
function setup() {
createCanvas(700, 700);
// Start with a random path.
vert = [];
sz = 100;
for (var i = 0; i < sz; i++) {
v = createVector(random(40, width - 40), random(40, height - 40));
vert.push(v);
}
k = 0; // Kludge.
frame = 0;
}
function draw() {
background(0);
frameRate(10);
beginShape();
for (var i = 0; i < sz; i++) {
vertex(vert[i].x, vert[i].y);
fill(255);
noStroke();
ellipse(vert[i].x, vert[i].y, 8, 8);
}
noFill();
stroke(255);
strokeWeight(2);
endShape(CLOSE);
// 2-opt move. Cycle through all pairs of disjoint edges of a path. For each pair there can be two other disjoint pairs of edges, but only one of them does not split the path in two. If this other pair’s total length is less, than that of the current pair, change current pair of edges to the better one and repeat the previous step.
buf = frame;
buf2 = k; // Kludge.
top:
{
for (var i = k; i < sz; i++) {
for (var j = i + 2; j < sz; j++) {
d1 = vert[i].dist(vert[(i + 1) % sz]) + vert[j].dist(vert[(j + 1) % sz]);
d2 = vert[i].dist(vert[j]) + vert[(i + 1) % sz].dist(vert[(j + 1) % sz]);
if (d2 < d1) {
m = vert.slice(Math.min((i + 1) % sz, (j + 1) % sz), Math.max((i + 1) % sz, (j + 1) % sz)).reverse();
l = vert.slice(0, Math.min((i + 1) % sz, (j + 1) % sz));
r = vert.slice(Math.max((i + 1) % sz, (j + 1) % sz), sz);
vert = l.concat(m).concat(r);
frame++;
k = i; // Cycling through all previous edges is probably for naught, so I scan only unchecked edges.
break top;
}
}
}
k = 0; // If there still are unfixed pairs of edges, cycle through all again from the beginning.
}
// When the previous step doesn’t change the path, we’re done.
if (frame == buf && buf2 == 0) {
noLoop();
}
var pathlength = 0;
for (var i = 0; i < sz; i++) {
var d1 = vert[i].dist(vert[(i + 1) % sz]);
pathlength+=d1;
}
textSize(25);
text(frame, 20, 20);
text(pathlength, 160, 20);
}
//