1
votes

As part of a game, I am building a 2d grid where I need to find out if two items on the grid are connected. There are e.g. traps and walls that are blocking the way so basically I end up with separate parts of the grid divided by the walls and traps, so I'm flood filling the grid starting from a point P on the grid to find out which points belong to the same part with P.

Here's what the code basically does:

1) build the grid based on an input file (works)

2) find the starting point P (works)

3) flood fill from P (DOES NOT WORK)

4) print the grid to check if it's right (works)

The grid is built just fine, and the starting point is found as well, but the flood fill function does not work. Any ideas?

Example input file:

7 9
#######
#..#G.#
#...TG#
#.....#
#...G.#
#...#.#
###.P.#
#G#.TG#
#######

(UPDATED, works ok now) Running the code with that prints the following:

Start point at: [4, 6] (i.e. in grid[6][4])
[0, '#'][2, '#'][2, '#'][0, '#'][2, '#'][2, '#'][0, '#']
[2, '#'][1, '.'][1, '.'][2, '#'][1, 'G'][1, '.'][2, '#']
[2, '#'][1, '.'][1, '.'][1, '.'][2, 'T'][1, 'G'][2, '#']
[2, '#'][1, '.'][1, '.'][1, '.'][1, '.'][1, '.'][2, '#']
[2, '#'][1, '.'][1, '.'][1, '.'][1, 'G'][1, '.'][2, '#']
[2, '#'][1, '.'][1, '.'][1, '.'][2, '#'][1, '.'][2, '#']
[0, '#'][2, '#'][2, '#'][1, '.'][1, 'P'][1, '.'][2, '#']
[0, '#'][0, 'G'][2, '#'][1, '.'][2, 'T'][1, 'G'][2, '#']
[0, '#'][0, '#'][0, '#'][2, '#'][0, '#'][2, '#'][0, '#']

(UPDATED, works fine) And here's the code itself:

if __name__ == "__main__":

  class Node:
    UNEXPLORED = 0
    CONNECTED = 1
    VISITED = 2

    def __init__(self, x, y, value):
      self.x = x
      self.y = y
      self.state = Node.UNEXPLORED
      self.value = value

    def neighbor_with(self, node):
      x_dist = abs(self.x - node.x)
      y_dist = abs(self.y - node.y)
      if x_dist == 1 and y_dist == 0:
        return True
      elif x_dist == 0 and y_dist == 1:
        return True
      else:
        return False

    def trap_or_wall(self):
      if self.value == "T" or self.value == "#":
        return True
      else:
        return False

    def __str__(self):
      return str([self.state,self.value])



  with open('in1.txt', 'r') as f:

    row = f.readline()
    dimensions = row.split(" ")
    w = int(dimensions[0])
    h = int(dimensions[1])

    grid = [[Node(j,i, None) for i in range(w)] for j in range(h)]

    #set grid
    for i in range(h):
      row = f.readline()
      for j in range(w):
        grid[i][j].value = row[j]

    #find P
    p = []
    for i in range(h):
      for j in range(w):
        if grid[i][j].value == "P":
          p = [grid[i][j].y, grid[i][j].x]
    print("Start point at: {:} (i.e. in grid[{:}][{:}])".format(p,p[1],p[0]))

    #define function to flood fill the connected part
    def fill_connected(matrix, node):
      if node.state == Node.UNEXPLORED:
        node.state = Node.VISITED
        if not node.trap_or_wall():
          node.state = Node.CONNECTED
          #recursively for neighbors
          for i in range(h):
            for j in range(w):
              if matrix[i][j].neighbor_with(node):
                fill_connected(matrix, grid[i][j])

    #flood fill from P
    fill_connected(grid, grid[p[1]][p[0]])

    #check grid, i.e. print it
    for i in range(h):
      for j in range(w):
        print(grid[i][j], end="")
      print("\n", end="")
    print()

EDIT:

I updated the code to account for the mistakes in the order of coordinates, x=4 and y=6 should now be grid[6][4]. I fixed the other errors after that then, but I still do not understand one thing: in the last line of the flood fill function definition, why does it have to be grid[i][j] instead of grid[j][i]? The latter one produces an out of range error.

1

1 Answers

2
votes

You mess up with the order of coordinates. You use grid(Y, X) almost everywhere, except for the fill function. See the initial call: you find the P at x=4 y=6 which is i=6 j=4. And then you call fill_connected(4,6). This is a point in the right wall.

I would work on list indices only, if there is no good reason for extra coordinates.