棋盘病毒模拟中的逻辑错误

Posted

技术标签:

【中文标题】棋盘病毒模拟中的逻辑错误【英文标题】:Logic Error in Chessboard Virus Simulation 【发布时间】:2022-01-04 13:17:40 【问题描述】:

棋盘病毒问题类似于康威的“生命游戏”。规则是任何两个相邻被感染的方格都会被感染。

我尝试在 Python 中实现模拟,但出现逻辑错误。我认为正在发生的事情是董事会在一轮内更新,因此错过了中间步骤。例如,与

grid = [
    [0, 1, 0, 1],
    [1, 0, 0, 0],
    [0, 0, 0, 0],
    [0, 0, 0, 0]
]

我得到以下输出:

Initial State of board:

 0 1 0 1
 1 0 0 0
 0 0 0 0
 0 0 0 0

State 2 of board:

 1 1 1 1
 1 1 1 1
 0 0 0 0
 0 0 0 0

Infinite loop entered.

第一轮应该只显示

1 1 1 1
1 1 0 0
0 0 0 0
0 0 0 0

除非我弄错了。

谁能帮我解决逻辑错误?

grid = [
    [0, 1, 0, 1],
    [1, 0, 0, 0],
    [0, 0, 0, 0],
    [0, 0, 0, 0]
]


def write(grid):
    """
    Writes the lists of lists of booleans
    in grid using 0 for False and 1 for True.
    """
    for row in grid:
        for item in row:
            print(f" item", end="")
        print()


def neighbors(grid, i, j):
    """
    Returns the number of live cells
    next to grid[i][j]. Does not include diagonals.
    """
    num_neighbours = 0
    if i > 0:
        if grid[i - 1][j]:
            num_neighbours = num_neighbours + 1
    if i < len(grid) - 1:
        if grid[i + 1][j]:
            num_neighbours = num_neighbours + 1
    if j > 0:
        if grid[i][j - 1]:
            num_neighbours = num_neighbours + 1
    if j < len(grid[i]) - 1:
        if grid[i][j + 1]:
            num_neighbours = num_neighbours + 1
    print(num_neighbours)
    return num_neighbours


def update(grid):
    """
    Applies the rule of the chessboard virus to grid
    and returns a new grid.
    """
    new_board = grid[:]
    for i in range(len(grid)):
        for j in range(len(grid[i])):
            num_neighbours = neighbors(grid, i, j)
            if num_neighbours >= 2:
                new_board[i][j] = 1
    return new_board


def check_all_ones(a):
    return not any(c != 1 for r in a for c in r)


def main():
    """
    Runs the simulation.
    """
    global grid
    grid = grid
    print("Initial State of board:")
    print()
    write(grid)
    state_num = 1
    while True:
        last_grid = grid[:]  # Clone grid.
        grid = update(grid)
        state_num = state_num + 1
        print()
        print(f"State state_num of board:")
        print()
        write(grid)
        if check_all_ones(grid):
            print()
            print("Virus has spread to whole board.")
            break
        if grid == last_grid:
            print()
            print("Infinite loop entered.")
            break


if __name__ == "__main__":
    main()

【问题讨论】:

【参考方案1】:

我认为问题在于 new_board = grid[:] 不是“深”副本 - 各个行列表是来自 grid 的原始列表对象,因此更新步骤设置 + 在第一次扫描中找到所有新填充的邻居.

它似乎适用于深层副本,例如,使用 new_board = [r.copy() for r in grid]new_board = copy.deepcopy(grid) (thnx @Demi-Lune)。

正如下面@Ramirez 的评论中所指出的,这同样适用于主循环中的克隆。

【讨论】:

要遵循这一点,对于last_grid,您可能还应该进行深拷贝。 关于 last_grid 的好点 - 我错过了。 (而且我不完全理解为什么没有它就可以在我的机器上工作。) 明确使用copy.deepcopy:new_board = copy.deepcopy(grid)会提高可读性。

以上是关于棋盘病毒模拟中的逻辑错误的主要内容,如果未能解决你的问题,请参考以下文章

模拟静态方法时出现内容类型错误

Mockgoose:如何模拟猫鼬中的错误?

python和netlogo软件模拟病毒传播仿真模型

python和netlogo软件模拟病毒传播仿真模型

防病毒软件正在阻止 nodemailer - 错误:证书链中的自签名证书

如何在单个进程中模拟 SQL Server 中的死锁?