首页 > 其他分享 >大一菜鸡QT大作业之五子棋

大一菜鸡QT大作业之五子棋

时间:2024-07-18 17:54:18浏览次数:8  
标签:大一菜 timeLabel QT int void 五子棋 mybutton QMessageBox include

作者本人为大一即将结束的菜鸡一枚,刚刚完成了暑期课程,上交了自己的QT编程项目----五子棋游戏,较为简陋,由于不打算投入大量时间(只投入了不到一个星期),且不会五子棋人机对战的算法,所以本人的项目是由自己在开源网站上搜索到的两个五子棋项目修改而成,该五子棋具有人人对战,人机对战,联机对战(仅限局域网)三种功能,每个模块中我加入了悔棋,以及倒计时功能。

 概览一下

 这是游戏的主页面,极端丑陋,原谅我的审美细胞实在太少,都是在网上找的图片。

 项目结构

 

 其中在basescene文件中定义了基本的页面样式,以及绘制棋子和背景的函数,mybutton文件中则是对于按钮的一些特性及动画进行了定义,确定了按钮的特性等,pwithpolscene函数用于完成联机对战的逻辑,pwithpsence函数用于完成人人对战的逻辑,pwithrsence函数用于完成人机对战的逻辑。 

 basescene

 basescene.h文件

#ifndef BASESCENE_H
#define BASESCENE_H


#include<QWidget>
#include"mybutton.h"
#include<QCloseEvent>

class basescene:public QWidget
{
    Q_OBJECT
public:
    explicit basescene(QWidget *parent = nullptr);

    bool isfinish();

    void paintEvent(QPaintEvent *event);

    int chess[19][19]={};
    int chessx=0,chessy=0;
    int colorflag=1;
    int win=0;
    int begin=0;
    void closeEvent(QCloseEvent *event);


signals:
    void back();

};

#endif // BASESCENE_H

 在.h文件中,isfinish()函数用来判定当前棋局的胜负,它的返回值对于我们判定游戏结束后执行的逻辑至关重要,paintEvent(QPaintEvent *event)函数则是完成了对于页面的绘制,closeEvent(QCloseEvent *event)则是重写了窗口关闭函数,完成窗口关闭事件的逻辑。

basescene.cpp 文件

#include "basescene.h"
#include<QPainter>
#include<QTimer>
#include<QDebug>
#include<QPixmap>
#include<QMessageBox>
basescene::basescene(QWidget *parent):QWidget{parent}
{
    setFixedSize(1452,950);

    setWindowIcon(QIcon(":/picture/ico.jpg"));

    setWindowTitle("来吧,五子棋!");
}


void basescene::paintEvent(QPaintEvent *event){
    QPainter painter(this);
    painter.drawPixmap(QRect(0,0,1452,950),QPixmap(":/picture/back.jpg"));
    painter.drawPixmap(QRect(100,0,782,799),QPixmap(":/picture/qipan2.jpg"));
    for (int i=0;i<19 ;i++ ) {
        for (int j=0;j<19 ;j++ ) {
            if(chess[i][j]==1){
                painter.drawPixmap(QRect(127+(int)i*38.4,27+(int)j*39.4,36,36),QPixmap(":/picture/black1.png"));
            }
            if(chess[i][j]==2){
                painter.drawPixmap(QRect(127+(int)i*38.4,27+(int)j*39.4,36,36),QPixmap(":/picture/white1.png"));
            }
        }
    }
    if(begin){
        painter.setBrush(Qt::red);
        painter.drawEllipse(QRect((int)chessx*38.4+140,(int)chessy*39.4+40,10,10));
    }

}





bool basescene::isfinish(){
    for(int i=0;i<19;i++){
        if(win) break;
        for(int j=0;j<15;j++){
            if(chess[i][j]==1&&chess[i][j+1]==1&&chess[i][j+2]==1&&chess[i][j+3]==1&&chess[i][j+4]==1){
                win = 1;
                break;
            }
        }
    }
    for(int i=0;i<15;i++){
        if(win) break;
        for(int j=0;j<19;j++){
            if(chess[i][j]==1&&chess[i+1][j]==1&&chess[i+2][j]==1&&chess[i+3][j]==1&&chess[i+4][j]==1){
                win = 1;
                break;
            }
        }
    }
    for(int i=0;i<15;i++){
        if(win) break;
        for(int j=0;j<15;j++){
            if(chess[i][j]==1&&chess[i+1][j+1]==1&&chess[i+2][j+2]==1&&chess[i+3][j+3]==1&&chess[i+4][j+4]==1){
                win = 1;
                break;
            }
        }
    }
    for(int i=0;i<15;i++){
        if(win) break;
        for(int j=0;j+i<33;j++){
            if(chess[i][j]==1&&chess[i+1][j-1]==1&&chess[i+2][j-2]==1&&chess[i+3][j-3]==1&&chess[i+4][j-4]==1){
                win = 1;
                break;
            }
        }
    }

    for(int i=0;i<19;i++){
        if(win) break;
        for(int j=0;j<15;j++){
            if(chess[i][j]==2&&chess[i][j+1]==2&&chess[i][j+2]==2&&chess[i][j+3]==2&&chess[i][j+4]==2){
                win = 2;
                break;
            }
        }
    }
    for(int i=0;i<15;i++){
        if(win) break;
        for(int j=0;j<19;j++){
            if(chess[i][j]==2&&chess[i+1][j]==2&&chess[i+2][j]==2&&chess[i+3][j]==2&&chess[i+4][j]==2){
                win = 2;
                break;
            }
        }
    }
    for(int i=0;i<15;i++){
        if(win) break;
        for(int j=0;j<15;j++){
            if(chess[i][j]==2&&chess[i+1][j+1]==2&&chess[i+2][j+2]==2&&chess[i+3][j+3]==2&&chess[i+4][j+4]==2){
                win = 2;
                break;
            }
        }
    }
    for(int i=0;i<15;i++){
        if(win) break;
        for(int j=0;j+i<33;j++){
            if(chess[i][j]==2&&chess[i+1][j-1]==2&&chess[i+2][j-2]==2&&chess[i+3][j-3]==2&&chess[i+4][j-4]==2){
                win = 2;
                break;
            }
        }
    }
    if(win) return true;

    bool equals = true;
    for(int i=0;i<19;i++){
        for(int j=0;j<19;j++){
            if(!chess[i][j])equals =0;
        }
    }
    if(equals){
        win=3;
        return true;
    }
    return false;
}



void basescene::closeEvent(QCloseEvent *event){
    emit this->back();
    this->hide();
    event->ignore();
}

 .cpp文件是对于.h文件的具体实现

setFixedSize(1452,950); //将五子棋游戏的窗口大小设置为固定的尺寸   setWindowIcon(QIcon(":/picture/ico.jpg")); //为自己的游戏设置一个图标,:/picture/ico.jpg这是该照片在我的项目中的资源文件中的路径  
 setWindowTitle("来吧,五子棋!");//为自己的游戏设置title
isfinish()//在该函数中我们通过win的值来判断和标识胜利方的颜色
 MainWindow

 MainWindow.h文件

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "pwithpscene.h"
#include "pwithrscene.h"
#include <QPaintEvent>
#include "pwithpolscene.h"
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    void paintEvent(QPaintEvent*);
    ~MainWindow();
    pwithpsence *playpwp = NULL;
    pwithrsence *playpwr = NULL;
    pwithpolscene *playpwpol = NULL;




private:
    Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H

 pwithpsence *playpwp = NULL;
