作者本人为大一即将结束的菜鸡一枚,刚刚完成了暑期课程,上交了自己的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