如何 link 两个嵌套列表的元素?可能吗?
How can I link elements of two nested lists? Is it possible?
所以我在 python 中做了一个井字游戏,主要游戏板基本上是列表列表如下:
board = [
[" ", " ", " "],
[" ", " ", " "],
[" ", " ", " "],
]
在游戏中移动会修改此 board
变量。现在我必须在每次移动后检查玩家是否赢了或游戏是否平局。基本上必须检查 board
中的每个配置,这在实际游戏中会是一场胜利。
为此,我有以下功能,将 win_lines
定义为包含所有可能获胜线的列表。
def check_has_won(board: list, player):
win_lines = [
board[0], # top row
board[1], # mid row
board[2], # bottom row
[row[0] for row in board], # first col
[row[1] for row in board], # sec col
[row[2] for row in board], # third col
[board[0][0], board[1][1], board[2][2]], # diag 1
[board[0][2], board[1][1], board[2][0]], # diag 2
]
for line in win_lines:
if " " not in line:
if foe[player] not in line: #foe = {"X":"O", "O":"X"}
return True # player has won
else:
for row in board:
if " " in row: # implies theres still empty positions to play
return False
else: # Game has tied
return None
我这样做的问题是:
我发现在每次移动后继续定义 win_lines
变量是低效的,如果在移动中修改 board
时它会自行修改,那就太好了。因此,以某种方式将 board
的正确元素与 win_lines
的元素链接起来。这可能吗?如果可以,我该怎么做?
可能有用的代码:(如果我缺少更多必需的代码,请告诉我。)
def make_move(board, player, position):
"""
checks 'board' to see if 'position' is playable. if so plays there, else prompts again\n
"""
board_indices = [
None, # so that `position` matches the index of this list.
# make first element of `board_indices` (index 0) = None
[0, 0], #e.g `position = 1` corresponds with index [0][0] in `board`
[0, 1],
[0, 2],
[1, 0],
[1, 1], # another e.g. `position = 5` corresponds with index [1][1] in `board`
[1, 2],
[2, 0],
[2, 1],
[2, 2],
]
f_index, s_index = board_indices[position]
if board[f_index][s_index] == " ":
board[f_index][s_index] = player
return None
else:
position = input("Choose a new position: ")
return make_move(board, player, position)
看来我已经回答了我自己的问题。它不完全是我所期待的,但它确实有效。我注意到修改任何列表 board[0], board[1] and board[2]
(恰好是行)修改了 board
中的元素,反之亦然。
所以我想如果我将 board
转换为一个 numpy 数组并使用它的索引来获取列,它也允许我对列执行此操作。这样就有 6 个可能的获胜选项。幸运的是,array.diagonal()
让我也可以用对角元素实现同样的效果。
import numpy as np
board = np.array(board)
win_lines = [
board[0], #top row
board[1], # mid row
board[2], #bottom row
board[:,0], # left col
board[:,1], # mid col
board[:,2], # right col
board.diagonal(), # diag 1
np.fliplr(board).diagonal(), # diag 2
]
现在...board
中的任何修改都会反映在 win_lines
中。可能重要的是要注意 win_lines
必须是数组列表,将其设为 numpy 数组会使它不再起作用。
工作示例:
make_move(board, "X", 2)
>>> print("board", board, sep="\n")
board
[[' ' 'X' ' ']
[' ' ' ' ' ']
[' ' ' ' ' ']]
>>> make_move(board, "O", 5)
>>> make_move(board, "X", 9)
>>> print("board", board, sep="\n")
board
[[' ' 'X' ' ']
[' ' 'O' ' ']
[' ' ' ' 'X']]
>>> for line in win_lines:
... print(line)
...
[' ' 'X' ' '] # this is the top row
[' ' 'O' ' '] # this is the mid row
[' ' ' ' 'X'] # this is the bottom row
[' ' ' ' ' '] # this is the left col
['X' 'O' ' '] # this is the mid col
[' ' ' ' 'X'] # this is the right col
[' ' 'O' 'X'] # diag 1
[' ' 'O' ' '] # diag 2
很好,win_lines
随 board
一起修改了自身,而无需在每次移动时重新定义 win_lines
所以我在 python 中做了一个井字游戏,主要游戏板基本上是列表列表如下:
board = [
[" ", " ", " "],
[" ", " ", " "],
[" ", " ", " "],
]
在游戏中移动会修改此 board
变量。现在我必须在每次移动后检查玩家是否赢了或游戏是否平局。基本上必须检查 board
中的每个配置,这在实际游戏中会是一场胜利。
为此,我有以下功能,将 win_lines
定义为包含所有可能获胜线的列表。
def check_has_won(board: list, player):
win_lines = [
board[0], # top row
board[1], # mid row
board[2], # bottom row
[row[0] for row in board], # first col
[row[1] for row in board], # sec col
[row[2] for row in board], # third col
[board[0][0], board[1][1], board[2][2]], # diag 1
[board[0][2], board[1][1], board[2][0]], # diag 2
]
for line in win_lines:
if " " not in line:
if foe[player] not in line: #foe = {"X":"O", "O":"X"}
return True # player has won
else:
for row in board:
if " " in row: # implies theres still empty positions to play
return False
else: # Game has tied
return None
我这样做的问题是:
我发现在每次移动后继续定义 win_lines
变量是低效的,如果在移动中修改 board
时它会自行修改,那就太好了。因此,以某种方式将 board
的正确元素与 win_lines
的元素链接起来。这可能吗?如果可以,我该怎么做?
可能有用的代码:(如果我缺少更多必需的代码,请告诉我。)
def make_move(board, player, position):
"""
checks 'board' to see if 'position' is playable. if so plays there, else prompts again\n
"""
board_indices = [
None, # so that `position` matches the index of this list.
# make first element of `board_indices` (index 0) = None
[0, 0], #e.g `position = 1` corresponds with index [0][0] in `board`
[0, 1],
[0, 2],
[1, 0],
[1, 1], # another e.g. `position = 5` corresponds with index [1][1] in `board`
[1, 2],
[2, 0],
[2, 1],
[2, 2],
]
f_index, s_index = board_indices[position]
if board[f_index][s_index] == " ":
board[f_index][s_index] = player
return None
else:
position = input("Choose a new position: ")
return make_move(board, player, position)
看来我已经回答了我自己的问题。它不完全是我所期待的,但它确实有效。我注意到修改任何列表 board[0], board[1] and board[2]
(恰好是行)修改了 board
中的元素,反之亦然。
所以我想如果我将 board
转换为一个 numpy 数组并使用它的索引来获取列,它也允许我对列执行此操作。这样就有 6 个可能的获胜选项。幸运的是,array.diagonal()
让我也可以用对角元素实现同样的效果。
import numpy as np
board = np.array(board)
win_lines = [
board[0], #top row
board[1], # mid row
board[2], #bottom row
board[:,0], # left col
board[:,1], # mid col
board[:,2], # right col
board.diagonal(), # diag 1
np.fliplr(board).diagonal(), # diag 2
]
现在...board
中的任何修改都会反映在 win_lines
中。可能重要的是要注意 win_lines
必须是数组列表,将其设为 numpy 数组会使它不再起作用。
工作示例:
make_move(board, "X", 2)
>>> print("board", board, sep="\n")
board
[[' ' 'X' ' ']
[' ' ' ' ' ']
[' ' ' ' ' ']]
>>> make_move(board, "O", 5)
>>> make_move(board, "X", 9)
>>> print("board", board, sep="\n")
board
[[' ' 'X' ' ']
[' ' 'O' ' ']
[' ' ' ' 'X']]
>>> for line in win_lines:
... print(line)
...
[' ' 'X' ' '] # this is the top row
[' ' 'O' ' '] # this is the mid row
[' ' ' ' 'X'] # this is the bottom row
[' ' ' ' ' '] # this is the left col
['X' 'O' ' '] # this is the mid col
[' ' ' ' 'X'] # this is the right col
[' ' 'O' 'X'] # diag 1
[' ' 'O' ' '] # diag 2
很好,win_lines
随 board
一起修改了自身,而无需在每次移动时重新定义 win_lines