72 lines
1.8 KiB
JavaScript
72 lines
1.8 KiB
JavaScript
/* eslint-disable no-restricted-globals */
|
|
import makeSolver from "../makeSolver";
|
|
import { pathCost, distance } from "../cost";
|
|
|
|
const nearestInsertion = async points => {
|
|
// from the starting point
|
|
const path = [points.shift()];
|
|
|
|
//
|
|
// INITIALIZATION - go to the nearest point first
|
|
//
|
|
points.sort((a, b) => distance(path[0], b) - distance(path[0], a));
|
|
path.push(points.pop());
|
|
|
|
self.setEvaluatingPaths(() => ({
|
|
paths: [{ path }],
|
|
cost: pathCost(path)
|
|
}));
|
|
|
|
await self.sleep();
|
|
|
|
while (points.length > 0) {
|
|
//
|
|
// SELECTION - nearest point to the path
|
|
//
|
|
let [selectedDistance, selectedIdx] = [Infinity, null];
|
|
for (const [freePointIdx, freePoint] of points.entries()) {
|
|
for (const pathPoint of path) {
|
|
const dist = distance(freePoint, pathPoint);
|
|
if (dist < selectedDistance) {
|
|
[selectedDistance, selectedIdx] = [dist, freePointIdx];
|
|
}
|
|
}
|
|
}
|
|
|
|
// get the next point to add
|
|
const [nextPoint] = points.splice(selectedIdx, 1);
|
|
|
|
//
|
|
// INSERTION - find the insertion spot that minimizes distance
|
|
//
|
|
let [bestCost, bestIdx] = [Infinity, null];
|
|
for (let i = 1; i < path.length; i++) {
|
|
const insertionCost = pathCost([path[i - 1], nextPoint, path[i]]);
|
|
if (insertionCost < bestCost) {
|
|
[bestCost, bestIdx] = [insertionCost, i];
|
|
}
|
|
}
|
|
path.splice(bestIdx, 0, nextPoint);
|
|
|
|
self.setEvaluatingPaths(() => ({
|
|
paths: [{ path }],
|
|
cost: pathCost(path)
|
|
}));
|
|
|
|
await self.sleep();
|
|
}
|
|
|
|
// return to start after visiting all other points
|
|
path.push(path[0]);
|
|
const cost = pathCost(path);
|
|
|
|
self.setEvaluatingPaths(() => ({
|
|
paths: [{ path }],
|
|
cost
|
|
}));
|
|
await self.sleep();
|
|
|
|
self.setBestPath(path, cost);
|
|
};
|
|
|
|
makeSolver(nearestInsertion);
|