I cant seem to get breadth first search right. Ive gone through redblobs implementation guides of hex grids and have that all figured out but pathfinding is proving to be difficult.

So I have a search function that implements the algorithm.

function searchPath(graph, start, goal) {
    let cameFrom = [start]
    let frontier = new Queue()

    while (!frontier.isEmpty) {
        const current = frontier.dequeue()

        if (current === goal) break

        graph[current].forEach(next => {
            if (!cameFrom.includes(next)) {
    return cameFrom

my graph is a two dimensional array where each index corresponds to a tile on the map and the value of each is an array of indexes of neighbors of that tile.


const graph = [

The function returns the indexes of searched tiles.

Example 1: searchPath(graph, 12, 13) will return [12, 7, 8, 13, 16, 3, 4, 9] Example 2: searchPath(graph, 8, 1) will return [8, 3, 7, 12, 4, 9, 13, 0, 16, 1, 5, 10, 14, 17]. Its returning a lot of nodes for what would seem to be a

Now I attempt to reconstruct a path with this function but I cant get it to work. It ends up with an infinite loop.

function findPath(cameFrom, start, goal) {
    let current = goal
    let path = []
    while (current !== start) {
        current = cameFrom[cameFrom.indexOf(current)]
    return path

I have a feeling my graph data structure is off but I just don't know. Heres a link to the current version of the "game". If you open the console you should see the output of the search and the start + goal arguments that are supplied.


Any help would be much appreciated. Thanks!


1 Answer 1


It looks like you are confusing Predecessor Node List and Closed Set.

What's the meaning of cameFrom? In searchPath you use it to store all visited node, but in findPath you use it to reconstruct a path. That's the crux of the matter.


function searchPath(graph, start, goal) {
    let frontier = new Queue();

    var predecessorMap = {}; //a map of the node found by which node

    while (!frontier.isEmpty) {
        const current = frontier.dequeue();
        if (current === goal) break;

        graph[current].forEach(next => {
            if (!(next in predecessorMap)) {
                predecessorMap[next] = current;
    return predecessorMap;

function findPath(predecessorMap, start, goal) {
    let current = goal;
    let path = [];
    while (current !== start) {
        current = predecessorMap[current];
    return path;
  • \$\begingroup\$ It worked like a charm, thank you so much! I honestly don't know what cameFrom was for, it was in a guide I was using for a* and it still didnt make sense to me. This makes so much more sense. I had a feeling I needed to use an object map instead of an array, but it felt weird using index numbers as keys in an object. Thank you again so much!!!! \$\endgroup\$
    – cwahlfeldt
    Apr 23, 2022 at 15:59
  • \$\begingroup\$ cameFrom in the guide is what Mangata calls predecessorMap: it's a map from one node to another. In your code you were using it as an array instead of an object map. \$\endgroup\$
    – amitp
    Apr 23, 2022 at 16:34
  • \$\begingroup\$ Ahh ok makes sense. Also @amitp just wanna say I am forever grateful for all your amazing work on red blob! \$\endgroup\$
    – cwahlfeldt
    Apr 23, 2022 at 17:25

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .