在这篇博客中,我们将展示如何使用 Python 和 PyQt5 制作一个简单的扫雷游戏。扫雷游戏是一款经典的益智游戏,玩家需要通过逻辑推理找出隐藏在网格中的所有地雷。
环境准备
首先,我们需要安装 PyQt5 库。可以使用以下命令进行安装:
pip install PyQt5
代码详解
1. 初始化游戏界面
我们首先创建一个 Minesweeper
类,继承自 QMainWindow
。在 __init__
方法中,我们初始化了游戏界面的大小和地雷数量,并调用 initUI
方法来设置用户界面。
def initUI(self):
self.central_widget = QWidget()
self.grid_layout = QGridLayout()
self.central_widget.setLayout(self.grid_layout)
self.setCentralWidget(self.central_widget)
self.setWindowTitle('Minesweeper')
2. 生成地雷
我们使用 generate_mines
方法来随机生成地雷的位置,并将这些位置存储在一个集合中。
def generate_mines(self):
while len(self.mine_positions) < self.mines:
mine = (random.randint(0, self.rows - 1), random.randint(0, self.cols - 1))
self.mine_positions.add(mine)
3. 生成按钮
我们使用 generate_buttons
方法在网格中生成按钮,每个按钮代表一个网格单元。我们还为每个按钮设置了一个点击事件。
def generate_buttons(self):
for row in range(self.rows):
for col in range(self.cols):
button = QPushButton('')
button.setFixedSize(40, 40)
button.clicked.connect(self.make_move(row, col))
self.grid_layout.addWidget(button, row, col)
self.buttons[row][col] = button
4. 处理点击事件
在 make_move
方法中,我们定义了按钮点击后的行为。如果点击的位置有地雷,我们就显示红色并结束游戏;否则,我们显示该位置周围的地雷数量。
def make_move(self, row, col):
def callback():
if (row, col) in self.mine_positions:
self.buttons[row][col].setStyleSheet('background-color: red')
self.game_over(False)
else:
self.reveal_cell(row, col)
if self.check_win():
self.game_over(True)
return callback
5. 显示单元格信息
在 reveal_cell
方法中,我们显示点击位置周围的地雷数量。如果该位置周围没有地雷,我们递归显示周围的空白单元格。
def reveal_cell(self, row, col):
if self.buttons[row][col].text() != '':
return
mine_count = self.count_mines(row, col)
self.buttons[row][col].setText(str(mine_count))
self.buttons[row][col].setStyleSheet('background-color: lightgrey')
if mine_count == 0:
for r, c in self.get_neighbors(row, col):
self.reveal_cell(r, c)
实现扫雷游戏
下面是实现扫雷游戏的完整代码。我们将从一个简单的用户界面开始,并逐步添加游戏逻辑。
import sys
import random
from PyQt5.QtWidgets import QApplication, QMainWindow, QGridLayout, QPushButton, QWidget, QMessageBox
class Minesweeper(QMainWindow):
def __init__(self, rows, cols, mines):
super().__init__()
self.rows = rows
self.cols = cols
self.mines = mines
self.initUI()
def initUI(self):
self.central_widget = QWidget()
self.grid_layout = QGridLayout()
self.central_widget.setLayout(self.grid_layout)
self.setCentralWidget(self.central_widget)
self.setWindowTitle('Minesweeper')
self.buttons = [[None for _ in range(self.cols)] for _ in range(self.rows)]
self.mine_positions = set()
self.generate_mines()
self.generate_buttons()
def generate_mines(self):
while len(self.mine_positions) < self.mines:
mine = (random.randint(0, self.rows - 1), random.randint(0, self.cols - 1))
self.mine_positions.add(mine)
def generate_buttons(self):
for row in range(self.rows):
for col in range(self.cols):
button = QPushButton('')
button.setFixedSize(40, 40)
button.clicked.connect(self.make_move(row, col))
self.grid_layout.addWidget(button, row, col)
self.buttons[row][col] = button
def make_move(self, row, col):
def callback():
if (row, col) in self.mine_positions:
self.buttons[row][col].setStyleSheet('background-color: red')
self.game_over(False)
else:
self.reveal_cell(row, col)
if self.check_win():
self.game_over(True)
return callback
def reveal_cell(self, row, col):
if self.buttons[row][col].text() != '':
return
mine_count = self.count_mines(row, col)
self.buttons[row][col].setText(str(mine_count))
self.buttons[row][col].setStyleSheet('background-color: lightgrey')
if mine_count == 0:
for r, c in self.get_neighbors(row, col):
self.reveal_cell(r, c)
def count_mines(self, row, col):
return sum((r, c) in self.mine_positions for r, c in self.get_neighbors(row, col))
def get_neighbors(self, row, col):
neighbors = [(row + i, col + j) for i in range(-1, 2) for j in range(-1, 2)
if 0 <= row + i < self.rows and 0 <= col + j < self.cols and (i != 0 or j != 0)]
return neighbors
def game_over(self, won):
msg = QMessageBox()
if won:
msg.setText('You won!')
else:
msg.setText('Game Over!')
msg.exec_()
self.close()
def check_win(self):
for row in range(self.rows):
for col in range(self.cols):
if (row, col) not in self.mine_positions and self.buttons[row][col].text() == '':
return False
return True
if __name__ == '__main__':
app = QApplication(sys.argv)
game = Minesweeper(10, 10, 10) # 10x10 grid with 10 mines
game.show()
sys.exit(app.exec_())
运行结果:
总结
这篇博客展示了如何使用 PyQt5 制作一个简单的扫雷游戏。通过这个项目,你可以学习到如何使用 PyQt5 创建用户界面,处理事件,以及实现游戏逻辑。希望你能从中学到更多,并享受编程的乐趣!
如果你有任何问题或建议,请在评论区留言。祝你编程愉快!