pwithrsence *playpwr = NULL;
pwithpolscene *playpwpol = NULL;
//创建三种游戏对应类的对象

 MainWindow.cpp文件

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "mybutton.h"
#include<QPainter>
#include<QTimer>
#include<QDebug>
#include<QPixmap>
#include<QMessageBox>
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    setFixedSize(1000,600);

    setWindowIcon(QIcon(":/picture/ico.jpg"));

    setWindowTitle("来吧,五子棋!");

    mybutton *pwp = new mybutton(":/picture/pwithp.jpeg");
    pwp->setParent(this);
    pwp->move(this->width()*0.25-pwp->width()*0.5,this->height()*0.7);

    mybutton *pwr = new mybutton(":/picture/pwithr.jpeg");
    pwr->setParent(this);
    pwr->move(this->width()*0.75-pwr->width()*0.5,this->height()*0.15);

    mybutton *pwpol = new mybutton(":/picture/pwithpol.jpeg");
    pwpol->setParent(this);
    pwpol->move(this->width()*0.25-pwpol->width()*0.5,this->height()*0.15);

    mybutton *off = new mybutton(":/picture/off.jpeg");
    off->setParent(this);
    off->move(this->width()*0.75-pwpol->width()*0.5,this->height()*0.7);

    playpwp = new pwithpsence();
    playpwr = new pwithrsence();


    connect(playpwp,&pwithpsence::back,[=](){
        playpwp->hide();
        this->show();
    });

    connect(playpwr,&pwithrsence::back,[=](){
        playpwr->hide();
        this->show();
    });



    connect(pwpol,&QPushButton::clicked,[=](){
        pwpol->down();
        pwpol->up();
        int ret = QMessageBox::question(this,"提示","是否作为【服务器】启动?<br>""- Yes: 服务器, 属白色<br>""- No: 客户端, 属黑方<br><br>",QMessageBox::Yes|QMessageBox::No);
        netWorkType netType = (ret == QMessageBox::Yes ? SERVER : CLIENT);
        chessType chessType = (ret == QMessageBox::Yes ? WHITEPIECE : BLACKPIECE);
        playpwpol = new pwithpolscene(netType,chessType);

        QTimer::singleShot(400,this,[=](){
            this->hide();
            //playpwpol->restart();
            playpwpol->show();
        });

    });

    connect(playpwpol,&pwithpolscene::back,[=](){

        playpwpol->hide();
        this->show();
    });


    connect(pwp,&QPushButton::clicked,[=](){
        pwp->down();
        pwp->up();
        QTimer::singleShot(400,this,[=](){
            this->hide();
            playpwp->restart();
            playpwp->show();
        });
    });

    connect(pwr,&QPushButton::clicked,[=](){
        pwr->down();
        pwr->up();
        QTimer::singleShot(400,this,[=](){
            this->hide();
            playpwr->restart();
            playpwr->show();
        });
    });

    connect(off,&QPushButton::clicked,[=](){
        off->down();
        off->up();
        QTimer::singleShot(400,this,[=](){
            this->hide();
            qApp->quit();
        });
    });


}



void MainWindow::paintEvent(QPaintEvent *){
    QPainter painter(this);
    QPixmap pix;
    pix.load(":/picture/background.jpeg");
    painter.drawPixmap(0,0,1000,600,pix);
}



MainWindow::~MainWindow()
{
    delete ui;
}

 在MainWindow的构造函数中,我们进行了主页面的构建,我们利用mybutton类设置了四个按钮,分别对应人人对战,人机对战,联机对战,退出游戏四个事件,并使用QT中的信号与槽机制将这些按钮的点击事件与其槽函数(即点击后的执行逻辑)进行绑定。

 mybutton

 mybutton.h文件

#ifndef MYBUTTON_H
#define MYBUTTON_H


#include<QPushButton>

class mybutton : public QPushButton
{
    Q_OBJECT
public:
    QString img;
    mybutton(QString image);
    void up();
    void down();
signals:

};

#endif // MYBUTTON_H

 mybutton.cpp文件

 

#include "mybutton.h"
#include<QPixmap>
#include<QPropertyAnimation>
mybutton::mybutton(QString image)
{
    QString img = image;
    QPixmap pix;
    bool ret = pix.load(img);
    if(!ret){
        return;
    }
    this->setFixedSize(pix.width(),pix.height());
    this->setStyleSheet("QPushButton{border:0px}");
    this->setIcon(pix);
    this->setIconSize(QSize(pix.width(),pix.height()));
}


void mybutton::up(){
    QPropertyAnimation * ani=new QPropertyAnimation(this,"geometry");
    ani->setDuration(200);

    ani->setStartValue(QRect(this->x(),this->y()+10,this->width(),this->height()));
    ani->setEndValue(QRect(this->x(),this->y(),this->width(),this->height()));

    //设置曲线
    ani->setEasingCurve(QEasingCurve::OutBounce);

    ani->start();
}


void mybutton::down(){
    QPropertyAnimation * ani=new QPropertyAnimation(this,"geometry");
    ani->setDuration(200);

    ani->setStartValue(QRect(this->x(),this->y(),this->width(),this->height()));
    ani->setEndValue(QRect(this->x(),this->y()+10,this->width(),this->height()));

    //设置曲线
    ani->setEasingCurve(QEasingCurve::OutBounce);

    ani->start();
}

 在文件中,我们在构造函数中定义了按钮的一些性质,在up()函数和down()函数中定义了按下按钮后的动画效果,即按钮将会向下移动然后再向上移动,展示出被点击的感觉,每一步耗时200毫秒。

 pwithpsence

 pwithpsence.h文件

#ifndef PWITHPSCENE_H
#define PWITHPSCENE_H


#include"basescene.h"
#include"mybutton.h"
#include<QLabel>
#include<QPoint>
#include<QStack>
#include<QTimer>
#include<QCloseEvent>
class pwithpsence : public basescene
{
    Q_OBJECT
public:
    explicit pwithpsence();
    mybutton * startbtn = new mybutton(":/picture/start1.jpg");
    mybutton * restartbtn = new mybutton(":/picture/restart2.jpeg");

    QLabel * label;
    void end();
    void mouseReleaseEvent(QMouseEvent *event);
    void restart();
    void regret();
    int step = 0;
    QStack<QPoint> drop;
    QTimer *timer;
    QLabel *timeLabel;
    int time;
    void ontimerTimout();
    void change();
    void closeEvent(QCloseEvent *event);
signals:

};

#endif // PWITHPSCENE_H

 在文件中完成人人对战的逻辑。

 pwithpsence.cpp文件

#include "pwithpscene.h"
#include <QStyle>
#include <QTimer>
#include <QMessageBox>
#include <QLabel>
#include <QFont>
pwithpsence::pwithpsence()
{
    mybutton * regretBtn = new mybutton(":/picture/Regret.png");
    regretBtn->setParent(this);
    regretBtn->setGeometry(QRect(950,310,300,120));
    regretBtn->show();

    startbtn->setParent(this);
    startbtn->setGeometry(QRect(350,815,120,120));

    restartbtn->setParent(this);
    restartbtn->setFixedSize(300,120);
    restartbtn->setGeometry(QRect(350,815,120,120));
    restartbtn->hide();

    label = new QLabel();
    label->setParent(this);
    label->setFixedSize(600,200);
    label->setStyleSheet("color:red;font-size:60px;");
    label->setFont(QFont("黑体"));
    label->setText("点击下方按钮开始游戏");
    label->move(190,300);
    label->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
    label->setAttribute(Qt::WA_TransparentForMouseEvents);




    timer = new QTimer(this);
    connect(timer,&QTimer::timeout,this,&pwithpsence::ontimerTimout);
    timer->setInterval(1000);


    connect(startbtn,&QPushButton::clicked,[=](){
        label->hide();
        startbtn->down();
        startbtn->up();
        QTimer::singleShot(400,this,[=](){
            startbtn->hide();
            restartbtn->show();
            begin=1;
            time=60;
            timeLabel = new QLabel(this);
            timeLabel->setGeometry(930, 100, 500, 100);
            timeLabel->setStyleSheet("QLabel { color: rgba(0, 255, 0, 1); font-size: 80px; font-weight: bold; background-color: transparent; }");
            timeLabel->setText(QString("倒计时: %1").arg(time));
            timeLabel->show();
            timer->start();
        });
    });

    connect(restartbtn,&QPushButton::clicked,[=](){
        restartbtn->down();
        restartbtn->up();
        QTimer::singleShot(400,this,[=](){
            timeLabel->hide();
            restart();
        });
    });

    connect(regretBtn,&QPushButton::clicked,[=](){
        regretBtn->down();
        regretBtn->up();
        QTimer::singleShot(400,this,[=](){
            regret();

        });
    });
}


void pwithpsence::mouseReleaseEvent(QMouseEvent *event){
    if(!begin){
        return;
    }
    int x =event->x(),y =event->y();
    if(x<125||x>855||y<25||y>770) return;
    chessx=(x-145+19)/39;
    chessy=(y-45+20)/40;
    if(chess[chessx][chessy]!=0)return;
    chess[chessx][chessy]=colorflag;
    drop.push(QPoint(chessx,chessy));
    step++;
    change();
    if(colorflag==1){
        colorflag=2;
    }
    else {
        colorflag=1;
    }
    bool ifis = this->isfinish();
    if(ifis){
        end();
    }
    update();
}


void pwithpsence::regret(){
    if(begin&&!isfinish()){
        if(step>0&&!drop.empty()){
            QPoint pos = drop.pop();
            chess[pos.x()][pos.y()] = 0;
            colorflag=3 - colorflag;
            step--;
        }
        update();
    }
}

void pwithpsence::change(){

    time = 60;
    timeLabel->setText(QString("倒计时: %1").arg(time));
    timeLabel->update();
    timer->start();
}

void pwithpsence::ontimerTimout(){
    if(time>0){
        time--;
        timeLabel->setText(QString("倒计时: %1").arg(time));
    }else{
        timer->stop();
        QMessageBox::information(this,"提示","您已经超时,本局游戏结束!");
        restart();
    }
}

void pwithpsence::end(){
    int ret = 0;
    if(win==1){
        ret = QMessageBox::information(this,"本局结果","恭喜黑棋方获得胜利!\n再来一局?",QMessageBox::Yes|QMessageBox::No,QMessageBox::Yes);
    }
    else if(win==2){
        ret = QMessageBox::information(this,"本局结果","恭喜白棋方获得胜利!\n再来一局?",QMessageBox::Yes|QMessageBox::No,QMessageBox::Yes);
    }
    else if(win==3){
        ret = QMessageBox::information(this,"本局结果","很遗憾,你们是平局!\n再来一局?",QMessageBox::Yes|QMessageBox::No,QMessageBox::Yes);
    }

    if(ret==QMessageBox::Yes){
        update();
        timeLabel->hide();
        restart();
    }else if(ret==QMessageBox::No){
        timeLabel->hide();
        timer->stop();
        emit this->back();
        this->hide();
    }
}



void pwithpsence::restart(){
    for(int i=0;i<19;i++){
        for(int j=0;j<19;j++){
            chess[i][j]=0;
        }
    }
    step = 0;
    label->show();
    restartbtn->hide();
    startbtn->show();
    begin=0;
    win=0;
    colorflag=1;
    update();
}

void pwithpsence::closeEvent(QCloseEvent *event){
    if(timeLabel){
        timeLabel->hide();
    }
    timer->stop();
    emit this->back();
    this->hide();
    event->ignore();
}

 首先,我们在构造函数中完成了对于“开始游戏”按钮,“重新开始”按钮,“悔棋”按钮,以及倒计时等的定义和初始化,并利用信号与槽机制确定了按钮点击事件被触发时要执行的槽函数,在mouseReleaseEvent函数中,通过重写鼠标释放函数,我们来监听鼠标释放事件,并进行判断释放事件是否有效,若有效,则进行下棋操作。在倒计时的实现上,我设置了倒计时的时间固定为60秒,若某一方未能在60秒内完成下棋操作则该剧游戏强制结束,具体实现上,我们通过QTimer实现这个倒记时,我们需要监视游戏是否开始,若开始,则开始计时,同时,用change()函数监控下棋方的更改,以实现倒计时的重置,ontimerTimout()函数则用来处理倒计时归零时的操作,切记实现倒计时时,应该在end()函数中完成对timeLabel的隐藏以及Timer的关闭,否则当你打开其他游戏模式或者是重新开始一局游戏时将会出现两个倒计时重叠的现象。在悔棋功能的实现上,我们用int step = 0; QStack<QPoint> drop;,事先定义,用step记录当前的下棋步数,用一个栈保存棋子的位置信息,当我们点击悔棋按钮时,regret()函数会将当前的栈顶的妻子位置信息弹出,同时步数-1,这样我们就可以实现悔棋操作了,同时记住实现悔棋后要及时改变当前的下棋方。

 pwithrsence

 pwithrsence.h文件

#ifndef PWITHRSCENE_H
#define PWITHRSCENE_H


#include"basescene.h"
#include"mybutton.h"
#include<QPoint>
#include<QStack>
#include<QTimer>
#include<QLabel>
#include<QCloseEvent>
class pwithrsence : public basescene
{
    Q_OBJECT
public:
    explicit pwithrsence();

    int aiflag=0;

    mybutton * pfirbtn = new mybutton(":/picture/pfir1.jpeg");
    mybutton * aiFirbtn = new mybutton(":/picture/aifir1.jpeg");
    mybutton * restartbtn = new mybutton(":/picture/restart2.jpeg");

    void end();

    void AI();

    int chesstype(int rotate, int i,int j);

    int value(int i,int j);
    void move(int rotate, int *i,int  *j);
    void mouseReleaseEvent(QMouseEvent *event);
    void restart();
    void regret();
    int step = 0;
    QStack<QPoint> drop;
    QTimer *timer;
    QLabel *timeLabel;
    int time;
    void ontimerTimout();
    void change();
    void closeEvent(QCloseEvent *event);
signals:

};

#endif // PWITHRSCENE_H

 pwithrscene.cpp文件

#include "pwithrscene.h"
#include<QWidget>
#include<QTimer>
#include<QMessageBox>
#include <QDebug>
#include<mybutton.h>

pwithrsence::pwithrsence()
{
    mybutton * regretBtn = new mybutton(":/picture/Regret.png");
    regretBtn->setParent(this);
    regretBtn->setGeometry(QRect(950,310,300,120));
    regretBtn->show();

    pfirbtn->setParent(this);
    pfirbtn->setGeometry(QRect(350,500,200,120));
    pfirbtn->show();
    aiFirbtn->setParent(this);
    aiFirbtn->setGeometry(QRect(350,250,200,120));
    aiFirbtn->show();
    restartbtn->setParent(this);
    restartbtn->setFixedSize(300,120);
    restartbtn->setGeometry(QRect(350,815,120,120));
    restartbtn->hide();

    timer = new QTimer(this);
    connect(timer,&QTimer::timeout,this,&pwithrsence::ontimerTimout);
    timer->setInterval(1000);

    connect(pfirbtn,&QPushButton::clicked,[=](){
        pfirbtn->down();
        pfirbtn->up();
        QTimer::singleShot(400,this,[=](){
            pfirbtn->hide();
            aiFirbtn->hide();
            restartbtn->show();
            aiflag=2;
            colorflag=1;
            begin=1;
            time=60;
            timeLabel = new QLabel(this);
            timeLabel->setGeometry(930, 100, 500, 100);
            timeLabel->setStyleSheet("QLabel { color: rgba(0, 255, 0, 1); font-size: 80px; font-weight: bold; background-color: transparent; }");
            timeLabel->setText(QString("倒计时: %1").arg(time));
            timeLabel->show();
            timer->start();
        });
    });

    connect(aiFirbtn,&QPushButton::clicked,[=](){
        aiFirbtn->down();
        aiFirbtn->up();
        QTimer::singleShot(400,this,[=](){
            pfirbtn->hide();
            aiFirbtn->hide();
            restartbtn->show();
            aiflag=1;
            colorflag=2;
            begin=1;
            time=60;
            timeLabel = new QLabel(this);
            timeLabel->setGeometry(930, 100, 500, 100);
            timeLabel->setStyleSheet("QLabel { color: rgba(0, 255, 0, 1); font-size: 80px; font-weight: bold; background-color: transparent; }");
            timeLabel->setText(QString("倒计时: %1").arg(time));
            timeLabel->show();
            timer->start();
            AI();
        });
    });


    connect(restartbtn,&QPushButton::clicked,[=](){
        restartbtn->down();
        restartbtn->up();
        QTimer::singleShot(400,this,[=](){
            timeLabel->hide();
            restart();
        });
    });

    connect(regretBtn,&QPushButton::clicked,[=](){
        regretBtn->down();
        regretBtn->up();
        QTimer::singleShot(400,this,[=](){
            regret();

        });
    });
}

