如何 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_linesboard 一起修改了自身,而无需在每次移动时重新定义 win_lines