扫雷棋盘生成器Bug:大尺寸棋盘周边地雷计数错误
扫雷游戏棋盘生成计数错误排查
问题描述
编写的扫雷棋盘生成Python代码,在生成10×10、含10个地雷的棋盘时输出正确,但生成10×15、含30个地雷的棋盘时,部分格子的周边地雷计数出现错误(例如标注的4应为3,5应为4)。
原代码
import random objects = [] class Minesweeper_gameboard(): def __init__(self, width, height, num_mines): self.width = width self.height = height self.num_mines = num_mines objects.append(self) def game_board(self): board = [[0 for i in range(self.height)] for j in range(self.width)] number_of_mines = 0 while number_of_mines < self.num_mines: x = random.randint(0, self.width - 1) y = random.randint(0, self.height - 1) #Create conditions, when test is true, adopt range: a_True; when test is false, adopt range: a_False a_test = (x - 1) >= 0 b_test = (x + 1) < self.width c_test = (y - 1) >= 0 d_test = (y + 1) < self.height #when (x-1) is more or equal to 0, use (x-1) as the starting point of the range, vice versa a_True = x-1 b_True = x+2 c_True = y-1 d_True = y+2 #when (x-1) is less than 0, x locate at the corner, use x as the starting point of the range, vice versa a_False = x b_False = x+1 c_False = y d_False = y+1 condition_list = [[a_test, a_True, a_False], [b_test, b_True, b_False], [c_test, c_True, c_False], [d_test, d_True, d_False]] #Delete the condition that is not satisfied for i in condition_list: if i[0] == True: del i[0] del i[1] else: del i[0] del i[0] #Flatten the list with a nested loop condition_list = [a for b in condition_list for a in b] #Create Rules to illustrate mine locations if board[x][y] != 'X': board[x][y] = 'X' number_of_mines += 1 try: #call out the flatten condition_list as the range to illustrate the number of mines nearby for i in range(condition_list[0], condition_list[1]): for j in range(condition_list[2], condition_list[3]): if board[i][j] != 'X': board[i][j] += 1 except: continue else: x = random.randint(0, self.width-1) y = random.randint(0, self.height-1) return board def player_board(self): player_board = [['-' for i in range(self.height)] for j in range(self.width)] def display_board(self, board): for row in board: print(" ".join(str(cell) for cell in row)) print("") #testing function mine = Minesweeper_gameboard(10,10,10) for object in objects: object.game_board() object.display_board(object.game_board())
测试情况
正确输出(10×10、10个地雷)
X 2 0 0 1 1 1 0 0 0 X 2 0 0 1 X 2 1 0 0 1 1 0 0 1 2 X 1 0 0 0 1 2 2 1 1 1 1 0 0 1 2 X X 1 0 0 1 2 2 X 2 2 2 1 0 0 1 X X 1 1 0 0 0 0 0 1 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 1 X 1 0 0
错误输出(10×15、30个地雷)
0 0 0 0 1 X 2 X X X 3 1 X 1 0 0 1 1 2 2 2 3 4 7 X 3 1 1 1 0 2 **4** X 3 X 1 1 X X 3 2 0 1 1 1 X **5** X 4 2 2 2 2 2 1 0 0 1 X 1 3 5 X 3 2 X 1 0 1 1 2 1 2 1 1 X 2 1 2 X 2 2 2 4 X 3 X 1 0 0 1 2 1 2 1 1 1 X X X 4 1 2 1 1 0 1 X 2 1 0 1 3 X X 2 0 1 X 1 0 1 2 X 3 2 2 2 3 3 1 0 2 2 2 0 0 1 1 3 X 2 1 X 1 0 0 1 X 1
错误说明:标注的4应为3,5应为4。
问题原因分析
- 重复累加计数:当随机数重复选中已存在地雷的位置时,代码不会新增地雷,但仍会执行周边格子的计数累加操作,导致这些格子的计数被多算一次。这是核心错误,当地雷数量占比越高(如10×15棋盘放30个地雷,占比20%),重复选中的概率就越高,计数错误就越明显。
- 棋盘重复生成:测试代码中连续调用两次
game_board(),第一次生成的棋盘未被使用,第二次生成新棋盘进行展示,虽然不直接导致计数错误,但属于冗余逻辑。 - 多余的else分支:
try-except后的else分支会重新生成随机坐标,但此时循环会继续迭代,导致逻辑混乱,可能引发不必要的重复处理。
修复方案
修复后的代码
import random objects = [] class Minesweeper_gameboard(): def __init__(self, width, height, num_mines): self.width = width self.height = height self.num_mines = num_mines objects.append(self) def game_board(self): board = [[0 for _ in range(self.height)] for _ in range(self.width)] number_of_mines = 0 while number_of_mines < self.num_mines: x = random.randint(0, self.width - 1) y = random.randint(0, self.height - 1) # 跳过已存在地雷的位置 if board[x][y] == 'X': continue # 设置当前位置为地雷 board[x][y] = 'X' number_of_mines += 1 # 计算周边格子的范围,避免越界 x_start = max(x - 1, 0) x_end = min(x + 2, self.width) y_start = max(y - 1, 0) y_end = min(y + 2, self.height) # 遍历周边格子并累加计数 for i in range(x_start, x_end): for j in range(y_start, y_end): if board[i][j] != 'X': board[i][j] += 1 return board def player_board(self): return [['-' for _ in range(self.height)] for _ in range(self.width)] def display_board(self, board): for row in board: print(" ".join(str(cell) for cell in row)) print("") # 测试函数 mine = Minesweeper_gameboard(10,15,30) for obj in objects: generated_board = obj.game_board() obj.display_board(generated_board)
修复要点
- 跳过重复地雷位置:新增判断,若选中的坐标已经是地雷则直接跳过,不执行后续计数累加。
- 简化范围计算:用
max()和min()直接计算合法的边界范围,替代原有的复杂列表处理逻辑,更简洁且不易出错。 - 避免重复生成棋盘:将生成的棋盘保存到变量中,再传入
display_board展示。 - 移除冗余逻辑:删除不必要的
try-except和else分支,简化代码流程。
内容的提问来源于stack exchange,提问作者Becky1122
相关产品推荐
相关产品推荐