void pwithrsence::AI(){
    bool fir=1;
    for(int i=0;i<19;i++){
        for(int j=0;j<19;j++){
            if(chess[i][j]!=0){
                fir=0;
            }
        }
    }
    if(fir){
        chess[9][9]=1;
        drop.push(QPoint(chessx,chessy));
        step++;
        change();
        update();
        return;
    }

    int temp=0,maxsource=0;
    chessx=0;
    chessy=0;
    for(int i=0;i<19;i++)
            for(int j=0;j<19;j++)
            {
                if(chess[i][j]==0)
                {
                    temp=value(i,j);
                    if(temp>=maxsource)
                    {
                        chessx=i;
                        chessy=j;
                        maxsource=temp;
                    }
                }
            }
    chess[chessx][chessy]=aiflag;
    drop.push(QPoint(chessx,chessy));
    step++;
    change();
    bool ifis=this->isfinish();
    if(ifis){
        end();
    }
    update();
}


int pwithrsence::value(int i, int j){
    int rotate=1,Value=0,source1,source2,score1,score2,X1,X2,Y1,Y2,Z1,Z2,temp;
    int V[2][4][4]={{{40,700,6000,20000},{6,10,600,20000},{20,670,5400,0},{6,10,500,0}},
                    {{30,300,2500,15000},{2,8,300,9000},{26,160,0,0},{4,20,300,0}}};
    while(rotate!=5)
    {
        source1=chesstype(rotate,i,j);
        rotate+=4;
        source2=chesstype(rotate,i,j);
        rotate-=3;
        if(source1>source2){
            temp=source1;
            source1=source2;
            source2=temp;
        }

        score1=source1;
        score2=source2;

        Z1=score1%10;
        score1/=10;
        Y1=score1%10;
        score1/=10;
        X1=score1%10;

        Z2=score2%10;
        score2/=10;
        Y2=score2%10;
        score2/=10;
        X2=score2%10;

        if(source1==-1){
            if(source2<0){
                Value+=0;
                continue;
            }
            else {
                Value+=V[X2][Y2][Z2]+5;
                continue;
            }
        }
        if(source1==-2){
            if(source2<0){
                Value+=0;
                continue;
            }
            else {
                Value+=V[X2][Y2][Z2]/2;
                continue;
            }
        }
        if(source1==-3){
            if(source2<0){
                Value+=0;
                continue;
            }
            else {
                Value+=V[X2][Y2][Z2]/3;
                continue;
            }
        }

        if(((source1>=0&&source1<=3)&&((source2>=0&&source2<=3)||(source2>=10&&source2<=13)))||((source1>=100&&source1<=103)&&((source2>=100&&source2<=103)||(source2>=110&&source2<=113))))
        {
            if(Z1+Z2>=2){
                Value+=V[X2][Y2][3];
                continue;
            }else {
                Value+=V[X2][Y2][Z1+Z2+1];
                continue;
            }
        }

        if(((source1>=10&&source1<=13)&&(source2>=10&&source2<=13))||((source1>=110&&source1<=113)&&(source2>=110&&source2<=113)))
        {
            if(Z1+Z2>=2){
                Value+=10000;
                continue;
            }
            else{
                Value+=0;
                continue;
            }
        }

        if(((source1>=0&&source1<=3)&&((source2>=100&&source2<=103)||(source2>=110&&source2<=113)))||((source1>=10&&source1<=13)&&((source2>=100&&source2<=103)||(source2>=110&&source2<=113)))){
            if(Z1==3||Z2==3){
                Value+=10000;
                continue;
            }
            else {
                Value+=V[X2][Y2][Z2]+V[X1][Y1][Z1]/4;
                continue;
            }
        }else{
            Value+=V[X1][Y1][Z1]+V[X2][Y2][Z2];
        }
        continue;
    }
    return Value;
}

int pwithrsence::chesstype(int rotate, int i, int j)
{
    if(aiflag==1){
        int t,count=0;
        move(rotate,&i,&j);
        if((i<0||i>18)||(j<0||j>18))return -2;
        switch (chess[i][j]) {
        case 2:
        {
            while (chess[i][j]==2) {
                ++count;move(rotate,&i,&j);
                if((i<0||i>18)||(j<0||j>18))
                {
                    t=count+9;
                    return t;
                }
            }
            if(chess[i][j]==0) {t=count-1;}
            else t=count+9;
        }break;
        case 1:
        {
            while(chess[i][j]==1){
                ++count;move(rotate,&i,&j);
                if((i<0||i>18)||(j<0||j>18))
                {
                    t=count+109;
                    return t;
                }
            }
            if(chess[i][j]==0) {t=count+99;}
            else t=count+109;
        }break;
        case 0:
        {
            move(rotate,&i,&j);
            if((i<0||i>18)||(j<0||j>18))return -3;
            switch (chess[i][j]) {
            case 2:
            {
                while (chess[i][j]==2) {
                    ++count;move(rotate,&i,&j);
                    if((i<0||i>18)||(j<0||j>18))
                    {
                        t=count+29;
                        return t;
                    }
                }
                if(chess[i][j]==0) {t=count+19;}
                else t=count+29;
            }break;
            case 1:
            {
                while(chess[i][j]==1){
                    ++count;move(rotate,&i,&j);
                    if((i<0||i>18)||(j<0||j>18))
                    {
                        t=count+129;
                        return t;
                    }
                }
                if(chess[i][j]==0) {t=count+119;}
                else t=count+129;
            }break;
            case 0:{
                t=-1;
            }break;
            }
        }break;
        }
        return t;
    }else if(aiflag==2){
        int t,count=0;
        move(rotate,&i,&j);
        if((i<0||i>18)||(j<0||j>18))return -2;
        switch (chess[i][j]) {
            case 1:
            {
                while (chess[i][j]==1) {
                    ++count;move(rotate,&i,&j);
                    if((i<0||i>18)||(j<0||j>18))
                    {
                        t=count+9;
                        return t;
                    }
                }
                if(chess[i][j]==0) {t=count-1;}
                else t=count+9;
            }break;
            case 2:
            {
                while(chess[i][j]==2){
                    ++count;
                    move(rotate,&i,&j);
                    if((i<0||i>18)||(j<0||j>18))
                    {
                        t=count+109;
                        return t;
                    }
                }
                if(chess[i][j]==0) {t=count+99;}
                else t=count+109;
            }break;
            case 0:
            {
                move(rotate,&i,&j);
                if((i<0||i>18)||(j<0||j>18))return -3;
                switch (chess[i][j]) {
                case 1:
                {
                    while (chess[i][j]==1) {
                        ++count;
                        move(rotate,&i,&j);
                        if((i<0||i>18)||(j<0||j>18))
                        {
                            t=count+29;
                            return t;
                        }
                    }
                    if(chess[i][j]==0) {t=count+19;}
                    else t=count+29;
                }break;
                case 2:
                {
                    while(chess[i][j]==2){
                        ++count;
                        move(rotate,&i,&j);
                        if((i<0||i>18)||(j<0||j>18))
                        {
                            t=count+129;
                            return t;
                        }
                    }
                    if(chess[i][j]==0) {t=count+119;}
                    else t=count+129;
                }break;
                case 0:{
                    t=-1;
                }break;
                }
            }break;
        }
        return t;
    }
}

void pwithrsence::move(int rotate, int *i, int *j){
    switch (rotate){
        case 1:{
            ++*i;
        }
        break;
        case 2:{
            ++*i;
            --*j;
        }
        break;
        case 3:{
            --*j;
        }
        break;
        case 4:{
            --*i;
            --*j;
        }
        break;
        case 5:{
            --*i;
        }
        break;
        case 6:{
            --*i;
            ++*j;
        }
        break;
        case 7:{
            ++*j;
        }
        break;
        case 8:{
            ++*i;
            ++*j;
        }
        break;
    }
}


