Public
Edited
Jul 21, 2024
Insert cell
Insert cell
MAP=`
##########
# a b@ c #
##########
`.split('\n').slice(1,-1)
Insert cell
DIRS = [
[0, 1], // right
[1, 0], // down
[-1, 0], // left
[0, -1], // up
];
Insert cell
function move([i, j], [di, dj]) {
return [i + di, j + dj];
}
Insert cell
on = ([i, j], [i2, j2]) => i == i2 && j == j2
Insert cell
function findItems(origin) {
let visited = {};
let queue = [[origin, null]];
let items = [];
const isOrigin = (p) => on(p, origin);
const char = ([i, j]) => MAP[i][j];
const isWall = (p) => char(p) == "#";
const isItem = (p) => char(p) >= "a" && char(p) <= "z";
function assemblePath(dest) {
let p = dest;
const res = [p];
while ((p = visited[p])) {
if (isOrigin(p)) break;
res.push(p);
}
return res.reverse();
}
while (queue.length) {
let [current, parent] = queue.shift();
visited[current] = parent;
if (isItem(current)) {
let path = assemblePath(current);
items.push([char(current), current, path.length])
}
for (let dir of DIRS) {
let next = move(current, dir);
if (isWall(next)) continue;
if (visited[next]) continue;
queue.push([next, current]);
}
}
return items;
}
Insert cell
findItems([1, 5])
Insert cell
function findObjectsW(origin) {
let visited = {};
let queue = [[origin, null]];
let objects = [];
const isOrigin = (p) => on(p, origin);
const char = ([i, j]) => MAP[i][j];
const isWall = (p) => char(p) == "#";
const isObject = (p) => char(p) >= "a" && char(p) <= "z";
function assemblePath(dest) {
let p = dest;
const res = [p];
while ((p = visited[p])) {
if (isOrigin(p)) break;
res.push(p);
}
return res.reverse();
}
while (queue.length) {
let [current, parent] = queue.shift();
visited[current] = parent;
if (isObject(current)) {
let path = assemblePath(current);
objects.push([char(current), current, path.length])
continue
}
for (let dir of DIRS) {
let next = move(current, dir);
if (isWall(next)) continue;
if (visited[next]) continue;
queue.push([next, current]);
}
}
return objects;
}
Insert cell
findObjectsW([1,5])
Insert cell
findObjectsW([1, 4])
Insert cell
function findItemsN(origin, collected) {
let visited = {};
let queue = [[origin, null]];
let items = [];
const isOrigin = (p) => on(p, origin);
const char = ([i, j]) => MAP[i][j];
const isWall = (p) => char(p) == "#";
const isItem = (p) => {
const c = char(p)
return c >= "a" && c <= "z" && !collected.includes(c)
}
function assemblePath(dest) {
let p = dest;
const res = [p];
while ((p = visited[p])) {
if (isOrigin(p)) break;
res.push(p);
}
return res.reverse();
}
while (queue.length) {
let [current, parent] = queue.shift();
visited[current] = parent;
if (isItem(current)) {
let path = assemblePath(current);
items.push([char(current), current, path.length])
continue
}
for (let dir of DIRS) {
let next = move(current, dir);
if (isWall(next)) continue;
if (visited[next]) continue;
queue.push([next, current]);
}
}
return items;
}
Insert cell
findItemsN([1, 4], 'b')
Insert cell
findItemsN([1, 2], 'ba')
Insert cell
findItemsN([1, 7], 'bac')
Insert cell
Insert cell
findItemsN([1, 5], '')
Insert cell
findItemsN([1, 7], 'c')
Insert cell
findItemsN([1, 4], 'cb')
Insert cell
findItemsN([1, 2], 'cba')
Insert cell
function findItemsM(map, origin, collected) {
let visited = {};
let queue = [[origin, null]];
let objects = [];
const isOrigin = (p) => on(p, origin);
const char = ([i, j]) => map[i][j];
const isWall = (p) => char(p) == "#";
const isItem = (p) => {
const c = char(p)
return c >= "a" && c <= "z" && !collected.includes(c)
}
function assemblePath(dest) {
let p = dest;
const res = [p];
while ((p = visited[p])) {
if (isOrigin(p)) break;
res.push(p);
}
return res.reverse();
}
while (queue.length) {
let [current, parent] = queue.shift();
visited[current] = parent;
if (isItem(current)) {
let path = assemblePath(current);
objects.push([char(current), current, path.length])
continue
}
for (let dir of DIRS) {
let next = move(current, dir);
if (isWall(next)) continue;
if (visited[next]) continue;
queue.push([next, current]);
}
}
return objects;
}
Insert cell
function findMinRoute(map, origin) {
let minCollected, minDist = Infinity
function visit(current, distance, collected) {
const items = findItemsM(map, current, collected)
if (items.length == 0) {
if (distance < minDist) {
minDist = distance
minCollected = collected
}
return
}
for (let [name, pos, steps] of items) {
visit(pos, distance + steps, collected + name)
}
}
visit(origin, 0, '')
return [minDist, minCollected]
}

Insert cell
findMinRoute(MAP, [1, 5])
Insert cell
MAP2 = `
##################
# a @ d #
### ##############
# e b c #
##################
`.split('\n').slice(1,-1)
Insert cell
findMinRoute(MAP2, [1, 5])
Insert cell
MAP3 = `
########################
# @a b d#
### # # ## ### ########
#h# # # ## ### ######e#
# #g#f## c# #
########################
`.split("\n")
.slice(1, -1);
Insert cell
findMinRoute(MAP3, [1, 5])
Insert cell
Insert cell
function findMinRouteR(map, origin) {
function minDistance(collected, current) {
const items = findItemsM(map, current, collected)
if (items.length == 0) return 0
let distances = []
for (let [item, itemPos, itemSteps] of items) {
distances.push(itemSteps + minDistance(collected + item, itemPos))
}
return Math.min(...distances)
}
return minDistance('', origin)
}
Insert cell
findMinRouteR(MAP, [1, 5])
Insert cell
findMinRouteR(MAP2, [1, 5])
Insert cell
findMinRouteR(MAP3, [1, 5])
Insert cell
function key(str) {
return str.slice(0, -1).split('').sort().join('') + str[str.length - 1]
}
Insert cell
function findMinRouteM(map, start) {
const m = {}
function minDistance(collected, current) {
const items = findItemsM(map, current, collected)
if (items.length == 0) return 0
const k = key(collected)
if (k in m) return m[k]
let distances = []
for (let [item, itemPos, itemDist] of items) {
distances.push(itemDist +
minDistance(collected + item, itemPos)
)
}
m[k] = Math.min(...distances)
return m[k]
}
return minDistance('', start)
}
Insert cell
findMinRouteM(MAP, [1, 5])
Insert cell
findMinRouteM(MAP2, [1, 5])
Insert cell
findMinRouteM(MAP3, [1, 5])
Insert cell
MAP4 = `
#################
#i. ..c...e.. .p#
########.########
#j. ..b...f.. .o#
########@########
#k. ..a...g.. .n#
########.########
#l. ..d...h.. .m#
#################
`.split('\n').slice(1,-1)
Insert cell
findMinRouteM(MAP4, [4, 8])
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more