[SOLVED] Python variable manipulated indirectly without being mentioned in function

Issue

I’m a coding beginner that’s putting a project together for a game. To update the game board, I use this function:

Board = [0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
def boardupdate(self, move):
    for index, val in enumerate(move):
        try:
            if val >= 15:
                val -= 3
                move[index] = val
        except TypeError:
            pass
    try: self[move[0]] = 1
    except Exception: None
    try: self[move[1]] = 0
    except Exception: None
    try: self[move[2]] = 0
    except Exception: None
    return self

Where the first item of the list move represents the location where a piece is being placed in a turn, the second item representing where the piece is being taken from (in this game, you can either place a new piece on the board or move a piece), and the third item represents where a piece is being completely removed from the game. A certain turn can involve any of or none of these actions, hence the try and except blocks (which I learned just today, so if I am using them incorrectly, help would be much appreciated).

The code works as intended inside the function, but for some reason after this function is called, Board gets changed as if it was run through the function.

print(Board)
print(boardupdate(Board, [0, None]))
print(Board)

returns:

[0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

I’ve tried to solve this by copying Board to a temporary variable like so:

def boardupdate(self, move):
    tempboard = self
    for index, val in enumerate(move):
        try:
            if val >= 15:
                val -= 3
                move[index] = val
        except TypeError:
            pass
    try: tempboard[move[0]] = 1
    except Exception: None
    try: tempboard[move[1]] = 0
    except Exception: None
    try: tempboard[move[2]] = 0
    except Exception: None
    return tempboard

Returns the same output as before. How can I change the output of this function without messing around with the initial conditions of Board? This is necessary in order for the rest of my code to run. Thanks!

Solution

tempboard = board doesn’t copy board, it just binds tempboard to the same value as board. If you do:

tempboard = board.copy()

it will actually copy board.

Some other miscellaneous advice on this function:

  • Don’t call the board parameter self, since this isn’t an instance method on the board itself. Just call it something like board.
  • Don’t catch all exceptions blindly; it makes errors very difficult to debug. If you have an error in your code, you want it to raise an exception so you can see exactly what went wrong right away, rather than spending hours trying to figure out why it’s just not doing anything! I’d suggest adopting a convention that a move you aren’t making is None, and then checking for None specifically, rather than just ignoring any attempted move that raises an exception.
  • Use named variables and/or comments to keep track of what the different move items represent.
def boardupdate(board, move):
    board = board.copy()
    # Subtract 3 from any move positions >= 15.
    move = [p if p is None or p < 15 else p - 3 for p in move]

    [moved_to, moved_from, removed] = move
    if moved_to is not None:
        board[moved_to] = 1
    if moved_from is not None:
        board[moved_from] = 0
    if removed is not None:
        board[removed] = 0

    return board

Answered By – Samwise

Answer Checked By – David Marino (BugsFixing Volunteer)

Leave a Reply

Your email address will not be published.