void pwithrsence::mouseReleaseEvent(QMouseEvent *event){
    if(!begin) return;
    int x=event->x(),y=event->y();
    if(x<125||x>855||y<25||y>770) return;
    chessx=(x-145+19)/39;
    chessy=(y-45+20)/40;
    if(chess[chessx][chessy]!=0) return;
    chess[chessx][chessy]=colorflag;
    drop.push(QPoint(chessx,chessy));
    step++;
    change();
    bool ifis=this->isfinish();
    if(ifis){
        end();
        return;
    }
    update();
    AI();
}



void pwithrsence::end(){
    int ret = 0;
    if(win==aiflag){
        ret = QMessageBox::information(this,"本局结果","很抱歉,您输了!\n再来一局?",QMessageBox::Yes|QMessageBox::No,QMessageBox::Yes);
    }else if(win!=aiflag){
        ret = QMessageBox::information(this,"本局结果","恭喜您击败了AI!\n再来一局?",QMessageBox::Yes|QMessageBox::No,QMessageBox::Yes);
    }else {
        ret = QMessageBox::information(this,"本局结果","很抱歉,本局为平局!\n再来一局?",QMessageBox::Yes|QMessageBox::No,QMessageBox::Yes);
    }
    if(ret==QMessageBox::Yes){
        timeLabel->hide();
        restart();
        update();
    }else if(ret==QMessageBox::No){
        timer->stop();
        timeLabel->hide();
        emit this->back();
        this->hide();
    }

}

void pwithrsence::regret(){
    if(begin&&!isfinish()){
        if(step>1&&!drop.empty()){
            QPoint pos = drop.pop();
            QPoint pos1 = drop.pop();
            chess[pos.x()][pos.y()] = 0;
            chess[pos1.x()][pos1.y()] = 0;
            step-=2;
        }else if(step == 1&&!drop.empty()){
            QMessageBox::information(this,"提示","这已经是最后一枚棋子!");
        }
        update();
    }
}

void pwithrsence::change(){

    time = 60;
    timeLabel->setText(QString("倒计时: %1").arg(time));
    timeLabel->update();
    timer->start();
}

void pwithrsence::ontimerTimout(){
    if(time>0){
        time--;
        timeLabel->setText(QString("倒计时: %1").arg(time));
    }else{
        timer->stop();
        QMessageBox::information(this,"提示","您已经超时,本局游戏结束!");
        restart();
    }
}


void pwithrsence::restart(){
    for(int i=0;i<19;i++){
        for(int j=0;j<19;j++){
            chess[i][j]=0;
        }
    }
    step = 0;
    restartbtn->hide();
    aiFirbtn->show();
    pfirbtn->show();
    begin=0;
    win=0;
    colorflag=0;
    aiflag=0;
    update();
}

void pwithrsence::closeEvent(QCloseEvent *event){
    if(timeLabel){
        timeLabel->hide();
    }
    timer->stop();
    emit this->back();
    this->hide();
    event->ignore();
}

 这个类中的操作与上一个类基本一致,只是加入了人先手,还是电脑(AI)先手的选择,以及AI下棋功能的实现,由于五子棋算法并不是我们关注的重点,只需要知道只是采用评估函数实现的一个性能较为一般的算法即可,同时悔棋功能有了一定的改变,我们需要判定当前的棋子数目是否大于一,因为人机对战中,我们需要一次性悔去两枚棋子(自己的和AI的),才能到达有自己下棋的回合。

 pwithpolscene

 pwithpolscene.h文件

#ifndef PWITHPOLSCENE_H
#define PWITHPOLSCENE_H
#include"basescene.h"
#include"mybutton.h"
#include<QLabel>
#include<QPoint>
#include<QStack>
#include<QTimer>
#include<QCloseEvent>
#include<QTcpServer>
#include<QTcpSocket>
#include<chessconfig.h>
#include<QMouseEvent>
#include<QLineEdit>
#include<QCloseEvent>

class pwithpolscene : public basescene
{
    Q_OBJECT
public:
    explicit pwithpolscene(netWorkType mmyNetType,chessType mmyChessType,QWidget *parent=nullptr);
    ~pwithpolscene();
    bool myFlag = false;
    //mybutton * netConnectbtn = new mybutton(":/picture/connect.jpeg");
    //mybutton * restartbtn = new mybutton(":/picture/restart2.jpeg");

    QPushButton * netConnectbtn = new QPushButton(this);
    QLabel * label;
    QLabel * label1;
    QLineEdit *lineEdit;
    QTimer *timer;
    QLabel *timeLabel;

    int time;
    void ontimerTimout();
    void change();
    void mouseReleaseEvent(QMouseEvent *event);
    void gameOverShow(playerType player);
    bool isWhite=0;
    bool candrop(int chessx,int chessy,chessType chessColor);
    void validClickHandle(int chessx,int chessy,chessType chessColor);
    void end();
    void closeEvent(QCloseEvent *event);
    void regret();
    //void restart();
    QTcpServer *tcpServer;
    QTcpSocket *tcpSocket;
    bool beginGame;
    chessType myCheType;
    chessType otherCheType;
    netWorkType myNetType;
    int regre=0;
    QStack<QPoint> drop;
    int step = 0;
    int timeout = 0;

public slots:
    void newConnectHandle();
    void serverReceiveMessages();
    void clientReceiveMessages();
    void serverStateChanged(QAbstractSocket::SocketState state);
    void clientStateChanged(QAbstractSocket::SocketState state);
    void tcpConnectClickHandle();

signals:

};

#endif // PWITHPOLSCENE_H

 pwitholscene.cpp文件

#include "pwithpolscene.h"
#include<QLabel>
#include<QMessageBox>
#include<QDebug>
#include<QMainWindow>
#include <QCoreApplication>


pwithpolscene::pwithpolscene(netWorkType mmyNetType,chessType mmyChessType,QWidget *parent)
{
    myNetType = mmyNetType;
    myCheType = mmyChessType;
    begin = 0;
    QString titleStr="";
    if(myCheType == WHITEPIECE){
        otherCheType = BLACKPIECE;
        titleStr = "白子";
    }else {
        otherCheType = WHITEPIECE;
        titleStr = "黑子";
    }

    mybutton * regretBtn = new mybutton(":/picture/Regret.png");
    regretBtn->setParent(this);
    regretBtn->setGeometry(QRect(950,550,300,120));
    regretBtn->show();

    timer = new QTimer(this);
    connect(timer,&QTimer::timeout,this,&pwithpolscene::ontimerTimout);
    timer->setInterval(1000);



    netConnectbtn->setParent(this);
    netConnectbtn->setGeometry(QRect(900,450,250,50));
    netConnectbtn->setStyleSheet("font-size: 30px; font-weight: bold;");



    label = new QLabel();
    label->setParent(this);
    label->setFixedSize(500,100);
    label->setStyleSheet("color:red;font-size:50px;font-weight: bold;background-color:black;");
    label->setFont(QFont("黑体"));
    label->move(900,200);
    label->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
    label->setAttribute(Qt::WA_TransparentForMouseEvents);


    label1 = new QLabel();
    label1->setParent(this);
    label1->setFixedSize(500,50);
    label1->setStyleSheet("color:red;font-size:30px;font-weight: bold;background-color:black;");
    label1->setFont(QFont("黑体"));
    label1->move(900,350);
    label1->setText(" IP:Port");


    lineEdit = new QLineEdit();
    lineEdit->setParent(this);
    lineEdit->setFixedSize(400,50);
    lineEdit->setStyleSheet("font-size:30px;");
    lineEdit->move(1050,350);

    qDebug()<<"ok1";

    connect(regretBtn,&QPushButton::clicked,[=](){
        regre = 1;
        regretBtn->down();
        regretBtn->up();
        QTimer::singleShot(1,this,[=](){

            switch (myNetType) {
                case SERVER:{
                    QList <QTcpSocket *> socketList = tcpServer->findChildren<QTcpSocket *>();
                    qDebug() << "tcpSocket 数量:" << socketList.count();
                    if (socketList.count() == 0) {
                        qDebug()<<"当前没有客户端连接,请先与客户端连接!";
                        return;
                    }
                    foreach (QTcpSocket *tmpTcpSocket, socketList) {
                        // 服务端向每个客户端发送消息
                        ptoP Datas;
                        Datas.col = -1;
                        Datas.row = -1;
                        Datas.timeoutt = timeout;
                        Datas.cheType = NOPIECE;
                        Datas.regrett = 1;
                        tmpTcpSocket->write((char *)(&Datas),sizeof(ptoP));
                    }
                    break;
                }
                case CLIENT:{
                    ptoP Datas;
                    Datas.col = -1;
                    Datas.row = -1;
                    Datas.timeoutt = timeout;
                    Datas.cheType = NOPIECE;
                    Datas.regrett = 1;
                    tcpSocket->write((char *)(&Datas),sizeof(ptoP));
                    break;
                }
            }
            regret();

        });
    });

    connect(netConnectbtn,SIGNAL(clicked()),this,SLOT(tcpConnectClickHandle()));

    if(myNetType == SERVER){
        tcpServer = new QTcpServer(this);
        netConnectbtn->setText("开启监听");
        label->setText("服务器,执"+titleStr);
        connect(tcpServer,SIGNAL(newConnection()), this, SLOT(newConnectHandle()));
    }
    qDebug()<<"ok2";
    if(myNetType == CLIENT){
        tcpSocket = new QTcpSocket(this);
        netConnectbtn->setText("连接服务器");
        label->setText("客户端,执"+titleStr);
        connect(tcpSocket,SIGNAL(readyRead()),this,SLOT(clientReceiveMessages()));
        connect(tcpSocket,SIGNAL(stateChanged(QAbstractSocket::SocketState)),
                this, SLOT(clientStateChanged(QAbstractSocket::SocketState)));

    }
    qDebug()<<"ok3";
}

