试图改变副本而不是改变原来的:(
Attempting to alter a copy but instead altering the original :(
我正试图在我的 Tic Tac Toe 程序中创建一个 'smart' 对手。为此,我创建了一个 'possible win' 函数,它将决定下一回合是否有可能获胜。当 运行 这段代码时,我的问题是在 for 循环的每次迭代中,变量 board 似乎都被更改了。
我想在每次迭代开始时将潜在板重置为原始板,这就是我在循环开始时包含 potential_board = board[:] 的原因。然后我编辑 potential_board 但每次循环重复时这个变量都没有重置,而且板实际上也改变了。这是为什么?
非常感谢!
import random,copy
board = [['o','o',' '],[' ',' ',' '],[' ',' ',' ']]
cols = [['o',' ',' '],['o','',''],['o','','']]
def possible_win(board,player):
""" This function should predict whether a winning move is possible in
the next turn. This could be done by simulating every possible next move
and running check_win() on those positions.
:param board,player: checks a win for the specified player
:return:
"""
spaces = empty_spaces(board)
print('Spaces',spaces)
winning_moves = []
for space in spaces:
potential_board = board[:]
print('PBoard',potential_board)
print(space[0],space[1])
potential_board[space[0]][space[1]] = 'o'
if check_win(potential_board,'o'):
winning_moves.append(space)
return winning_moves
def choose_space(board):
a = True
while a:
col = int(input('Choose your column of 1,2,3: ')) - 1
row = int(input('Choose your row of 1,2,3: ')) - 1
if board[row][col] == ' ':
board[row][col] = 'o'
a = False
else: print('Sorry, try again')
return board
def empty_spaces(board):
empty_spaces = []
ind = 0
for row in board:
ind1 = 0
for space in row:
if space == ' ':
empty_spaces.append((ind, ind1))
ind1 += 1
ind += 1
return empty_spaces
def comp_choose_space(board):
choice = random.choice(empty_spaces(board))
board[choice[0]][choice[1]] = 'x'
return board
def check_win(board,player):
rows = board
columns = construct_cols(board)
for row in board:
# if player fills row win = True
a = ind = 0
for space in row:
if rows[board.index(row)][ind] != player: break
else: a += 1
ind += 1
if a == 3:
return True
for col in columns:
a = ind = 0
for space in col:
if rows[columns.index(col)][ind] != player:
break
else:
a += 1
ind += 1
if a == 3:
return True
if rows[0][0] == player and rows[1][1] == player and rows[2][2] == player \
or rows[0][2] == player and rows[1][1] == player and rows[2][0] == player:
return True
return False
def construct_cols(board):
cols = [['','',''],['','',''],['','','']]
for row in range(len(board)):
for col in range(row):
cols[col][row] = board[row][col] # sounds like this should work
return cols
def print_board(board):
for row in board:
print('| {} {} {} |'.format(row[0],row[1],row[2]))
def main():
turns = 0
board = [[' ',' ',' '],[' ',' ',' '],[' ',' ',' ']]
print_board(board)
win = False
while win == False and turns < 9:
turns += 1
board = choose_space(board)
if check_win(board,'o'): win,winner = True,'won'
board = comp_choose_space(board)
if check_win(board,'x'): win,winner = True,'lost'
print_board(board)
if turns == 9: print('You drew!')
else:
print('{}, you {}'.format('Congratulations' if winner == 'won' else 'Sorry',winner))
print(possible_win(board,'o'))
# print(empty_spaces(board))
# print(check_win(board,'o'))
# print_board(board)
# print(comp_choose_space(board))
# main()
# Future project - make the computer smarter than just randomly choosing a space
# ie seeing how close i am to winning
编辑:
通过使用 copy.deepcopy() 我设法解决了这个问题,但我不明白为什么它有效而 copy.copy() 和 board[:] 无效?有人可以解释一下吗?
这就是 copy.deepcopy
的用途。它将遍历结构,在其中创建每个可变对象的副本。使用 slice [:]
或 shallow copy
仅复制顶层,使每行的列表共享。
基本上,如果我们从列表开始:
l = [a, b, c]
shallow = l[:]
shallow2 = copy(l)
deep = deepcopy(l)
两个shallow
副本只对l
进行了操作,没有对a
、b
或c
进行操作。它们都具有 [a, b, c]
值,但是是不同的列表。他们都引用相同的 a
、b
和 c
对象(从他们的角度来看,唯一的变化是引用更多)。
deep
复制更深入,复制了每一个元素;它是一个形状为 [deepcopy(a), deepcopy(b), deepcopy(c)]
的新列表,无论这些值变成什么。
我正试图在我的 Tic Tac Toe 程序中创建一个 'smart' 对手。为此,我创建了一个 'possible win' 函数,它将决定下一回合是否有可能获胜。当 运行 这段代码时,我的问题是在 for 循环的每次迭代中,变量 board 似乎都被更改了。
我想在每次迭代开始时将潜在板重置为原始板,这就是我在循环开始时包含 potential_board = board[:] 的原因。然后我编辑 potential_board 但每次循环重复时这个变量都没有重置,而且板实际上也改变了。这是为什么?
非常感谢!
import random,copy
board = [['o','o',' '],[' ',' ',' '],[' ',' ',' ']]
cols = [['o',' ',' '],['o','',''],['o','','']]
def possible_win(board,player):
""" This function should predict whether a winning move is possible in
the next turn. This could be done by simulating every possible next move
and running check_win() on those positions.
:param board,player: checks a win for the specified player
:return:
"""
spaces = empty_spaces(board)
print('Spaces',spaces)
winning_moves = []
for space in spaces:
potential_board = board[:]
print('PBoard',potential_board)
print(space[0],space[1])
potential_board[space[0]][space[1]] = 'o'
if check_win(potential_board,'o'):
winning_moves.append(space)
return winning_moves
def choose_space(board):
a = True
while a:
col = int(input('Choose your column of 1,2,3: ')) - 1
row = int(input('Choose your row of 1,2,3: ')) - 1
if board[row][col] == ' ':
board[row][col] = 'o'
a = False
else: print('Sorry, try again')
return board
def empty_spaces(board):
empty_spaces = []
ind = 0
for row in board:
ind1 = 0
for space in row:
if space == ' ':
empty_spaces.append((ind, ind1))
ind1 += 1
ind += 1
return empty_spaces
def comp_choose_space(board):
choice = random.choice(empty_spaces(board))
board[choice[0]][choice[1]] = 'x'
return board
def check_win(board,player):
rows = board
columns = construct_cols(board)
for row in board:
# if player fills row win = True
a = ind = 0
for space in row:
if rows[board.index(row)][ind] != player: break
else: a += 1
ind += 1
if a == 3:
return True
for col in columns:
a = ind = 0
for space in col:
if rows[columns.index(col)][ind] != player:
break
else:
a += 1
ind += 1
if a == 3:
return True
if rows[0][0] == player and rows[1][1] == player and rows[2][2] == player \
or rows[0][2] == player and rows[1][1] == player and rows[2][0] == player:
return True
return False
def construct_cols(board):
cols = [['','',''],['','',''],['','','']]
for row in range(len(board)):
for col in range(row):
cols[col][row] = board[row][col] # sounds like this should work
return cols
def print_board(board):
for row in board:
print('| {} {} {} |'.format(row[0],row[1],row[2]))
def main():
turns = 0
board = [[' ',' ',' '],[' ',' ',' '],[' ',' ',' ']]
print_board(board)
win = False
while win == False and turns < 9:
turns += 1
board = choose_space(board)
if check_win(board,'o'): win,winner = True,'won'
board = comp_choose_space(board)
if check_win(board,'x'): win,winner = True,'lost'
print_board(board)
if turns == 9: print('You drew!')
else:
print('{}, you {}'.format('Congratulations' if winner == 'won' else 'Sorry',winner))
print(possible_win(board,'o'))
# print(empty_spaces(board))
# print(check_win(board,'o'))
# print_board(board)
# print(comp_choose_space(board))
# main()
# Future project - make the computer smarter than just randomly choosing a space
# ie seeing how close i am to winning
编辑: 通过使用 copy.deepcopy() 我设法解决了这个问题,但我不明白为什么它有效而 copy.copy() 和 board[:] 无效?有人可以解释一下吗?
这就是 copy.deepcopy
的用途。它将遍历结构,在其中创建每个可变对象的副本。使用 slice [:]
或 shallow copy
仅复制顶层,使每行的列表共享。
基本上,如果我们从列表开始:
l = [a, b, c]
shallow = l[:]
shallow2 = copy(l)
deep = deepcopy(l)
两个shallow
副本只对l
进行了操作,没有对a
、b
或c
进行操作。它们都具有 [a, b, c]
值,但是是不同的列表。他们都引用相同的 a
、b
和 c
对象(从他们的角度来看,唯一的变化是引用更多)。
deep
复制更深入,复制了每一个元素;它是一个形状为 [deepcopy(a), deepcopy(b), deepcopy(c)]
的新列表,无论这些值变成什么。