0

Suppose I have a grid in javascript represented as such: ** Note this is just a tiny grid to serve as an example.

{
    "width": 5,
    "height": 5,
    "nodes": [
        [{
            "x": 0,
            "y": 0,
            "walkable": true
        }, {
            "x": 1,
            "y": 0,
            "walkable": true
        }, {
            "x": 2,
            "y": 0,
            "walkable": true
        }, {
            "x": 3,
            "y": 0,
            "walkable": true
        }, {
            "x": 4,
            "y": 0,
            "walkable": true
        }],
        [{
            "x": 0,
            "y": 1,
            "walkable": true
        }, {
            "x": 1,
            "y": 1,
            "walkable": true
        }, {
            "x": 2,
            "y": 1,
            "walkable": true
        }, {
            "x": 3,
            "y": 1,
            "walkable": true
        }, {
            "x": 4,
            "y": 1,
            "walkable": true
        }],
        [{
            "x": 0,
            "y": 2,
            "walkable": true
        }, {
            "x": 1,
            "y": 2,
            "walkable": true
        }, {
            "x": 2,
            "y": 2,
            "walkable": true
        }, {
            "x": 3,
            "y": 2,
            "walkable": true
        }, {
            "x": 4,
            "y": 2,
            "walkable": true
        }],
        [{
            "x": 0,
            "y": 3,
            "walkable": true
        }, {
            "x": 1,
            "y": 3,
            "walkable": true
        }, {
            "x": 2,
            "y": 3,
            "walkable": true
        }, {
            "x": 3,
            "y": 3,
            "walkable": true
        }, {
            "x": 4,
            "y": 3,
            "walkable": true
        }],
        [{
            "x": 0,
            "y": 4,
            "walkable": true
        }, {
            "x": 1,
            "y": 4,
            "walkable": true
        }, {
            "x": 2,
            "y": 4,
            "walkable": true
        }, {
            "x": 3,
            "y": 4,
            "walkable": true
        }, {
            "x": 4,
            "y": 4,
            "walkable": true
        }]
    ]
}

The "walkable" boolean will determine which areas are blocked off so to speak.

How would I flood this grid to mark the isolated areas? In the above example, a flood fill would fill the entire grid with a single color, because all areas are walkable. But supposing the grid had some areas which were unreachable from other areas (based on the walkable bool), how would I mark the different areas? I basically want to set a color property for each node. If the node isn't the same color as another node, then I know it can't be reached from that node.

EDIT:

Here's what I have so far. Can't run this on a node without getting a maximum call stack error:

function floodFill(node, grid) {

    if (node.walkable == false) {
        return;
    }
    if ((node.floodColor != undefined) && (node.floodColor == 'red')) {
        return;
    }

    node.floodColor = 'red';

    if ((grid.nodes[node.y + 1] != undefined) && (grid.nodes[node.y + 1][node.x] != undefined)) {
        floodFill(grid.nodes[node.y + 1][node.x], grid);
    }
    if ((grid.nodes[node.y - 1] != undefined) && (grid.nodes[node.y - 1][node.x] != undefined)) {
        floodFill(grid.nodes[node.y - 1][node.x], grid);
    }

    if ((grid.nodes[node.y] != undefined) && (grid.nodes[node.y][node.x + 1] != undefined)) {

        floodFill(grid.nodes[node.y][node.x + 1], grid);

    }

    if ((grid.nodes[node.y] != undefined) && (grid.nodes[node.y][node.x - 1] != undefined)) {

        floodFill(grid.nodes[node.y][node.x - 1], grid);

    }

}

For those of you who did answer, the above is the sort of thing i am looking for. Descriptions of what to do don't help me, as I've already read quite a bit of descriptions of what to do. Explicit code please :p

Chris Scott
  • 583
  • 1
  • 7
  • 23
  • Not related, but you should organize that table. You could use a matrix (an array of arrays) instead of a messy object like that. It provides length and indexes so you don't have to write them yourself. And it's also much more easy to write and read. ```[[true,true,true,true],[true,true,true,true],[true,true,true,true],[true,true,true,true]]``` or shorter using 1 instead of true – Stefan Octavian Feb 11 '18 at 21:02
  • is walkability determined based on the clicked node, or is it used to determine if a node is an island (and unreachable) – Fallenreaper Feb 11 '18 at 21:07

2 Answers2

0

Simply repeat flood-fill from many different locations. Just make sure to not fill the same area twice and your algorithm would still work in linear time, assuming reasonable representation of neighborhood (for example a matrix).

n_colors = 0;
for field in grid:
    if field has no color assigned yet:
        floodFill(fromField: field, color: n_colors)
        n_colors = n_colors + 1
zch
  • 14,931
  • 2
  • 41
  • 49
0

I will try this :

  • first create a resultMap which is a copy of your current grid with a color attribute by point, set all the walkable === false points to color: black

    const floodMap = yourData.nodes
       .map(n => n.map(p => {...p, {color: p.walkable ? 'black': undefined ));
    
  • create a function flood(x, y, color) which take a point in input. If this point is already colored, then do nothing (and return false), otherwise apply color take the (4 or 8 according to your rule) connected points if they aren't colored, and run flood(x', y', color) on them (and return true).

    function flood(x, y, color) {
        if(!floodMap[y][x].color) {
          floodMap(x + 1, y, color);
          floodMap(x - 1, y, color);
          floodMap(x, y + 1, color);
          floodMap(x, y - 1, color);
          return true;
        }
        return false;
    }
    
  • apply this function for each point of the matrix by changing the color each time the previous call have returned true.

    const colors = ['red', 'blue', 'yellow', 'green', 'purple'];
    const currentColor = 0;
    floodMap.forEach(n => n.forEach(p => {
      const flooded = flood(p.x, p.y, colors[currentColor]);
      if(flooded) currentColor++;
    }));
    
  • i was hoping for some literal code as reading descriptions of what to do gets me no further than reading the wikipedia article on flood fills. – Chris Scott Feb 11 '18 at 21:59
  • i have added some examples of codes below each comments. – Not the best answer Feb 12 '18 at 07:29
  • please see my edit. i more of less do what you suggest. however, i keep getting call stack error. sometimes i don't get an error and it works perfectly (depends on the node i start with). – Chris Scott Feb 12 '18 at 20:08