pythonflood-fill

How do I use flood fill in a nested for loop to count the number of "rooms" in a 2d grid?


I'm trying to use a flood fill algorithm to count the number of "rooms" in a 2d grid. I have the algorithm already which is:

import sys

im = [list('...##########....................................'),
      list('...#........#....####..................##########'),
      list('...#........#....#..#...############...#........#'),
      list('...##########....#..#...#..........#...##.......#'),
      list('.......#....#....####...#..........#....##......#'),
      list('.......#....#....#......############.....##.....#'),
      list('.......######....#........................##....#'),
      list('.................####........####..........######')]

HEIGHT = len(im)
WIDTH = len(im[0])

def floodFill(image,x,y,newChar, oldChar = None):
        if oldChar == None:
            oldChar = image[y][x]
        if oldChar == newChar or image[y][x] != oldChar:
            return

        image[y][x] = newChar

        if y + 1 < HEIGHT and image[y + 1][x] == oldChar:
            floodFill(image, x, y + 1, newChar, oldChar)
        if y - 1 >= 0 and image[y - 1][x] == oldChar:
            floodFill(image, x, y - 1, newChar, oldChar)

        if x + 1 < WIDTH and image[y][x + 1] == oldChar:
            floodFill(image, x + 1, y, newChar, oldChar)
        if x - 1 >= 0 and image[y][x - 1] == oldChar:
            floodFill(image, x - 1, y, newChar, oldChar)
        return

def printImage(image):
    for y in range(HEIGHT):
        for x in range(WIDTH):
            sys.stdout.write(image[y][x])
        sys.stdout.write('\n')
    sys.stdout.write('\n')

What I'm trying to do is use a nested for loop to find the periods and run the algorithm, but I'm not sure how to successfully adjust the x and y coordinates as I run through the list. So far what I have is:

def loops(image):
    count = 0
    for i in image:
        for j in i:
            if j == '.':
                count += 1
                x =
                y =
                floodFill(image,x,y,'?',oldChar=None)

My question is, how do I find the x and y coordinate of the periods to place into my function?


Solution

  • You could use Python's built-in enumerate() function to determine the needed indices easily. You didn't ask, but I also suggest that you use its print() function to output the image instead of writing directly to sys.stdout. In addition to that, the whole function could be simplified by outputting a whole row at a time.

    Here's your code with those modifications (along with some other formatting changes I made to make it more readable). Note that I don't think your loops() function is identifying the "rooms" correctly, but also don't think that was what you asked about.

    img = [list('...##########....................................'),
           list('...#........#....####..................##########'),
           list('...#........#....#..#...############...#........#'),
           list('...##########....#..#...#..........#...##.......#'),
           list('.......#....#....####...#..........#....##......#'),
           list('.......#....#....#......############.....##.....#'),
           list('.......######....#........................##....#'),
           list('.................####........####..........######')]
    
    HEIGHT = len(img)
    WIDTH = len(img[0])
    
    def floodFill(image, x, y, newChar, oldChar=None):
            if oldChar == None:
                oldChar = image[y][x]
            if oldChar == newChar or image[y][x] != oldChar:
                return
    
            image[y][x] = newChar
    
            if y+1 < HEIGHT and image[y+1][x] == oldChar:
                floodFill(image, x, y+1, newChar, oldChar)
            if y-1 >= 0 and image[y-1][x] == oldChar:
                floodFill(image, x, y-1, newChar, oldChar)
    
            if x+1 < WIDTH and image[y][x+1] == oldChar:
                floodFill(image, x+1, y, newChar, oldChar)
            if x-1 >= 0 and image[y][x-1] == oldChar:
                floodFill(image, x-1, y, newChar, oldChar)
            return
    
    def printImage(image):
    #    for y in range(HEIGHT):
    #        for x in range(WIDTH):
    #            print(image[y][x], end='')
    #        print()
    #    print()
        for row in image:
            print(''.join(row))
    
    def loops(image):
        count = 0
        for y, i in enumerate(image):
            for x, j in enumerate(i):
                if j == '.':
                    count += 1
                    floodFill(image, x, y, '?', oldChar=None)
    
    loops(img)
    printImage(img)
    
    

    Results:

    ???##########????????????????????????????????????
    ???#????????#????####??????????????????##########
    ???#????????#????#??#???############???#????????#
    ???##########????#??#???#??????????#???##???????#
    ???????#????#????####???#??????????#????##??????#
    ???????#????#????#??????############?????##?????#
    ???????######????#????????????????????????##????#
    ?????????????????####????????####??????????######