Published
Edited
Nov 23, 2020
Insert cell
md`# Travelling Salesman Problem`
Insert cell
d3 = require("d3@5", "d3-geo-projection@2")
Insert cell
import { MONOPOLY_NAME_TO_DATA } from '@nuuuwan/monopoly'
Insert cell
import { sum, range } from '@nuuuwan/list-utils'
Insert cell
RADIUS_OF_EARTH_M = 6_371_000
Insert cell
M_IN_KM = 1_000
Insert cell
function getDistance(startName, endName) {
return (
Math.round(
d3.geoDistance(
MONOPOLY_NAME_TO_DATA[startName].latLng,
MONOPOLY_NAME_TO_DATA[endName].latLng
) * RADIUS_OF_EARTH_M
) / M_IN_KM
);
}
Insert cell
[
// test
getDistance('Park Lane', 'Mayfair'),
getDistance('Mayfair', 'Park Lane'),
getDistance('Bond Street', 'Park Lane')
]
Insert cell
function getPathDistance(path) {
return sum(
path.map(function(name, i) {
if (i === 0) {
return 0;
}
return getDistance(path[i - 1], name);
})
);
}
Insert cell
[
// test
getPathDistance(['Park Lane', 'Mayfair']),
getPathDistance(['Park Lane', 'Mayfair', 'Bond Street'])
]
Insert cell
function getClosest(startName, visitedList) {
const startLatLng = MONOPOLY_NAME_TO_DATA[startName].latLng;

return Object.entries(MONOPOLY_NAME_TO_DATA).reduce(
function([closestName, closestDistance], [name, d]) {
if (startName != name && !visitedList.includes(name)) {
const distance = getDistance(startName, name);
if (!closestDistance || distance < closestDistance) {
closestName = name;
closestDistance = distance;
}
}
return [closestName, closestDistance];
},
[undefined, undefined]
);
}
Insert cell
[
// test
getClosest('Park Lane', []),
getClosest('Park Lane', ['Park Lane', 'Mayfair']),
getClosest('Park Lane', ['Mayfair']),
getClosest('Park Lane', ['Mayfair', 'Bond Street'])
]
Insert cell
function getGreedyShortestPath(startName) {
let name = startName;
let path = [name];
let distance = 0;
while (true) {
const [closestName, closestDistance] = getClosest(name, path);
if (closestName) {
path.push(closestName);
distance += closestDistance;
name = closestName;
} else {
break;
}
}
return [path, distance];
}
Insert cell
[
// test
getGreedyShortestPath('Park Lane'),
getGreedyShortestPath('Marylebone station'),
getGreedyShortestPath('Old Kent Road')
]
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more