【问题标题】:Problem when creating Minesweeper in Python在 Python 中创建扫雷时出现的问题
【发布时间】:2021-06-16 08:10:42
【问题描述】:

我的任务是在终端中创建扫雷作为一个项目。我对 Python 比较陌生,所以这对我来说是一项艰巨的任务。出于某种原因,我无法正确计算炸弹周围的数字。我在下面粘贴了代码和一些输出。运行代码时我没有收到任何错误。 (我注意到它可能与炸弹上方右上角的代码有关,但我已经查看了所有内容,似乎找不到问题。有时炸弹也比应有的少。 )

import random

def minesweeper(dim_size, num_bombs):

    print_list = []

    for i in range(dim_size):
        print_list.append([])
        for j in range(dim_size):
            print_list[i].append(0)

    for i in range(num_bombs):
        random_row = random.randrange(0,dim_size-1)
        random_column = random.randrange(0,dim_size-1)
        print_list[random_row][random_column] = 'X'

        # centre-top
        if random_row >= 1:
            if print_list[random_row - 1][random_column] != 'X':
                print_list[random_row - 1][random_column] += 1
        # right-top
        if random_row >= 1 and random_column > dim_size:
            if print_list[random_row - 1][random_column + 1] != 'X':
                print_list[random_row - 1][random_column + 1] += 1
        # right
        if random_column < dim_size:
            if print_list[random_row][random_column + 1] != 'X':
                print_list[random_row][random_column + 1] += 1
        # bottom-right
        if random_row < dim_size and random_column < dim_size:
            if print_list[random_row + 1][random_column + 1] != 'X':
                print_list[random_row + 1][random_column + 1] += 1
        # bottom
        if random_row < dim_size:
            if print_list[random_row + 1][random_column] != 'X':
                print_list[random_row + 1][random_column] += 1
        # bottom-left
        if random_row < dim_size and random_column >= 1:
            if print_list[random_row + 1][random_column - 1] != 'X':
                print_list[random_row + 1][random_column - 1] += 1
        # left
        if random_column >= 1:
            if print_list[random_row][random_column - 1] != 'X':
                print_list[random_row][random_column - 1] += 1
        # top-left
        if random_row >= 1 and random_column >= 1:
            if print_list[random_row - 1][random_column - 1] != 'X':
                print_list[random_row - 1][random_column - 1] += 1

    for row in range(dim_size):
        for column in range(dim_size):
            print(print_list[row][column], end='    ')
        print()

if __name__ == '__main__':
    minesweeper(5,5)

输出:

1    X    1    0    0    
2    3    3    1    0    
2    X    X    X    1    
X    3    3    2    1    
1    1    0    0    0  


2    X    1    0    0    
4    X    2    0    0    
X    X    3    0    0    
2    3    X    1    0    
0    1    1    1    0   


X    2    X    X    1    
X    3    2    2    1    
1    2    1    0    0    
0    1    X    1    0    
0    1    1    1    0    


X    3    X    2    0    
1    4    3    2    0    
1    1    X    1    0    
X    2    1    1    0    
1    1    0    0    0 

【问题讨论】:

  • 在右上角有一个 > 而不是 <.>

标签: python python-3.x terminal


【解决方案1】:

有几件事很突出:

random.randrange 不包括端点,所以如果你的端点是dim_size-1,这意味着你只会生成介于零和三之间的数字。这意味着地雷永远不会出现在底行或最右列的任何位置。

您已经指出的第二个问题与您放置地雷的方式有关。你生成一个随机的 xy 坐标,然后在那里放置一个地雷。如果您碰巧不止一次生成相同的坐标怎么办?您只需将另一个地雷放置在已经被地雷占据的同一块区域中。

我不会使用random.randrange,甚至random.randint 来生成随机坐标,而是首先生成所有可能坐标的集合,然后使用random.sample 从该集合中提取五个唯一坐标。以同样的方式抽出彩票号码,相同的号码(在我们的例子中是坐标)永远不能被抽出超过一次:

import random
import itertools

dim_size = 5
num_mines = 5

for x, y in random.sample(list(itertools.product(range(dim_size), repeat=2)), k=num_mines):
    print("Put a mine at {}, {}".format(x, y))

输出:

Put a mine at 4, 4
Put a mine at 4, 3
Put a mine at 3, 1
Put a mine at 1, 0
Put a mine at 3, 0
>>> 

【讨论】:

  • +1 建议random.sample。请注意,这可以通过sample 处理range(dim_size ** 2) 对象,然后使用divmod(num, dim_size) 将每个原始数字转换为坐标来更有效地完成。由于range 是一个惰性序列,因此无论板子有多大,制作一个都没有成本,而listifying itertools.product 必须执行更多的工作(诚然,对于任何合理大小的板子,它可能“快足够用户永远不会注意到”)。
【解决方案2】:

好的,为此“有时炸弹也比应有的少”...您需要使用 While 循环来跟踪您在 Grid 中放置的炸弹数量。使用 for 循环将仅在 range(num_bombs) 内运行,并且它不会关心它是否已经种植了所需的炸弹数量。但是 While 循环会首先检查代码是否已经植入了所需的 num_bombs,如果是......它将停止运行,但如果没有,它将继续运行

另外在放炸弹之前,你需要检查一下row_column是否有Bomb,如果有...不要放炸弹...如果没有放炸弹。

这里是代码:

    planted_num_bomb = 0 #number of bombs planted
        while planted_num_bomb < num_bombs:
        # for i in range(num_bombs):
            random_row = random.randrange(0,dim_size-1)
            random_column = random.randrange(0, dim_size - 1)
            # check if the row_colm has a Bomb
            if print_list[random_row][random_column] == 'X': #contains the bomb
                continue #pass it
            else:
                print_list[random_row][random_column] = 'X'
                planted_num_bomb += 1

有 5 个结果:

    0    0    2    X    1    
    1    1    3    X    2    
    2    X    3    X    2
    2    X    3    1    1
    1    1    1    0    0
    
    1    2    1    0    0    
    1    X    X    1    0    
    2    4    X    3    0
    1    X    3    X    1
    1    1    2    1    1
    5 #number of bombs planted
    
    1    0    2    X    1    
    X    1    2    X    2    
    3    2    1    1    1
    X    X    1    0    0
    2    2    1    0    0
    5 #number of bombs planted
    
    1    0    1    1    0    
    X    2    2    X    1    
    3    3    X    2    1    
    X    X    2    1    0
    2    2    1    0    0
    5 #number of bombs planted

0    0    0    0    0    
2    2    1    0    0    
X    X    X    2    0    
X    4    3    X    1
1    1    1    1    1
5 #number of bombs planted

现在,如果您看一下...代码无法将地雷放置在第 5 列...为什么?答案在顶部(第一个答案)。如果你找到了解决这个问题的方法,仍然使用 while 循环,因为 for 循环不会总是植入所需数量的炸弹,为什么?因为,在 for 循环中,当我们跳过(有炸弹时代码中的 continue 部分)时,for 循环仍将其视为一次迭代。

无论如何,祝你在 WTC 训练营上好运。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-04-25
    • 1970-01-01
    • 2023-03-31
    • 2016-06-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-04
    • 2021-10-09
    相关资源
    最近更新 更多