首页 > 解决方案 > 我将如何检查我的扫雷游戏的所有相邻单元格?

问题描述

我一直在尝试找出一种方法来检查我的扫雷游戏中的每个相邻单元格,但我做不到。我是 python 的初学者,也想开始使用 OOP。但是,在我到达那里之前,我需要纠正这一点。我见过的所有教程都没有使用基本的python,但是我使用的IDLE版本不同,所以我很挣扎。谁能帮我?我需要能够绕过每个相邻的牢房并检查那里是否有炸弹。检查是否有炸弹的值是 1 并且也会变成红色。非常感谢大家!另外,如果你能为我把它简化一点,那就太好了。

import random
import pygame

BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0) 
WIDTH = 20
HEIGHT = 20 
MARGIN = 5
bombnum = 10
grid = []
for row in range(10):
    grid.append([])
    for column in range(10):
        grid[row].append(0)
print(grid)

pygame.init()
 
WINDOW_SIZE = [255, 315]
screen = pygame.display.set_mode(WINDOW_SIZE)
 
pygame.display.set_caption("Array Backed Grid")
 
done = False
 
clock = pygame.time.Clock()

#class bomb:
    #def revealed(self,pick):#this is the grid thats been picked
     #   self.shown = shown
def placebomb():
    for i in range(bombnum):
        while True:
            row  = random.randint(0,8)
            column = random.randint(0,8)
            if grid[row][column] == 0:
                grid[row][column] = 1
                break
placebomb()  
        
                
# -------- Main Program Loop -----------
while not done:
    for event in pygame.event.get():  
        if event.type == pygame.QUIT:  
            done = True 
        elif event.type == pygame.MOUSEBUTTONDOWN:
            pos = pygame.mouse.get_pos()
            column = pos[0] // (WIDTH + MARGIN)
            row = (pos[1]-50) // (HEIGHT + MARGIN)
            grid[row][column] = 1
            print("Click ", pos, "Grid coordinates: ", row, column)


    screen.fill(BLACK)
 
    for row in range(10):
        for column in range(10):
            color = WHITE
            if grid[row][column] == 1:
                color = RED
            pygame.draw.rect(screen,
                             color,
                             [(MARGIN + WIDTH) * (column) + MARGIN,
                              50+(MARGIN + HEIGHT) * row + MARGIN,
                              WIDTH,
                              HEIGHT])
 

    clock.tick(60)
 

    pygame.display.flip()
 

pygame.quit()

标签: pythonminesweeper

解决方案


首先,您肯定想以此创建一个 OOP 项目。Minesweeper 的复杂性可能接近你可以在没有面向对象编程的情况下合理地做的事情的限制,但是如果你想采用基本的 Minesweeper 概念并使其更有趣/更复杂,你将需要更好的结构。

即使你不考虑让它变得更复杂,考虑你可以添加什么样的复杂性也有助于规划你的课程。(也许你没有意识到有一个“计划你的课程”步骤?我会讲到的。)我这里的步骤应该适用于几乎所有开始的 OOP 项目,因为扫雷似乎只是一个方便的例子。

