Skip to content
Advertisement

How to perform a Javascript object recursive search that match my needs?

Good day,

I am working on a text-based games written in Javascript. I have variable named map that is an associating object containing another object for each rooms. I have found a little algorithm somewhere and I am not sure how to modify it for my specific task.

My variable:

/**
 *       [003]-[004]
 *         |     |
 * [001]-[002] [007]
 *         |     |
 *       [005]-[006]
 **/     
var map = {
    "001" : {
        "Id" : "001",
        "Name" : "Room 001",
        "Directions" : {
            "N" : "",
            "S" : "",
            "E" : "002",
            "W" : ""
        }
    },
    "002" : {
        "Id" : "002",
        "Name" : "Room 002",
        "Directions" : {
            "N" : "003",
            "S" : "005",
            "E" : "",
            "W" : "001"
        }
    },
    "003" : {
        "Id" : "003",
        "Name" : "Room 003",
        "Directions" : {
            "N" : "",
            "S" : "002",
            "E" : "004",
            "W" : ""
        }
    },
    "004" : {
        "Id" : "004",
        "Name" : "Room 004",
        "Directions" : {
            "N" : "",
            "S" : "007",
            "E" : "",
            "W" : "003"
        }
    },
    "005" : {
        "Id" : "005",
        "Name" : "Room 005",
        "Directions" : {
            "N" : "002",
            "S" : "",
            "E" : "006",
            "W" : ""
        }
    },
    "006" : {
        "Id" : "006",
        "Name" : "Room 006",
        "Directions" : {
            "N" : "007",
            "S" : "",
            "E" : "",
            "W" : "005"
        }
    },
    "007" : {
        "Id" : "007",
        "Name" : "Room 007",
        "Directions" : {
            "N" : "004",
            "S" : "006",
            "E" : "",
            "W" : ""
        }
    }
};


function findSteps( id, map, array ) {
    if ( ! ( map && "object" === typeof map ) ) { return; }
    if ( map.Id === id ) { return map; }

    for ( var x in map ) {
        if ( Object.hasOwnProperty.call( map, x ) ) {
            map.Id && array.push( map.Id ); //used to exclude undefined
            var result = findSteps( id, map[ x ], array );

            if ( result !== undefined ) {
                return [ result, array ];
            }
        }
    }
}

console.dir( findSteps( "004", map, [] ) );
// Actually returns [objectObject],001,001,001,002,002,002,003,003,003

I would like the function to return an array of array with all the possible paths that I will later iterate to find the closest available path.

The desired result would be something like:

output = [
    [ "001", "002", "003", "004" ],
    [ "001", "002", "005", "006", "007", "004" ]
]

The function should also accept a startup Id. I am thinking about something that would stop the recursivity if nothing have been found before "map.length"n iterations.

Maybe a little hint would be also appreciated.

Thank you!

http://jsfiddle.net/GxZYX/

PS: I have looked at a few Q/A founds on SO about recursive object search, this is exactly where I found the function I am using.

Edit:

After much thinking, and hopefully I won’t be wrong on that. I believe I only need THE shortest path.

Edit:

http://jsfiddle.net/GxZYX/1/ here is my test of implementing breadth first search. (bugged)

Advertisement

Answer

To find the shortest path between two nodes in an unwheight graph like yours you just need to do a Breadth-first-search.

function linkedPathToList(next, node){
    var path = [];
    while(true){
        path.push(node);
        if(node == next[node]) break;
        node = next[node];
    }
    return path;
}       

var breadthFirstSearch = function( map, startRoomId, endRoomId ) {

    var next = {};
    next[endRoomId] = endRoomId;

    var currentLevel = [ map[endRoomId] ];

    //(the traditional version of the algorithm uses a queue instead of the
    // complicated two-array thing though)

    while( currentLevel.length ) {

        //if curr level is nodes at distance d from the end
        //next level is d+1
        var nextLevel = [];

        for(var i=0; i<currentLevel.length; i++) {
            var node = currentLevel[i];

            if ( node.Id == startRoomId ) {
                return linkedPathToList(next, startRoomId);
            }

            for( var direction in node.Directions ) {
                var neighbor = node.Directions[direction]; 
                if( !next[neighbor] ) {
                    next[neighbor] = node.Id;
                    nextLevel.push( map[neighbor] );
                }
            }
        }

        currentLevel = nextLevel;
    }

    return null;
};

var map = {
    "001" : {
        "Id" : "001",
        "Name" : "Room 001",
        "Directions" : {
            "E" : "002"
        }
    },
    "002" : {
        "Id" : "002",
        "Name" : "Room 002",
        "Directions" : {
            "N" : "003",
            "S" : "005",
            "W" : "001"
        }
    },
    "003" : {
        "Id" : "003",
        "Name" : "Room 003",
        "Directions" : {
            "S" : "002",
            "E" : "004"
        }
    },
    "004" : {
        "Id" : "004",
        "Name" : "Room 004",
        "Directions" : {
            "S" : "007",
            "W" : "003"
        }
    },
    "005" : {
        "Id" : "005",
        "Name" : "Room 005",
        "Directions" : {
            "N" : "002",
            "E" : "006"
        }
    },
    "006" : {
        "Id" : "006",
        "Name" : "Room 006",
        "Directions" : {
            "N" : "007",
            "W" : "005"
        }
    },
    "007" : {
        "Id" : "007",
        "Name" : "Room 007",
        "Directions" : {
            "N" : "004",
            "S" : "006"
        }
    }
};

console.log('shortest path',  breadthFirstSearch( map, "001", "004" ) );
User contributions licensed under: CC BY-SA
10 People found this is helpful
Advertisement