我将如何检查我的扫雷游戏的所有相邻单元格?
how would i check all adjacent cells for my minesweeper game?
我一直在努力寻找一种方法来检查我的扫雷游戏的每个相邻单元格,但我做空了。我是 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()
所以基本上就像这个线程中的另一个答案一样,您可以通过向当前的 x 和 y 添加 -1、0 或 1 来检查 surrounding/adjacent 图块。
您可以编写一个单独的函数,该函数将 return 带有炸弹的周围瓷砖的坐标列表,并将瓷砖坐标和网格作为参数,如下所示:
def check_surrounding_tiles(current_x, current_y, grid):
bomb_tiles = []
#Check starting from position (current_x - 1, current_y - 1)
for i in range(-1, 2):
for j in range(-1, 2):
#Ignore the current x and y, and do bounds checking
if (i != 0 or j != 0) and (current_x + i) > -1 and (current_y + j) > -1 and (current_x + i) < len(grid) and (current_y + j) < len(grid[0]):
if grid[current_x + i][current_y + j] == 1
bomb_tiles.append[(current_x + i, current_y + j)]
return bomb_tiles
如上所述,这将 return 包含炸弹的坐标对列表。
如果需要获取炸弹数量,只需使用以下命令:
adjacent_bomb_count = len(check_surrounding_tiles(<x position>,<y position>, grid))
只有8([1,1],[1,0],[1,-1],[0,1],[0,-1],[-1,1],[ -1,0],[-1,-1] 相对于点击的网格坐标)相邻的方块,所以只用“if”语句
就可以很容易地做你想做的事情
无论如何,只需检查周围的方块,如果为真,则添加到变量。
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()
print(grid)
# -------- 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)
NBombs = 0
for i in range(-1,2):
for k in range(-1,2):
if (i!=0 or k!=0) and (row+i>=0) and (column+k>=0) and (row+i<len(grid)) and (column+k<len(grid[0])):#prevents from both being 0, or for the index to be negative or out of range
print(i,k)
if grid[row+i][column+k] == 1:
NBombs+=1
print("Number of bombs:",NBombs)
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()
首先,您肯定想以此为基础制作一个 OOP 项目。扫雷可能接近您无需 object-oriented 编程即可合理完成的复杂性极限,但如果您想采用基本的扫雷概念并使其更有趣/更复杂,您将需要更好的结构。
即使您不考虑让它变得更复杂,考虑一下您 可以 添加什么样的复杂性也有助于规划您的 classes。 (也许你没有意识到有一个“计划你的 classes”步骤?我会讲到。)我这里的步骤应该适用于几乎所有开始的 OOP 项目,因为扫雷似乎只是一个方便的例子.
我意识到这个答案将 giant 从 OP 的 how-do-I-check-the-nearest-neighbors 问题转移,但 OP 也在询问 OOP 并在 OOP 上下文中回答他们的问题意味着得到class 模型到位。尝试将 OOP 改造为 non-OOP 代码是可能的,但通常比从头开始进行 OOP 更难。
- 如果您是 Python 中的 OOP 新手,请检查 these two tutorials。它们都 运行 通过基础知识,既不需要 IDE,也不会引入超出您需要开始的复杂性/功能。我的其余回答将假定您熟悉如何编写 classes。我强烈建议您在自己的终端上输入这两个教程,并在继续之前尝试几个变体。
- 既然您已经大致了解了 class 是什么,,请列出您在扫雷程序中需要的所有操作,以及哪些类型里面有很多东西。这里的重点不是写代码,自然语言将在这里充当伪代码。您可能想要包括的内容:“将地雷添加到网格上的单元格”、“检查网格上的单元格”、“显示网格上给定单元格附近的点数”。您还可以包括一些“未来计划”,例如“在游戏中间调整网格大小”、“限制移动次数”、“获得提示”、“允许地雷移动”、“让人们穿过雷区”,多种类型的检查/地雷/单元格,作为正方形网格替代的六角网格,strangely-shaped 和 3D 网格等。如果您还不知道如何编写这些东西,请不要担心。如果您有一个有趣的想法,请将其添加到列表中。
- 浏览该列表并对不断出现的主要词/概念做一些笔记。这些将是您的 classes。对于 Minesweeper,我会列出“Cell”、“Grid”、“Game”、“Check”和“Mine”,但您的里程数可能会有所不同。这些 不是 必然 最终的 class 列表。它们只是组织您的想法的一个步骤,因此您可以将 high-level“扫雷游戏”变成具体且可扩展的游戏。您可以稍后添加/删除 classes,一旦您对实际使用的内容有了更好的了解。
- 注意 classes 对象之间的关系,包括需要描述哪些对象才能使其他对象有意义/被实例化。这一步类似于你如何计划一个relational database:一个游戏有一个且只有一个网格,一个网格是以固定模式排列的单元格的集合,一个单元格可能包含也可能不包含一个地雷,一个检查显示地雷是否在给定单元格中,如果不在,则显示与已检查单元格相邻的单元格中地雷的数量等。
- 打开您的 IDE,然后开始在文件中屏蔽 classes。这里的重点不是编写代码,而是将所有 classes 和注释放入代码中以便于参考。如果这个文件开始变大,想一想 classes 如何组合在一起并将一个文件拆分成几个文件,并用
import
语句将它们连接起来。通过“屏蔽 classes”,我的意思是“编写最简单的 classes 可以编译,但不要试图让它们成为 运行”。在此阶段,您可以/应该拥有如下所示的 classes:
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 步中的所有注释都应该以文档字符串结尾。您在笔记中描述的所有目标功能都对应于 classes 上与这些功能有关的特定方法。您描述的每个 class 都存在,并且有一个描述其目的和结构的文档字符串。每个 class 的 __init__()
方法都采用实例化 class 所需的参数。每个方法都有一些可能有用的参数。您以后总是可以编辑参数列表,但同样,重点是在编写代码之前组织代码,以便轻松跟踪关系和功能。如果您正在使用 Git 或其他 version-tracking 工具,请在完成此步骤后立即进行首次提交。
- 现在你已经掌握了所有的结构封锁,弄清楚“主要入口点”是什么,实例化 class(在我的方法中可能是游戏),并检查您的代码是否编译,运行s,并以NotImplementedError 与您期望的行和消息一起出现。 (如果是这样,那就成功了!)如果项目感觉很大,或者如果您要与其他开发人员共享代码,您可能还想在此阶段添加单元测试。期望每个测试都会失败,但编写测试有助于记录计划的功能。
- 一个一个地填写方法,添加单元测试以配合新的或更新的方法,然后尝试 运行一次一点地修改代码。您不必按任何特定顺序编写方法,但是一旦所有
__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
我一直在努力寻找一种方法来检查我的扫雷游戏的每个相邻单元格,但我做空了。我是 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()
所以基本上就像这个线程中的另一个答案一样,您可以通过向当前的 x 和 y 添加 -1、0 或 1 来检查 surrounding/adjacent 图块。
您可以编写一个单独的函数,该函数将 return 带有炸弹的周围瓷砖的坐标列表,并将瓷砖坐标和网格作为参数,如下所示:
def check_surrounding_tiles(current_x, current_y, grid):
bomb_tiles = []
#Check starting from position (current_x - 1, current_y - 1)
for i in range(-1, 2):
for j in range(-1, 2):
#Ignore the current x and y, and do bounds checking
if (i != 0 or j != 0) and (current_x + i) > -1 and (current_y + j) > -1 and (current_x + i) < len(grid) and (current_y + j) < len(grid[0]):
if grid[current_x + i][current_y + j] == 1
bomb_tiles.append[(current_x + i, current_y + j)]
return bomb_tiles
如上所述,这将 return 包含炸弹的坐标对列表。
如果需要获取炸弹数量,只需使用以下命令:
adjacent_bomb_count = len(check_surrounding_tiles(<x position>,<y position>, grid))
只有8([1,1],[1,0],[1,-1],[0,1],[0,-1],[-1,1],[ -1,0],[-1,-1] 相对于点击的网格坐标)相邻的方块,所以只用“if”语句
就可以很容易地做你想做的事情无论如何,只需检查周围的方块,如果为真,则添加到变量。
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()
print(grid)
# -------- 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)
NBombs = 0
for i in range(-1,2):
for k in range(-1,2):
if (i!=0 or k!=0) and (row+i>=0) and (column+k>=0) and (row+i<len(grid)) and (column+k<len(grid[0])):#prevents from both being 0, or for the index to be negative or out of range
print(i,k)
if grid[row+i][column+k] == 1:
NBombs+=1
print("Number of bombs:",NBombs)
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()
首先,您肯定想以此为基础制作一个 OOP 项目。扫雷可能接近您无需 object-oriented 编程即可合理完成的复杂性极限,但如果您想采用基本的扫雷概念并使其更有趣/更复杂,您将需要更好的结构。
即使您不考虑让它变得更复杂,考虑一下您 可以 添加什么样的复杂性也有助于规划您的 classes。 (也许你没有意识到有一个“计划你的 classes”步骤?我会讲到。)我这里的步骤应该适用于几乎所有开始的 OOP 项目,因为扫雷似乎只是一个方便的例子.
我意识到这个答案将 giant 从 OP 的 how-do-I-check-the-nearest-neighbors 问题转移,但 OP 也在询问 OOP 并在 OOP 上下文中回答他们的问题意味着得到class 模型到位。尝试将 OOP 改造为 non-OOP 代码是可能的,但通常比从头开始进行 OOP 更难。
- 如果您是 Python 中的 OOP 新手,请检查 these two tutorials。它们都 运行 通过基础知识,既不需要 IDE,也不会引入超出您需要开始的复杂性/功能。我的其余回答将假定您熟悉如何编写 classes。我强烈建议您在自己的终端上输入这两个教程,并在继续之前尝试几个变体。
- 既然您已经大致了解了 class 是什么,,请列出您在扫雷程序中需要的所有操作,以及哪些类型里面有很多东西。这里的重点不是写代码,自然语言将在这里充当伪代码。您可能想要包括的内容:“将地雷添加到网格上的单元格”、“检查网格上的单元格”、“显示网格上给定单元格附近的点数”。您还可以包括一些“未来计划”,例如“在游戏中间调整网格大小”、“限制移动次数”、“获得提示”、“允许地雷移动”、“让人们穿过雷区”,多种类型的检查/地雷/单元格,作为正方形网格替代的六角网格,strangely-shaped 和 3D 网格等。如果您还不知道如何编写这些东西,请不要担心。如果您有一个有趣的想法,请将其添加到列表中。
- 浏览该列表并对不断出现的主要词/概念做一些笔记。这些将是您的 classes。对于 Minesweeper,我会列出“Cell”、“Grid”、“Game”、“Check”和“Mine”,但您的里程数可能会有所不同。这些 不是 必然 最终的 class 列表。它们只是组织您的想法的一个步骤,因此您可以将 high-level“扫雷游戏”变成具体且可扩展的游戏。您可以稍后添加/删除 classes,一旦您对实际使用的内容有了更好的了解。
- 注意 classes 对象之间的关系,包括需要描述哪些对象才能使其他对象有意义/被实例化。这一步类似于你如何计划一个relational database:一个游戏有一个且只有一个网格,一个网格是以固定模式排列的单元格的集合,一个单元格可能包含也可能不包含一个地雷,一个检查显示地雷是否在给定单元格中,如果不在,则显示与已检查单元格相邻的单元格中地雷的数量等。
- 打开您的 IDE,然后开始在文件中屏蔽 classes。这里的重点不是编写代码,而是将所有 classes 和注释放入代码中以便于参考。如果这个文件开始变大,想一想 classes 如何组合在一起并将一个文件拆分成几个文件,并用
import
语句将它们连接起来。通过“屏蔽 classes”,我的意思是“编写最简单的 classes 可以编译,但不要试图让它们成为 运行”。在此阶段,您可以/应该拥有如下所示的 classes:
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 步中的所有注释都应该以文档字符串结尾。您在笔记中描述的所有目标功能都对应于 classes 上与这些功能有关的特定方法。您描述的每个 class 都存在,并且有一个描述其目的和结构的文档字符串。每个 class 的 __init__()
方法都采用实例化 class 所需的参数。每个方法都有一些可能有用的参数。您以后总是可以编辑参数列表,但同样,重点是在编写代码之前组织代码,以便轻松跟踪关系和功能。如果您正在使用 Git 或其他 version-tracking 工具,请在完成此步骤后立即进行首次提交。
- 现在你已经掌握了所有的结构封锁,弄清楚“主要入口点”是什么,实例化 class(在我的方法中可能是游戏),并检查您的代码是否编译,运行s,并以NotImplementedError 与您期望的行和消息一起出现。 (如果是这样,那就成功了!)如果项目感觉很大,或者如果您要与其他开发人员共享代码,您可能还想在此阶段添加单元测试。期望每个测试都会失败,但编写测试有助于记录计划的功能。
- 一个一个地填写方法,添加单元测试以配合新的或更新的方法,然后尝试 运行一次一点地修改代码。您不必按任何特定顺序编写方法,但是一旦所有
__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