Created
December 7, 2022 18:26
-
-
Save EvanWieland/3fdfc74e064a335b4221d74e8575e853 to your computer and use it in GitHub Desktop.
DFS & Hill Climb in NodeJS
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Evan Wieland | |
12/7/2022 | |
Usage: | |
$ node dfs-hill-climb.js | |
> Would you like to run the tests or supply your own graph (y/n)? | |
> n | |
> | |
> Please supply the weighted graph to be searched, as an adjacency list: | |
> a b 8 c 4 | |
> b c 2 d 7 | |
> c b 2 d 1 | |
> d b 1 c 5 g 3 | |
> g c 4 d 3 | |
> | |
> Please supply the start node: | |
> a | |
> | |
> Please supply the goal node: | |
> g | |
> | |
> DFS: a -> c -> d -> g | |
> Hill climb: a -> c -> d -> g | |
*/ | |
const readline = require("readline"); | |
const rl = readline.createInterface({ | |
input: process.stdin, | |
output: process.stdout | |
}); | |
const dfs = (graph, start, goal) => { | |
const stack = [start]; | |
const visited = new Set(); | |
const path = []; | |
while (stack.length > 0) { | |
const node = stack.pop(); | |
if (node === goal) { | |
path.push(node); | |
break; | |
} | |
if (!visited.has(node)) { | |
visited.add(node); | |
path.push(node); | |
for (const child in graph[node]) { | |
stack.push(child); | |
} | |
} | |
} | |
return pathToString(path); | |
}; | |
const hillClimb = (graph, start, goal) => { | |
const stack = [start]; | |
const visited = new Set(); | |
const path = []; | |
while (stack.length > 0) { | |
const node = stack.pop(); | |
if (node === goal) { | |
path.push(node); | |
break; | |
} | |
if (!visited.has(node)) { | |
visited.add(node); | |
path.push(node); | |
const children = Object.entries(graph[node]); | |
// Find if children contains goal | |
const goalChild = children.find(([child]) => child === goal); | |
if (goalChild) { | |
path.push(goal); | |
break; | |
} | |
// Sort children by weight | |
const sorted = children.sort((a, b) => a[1] - b[1]); | |
const child = sorted[0][0]; | |
stack.push(child); | |
} | |
} | |
return pathToString(path); | |
}; | |
const pathToString = (path) => { | |
return path.join(' -> '); | |
}; | |
const runTests = () => { | |
const graph = { | |
a: {b: 8, c: 4}, | |
b: {c: 2, d: 7}, | |
c: {b: 2, d: 1}, | |
d: {b: 1, c: 5, g: 3}, | |
g: {c: 4, d: 3}, | |
}; | |
const testCases = [ | |
['a', 'g'], | |
['a', 'b'], | |
['b', 'g'], | |
['b', 'c'], | |
['c', 'g'], | |
['c', 'b'], | |
['d', 'c'], | |
['d', 'b'], | |
]; | |
testCases.forEach(([start, goal]) => { | |
console.log('Start', start, ', Goal', goal); | |
console.log('DFS:', dfs(graph, start, goal)); | |
console.log('Hill climb:', hillClimb(graph, start, goal), '\n'); | |
}); | |
rl.close(); | |
}; | |
const runUserInput = () => { | |
const graph = {}; | |
console.log('Please supply the weighted graph to be searched, as an adjacency list:'); | |
rl.on('line', (input) => { | |
input = input.trim(); | |
if (input === '') { | |
rl.question('Please supply the start node:\n', (start) => { | |
rl.question('\nPlease supply the goal node:\n', (goal) => { | |
console.log('\nDFS:', dfs(graph, start, goal)); | |
console.log('Hill climb:', hillClimb(graph, start, goal)); | |
rl.close(); | |
}); | |
}); | |
} else { | |
const [node, ...adj] = input.split(' '); | |
graph[node] = {}; | |
for (let i = 0; i < adj.length; i += 2) { | |
graph[node][adj[i]] = parseInt(adj[i + 1]); | |
} | |
} | |
}); | |
}; | |
rl.question('Would you like to run the tests or supply your own graph (y/n)?', (input) => { | |
if (input === 'y') { | |
runTests(); | |
} else { | |
runUserInput(); | |
} | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment