I’m currently working for a project with TOP and I’m asked to find the shortest path between 2 squares with a Knight on a 8×8 chessboard. Imagine I want to go from 0,0 to 7,7, my algo need to return me the shortest path, with all squares visited relative to this shortest path.
For this project, I’ve created a Graph class with an Adjacency List object. I’ve created an addEdge and addVertex functions and populateGraph and populateEdge functions.
populateGraph create vertexs from 00 to 77 as properties of adjacency List and populateEdges create edges for all properties following the knight moves rules in a chess game.
With this, I can create a BFS function with 2 params ( start and end ) who will give me the number of moves before reaching the end from the start.
For this, I create a queue with source as first element and create a visited Set and knightMove counter at 0.
While my queue is not empty, I take the first element of my queue, if it has been visited, it loop until a fresh element, else if this element is my end, I return my number of moves, else I increase my knightMove, put this element in my visited Set and take his childrens and push them into the queue.
To reach 0.0 to 7.7, it take me 63 moves. To move from 0.0 to 1.2 it take me one move.
I think I could once the ending node has been found, reconstruct the path by working on all the visited squares, but I don’t know how to do this or if this is a good solution.
Here is my BFS :
js
bfs(source, destination) {
const queue = [source];
const result = [];
const visited = new Set();
let knightMoves = 0;
while (queue.length !== 0) {
let max = queue[0];
for (let i = 0; i < queue.length; i += 1) {
if (queue[i] > max) {
max = queue[i];
}
}
let current = max;
while (visited.has(current)) {
current = queue.shift();
}
console.log(visited);
if (current === destination) {
console.log('Ive found the position.');
console.log(`This is number of moves before found : ${knightMoves}`);
return;
}
knightMoves += 1;
visited.add(current);
const neighbor = this.adjacencyList[current];
neighbor.forEach((value) => {
if (visited.has(value)) {
return;
}
queue.push(value);
});
}
}
2
Answers
You can simply store the coordinate of the square from which the move was made to go to every other square. Then the path can be reconstructed in reverse. Alternatively, you can run a DFS where you keep track of the current path instead.
A simplified version of your code that handles this:
Note that is is a very bad idea to use an array as a queue: removing from the front takes linear, not constant, time.
That is far from optimal. The target can be reached in 6 moves.
To reconstruct the path, keep track where you came from whenever you mark a square as visited.
Similar to the other answer, here is one that doesn’t use a queue, but uses two arrays. Also, I didn’t build a graph, but looked for valid knight jumps while performing BFS. The square positions in
bfs
are single integers from 0 to 63. There are conversion functions from/to row/col coordinates.The path that is output has these visited squares to go from 0,0 to 7,7:
…so 6 moves in total.