Hey. I'm working on a simple project that requires a way to find all the empty grid cells accessible along a path that's <= n cells long (an analogy would be TBS movement), and I've got an almost-working piece of code for it. Here's the function I wrote:

def findArea(distance,origin,gridUsed,emptyChar):
    if emptyChar == "x":
        seenChar = "X"
    else:
        seenChar = "x"
    grid = gridUsed
    grid[origin[0]][origin[1]] = seenChar
    returnList = [[origin[0],origin[1]]]
    if distance > 0:
        # x,y-1
        if (origin[1]-1) >= 0:
            if (grid[origin[0]][origin[1]-1] == emptyChar):
                returnList += findArea(distance-1,[origin[0],origin[1]-1],grid,emptyChar)

        # x,y+1
        if (origin[1]+1) < len(grid[0]):
            if (grid[origin[0]][origin[1]+1] == emptyChar):
                returnList += findArea(distance-1,[origin[0],origin[1]+1],grid,emptyChar)

        # x-1,y
        if (origin[0]-1) >= 0:
            if (grid[origin[0]-1][origin[1]] == emptyChar):
                returnList += findArea(distance-1,[origin[0]-1,origin[1]],grid,emptyChar)

        # x+1,y
        if (origin[0]+1) < len(grid):
            if (grid[origin[0]+1][origin[1]] == emptyChar):
                returnList += findArea(distance-1,[origin[0]+1,origin[1]],grid,emptyChar)
    returnList.sort()
    print "gridUsed:"
    print gridUsed
    print "grid:"
    print grid
    return returnList

gridW = 4
gridH = 4
emptyChar = " "

gameGrid = []
for xVar in range(0,gridW):
    gameGrid.append([])
    for yVar in range(0,gridH):
        gameGrid[xVar].append(emptyChar)

print "Before anything:"
print gameGrid
findArea(1,[2,2],gameGrid,emptyChar)
print "After everything:"
print gameGrid

You'll notice a lot of print-ing going on that's not really needed. The reason for that is I'm trying to debug it, and I'm having serious trouble. gameGrid, which exists on the main level, is somehow being altered within findArea. Which makes no sense. As far as I know, findArea has its own level of scope, it shouldn't be able to make changes outside that. Not to mention that I don't actually use gameGrid within findArea. The problem persists no matter what the variable is named.

This really is starting to get to me. Anyone know what's going on, and how to fix it?

When you send a mutable object like a list to a function as an argument, a pointer to the object is established (allows the objects to be mutable). Inside the function you have created a simple alias copy of the list, that still has the same pointer reference. With a nested list like you have, you really have to make a true or deep copy that will have its own reference even to the nested lists inside of it. Just look over the modified code ...

def findArea(distance, origin, gridUsed, emptyChar):
    if emptyChar == "x":
        seenChar = "X"
    else:
        seenChar = "x"
    # make a true copy rather than an alias copy  !!!!!
    import copy
    grid = copy.deepcopy(gridUsed)
    grid[origin[0]][origin[1]] = seenChar
    returnList = [[origin[0],origin[1]]]
    if distance > 0:
        # x,y-1
        if (origin[1]-1) >= 0:
            if (grid[origin[0]][origin[1]-1] == emptyChar):
                returnList += findArea(distance-1,[origin[0],origin[1]-1],grid,emptyChar)

        # x,y+1
        if (origin[1]+1) < len(grid[0]):
            if (grid[origin[0]][origin[1]+1] == emptyChar):
                returnList += findArea(distance-1,[origin[0],origin[1]+1],grid,emptyChar)

        # x-1,y
        if (origin[0]-1) >= 0:
            if (grid[origin[0]-1][origin[1]] == emptyChar):
                returnList += findArea(distance-1,[origin[0]-1,origin[1]],grid,emptyChar)

        # x+1,y
        if (origin[0]+1) < len(grid):
            if (grid[origin[0]+1][origin[1]] == emptyChar):
                returnList += findArea(distance-1,[origin[0]+1,origin[1]],grid,emptyChar)
    returnList.sort()
    print "gridUsed:"
    print gridUsed
    print "grid:"
    print grid
    return returnList

gridW = 4
gridH = 4
emptyChar = " "

gameGrid = []
for xVar in range(0,gridW):
    gameGrid.append([])
    for yVar in range(0,gridH):
        gameGrid[xVar].append(emptyChar)

print "Before anything:"
print gameGrid
returnList = findArea(1, [2,2], gameGrid, emptyChar)
print "After everything:"
print gameGrid  # now unchanged!
print returnList

Actually, Zoe brought this up just recently:
http://www.daniweb.com/forums/post593852-134.html

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.