我意识到这个答案将是对 OP 的 how-do-I-check-the-nearest-neighbors 问题的巨大转移,但 OP 也在询问 OOP 并且在 OOP 上下文中回答他们的问题意味着建立一个类模型。尝试将 OOP 改造成非 OOP 代码是可能的,但通常比从头开始做 OOP 更难。

  1. 如果您不熟悉 Python 中的 OOP,请查看两个教程。它们都贯穿了基础知识,既不需要 IDE,也不会引入超出您需要开始的复杂性/功能。我的其余答案将假设您熟悉如何编写类。我强烈建议您在您自己的终端上输入这两个教程,并在您继续之前尝试它们的几个变体。
  2. 现在你大致知道什么是,列出您想要在扫雷程序中执行的所有操作,以及其中会出现哪些类型的内容。这里的重点不是编写代码,自然语言将在这里充当伪代码。您可能想要包括的内容:“将地雷添加到网格上的单元格”、“检查网格上的单元格”、“显示网格上给定单元格附近的点数”。您可能还包括一些“未来计划”,例如“在游戏中间调整网格大小”、“限制移动次数”、“获取提示”、“允许地雷移动”、“让人们穿过雷区”多种类型的检查/地雷/单元格,六角网格作为方形网格的替代品,奇怪形状和 3D 网格等。如果您不这样做,请不要担心 还不知道如何编码这些东西。如果您有一个有趣的想法,请将其列入清单。
  3. 浏览该列表并对不断出现的主要单词/概念做一些注释。这些将是你的课程。对于扫雷,我会列出“Cell”、“Grid”、“Game”、“Check”和“Mine”,但你的里程可能会有所不同。这些不一定 最终的班级名单。它们只是组织您的想法的一步,因此您可以将高级“扫雷游戏”变成具体和可扩展的东西。一旦您更好地了解您将实际使用哪些类,您可以稍后添加/删除类。
  4. 注意类对象之间的关系,包括需要描述哪些对象才能使其他对象有意义/被实例化。这一步类似于你如何规划一个关系数据库:一个游戏只有一个网格,一个网格是按固定模式排列的单元的集合,一个单元可能包含也可能不包含一个地雷,检查显示是否地雷在给定的单元格中,如果没有,则显示与检查的单元格相邻的单元格中的地雷数量等。
  5. 打开您的 IDE,并开始屏蔽文件中的类。这里的重点不是编写代码,而是将所有类和注释放入代码中以便于参考。如果此文件开始变大,请考虑类如何组合在一起并将该文件拆分为多个文件,并使用import语句将它们连接起来。通过“阻止类”,我的意思是“编写可以编译的最简单的类,但不要试图让它们运行”。在这个阶段,您可以/应该拥有如下所示的类:
class Grid:
    """A Game has one and only one Grid, a Grid is a collection of Cells arranged in a fixed pattern"""
    def __init__(self, game, **setup_params):
        """Initialize the grid given a game and possibly other parameters for shape and size"""
        raise NotImplementedError('This code has not yet been written.')

    def resize_grid(self, new_size):
        raise NotImplementedError('This code has not yet been written.')

    def check_cell_at(self, position):
        raise NotImplementedError('This code has not yet been written.')

要检查的东西:这是完全合法的 Python 并且编译得很好。步骤 2-4 中的所有笔记都应该以文档字符串结尾。您在笔记中描述的所有目标功能都对应于与这些功能有关的类上的特定方法。您描述的每个类都存在,并且有一个描述其用途和结构的文档字符串。每个班级的__init__()方法接受实例化类所需的参数。每个方法都需要一些可能有用的参数。您可以随时编辑参数列表,但同样,重点是在编写太多代码之前组织代码,以便轻松跟踪关系和功能。如果您使用 Git 或其他版本跟踪工具,请在完成此步骤后立即进行第一次提交。

  1. 现在你已经把所有的结构都屏蔽了,弄清楚“主入口点”将是什么,实例化那个类(在我的方法中可能是 Game),并检查你的代码是否可以编译、运行和退出NotImplementedError 与您期望的行和消息一起出现。(如果是这样,那就成功了!)如果项目感觉很大,或者如果您要与其他开发人员共享代码,您可能还想在这个阶段添加单元测试。期望每个测试都会失败,但编写测试有助于记录计划的功能。
  2. 一个一个地填写方法,添加单元测试以使用新的或更新的方法,并尝试一次运行代码。您不必以任何特定的顺序编写方法,但是一旦所有__init__()方法都完成后测试会更容易,而且这些方法通常很简单。

现在,您如何检查单元格的邻居?

  • 您应该在 Cell 上有用于“获取我的邻居列表”和“获取此单元格是否包含地雷”的方法。您可能在 Grid 上也有一个方法来“让 Cell 处于某个位置”。你可能有多种类型的检查,但基础扫雷游戏只有一种,所以 Cell 有一个类似的方法
   def check(self):
       """Returns "BOMB" if this cell has a Bomb. Otherwise, returns the number of neighbors with bombs as an integer."""
       if self.has_bomb:
           return "BOMB"
       neighboring_mines = 0
       for cell in self.grid.get_neighbors_of(self.position):
            if cell.has_bomb:
                neighboring_mines += 1
       return neighboring_mines

推荐阅读