pwithpolscene::~pwithpolscene(){
    qDebug() << "delete pwithpolscene";
}

void pwithpolscene::mouseReleaseEvent(QMouseEvent *event){
    if(!begin) return;
    int x = event->x(), y = event->y();
    qDebug()<<"x="<<x<<","<<"y="<<y;
    if(x < 125||x > 855||y < 25||y > 770) return;
    int chessx = (x-145+19)/39;
    int chessy = (y-45+20)/40;
    qDebug()<<"chessx="<<chessx<<","<<"chessy="<<chessy;
    if(!candrop(chessx,chessy,myCheType)) return;
    switch (myNetType) {
        case SERVER:{
            QList <QTcpSocket *> socketList = tcpServer->findChildren<QTcpSocket *>();
            qDebug() << "tcpSocket 数量:" << socketList.count();
            if (socketList.count() == 0) {
                qDebug()<<"当前没有客户端连接,请先与客户端连接!";
                return;
            }
            foreach (QTcpSocket *tmpTcpSocket, socketList) {
                // 服务端向每个客户端发送消息
                ptoP Datas;
                Datas.col = chessy;
                Datas.row = chessx;
                Datas.timeoutt = timeout;
                Datas.cheType = myCheType;
                Datas.regrett = 0;
                //Datas.regrett = regre;
                tmpTcpSocket->write((char *)(&Datas),sizeof(ptoP));
            }
            break;
        }
        case CLIENT:{
            ptoP Datas;
            Datas.col = chessy;
            Datas.row = chessx;
            Datas.timeoutt = timeout;
            Datas.cheType = myCheType;
            Datas.regrett = 0;
            //Datas.regrett = regre;
            tcpSocket->write((char *)(&Datas),sizeof(ptoP));
            break;
        }
    }
    validClickHandle(chessx,chessy,myCheType);

}



void pwithpolscene::gameOverShow(playerType player){
    qDebug()<<"ok4";
    //GomokuBoard::gameOverShow(player);
    //ui->restartPushButton->setEnabled(true);
    begin = 0;
    switch (myNetType) {
        case CLIENT:{
            tcpSocket->close();
            netConnectbtn->setText("连接服务器");
            break;
        }
        case SERVER:{
            tcpServer->close();
            netConnectbtn->setText("开启监听");
            break;
        }
    }
}

void pwithpolscene::newConnectHandle()
{
    qDebug()<<"ok5";
    // 与客户端连接
    QTcpSocket *tmpTcpSocket = tcpServer->nextPendingConnection();
    qDebug()<<"ok6";
    // 客户端的ip地址
    QString ipaddr = tmpTcpSocket->peerAddress().toString();
    quint16 port = tmpTcpSocket->peerPort();
    qDebug()<< "客户端连接,ip:" << ipaddr<<" port:"<<port;
    begin = 1;
    time=60;
    timeLabel = new QLabel(this);
    timeLabel->setGeometry(930, 50, 500, 100);
    timeLabel->setStyleSheet("QLabel { color: rgba(0, 255, 0, 1); font-size: 80px; font-weight: bold; background-color: transparent; }");
    timeLabel->setText(QString("倒计时: %1").arg(time));
    timeLabel->show();
    timer->start();

    qDebug()<<"ok7";
    connect(tmpTcpSocket, SIGNAL(readyRead()), this, SLOT(serverReceiveMessages()));
    connect(tmpTcpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
            this, SLOT(serverStateChanged(QAbstractSocket::SocketState)));
    qDebug()<<"ok8";
}


void pwithpolscene::serverReceiveMessages()
{
    qDebug()<<"ok9";
    QTcpSocket *tmpTcpSocket = (QTcpSocket *)sender();
    // 接收消息
    //qDebug() <<  "客户端接收消息:" <<  tmpTcpSocket->readAll();
    auto res = tmpTcpSocket->readAll();
    ptoP* resPtoP = (ptoP*)res.begin();
    qDebug() << "row:" << resPtoP->row << " col:" << resPtoP->col;
    if(resPtoP->cheType == WHITEPIECE){
        qDebug() << "server:white";
    }
    if(resPtoP->cheType == BLACKPIECE){
        if(myCheType==WHITEPIECE){
            qDebug()<<"our:white";
        }

        qDebug() << "server:black";
    }
    if(resPtoP->regrett == 1){
        qDebug() << "服务端开始悔棋!";
        regret();
    }
    if(resPtoP->timeoutt == 1){
        timer->stop();
        timeLabel->hide();
        QMessageBox::information(this,"提示","时间已到,本局游戏结束!");
        regre = 0;
        isWhite=false;
        begin =1;
        win =0;
        step = 0;
        timeout = 0;
        for(int i=0;i<19;i++){
            for(int j=0;j<19;j++){
                chess[i][j]=NOPIECE;
            }
        }
        update();
    }
    //if(m_enemyPieceType==resPtoP->pieceType && (m_enemyPieceType==m_isWhiteRound?WHITEPIECE:BLACKPIECE)){
    validClickHandle(resPtoP->row,resPtoP->col,resPtoP->cheType);

}


void pwithpolscene::clientReceiveMessages(){
    auto res = tcpSocket->readAll();
    ptoP* resPtoP = (ptoP*)res.begin();
    qDebug() << "row:" << resPtoP->row << " col:" << resPtoP->col;
    if(resPtoP->cheType == WHITEPIECE){
        qDebug() << "client:white";
    }
    if(resPtoP->cheType == BLACKPIECE){
        qDebug() << "client:black";
    }
    if(resPtoP->regrett == 1){
        qDebug() << "客户端开始悔棋!";
        regret();
    }
    if(resPtoP->timeoutt == 1){
        timer->stop();
        timeLabel->hide();
        QMessageBox::information(this,"提示","时间已到,本局游戏结束!");
        regre = 0;
        isWhite=false;
        begin =1;
        win =0;
        step = 0;
        timeout = 0;
        for(int i=0;i<19;i++){
            for(int j=0;j<19;j++){
                chess[i][j]=NOPIECE;
            }
        }
        update();
    }
    //if(m_enemyPieceType==resPtoP->pieceType && (m_enemyPieceType==m_isWhiteRound?WHITEPIECE:BLACKPIECE)){
    validClickHandle(resPtoP->row,resPtoP->col,resPtoP->cheType);
    // }

}

