Skip to content

Instantly share code, notes, and snippets.

@rikyperdana
Created April 28, 2024 09:44
Show Gist options
  • Save rikyperdana/af7551222a6637cbc30e4900bd9e214d to your computer and use it in GitHub Desktop.
Save rikyperdana/af7551222a6637cbc30e4900bd9e214d to your computer and use it in GitHub Desktop.
Pathfinder Algorithm and Vehicle Routing Problem in Functional Javascript
cityMap = {
a: {b: 20, d: 80, g: 90},
b: {f: 10},
c: {f: 50, h: 20, d: 10},
d: {g: 20, c: 10},
e: {b: 50, g: 30},
f: {c: 10, d: 40},
g: {a: 20},
h: {h: 0}
}
largeMap = {
a: {b: 8, c: 3, f: 13},
b: {d: 1, c: 2},
c: {b: 3, d: 9, e: 2},
d: {e: 4, h: 2, g: 6},
e: {i: 4, f: 5, a: 5},
f: {i: 7, g: 1},
g: {h: 4},
h: {i: 1},
i: {g: 5}
}
pFinder = (graph, from, dest, path = {[from]: 1}) =>
Object.keys(graph).filter(i => !path[i]).reduce(
(acc, next) => graph[from]?.[next] ? [...acc, ...pFinder(
graph, next, dest, {...path, [from]: graph[from][next]}
)] : [...acc, ...(!acc.length && from === dest ? [path] : [])], []
)
between = (low, mid, high) => low < mid && mid < high
sum = arr => arr.reduce((a, b) => a + b)
sub = arr => arr.splice(1).reduce((a, b) => a - b, arr[0])
shortestPath = (graph, from, dest) =>
pFinder(graph, from, dest).sort((a, b) => sub([
sum(Object.values(a)), sum(Object.values(b))
]))[0]
longestPath = (graph, from, dest) =>
pFinder(graph, from, dest).sort((a, b) => sub([
sum(Object.values(b)), sum(Object.values(a))
]))[0]
conditionPath = (graph, from, dest, cond) =>
pFinder(graph, from, dest).filter(cond)
withAs = (obj, cb) => cb(obj)
uniqObj = arrObj =>
[...new Set(arrObj.map(JSON.stringify) || {})]
.map(JSON.parse)
lastNode = paths => Object.keys(
paths.slice(-1)[0] || {}
).slice(-1)[0]
subset = (sub, set) => sub.length && set.length &&
sub.reduce((a, b) => a && set.includes(b), true)
solveVRP =
(algo, graph, from, places, trace = places, paths = []) =>
!trace.length || subset(places, Object.keys(paths.reduce(
(a, b) => ({...a, ...b}), {}
))) ? paths.map(JSON.stringify).join(';') :
trace.reduce((acc, dest) => [...acc, solveVRP(
algo, graph, lastNode(paths), places,
trace.filter(i => i !== dest), [...paths, withAs(
algo(graph, lastNode(paths) || from, dest),
short => short && ({...short, [dest]: 0})
)]
)], []).flat(1)
pathVRP = result => uniqObj(result.map(i => i.split(';').flatMap(
j => withAs(JSON.parse(j), obj => Object.keys(obj))
.map(k => [k, JSON.parse(j)[k]])
).filter((j, jx, arr) => jx === arr.length - 1 ? j : j[1])))
shortestVRP = (graph, from, destinations) =>
pathVRP(solveVRP(shortestPath, graph, from, destinations))
.sort((a, b) => sub([
sum(a.map(i => i[1])),
sum(b.map(i => i[1]))
]))[0]
longestVRP = (graph, from, destinations) =>
pathVRP(solveVRP(longestPath, graph, from, destinations))
.sort((a, b) => sub([
sum(b.map(i => i[1])),
sum(a.map(i => i[1]))
]))[0]
/* Functions call samples
pFinder(cityMap, 'g', 'h')
longestPath(cityMap, 'e', 'h')
shortestPath(cityMap, 'e', 'h')
conditionPath(cityMap, 'e', 'h', path => Object.keys(path).includes('d'))
conditionPath(cityMap, 'e', 'h', path => Object.keys(path).length <= 4)
conditionPath(cityMap, 'e', 'h', path => between(110, sum(Object.values(path)), 150))
conditionPath(cityMap, 'e', 'h', path => Object.values(path).filter(i => i >= 80).length)
pathVRP(solveVRP(shortestPath, largeMap, 'a', ['g', 'h', 'i']))
solveVRP(shortestPath, largeMap, 'a', ['g', 'h', 'i'])
shortestVRP(largeMap, 'a', ['g', 'h', 'i'])
longestVRP(largeMap, 'a', ['g', 'h', 'i'])
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment