1
用Qt做个井字棋小游戏
ui界面
使用9个PushButton来作为井字格
PushButton需要编好名称,方便后续统一处理
在菜单栏中添加三个action分别负责:重开游戏,退出游戏,帮助文档。
整体思路
我们的思路是:
当游戏开始时,通过点击PushButton改变PushButton的文本内容来表示下棋的过程
当玩家下完一步后,电脑接着下一步(设置电脑延迟,使游戏更有真实感)
当下棋步数>=3时,对游戏的胜负进行判断。(考虑平局)
通过菜单栏重启游戏或退出。
事先准备
头文件
#include <QMainWindow>
#include <QDebug>
#include <QMessageBox>
#include <QRandomGenerator>
#include <QList>
#include <QPushButton>
#include <QTimer>
函数和成员
mainwindow.h
private slots:
void on_action_3_triggered();//退出游戏
void on_action_2_triggered();//重开游戏
void on_action_triggered();//游戏帮助文档
void PlayerChess();//玩家下棋
void ComputerChess();//电脑下棋
void playerWinner();//玩家获胜
void computerWinner();//电脑获胜
private:
Ui::MainWindow *ui;
QList<QPushButton*> buttons;//创建buttons列表存储PushButton
int count=0; //计数器记录步数
mainwindow.cpp
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
//统一管理PushButton
buttons = { ui->pushButton_1, ui->pushButton_2, ui->pushButton_3,
ui->pushButton_4, ui->pushButton_5, ui->pushButton_6,
ui->pushButton_7, ui->pushButton_8, ui->pushButton_9 };
//当buttons中被点击时,触发PlayerChess函数
for (auto button : buttons) {
connect(button, &QPushButton::clicked, this, &MainWindow::PlayerChess);
}
}
玩家下棋
按钮被点击后获取按钮指针,确定被点击的按钮,检查按钮的文本内容,并进行修改,若步数大于等于3,进行胜负判断,若不存在胜负关系,则延迟触发电脑下棋。
void MainWindow::PlayerChess()//Player
{
// 获取发送信号的按钮指针
QPushButton *clickedButton = qobject_cast<QPushButton*>(sender());
if (clickedButton) {
if (clickedButton->text().isEmpty()) {
count++;
clickedButton->setText("X");
if(count>=3){
playerWinner();
}
}
QTimer::singleShot(1000, this, &MainWindow::ComputerChess);
}
}
电脑下棋
创建另一个列表保存空按钮(text为空),通过随机数获得索引,将索引指向的按钮转换为O,即为电脑的下棋。并进行判断胜负(此处判断也可以通过步数count限制判断时机)。
void MainWindow::ComputerChess()
{
QList<QPushButton*> emptyButtons;
// 遍历所有按钮,找出所有空按钮
for (auto button : buttons) {
if (button->text().isEmpty()) {
emptyButtons.append(button);
}
}
// 如果有空按钮,则随机选择一个空按钮并设置为"O"
if (!emptyButtons.isEmpty()) {
int randomIndex = QRandomGenerator::global()->bounded(0, emptyButtons.size());
QPushButton *randomButton = emptyButtons[randomIndex];
randomButton->setText("O");
computerWinner();
}
}
胜负判断
胜负判断,我之前是写到一个函数里面的,但是通过if else进行判断时因为存在先后顺序的影响,对于电脑获胜的判断存在bug,于是使用了两个函数,如果有一个函数写出来的,希望能分享代码,一起学习。同样我的平局判断也是存在重复,其实可以单独写一个平局的函数,当棋盘上的所有格子都被修改过后,进行判断,若所有胜利条件都不符合,则平局。
void MainWindow::computerWinner()
{
QVector<QVector<QPushButton*>> winCombinations {
{ ui->pushButton_1, ui->pushButton_2, ui->pushButton_3 },
{ ui->pushButton_4, ui->pushButton_5, ui->pushButton_6 },
{ ui->pushButton_7, ui->pushButton_8, ui->pushButton_9 },
{ ui->pushButton_1, ui->pushButton_4, ui->pushButton_7 },
{ ui->pushButton_2, ui->pushButton_5, ui->pushButton_8 },
{ ui->pushButton_3, ui->pushButton_6, ui->pushButton_9 },
{ ui->pushButton_1, ui->pushButton_5, ui->pushButton_9 },
{ ui->pushButton_3, ui->pushButton_5, ui->pushButton_7 }
};
// 遍历每个胜利组合,检查是否有一方胜利
for (const auto& combination : winCombinations) {
if (combination[0]->text() == "O" &&
combination[0]->text() == combination[1]->text() &&
combination[1]->text() == combination[2]->text()) {
QMessageBox::information(this, "游戏结束", "电脑胜利!");
return;
}
}
bool allFilled = true;
for (const auto& combination : winCombinations) {
for (auto button : combination) {
if (button->text().isEmpty()) {
allFilled = false;
break;
}
}
if (!allFilled) break;
}
if (allFilled) {
QMessageBox::information(this, "游戏结束", "平局!");
}
}
void MainWindow::playerWinner()
{
QVector<QVector<QPushButton*>> winCombinations {
{ ui->pushButton_1, ui->pushButton_2, ui->pushButton_3 },
{ ui->pushButton_4, ui->pushButton_5, ui->pushButton_6 },
{ ui->pushButton_7, ui->pushButton_8, ui->pushButton_9 },
{ ui->pushButton_1, ui->pushButton_4, ui->pushButton_7 },
{ ui->pushButton_2, ui->pushButton_5, ui->pushButton_8 },
{ ui->pushButton_3, ui->pushButton_6, ui->pushButton_9 },
{ ui->pushButton_1, ui->pushButton_5, ui->pushButton_9 },
{ ui->pushButton_3, ui->pushButton_5, ui->pushButton_7 }
};
// 遍历每个胜利组合,检查是否有一方胜利
for (const auto& combination : winCombinations) {
if (combination[0]->text() == "X" &&
combination[0]->text() == combination[1]->text() &&
combination[1]->text() == combination[2]->text()) {
QMessageBox::information(this, "游戏结束", "玩家胜利!");
return;
}
}
bool allFilled = true;
for (const auto& combination : winCombinations) {
for (auto button : combination) {
if (button->text().isEmpty()) {
allFilled = false;
break;
}
}
if (!allFilled) break;
}
if (allFilled) {
QMessageBox::information(this, "游戏结束", "平局!");
}
}
源代码
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QDebug>
#include <QMessageBox>
#include <QRandomGenerator>
#include <QList>
#include <QPushButton>
#include <QTimer>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_action_3_triggered();
void on_action_2_triggered();
void on_action_triggered();
void PlayerChess();
void ComputerChess();
void playerWinner();
void computerWinner();
private:
Ui::MainWindow *ui;
QList<QPushButton*> buttons;
int count=0;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
buttons = { ui->pushButton_1, ui->pushButton_2, ui->pushButton_3,
ui->pushButton_4, ui->pushButton_5, ui->pushButton_6,
ui->pushButton_7, ui->pushButton_8, ui->pushButton_9 };
for (auto button : buttons) {
connect(button, &QPushButton::clicked, this, &MainWindow::PlayerChess);
}
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_action_3_triggered()
{
this->close();
}
void MainWindow::on_action_2_triggered()
{
this->close();
// 创建新的主窗口实例并显示
MainWindow *newMainWindow = new MainWindow();
newMainWindow->show();
}
void MainWindow::on_action_triggered()
{
QMessageBox::information(this,"游戏提示","点击按钮下棋,"
"三点一线获胜");
}
void MainWindow::PlayerChess()//Player
{
QPushButton *clickedButton = qobject_cast<QPushButton*>(sender()); // 获取发送信号的按钮指针
qDebug()<<"buttonsize"<<buttons.size();
if (clickedButton) {
qDebug() << "玩家点击了按钮:" << clickedButton->objectName();
if (clickedButton->text().isEmpty()) {
count++;
clickedButton->setText("X");
if(count>=3){
playerWinner();
}
}
QTimer::singleShot(1000, this, &MainWindow::ComputerChess);
}
}
void MainWindow::ComputerChess()
{
QList<QPushButton*> emptyButtons;
// 遍历所有按钮,找出所有空按钮
for (auto button : buttons) {
if (button->text().isEmpty()) {
emptyButtons.append(button);
}
}
qDebug() << "空按钮个数:" << emptyButtons.size();
// 如果有空按钮,则随机选择一个空按钮并设置为"O"
if (!emptyButtons.isEmpty()) {
int randomIndex = QRandomGenerator::global()->bounded(0, emptyButtons.size());
QPushButton *randomButton = emptyButtons[randomIndex];
randomButton->setText("O");
computerWinner();
qDebug() << "计算机在按钮:" << randomButton->objectName() << " 下了一步";
} else {
qDebug() << "所有按钮都已经有了棋子,无法继续下棋";
}
}
void MainWindow::computerWinner()
{
QVector<QVector<QPushButton*>> winCombinations {
{ ui->pushButton_1, ui->pushButton_2, ui->pushButton_3 },
{ ui->pushButton_4, ui->pushButton_5, ui->pushButton_6 },
{ ui->pushButton_7, ui->pushButton_8, ui->pushButton_9 },
{ ui->pushButton_1, ui->pushButton_4, ui->pushButton_7 },
{ ui->pushButton_2, ui->pushButton_5, ui->pushButton_8 },
{ ui->pushButton_3, ui->pushButton_6, ui->pushButton_9 },
{ ui->pushButton_1, ui->pushButton_5, ui->pushButton_9 },
{ ui->pushButton_3, ui->pushButton_5, ui->pushButton_7 }
};
// 遍历每个胜利组合,检查是否有一方胜利
for (const auto& combination : winCombinations) {
if (combination[0]->text() == "O" &&
combination[0]->text() == combination[1]->text() &&
combination[1]->text() == combination[2]->text()) {
qDebug() << "电脑胜利";
QMessageBox::information(this, "游戏结束", "电脑胜利!");
return;
}
}
bool allFilled = true;
for (const auto& combination : winCombinations) {
for (auto button : combination) {
if (button->text().isEmpty()) {
allFilled = false;
break;
}
}
if (!allFilled) break;
}
if (allFilled) {
qDebug() << "平局";
QMessageBox::information(this, "游戏结束", "平局!");
}
}
void MainWindow::playerWinner()
{
QVector<QVector<QPushButton*>> winCombinations {
{ ui->pushButton_1, ui->pushButton_2, ui->pushButton_3 },
{ ui->pushButton_4, ui->pushButton_5, ui->pushButton_6 },
{ ui->pushButton_7, ui->pushButton_8, ui->pushButton_9 },
{ ui->pushButton_1, ui->pushButton_4, ui->pushButton_7 },
{ ui->pushButton_2, ui->pushButton_5, ui->pushButton_8 },
{ ui->pushButton_3, ui->pushButton_6, ui->pushButton_9 },
{ ui->pushButton_1, ui->pushButton_5, ui->pushButton_9 },
{ ui->pushButton_3, ui->pushButton_5, ui->pushButton_7 }
};
// 遍历每个胜利组合,检查是否有一方胜利
for (const auto& combination : winCombinations) {
if (combination[0]->text() == "X" &&
combination[0]->text() == combination[1]->text() &&
combination[1]->text() == combination[2]->text()) {
qDebug() << "玩家胜利";
QMessageBox::information(this, "游戏结束", "玩家胜利!");
return;
}
}
bool allFilled = true;
for (const auto& combination : winCombinations) {
for (auto button : combination) {
if (button->text().isEmpty()) {
allFilled = false;
break;
}
}
if (!allFilled) break;
}
if (allFilled) {
qDebug() << "平局";
QMessageBox::information(this, "游戏结束", "平局!");
}
}
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}