I'm writing a chess interface for fun with my friend, the eventuality being we both make bots and fight them out. I've met a roadblock when I re-evaluate the moves that are legal to look for checks as they should be illegal moves. The actual code for the interface is a couple thousand lines long, but I've simplified the code to show the problem. I'll post the simplified code in which I can replicate the problem and then the key parts which I think cause the problem. The simplified code:
class Pieces():
def __init__(self):
self.white_pawns_inf = [[0, 1, False, True], [1, 1, False, True], [2, 1, False, True], [3, 1, False, True], [4, 1, False, True], [5, 1, False, True], [6, 1, False, True], [7, 1, False, True]]
self.white_bishops_inf = [[2, 0, False], [5, 0, False], [0, 7, False], [0, 7, False], [0, 7, False], [0, 7, False], [0, 7, False], [0, 7, False], [0, 7, False], [0, 7, False]]
self.white_knights_inf = [[1, 0, False], [6, 0, False], [0, 7, False], [0, 7, False], [0, 7, False], [0, 7, False], [0, 7, False], [0, 7, False], [0, 7, False], [0, 7, False]]
self.white_rooks_inf = [[0, 0, False, True], [7, 0, False, True], [0, 7, False, False], [0, 7, False, False], [0, 7, False, False], [0, 7, False, False], [0, 7, False, False], [0, 7, False, False], [0, 7, False, False], [0, 7, False, False]]
self.white_queens_inf = [[3, 0, False], [0, 7, False], [0, 7, False], [0, 7, False], [0, 7, False], [0, 7, False], [0, 7, False], [0, 7, False], [0, 7, False]]
self.white_king_inf = [[4, 0, True, True]]
self.black_pawns_inf = [[0, 6, True, True], [1, 6, True, True], [2, 6, True, True], [3, 6, True, True], [4, 6, True, True], [5, 6, True, True], [6, 6, True, True], [7, 6, True, True]]
self.black_bishops_inf = [[2, 2, True], [5, 7, True], [0, 7, False], [0, 7, False], [0, 7, False], [0, 7, False], [0, 7, False], [0, 7, False], [0, 7, False], [0, 7, False]]
self.black_knights_inf = [[6, 2, True], [6, 7, True], [0, 7, False], [0, 7, False], [0, 7, False], [0, 7, False], [0, 7, False], [0, 7, False], [0, 7, False], [0, 7, False]]
self.black_rooks_inf = [[0, 7, True, True], [7, 7, True, True], [0, 7, False, False], [0, 7, False, False], [0, 7, False, False], [0, 7, False, False], [0, 7, False, False], [0, 7, False, False], [0, 7, False, False], [0, 7, False, False]]
self.black_queens_inf = [[3, 7, True], [0, 7, False], [0, 7, False], [0, 7, False], [0, 7, False], [0, 7, False], [0, 7, False], [0, 7, False], [0, 7, False]]
self.black_king_inf = [[4, 7, True, True]]
self.white_occupation_x = [0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7]
self.white_occupation_y = [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1]
self.black_occupation_x = [0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7]
self.black_occupation_y = [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1]
def check_checks(self):
take = True
for notation_val in ['a6', 'a5', 'b6', 'b5', 'c6', 'c5', 'd6', 'd5', 'e6', 'e5', 'f6', 'f5', 'g6', 'g5', 'h6', 'h5']:
#print(self.black_pawns_inf)
black_pawns = self.black_pawns_inf
#print(self.black_pawns_inf)
if True:
if True:
tox = notation.get_column_char(notation_val[-2])
toy = int(notation_val[-1]) - 1
if True:
fromx = tox
if True:
if toy == 4:
fromy = toy + 2
for i in range(0, 8):
if black_pawns[i][2] == True and black_pawns[i][0] == fromx and black_pawns[i][1] == toy + 1:
fromy = toy + 1
else:
fromy = toy + 1
if True:
for i in range(0, 8):
if black_pawns[i][2] == True and black_pawns[i][0] == fromx and black_pawns[i][1] == fromy:
print(self.black_pawns_inf)
black_pawns[i][0] = tox
black_pawns[i][1] = toy
black_pawns[i][3] = False
print(self.black_pawns_inf)
class Notation():
def __init__(self):
pass
def get_column(self, x):
if x == 0:
return "a"
elif x == 1:
return "b"
elif x == 2:
return "c"
elif x == 3:
return "d"
elif x == 4:
return "e"
elif x == 5:
return "f"
elif x == 6:
return "g"
elif x == 7:
return "h"
def get_column_char(self, x):
if x == "a":
return 0
elif x == "b":
return 1
elif x == "c":
return 2
elif x == "d":
return 3
elif x == "e":
return 4
elif x == "f":
return 5
elif x == "g":
return 6
elif x == "h":
return 7
def get_row(self, y):
for i in range(0, 8):
if y == i:
return str(i + 1)
if y != 0 and y != 1 and y != 2 and y != 3 and y != 4 and y != 5 and y != 6 and y != 7:
return "9"
white_turn = False
pieces = Pieces()
notation = Notation()
#print(pieces.black_pawns_inf)
pieces.check_checks()
#print(pieces.black_pawns_inf)
And the key parts are:
print(self.black_pawns_inf)
black_pawns[i][0] = tox
black_pawns[i][1] = toy
black_pawns[i][3] = False
print(self.black_pawns_inf)
And
black_pawns = self.black_pawns_inf
The issue is, that the variable "self.black_pawns_inf" changes in the function, where it occurs once (excluding print statements) in which black_pawns is set to it. It makes no sense to me that this variable changes. The isolated area of code where the variable changes is in the first key part as I have shown above. I print the variable before and after, and it changes, even though the 3 lines of code that supposedly change it do not even include this variable!!! I assume I am missing something in python that it creates a link between variables that are set to each other and somehow by changing one, it also changes the other. Below I will show the output when the program is run for the first iteration of "for notation_val in ['a6', 'a5', 'b6', 'b5', 'c6', 'c5', 'd6', 'd5', 'e6', 'e5', 'f6', 'f5', 'g6', 'g5', 'h6', 'h5']:" in which the change occurs:
[[0, 6, True, True], [1, 6, True, True], [2, 6, True, True], [3, 6, True, True], [4, 6, True, True], [5, 6, True, True], [6, 6, True, True], [7, 6, True, True]]
[[0, 5, True, False], [1, 6, True, True], [2, 6, True, True], [3, 6, True, True], [4, 6, True, True], [5, 6, True, True], [6, 6, True, True], [7, 6, True, True]]
as you can see, the first list in each list changes - 6 becomes 5 and True becomes False - this is expected for the variable "black_pawns", but also happens for the variable "self.black_pawns_inf"...
I've tried to explain the problem as best I can, any help would be appreciated, thanks!
I assume I am missing something in python that it creates a link between variables that are set to each other and somehow by changing one, it also changes the other.
You're right - some types in Python such as list
s are mutable and will display this behaviour. Other types such as int
s and str
s are immutable and do not have this behaviour. See a previous answer on this topic for an explanation.
You could make a copy of self.black_pawns_inf
to avoid modifying it in place. In your case, your have a list of lists, so you will need to make a deep copy to avoid modifying it in place:
from copy import deepcopy
black_pawns = deepcopy(self.black_pawns_inf)
You will then be able to modify the elements of black_pawns
without modifying those of self.black_pawns_inf
.