I am working on a project that makes an 'ai' for a game called hexapawn that works via removing the possibility of a move occurring at that board position if the player ends up winning right after. For some that I am unaware of, whenever I append my board position and move that was made, when I print the whole list at the end, everything is right except the board inside each entry in the list.
Note: If I append the move entry as a string, everything works. But I need to have it be a list so that I can index from it later.
I know this has something to do with multiple references to the same list but I don't see where it's happening.
Here is my code.
import random
def main():
print(printBoard(board))
move(0, 0, board)
print(printBoard(board))
move(2, 1, board)
print(printBoard(board))
print(f'What I have in the end: {moves_ai}')
board = [
[1, 1, 1],
[0, 0, 0],
[2, 2, 2]
]
moves_ai = []
forbiden_moves_ai = []
#Board Mechanics
def printBoard(board):
return str(board[0]) + '\n' + str(board[1]) + '\n' + str(board[2]) + '\n'
def move(row, col, board):
if board[row][col] == 1:
if board[row + 1][col] == 0:
moves_ai.append([row, col, row + 1, col, board])
print(f'What I appended: {[row, col, row + 1, col, board]}')
board[row + 1][col] = 1
board[row][col] = 0
else:
return -1
if board[row][col] == 2:
if board[row - 1][col] == 0:
moves_ai.append([row, col, row - 1, col, board])
print(f'What I appended: {[row, col, row - 1, col, board]}')
board[row - 1][col] = 2
board[row][col] = 0
else:
return -1
def is_possible(end_row, end_col, board):
if end_row < 0 or end_row > 2 or end_col < 0 or end_col > 2:
return False
return True
#AI Section
def random_move(board):
ind = []
move_decided = False
for row in range(3):
for col in range(3):
if board[row][col] == 2:
ind.append([row, col])
while not move_decided:
r_move = random.choice(ind)
if bool(random.getrandbits(1)):
if [r_move[0], r_move[1], r_move[0] - 1, r_move[1], board] not in forbiden_moves_ai and move(r_move[0], r_move[1], board) != -1:
move_decided = True
else:
continue
else:
left = bool(random.getrandbits(1))
if left:
if [r_move[0], r_move[1], r_move[0] - 1, r_move[1] - 1, board] not in forbiden_moves_ai:
if capture(left, r_move[0], r_move[1], board) != -1:
move_decided = True
else:
continue
else:
if [r_move[0], r_move[1], r_move[0] - 1, r_move[1] + 1, board] not in forbiden_moves_ai:
if capture(left, r_move[0], r_move[1], board) != -1:
move_decided = True
else:
continue
def remove_move(row1, col1, row2, col2, situation):
forbiden_moves_ai.append([row1, col1, row2, col2, situation])
if __name__ == '__main__':
main()
This is the expected output:
What I have in the end: [[0, 0, 1, 0, [[1, 1, 1], [0, 0, 0], [2, 2, 2]]], [2, 1, 1, 1, [[0, 1, 1], [1, 0, 0], [2, 2, 2]]]]
This is the output:
What I have in the end: [[0, 0, 1, 0, [[0, 1, 1], [1, 2, 0], [2, 0, 2]]], [2, 1, 1, 1, [[0, 1, 1], [1, 2, 0], [2, 0, 2]]]]
Also, here is an easy way to recreate the problem:
l = []
num = [1]
l.append(num)
num[0] = 9
l.append(num)
print(l)
Expected result:
[[1], [9]]
Result:
[[9], [9]]
I am still keeping the full code I wrote so that anyone who used that can still copy and paste it again.
l = []
num = [1]
l.append(num)
print(l) # [[1]]
num[0] = 9
print(l) # [[9]]
l.append(num)
print(l)
The issue is as @Itagyba Abondanza Kuhlmann stated. num
is mutable. When you append it to l
, you're not appending a snapshot of num
, you're appending a "reference" to num
. In the end, l
contains as its elements two references, both to num
which equals [9]
which is why you l
is [[9], [9]]
.
pythontutor.com might help you see what is going on behind the scenes. Also, this presentation by Ned Batchelder explains some of this in a very good way: presentation .
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.