0

I am making a chess game and have a class function that calculates all the legal moves. It does so by having a piece as a parameter and gets all its possible attacking moves. It then loops through these moves and move the piece their temporarily to see if that moves puts himself in check, if it does then it isn't a legal move:

def calculate_legal_moves(self, piece):
    """Get all the legal moves of a piece and returns them"""
    legal_moves = []
    if not isinstance(piece, Pawn):
        possible_legal_moves = self.get_attacking_moves(piece)
        for move in possible_legal_moves:
            if isinstance(self.board[move[0]][move[1]], Piece):
                if not piece.colour == self.board[move[0]][move[1]].colour:
                    possible_board = self.preliminary_move_piece(self.board, piece.position, move)
                    if not self.is_in_check(piece.colour, possible_board):
                        legal_moves.append(move)
            else:
                possible_board = self.preliminary_move_piece(self.board, piece.position, move)
                if not self.is_in_check(piece.colour, possible_board):
                    legal_moves.append(move)
    else:
        if piece.colour == "White":
            legal_moves.append([piece.position[0]-1, piece.position[1]])
            if piece.position[0] == 6:
                legal_moves.append([piece.position[0]-2, piece.position[1]])
        else:
            legal_moves.append([piece.position[0]+1, piece.position[1]])
            if piece.position[0] == 1:
                legal_moves.append([piece.position[0]+2, piece.position[1]])
    return legal_moves

def preliminary_move_piece(self, chess_board, old_coords, new_coords):
    chess_board[new_coords[0]][new_coords[1]] = self.board[old_coords[0]][old_coords[1]]
    chess_board[old_coords[0]][old_coords[1]] = 0
    if isinstance(chess_board[new_coords[0]][new_coords[1]], Piece):
        chess_board[new_coords[0]][new_coords[1]].position = [new_coords[0], new_coords[1]]
    return chess_board

The problem is, that I pass in the instance of the board (a 2d array) and move a piece temporarily to see if that puts him in check, however it seems to be passing the instance variable by reference and so is actually permanently changing the pieces position, thus my piece automatically moves to the last possible legal move when i click on it. Is there a way that I can leave my instance variable (self.board) untouched when i use the preliminary_move_piece function

  • List is mutable in python. Parameter which is mutable object is always passed by reference. Is it possible to make a copy of chess_board and pass the copy to preliminary_move_piece? – Ma Tingchen Mar 01 '16 at 10:28
  • That's what I tried to do but to no avail (original_board = self.board). However when I get home I'll try all these suggestions when possible – user2867973 Mar 01 '16 at 15:00
  • original_board = self.board makes original_board an reference of self.board. What I mean is to create a new list and copy every element of self.board to it. original_board = [[x for x in y] for y in self.board] – Ma Tingchen Mar 02 '16 at 03:50

1 Answers1

2

Since list is mutable in python, it passed by reference to function. To figure it out you can:
a) convert it to tuple: tuple(your_list) because tuple is immutable and passed by value
b) copy your list, in one of different ways, e.g.: copied_list = your_list[:] The very similar question about actually same issue: Python passing list as argument

Community
  • 1
  • 1
Andrii Rusanov
  • 4,405
  • 2
  • 34
  • 54
  • I dont think I can try a tuple but ill see a bit later if I can but I have literally no clue why b) isn't working because I have being trying it earlier and now and it just is still copying. Does it make a difference that it is a class variable and function and that's why its automatically copying, because if i have to convert to tuple then I have to refactor a lot of cocde – user2867973 Mar 01 '16 at 17:32
  • 1
    @user2867973 in this case just copy incoming list inside the function(see link in the answer to check how you can do it). E.g. you can use example I mentioned or `import copy` and make `copy.copy(incoming_list)` – Andrii Rusanov Mar 02 '16 at 08:58
  • 1
    Thank you, I'd just like to make a note for anyone else reading in the future that for me only copy.deepcopy() worked for me, I dont know why, maybe someone can comment on why this is. – user2867973 Mar 02 '16 at 13:41
  • @user2867973, yeah, deepcopy is correct here, my bad. The difference is that `copy` copies the list, but if elements of the list are also mutable object(lists or dict) it doesn't makes a copy - it makes references instead. Deepcopy copies completely all. – Andrii Rusanov Mar 02 '16 at 13:46