void pwithpolscene::serverStateChanged(QAbstractSocket::SocketState state)
{
    qDebug()<<"ok10";
    QTcpSocket *tmpTcpSocket = (QTcpSocket *)sender();
    switch (state) {
    // 已断开
    case QAbstractSocket::UnconnectedState:
        qDebug() << "服务端:客户端断开连接";
        tmpTcpSocket->deleteLater();
        begin = 0;
        break;
        // 已连接
    case QAbstractSocket::ConnectedState:
        qDebug() << "服务端:客户端已连接";
        begin =1;
        //qDebug() << "hahahahahahhahahahhahahahahahhahahahahahhahahah";
        break;
    default:
        break;
    }
}

void pwithpolscene::clientStateChanged(QAbstractSocket::SocketState state){
    qDebug()<<"ok11";
    switch (state) {
    // 已断开
    case QAbstractSocket::UnconnectedState:
        qDebug() << "与服务器断开连接";
        netConnectbtn->setText("连接服务器");
        begin = 0;
        break;
        // 已连接
    case QAbstractSocket::ConnectedState:
        qDebug() << "与服务器建立连接";
        netConnectbtn->setText("断开连接");
        begin = 1;
        time=60;
        timeLabel = new QLabel(this);
        timeLabel->setGeometry(930, 50, 500, 100);
        timeLabel->setStyleSheet("QLabel { color: rgba(0, 255, 0, 1); font-size: 80px; font-weight: bold; background-color: transparent; }");
        timeLabel->setText(QString("倒计时: %1").arg(time));
        timeLabel->show();
        timer->start();
        break;
    default:
        break;
    }

}


void pwithpolscene::tcpConnectClickHandle()
{
    qDebug()<<"ok12";
    if(netConnectbtn->text()=="连接服务器"){
        qDebug() << "连接服务器";
        // 指定服务端的ip地址与端口
        QStringList ipPortList = lineEdit->text().split(":");
        if(ipPortList.count() == 2){
            qDebug() << "ip:" << ipPortList[0]<<" port:" << ipPortList[1].toInt();
        }else {
            qDebug("ip/Port输入错误");
            return;
        }
        tcpSocket->connectToHost(QHostAddress(ipPortList[0]), ipPortList[1].toInt());
    }else if(netConnectbtn->text() == "断开连接"){
        qDebug() << "断开连接";
        tcpSocket->close();
        timeLabel->hide();                                                 //更改
        timer->stop();
        netConnectbtn->setText("连接服务器");
    }
    else if(netConnectbtn->text() == "开启监听"){
        qDebug()<<"开启中";
        // 指定服务端的ip地址与端口
        QStringList ipPortList = lineEdit->text().split(":");
        if(ipPortList.count() == 2){
            qDebug() << "ip:" << ipPortList[0]<<" port:" << ipPortList[1].toInt();
        }else {
            qDebug("ip/Port输入错误");
            return;
        }
        // 绑定ip地址和端口
        if(tcpServer->listen(QHostAddress(ipPortList[0]), ipPortList[1].toInt())){
            netConnectbtn->setText("关闭监听");
            qDebug()<< "tcp服务器创建成功,等待连接";
        }else {
            qDebug()<<"tcp服务器创建失败";
        }
    }else if(netConnectbtn->text() == "关闭监听"){
        tcpServer->close();
        timeLabel->hide();                                              //更改
        timer->stop();
        qDebug()<<"tcp服务器关闭";
        netConnectbtn->setText("开启监听");
    }
}

bool pwithpolscene::candrop(int chessx, int chessy, chessType chessColor){
    if(chessColor == WHITEPIECE){
        return (chess[chessx][chessy]==NOPIECE) && isWhite;
    }else{
        return (chess[chessx][chessy]==NOPIECE) && (!isWhite);
    }
    return false;
}


void pwithpolscene::validClickHandle(int chessx, int chessy, chessType chessColor){
    if(!candrop(chessx,chessy,chessColor)){
        return;
    }
    if(isWhite){
        chess[chessx][chessy]=WHITEPIECE;
        drop.push(QPoint(chessx,chessy));
        step++;
        change();
        isWhite = false;
    }else{
        chess[chessx][chessy]=BLACKPIECE;
        drop.push(QPoint(chessx,chessy));
        step++;
        change();
        isWhite = true;
    }

    update();
    bool ifis =this->isfinish();
    if(ifis){
        end();
    }
}

void pwithpolscene::end(){
    int ret = 0;
    if(win == 1){
        ret = QMessageBox::information(this,"本局结果","恭喜黑棋方获得胜利!\n再来一局?",QMessageBox::Yes|QMessageBox::No,QMessageBox::Yes);
    }else if(win == 2){
        ret = QMessageBox::information(this,"本局结果","恭喜白棋方获得胜利!\n再来一局?",QMessageBox::Yes|QMessageBox::No,QMessageBox::Yes);
    }else if(win == 3){
        ret = QMessageBox::information(this,"本局结果","很遗憾,你们是平局!\n再来一局?",QMessageBox::Yes|QMessageBox::No,QMessageBox::Yes);
    }
    if(ret == QMessageBox::Yes){
        regre = 0;
        isWhite=false;
        begin =1;
        win =0;
        step = 0;
        timeout = 0;
        for(int i=0;i<19;i++){
            for(int j=0;j<19;j++){
                chess[i][j]=NOPIECE;
            }
        }
        update();
    }
    else if(ret == QMessageBox::No){
        timeLabel->hide();
        timer->stop();
        emit this->back();
        this->hide();
        qApp->quit();
    }

}

void pwithpolscene::closeEvent(QCloseEvent *event){
    if(timeLabel){
        timeLabel->hide();
    }
    timer->stop();
    emit this->back();
    this->hide();
    qApp->quit();
    event->ignore();
}

void pwithpolscene::regret(){
    if(begin&&!isfinish()){
        if(step>0&&!drop.empty()){
            QPoint pos = drop.pop();
            chess[pos.x()][pos.y()] = NOPIECE;
            step--;
            isWhite = !(isWhite);
            regre = 0;
        }
        update();
    }
}

void pwithpolscene::ontimerTimout(){
    if(time>0){
        time--;
        timeLabel->setText(QString("倒计时: %1").arg(time));
    }else{
        timeout = 1;
        timer->stop();
        timeLabel->hide();
        QMessageBox::information(this,"提示","时间已到,本局游戏结束!");
        regre = 0;
        isWhite=false;
        begin =1;
        win =0;
        step = 0;
        timeout = 0;
        for(int i=0;i<19;i++){
            for(int j=0;j<19;j++){
                chess[i][j]=NOPIECE;
            }
        }
        time=60;
        timeLabel = new QLabel(this);
        timeLabel->setGeometry(930, 50, 500, 100);
        timeLabel->setStyleSheet("QLabel { color: rgba(0, 255, 0, 1); font-size: 80px; font-weight: bold; background-color: transparent; }");
        timeLabel->setText(QString("倒计时: %1").arg(time));
        timeLabel->show();
        timer->start();
        update();

    }
}


void pwithpolscene::change(){

    time = 60;
    timeLabel->setText(QString("倒计时: %1").arg(time));
    timeLabel->update();
    timer->start();
}

 联机对战的模式的实现相对复杂,这里我们将下棋的其中一方作为服务端启动,另一方作为客户端启动,利用QTcpServer和QTcpSocket完成两端的TCP通信。以下为解释:

构造函数 pwithpolscene

  • 接受网络类型(netWorkType)和棋子类型(chessType)作为参数。

  • 初始化成员变量,如网络类型、棋子类型、悔棋按钮(regretBtn)和计时器(timer)。

  • 根据棋子类型设置窗口标题。

  • 创建和配置悔棋按钮、网络连接按钮(netConnectbtn)、标签(label 和 label1)和输入框(lineEdit)。

  • 使用信号和槽连接按钮点击事件和计时器超时事件。

成员函数解释

mouseReleaseEvent

  • 处理鼠标释放事件,判断是否在棋盘区域内点击,并发送棋子放置信息。

gameOverShow

  • 游戏结束时调用,关闭网络连接,更新按钮文本。

newConnectHandle

  • 处理新的网络连接请求,显示连接信息,启动计时器。

serverReceiveMessages 和 clientReceiveMessages

  • 分别处理服务器和客户端接收到的消息,更新游戏状态。

serverStateChanged 和 clientStateChanged

  • 处理网络连接状态变化,更新 UI 和游戏状态。

tcpConnectClickHandle

  • 处理网络连接按钮的点击事件,根据按钮文本决定是连接服务器、断开连接、开启监听还是关闭监听。

candrop

  • 判断当前点击位置是否可以放置棋子。

validClickHandle

  • 处理有效的点击事件,放置棋子并更新游戏状态。

end

  • 游戏结束时显示结果对话框,并处理重新开始或退出游戏的选项。

closeEvent

  • 处理窗口关闭事件,关闭计时器和隐藏计时标签。

regret

  • 处理悔棋操作,撤销最后一次放置的棋子。

ontimerTimout

  • 计时器超时时调用,更新倒计时标签,时间结束时显示提示并重置计时器。

UI 组件

  • regretBtn:悔棋按钮。

  • netConnectbtn:网络连接按钮。

  • label:显示当前玩家类型(黑子或白子)的标签。

  • label1:显示 IP 和端口的标签。

  • lineEdit:输入 IP 和端口的文本框。

  • timeLabel:显示倒计时的标签。

网络通信

  • 使用 QTcpServer 和 QTcpSocket 处理网络连接和数据传输。

  • 定义了 ptoP 结构体用于传输棋子位置、类型和悔棋信息。

游戏逻辑

  • 使用二维数组 chess 存储棋盘状态。

  • 使用 step 变量记录落子次数。

  • 使用 isWhite 变量判断当前应该哪个颜色的棋子落子。

  • 使用 drop 栈存储落子历史,用于悔棋操作。

计时器

  • 使用 QTimer 类管理游戏的倒计时,每秒钟触发一次 ontimerTimout 函数。

 总而言之,这个模式中加入了网络通信的相关知识,要完成服务端与客户端的数据的传输和状态的实时更新,以便完成两端玩家享有流畅的游戏体验。

 chessconfig

 chessconfig.h文件

#ifndef CHESSCONFIG_H
#define CHESSCONFIG_H

#include<QTcpSocket>
#include<QMetaType>

#define MAXCHESSX 19
#define MAXCHESSY 19

enum chessType{NOPIECE, BLACKPIECE, WHITEPIECE};
enum playerType{WHITEPLAYER, BLACKPLAYER, NOPLAYER};
enum netWorkType{CLIENT, SERVER};



struct ptoP{
    ptoP(){
        cheType = NOPIECE;
        row = -1;
        col = -1;
        regrett = 0;
        timeoutt = 0;
    }
    chessType cheType;
    int row;
    int col;
    int regrett;
    int timeoutt;
};

enum netBoardCmd{   // 网络传输过程中命令
    enterRoom,
    quitRoom,
    moveChess,
    beginGame,
    err
};


struct Response_t{      // 服务器传输给客户端结构体
    netBoardCmd cmd;
    bool isAns;
    int roomId;
    //int stepNum;
    int err;
    chessType playerPieceType;
    int playerNum;
    ptoP nextStep;
    //bool unDo;
};
Q_DECLARE_METATYPE(Response_t);

#endif // CHESSCONFIG_H

 在这个头文件中我们主要定义了联机对战模块中,服务器端与客户端进行数据传输时用到的结构体和一些枚举类型等。

 main

 main.cpp文件

#include "mainwindow.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

 这个文件中的代码是每个项目中都会有的,在该项目中并未对其进行更改。

 picture

 不知道怎么打包上传,只能在这里给出我的项目中使用到的图片,有些并未用到是多余的,具体视代码而定。
 

 aifir1.jpeg

 

 back.jpg

 

 background.jpeg

 

 black1.png

 

 ico.jpg

 

 off.jpeg

 

 pfir1.jpeg

 

 pwithp.jpeg

 

pwithpol.jpeg 

 

 pwithr.jpeg

 

 qipan2.jpg

 

 Regret.png

 

 restart2.jpeg

 

 start1.jpg

 

 white1.png

 

 我所借鉴使用的两个开源的五子棋项目:

 项目一:Qt五子棋小程序: 使用Qt实现五子棋小程序,包含单机、PtoP和网络对战
 项目二:基于qt(后端golang+mysql)的五子棋程序: 大一c++大作业,实现了五子棋对战的功能

 感谢各位的阅读,真切地希望能给各位带来一点帮助!

 

 

 

 

 


 

 

 

标签:大一菜,timeLabel,QT,int,void,五子棋,mybutton,QMessageBox,include
From: https://blog.csdn.net/2301_80176766/article/details/140525229

相关文章

  • 【Python】使用PySide6 + Qt Designer创建简易用户界面(含用户交互)
    【Python】使用PySide6+QtDesigner创建简易用户界面(含用户交互)文章目录【Python】使用PySide6+QtDesigner创建简易用户界面(含用户交互)相关代码运行环境操作过程1.PySide6和QtDesigner的安装2.创建外部工具PyUIC和QtDesigner3.QtDesigner的简单使用说明4.完整代......
  • springboot整合mqtt
    安装emqxhttps://blog.csdn.net/weixin_41542513/article/details/134328627springboot整合mqtt1、引入依赖<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-integration&l......
  • Qt区分鼠标按下时移动的是哪个多边形
    使用不同的鼠标事件处理器:为每个多边形分配不同的事件处理器,或者在同一个处理器中使用逻辑来区分。检查鼠标点击位置:在鼠标按下事件中,检查鼠标的位置是否在某个多边形的边上或顶点上。使用图形的标识符:给每个多边形分配一个唯一的标识符,并在鼠标事件中使用这个标识符来识......
  • Socket、WebSocket 和 MQTT 的区别
    Socket协议定义:操作系统提供的网络通信接口,抽象了TCP/IP协议,支持TCP和UDP。特点:通用性:不限于Web应用,适用于各种网络通信。协议级别:直接使用TCP/UDP,需要手动管理连接和数据传输。实现复杂性:需要编写代码处理连接、数据传输和错误。使用场景:实时通信(聊天应用)、文件传输......
  • QT中常见QImage、Pixmap、Mat三种图像格式的转换
    写在前面    暑假实习参与了单位的QT项目开发,在过程中遇见了一些困扰以及解决方式,在此记录下来常见图像格式之间的转换    我将他们都封装在了一个类中,代码见下#ifndefUTIL_H#defineUTIL_H#include"qimage.h"#include"QPixmap"#include"opencv2/open......
  • qtchooser -install qt6 $(which qmake6)
    qtchooser-installqt6$(whichqmake6)https://askubuntu.com/questions/1460242/ubuntu-22-04-with-qt6-qmake-could-not-find-a-qt-installation-of InUbuntu22.04afterinstalling Qt6 usingsudoaptinstallqt6-base-devcalling qmake resultsinaner......
  • Qt实现仪表盘-自定义控件
            仪表盘在很多汽车和物联网相关的系统中很常用,本文就来介绍一下Qt 仪表盘的实现示例,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下。一、简述         使用Qt绘制一个仪表盘,用来显示当前的温度,绘制刻度、绘制数字......
  • QT利用QPainter实现自定义圆弧进度条组件
               在可视化应用中,弧形进度条应用也比较广泛,本文示例封装了一个可复用、个性化的弧形进度条组件。本文示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下。主要结构就是外围一圈圆角进度,中间加上标题和对应进度的百分比,进度条的起始角......
  • 【Qt】探索Qt框架:开发经典贪吃蛇游戏的全过程与实践
    文章目录引言项目链接:1.Qt框架的使用简介2.贪吃蛇游戏设计2.1游戏规则和玩法介绍2.2游戏界面设计概述3.核心代码解析3.1主界面(GameHall)3.1.1布局和功能介绍3.1.2代码实现分析3.2游戏选择界面(GameSelect)3.2.1功能介绍3.2.2代码实现分析3.3游戏房间(GameRoom......
  • 【QT开发】串口通信管理QSerialPort类详解及实战应用
    QSerialPort是Qt提供的一个功能强大、简单易用的串口通信类。通过本文的学习,您应该对QSerialPort的基本使用、高级应用技巧及相关注意事项有了全面的理解。在实际项目中,QSerialPort可以帮助实现与外部设备的串口通信,确保数据的可靠传输和接收。希望本文能帮助您更好地......