gdut大一下学期c++课设(得分:95)

实验报告及源码压缩包百度云下载:
链接:https://pan.baidu.com/s/1zO5ofMz09fiWihxCcZcFbg
提取码:ddav

首先需要下载mysql(我使用的是5.7)和QT creator 4.4.1
这里mysql记得配路径,在环境里配path路径。

然后打开项目。将里面的mysql代码全部改成自己的数据库名、密码、表名。即可运行。

本文目录:

五子棋程序介绍
打开运行项目教程
附上所有程序的代码

五子棋课设

摘 要

通过一学期的c++语言学习,已经掌握了数据类型、数组、指针,类等c++语言基础。根据课程实践的要求,通过已有的知识储备以及在课程过后个人的学习,完成了课程要求中的五子棋游戏的制作。由于程序使用了mysql数据库,所以程序无法实现打包发出,让别人测试。不过,若他人电脑中已配置了mysql数据库及环境,只需要修改数据库账号,密码及表名即可使用。
关键词:五子棋、QT、mysql

一、总体设计

程序框架

1.1界面设计

本程序有三个界面,分别为登陆界面,注册界面,游戏界面。在界面上,一切设计都以为用户提供更好的使用体验为原则而设计。本游戏界面均用QT设计,通过定义控件及槽函数组成。

1.2功能设计

本程序可以实现基本的五子棋的双人对战,人机对战,计时,撤回,投降,认输,暂停,换背景等功能,还有数据库支持的登陆,注册,玩家信息系统等功能

1.3代码实现

在代码的实现上,基础界面的代码为QT中的自己手写槽函数、控件和类,手动摆放控件位置来实现的,并为使用ui界面。本五子棋的代码核心是窗口类的切换及游戏框架类的应用,以此来实现较多的基本功能。

1.4小结

该五子棋程序的功能基本实现,通过精美简洁的界面设计和使用方式,给用户提供更好的使用体验。可惜的是本程序基于自己的mysql数据库实现,没法打包,但是若其他人想要使用这个代码,可以更改其中的数据库账户密码,或者创造个.db的静态数据库来储存。即可使用本程序的代码。

二、详细设计

2.1界面设计详细讲解

1)登陆界面


登陆界面为一个c++类,属于widget类。背景由两张图片组成。可在此界面中输入账号密码,账号密码将会在数据库中搜索,若与数据库中的数据一致,即可登陆到游戏界面中。

2)注册界面

注册界面为一个c++类,属于widget类。可以输入账号及注册的密码。

注册时会搜素mysql数据库的已存在账号。
当注册账号已存在时:

同时,注册账号密码不可为空

3)游戏界面

注册界面由两个类组成,属于mainwindow类。一个为界面绘画类,一个为下棋类(包括人工AI下棋)
由于程序总是出bug,让我在显示数据库数据时出了问题,导致个人信息界面和排行榜界面没能显示出来,试过很多种方法还是不行,只能暂时放弃这两个功能。

2.2 部分功能详解

1) mysql数据库

首先是连接数据库,这个在很多个.cpp里都用到了。
代码如下:

  qDebug()<<QSqlDatabase::drivers();//添加MYSQL数据库QSqlDatabase db=QSqlDatabase::addDatabase("QMYSQL"); //数据库对象//连接数据库db.setHostName("127.0.0.1"); //数据库服务器IPdb.setUserName("root"); //数据库用户名db.setPassword("holdworld000312"); //数据库密码db.setDatabaseName("slimes"); //使用哪个数据库if(!db.open()){QMessageBox::information(this, "连接结果", "连接数据库失败!");return;
}

下面是我的mysql中的数据库。(这里数据库可视化我用SQLyog)

数据库中有两个表。
一个是wuziqi_info
用来存取注册后的个人信息。

其中包括id,账号,密码,赢的局数,输的局数,姓名,性别。
另一个是我用来存储登陆的账户,以便于反馈给各各界面是哪个用户在玩游戏。

中间涉及到的数据库操作有:
【1】 查看登陆账号密码是否正确

 QSqlTableModel model;model.setTable("wuziqi_info");model.setFilter(tr("handle = '%1' and passwd = '%2'").arg(handle).arg(passwd));model.select();

【2】注册时存入新用户的信息

QString str=QString("insert into wuziqi_info(handle, passwd,  win, lose, name, sex) values('%1','%2', 0 , 0 ,'%3','%4')").arg(handle).arg(passwd1).arg(name).arg(sex);QSqlQuery query;query.exec(str);

【3】在游戏输赢时获取用户的输赢局数,然后决定哪个+1,再修改表中的数据

 QString  win;//这里就举例一个QString sq=QStringLiteral("select *from wuziqi_info where handle='%1' ").arg(NAME);QSqlQuery sqlquery=QSqlQuery(db);sqlquery.exec(sq);while (sqlquery.next()){win.append(sqlquery.value(3).toString());
}
//这里就举例一个QSqlQuery query;query.prepare("update wuziqi_info set win=? where handle=?");query.addBindValue(newwin);query.addBindValue(NAME);query.exec();
2) 背景设置

用画笔Qpainter 在paintEvent(QPaintEvent *event),获取图片名称(图片存储于与此代码统一位置中,即可实现背景画图)

 //QPainter p(this);QPainter p;  //创建画家对象p.begin(this); //指定当前窗口为绘图设备//绘图操作                                                                          //画背景图if(color == 0)p.drawPixmap(0,0,width(),height(),    QPixmap("../Image/u=3967820435,4109070133&fm=26&gp=0.jpg"));

3) 五子棋棋盘棋子绘画

用到paintEvent(QPaintEvent *event)这个函数,可以实时更新页面。

用painter.drawLine画棋盘的格子。

画棋子(颜色,粉刷):

 brush.setColor(Qt::white);painter.setBrush(brush);painter.drawEllipse(kBoardMargin + kBlockSize * j - kRadius, kBoardMargin + kBlockSize * i - kRadius, kRadius * 2, kRadius * 2);

用mouseMoveEvent(QMouseEvent *event)通过鼠标的hover确定落子的标记
还有用一个update()函数,每次都重绘,即时时更新。
程序中用了一个数组game->gameMapVec[clickPosRow][clickPosCol]为0的时
候没有棋子,为1的时候有棋子。

4)人机代码的编写

人机代码我放在一个GameModel类中,有个初始话评分系统,从各种角度对每个格子的分数进行加分。这里我用了暴力搜索每个点的四个方向哈哈,其实如果要降低复杂度可以用dfs来优化。然后就两个量personNum(botNum),emptyNum用来记录自己连子的个数,和对方连子的个数。最后分别给黑子进行统一打分。分数高的位置优先考虑下子。

(在这里选择人机或非人机操作)
目前还有缺陷,就是计分时,没有考虑到优先取胜策略,只是在防守,不过,给宿友们测试了一下,发现人机还是很厉害的,成功将宿友的耐心消磨哈哈。当然可以通过修改每个落点的得分,来安排人机的攻守风格。
部分代码:

for (int i = 1; i <= 4; i++){if (row + i * y > 0 && row + i * y < kBoardSizeNum &&col + i * x > 0 && col + i * x < kBoardSizeNum &&gameMapVec[row + i * y][col + i * x] == 1) // 玩家的子{personNum++;}else if (row + i * y > 0 && row + i * y < kBoardSizeNum &&col + i * x > 0 && col + i * x < kBoardSizeNum &&gameMapVec[row + i * y][col + i * x] == 0) // 空白位{emptyNum++;break;
}else// 出边界
break;if (personNum == 1)                      // 杀二scoreMapVec[row][col] += 10;else if (personNum == 2)                 // 杀三
{if (emptyNum == 1)scoreMapVec[row][col] += 30;else if (emptyNum == 2)scoreMapVec[row][col] += 40;
}else if (personNum == 3)                 // 杀四
{// 量变空位不一样,优先级不一样if (emptyNum == 1)scoreMapVec[row][col] += 60;else if (emptyNum == 2)scoreMapVec[row][col] += 110;}else if (personNum == 4)                 // 杀五
scoreMapVec[row][col] += 10100;
}

由于棋盘不大,就225个格子,每个格子八个方向扫一遍,22585=9000
所以每次操作最复杂的时间复杂度才O(1000)只需要0.00001秒,这里就不节省时间复杂度啦。

5)计时器

写个状态栏,将计时器放于状态栏中。用到time_update()函数,可以时时更新时间

    currentTimeLabel = new QLabel; // 创建QLabel控件QStatusBar *sBar = statusBar();sBar->addWidget(new QLabel("time:",this));sBar->addWidget(currentTimeLabel);timer = new QTimer(this);time = new QTime(0,0,0);timer->start(1000); //每隔1000ms发送timeout的信号
connect(timer, SIGNAL(timeout()),this,SLOT(time_update()));void MainWindow::time_update()
{//time->addSecs(1);*time=time->addSecs(1);//QDateTime current_time =  new QDateTime(0,0,0);QString timestr = time->toString("hh:mm:ss"); //设置显示的格式currentTimeLabel->setText(timestr); //设置label的文本内容为时间
}


(本计时器可以在游戏结束或认输时重计,在暂停时停止)

6)Mainwindow的菜单栏的创建

举例:

    // 添加游戏菜单QMenu *gameMenu = menuBar()->addMenu(tr("Game")); // menuBar默认是存在的,直接加菜单就可以了QAction *actionPVP = new QAction("Person VS Person", this);connect(actionPVP, SIGNAL(triggered()), this,SLOT(initPVPGame()));gameMenu->addAction(actionPVP);

7)设置(setting)

Information 和rank 都还没完成,这里先不介绍。

【1】换背景(Background):


四种背景可供选择。
Deepwood:

Lightwood:

Graywood:

Orangewood:

【2】退出登陆(Exit landing):

这是退出登陆的按钮,可以通过这个回到登陆界面,换另一个账号继续玩本游戏。

8) 操作(operation)

【1】投降(give up)

投降后自己的输的局数在数据库中的记录会+1,同时计时器重新计时。(自己为白方)

【2】暂停(pause)

暂停后,玩家将无法下棋,计时器也会随之暂停。

总结:

很多功能都是慢慢想到的,然后再加上去,

【3】悔棋(return)

这里我用了个二维数组来存储每次放棋后的操作,若点击撤回,则now的位置变为0,然后now-1,到上一个状态。

【4】退出登陆(exit)

退出游戏。

2.3 总结:

这次的代码大部分是边学边完成的,所以框架较凌乱,有一些功能无法实现。但基础功能还是实现啦,由于一开始写程序框架的时候没有使用ui去做,而是自己手写控件和槽函数,所以界面比较简陋。但是基本功能都差不多实现啦。

三、实验过程:

3.1 配环境

本来想着用visual studio 2017连接mysql数据库来写程序的。但是我配了一个多星期的环境加上静态库,还是会报出一堆错误,所以果断放弃visual studio 2017 ,改用QT5.7+mysql,完成程序的编写。

本人先写了游戏框架及规则,在编写完mainwindow界面后才逐渐添加其他界面。在游戏编写的过程中,也是遇到了许许多多的问题,比如可以在网格外放棋子等。在观看众多博客后,才慢慢的将bug修改完。

之后,我才开始编写界面类,先写了登陆界面,这时候,我开始尝试数据库的连接,在我的电脑的path路径中加入mysql.dll静态数据库的路径后,总算成功连接上了数据库。之后便学了一系列的数据添加,读取,搜索。才成功实现了登陆界面及注册界面的编写。但这时候我面临了一个问题。

3.2 编写代码

因为,其实从一开始,界面就全部存在,所以,每个界面拥有的都是在那一时刻的数据,无法更新到最新,就比如我想要的个人信息查询,排行榜。。。(这两个只是显示上除了问题,获取最新的数据我已经解决了),而且每个界面都是,独立的,无法知道是哪个用户在进行游戏。当时的第一做法便是,运用信号和槽。通过登陆界面,放送信号给其他窗口。但是却在主窗口传信息给子窗口时出现了问题。而且窗口众多,导致代码越写越乱。所以我便创造了个数据库的表,用来记录,此时在线的玩家的信息。最后就是每个窗口获得最新的信息的问题了。这里,因为要让窗口显示,肯定要先按一个按钮,所以,我在按钮里增加信息的更新。这样子,这个问题就被解决啦。编写这个代码中间还遇到了大大小小的问题,有些解决了,有些仍无法解决。

3.3无法解决的问题:

1)个人信息无法显示:



如图,我已经将数据库中的用户信息获取,并用qDebug输出,但是我尝试了好几种方法,还是不能将其显示在窗口上。现在只能根据男女,给用户安排了个头像哈哈。

2)排行榜无法显示问题:




因为排行榜很多数据,所以我想要将数据库的数据直接排序,然后再可视化。但是这时候又出现问题了,也许因为不是主窗口,所以,我可视化的表格里,都是空白的。但是,当我重新创个项目,去尝试这个代码时,又可以显示。

3.4 总结:

编写代码中遇到好多问题,大部分得以解决,可是还有几个至今都还无法解决,不过,等有一定的时间后还是应该将其解决,加上以后,我希望可以给该游戏连上区域网,实现玩家的对战。

四、关于未来:

虽然这只是一个课设,但是我的完成程度还让我很不满意,还有很多的功能无法实现,还有实现玩家联网对抗等等,慢慢的我会在进行改进,希望可以不断完善,最后将其变成一个app应用。所以在即将到来的暑假中,我会花一定的时间去考虑如何实现以上功能,从而更好的完善该程序的功能。当然我还想加入围棋等各种棋类,慢慢的去更多了解界面设计的其他知识点。让自己学到的知识更多。

五、总结

之前社团考核用过c语言去写了一个部员管理系统,还有写过成绩管理系统,不过,当时的代码,还是只能在cmd窗口上运行,文件只能用txt保存,用链表来存数据,但是这次课设,成功脱离了小黑框,有了比较美观的界面,有很大的成就感。当然,主要还是得满足对客户的需求,所以我请了挺多同学来测试我的程序的,反响还行,人机也挺给力的哈哈。不过还是有很多不妥的地方需要我慢慢的改进,慢慢的去满足用户的需求。
通过这次课设的学习,我还是学到了好多,比如类,基类,派生类,继承,信号与槽等。对于界面设计,虽然不是主方向,但是,以后一定很多用得上的时候,所以这次的课设让我收获很大很大。

六、参考文献

【1】哔哩哔哩视频:妙韵含的QT开发全套视频

七、致谢

在这里,我要感谢**老师给予我的指导和帮助,没有老师的指明方向,我现在肯定还是一头雾水的。这学期的c++程序设计课也接近尾声了,感谢老师传授我们的知识,还有对我的关注。

打开教程:

文件目录:


红色的是初始文件,蓝色的是类文件,这里要创建5个类文件。记住
GameModel和mainwindow用的是MainWindow类型,其他的均是Widget类型。在创建的时候记得选择,且不要ui页面。

文件名要一致,不然代码无法运行。

首先创建个不含ui的qt文件,具体操作可查看
https://blog.csdn.net/qq_43333395/article/details/90814951

文件目录要不含中文

这里不打勾,本程序不使用ui文件

接下来就是创建类


如此创建五个类,复制代码到其中即可。

至于mysql操作:
看博客:https://blog.csdn.net/qq_43333395/article/details/91126477
记得将mysql的数据库名和密码改为自己的。(可先创建个QT文件看看数据库是否连接成功)

注意:

上面百度云网盘中含有一个Image文件夹,里面是图片文件,记得拷贝后放在
和项目文件统一目录下。

如果第一次运行报错,请先删除

该自动生成的文件后,再重新编译运行。

如果有问题请大家多多指出啦( ̄▽ ̄)",第一次用QT写项目,有不好的地方请大家见谅。

附上所有程序的代码:

1.WUZIQI.pro
2.GameModel.h
3.informationwindow.h
4.mainwindow.h
5.rankwindow.h
6.registerwindow.h
7.subwindow.h
8.GameModel.cpp
9.informationwindow.cpp
10.main.cpp
11.mainwindow.cpp
12.rankwindow.cpp
13.registerwindow.cpp
14.subwindow.cpp

1.WUZIQI.pro
这个文件代码,不用复制,只需再QT += core gui 后面加上 sql 其他的在添加类的时候会自动产生

#-------------------------------------------------
#
# Project created by QtCreator 2019-06-24T10:20:30
#
#-------------------------------------------------QT       += core gui sqlgreaterThan(QT_MAJOR_VERSION, 4): QT += widgetsTARGET = WUZIQI
TEMPLATE = app# The following define makes your compiler emit warnings if you use
# any feature of Qt which has been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0SOURCES += \main.cpp \mainwindow.cpp \GameModel.cpp \subwindow.cpp \registerwindow.cpp \informationwindow.cpp \rankwindow.cppHEADERS += \mainwindow.h \GameModel.h \subwindow.h \registerwindow.h \informationwindow.h \rankwindow.h
FORMS +=

2.GameModel.h

#ifndef GAMEMODEL_H
#define GAMEMODEL_H// ---- 五子棋游戏模型类 ---- //
#include <vector>  //变长数组
#include <QWidget>
// 游戏类型,双人还是AI(目前固定让AI下黑子)
enum GameType
{PERSON,BOT
};
// 游戏状态
enum GameStatus
{PLAYING,WIN,DEAD
};
// 棋盘尺寸
const int kBoardSizeNum = 18;
class GameModel
{public:GameModel();
public:std::vector<std::vector<int>> gameMapVec; // 存储当前游戏棋盘和棋子的情况,空白为0,白子1,黑子-1std::vector<std::vector<int>> scoreMapVec; // 存储各个点位的评分情况,作为AI下棋依据bool playerFlag; // 标示下棋方GameType gameType; // 游戏模式GameStatus gameStatus; // 游戏状态void startGame(GameType type); // 开始游戏void calculateScore(); // 计算评分void actionByPerson(int row, int col); // 人执行下棋void actionByAI(int &clickRow, int &clickCol); // 机器执行下棋void updateGameMap(int row, int col); // 每次落子后更新游戏棋盘bool isWin(int row, int col); // 判断游戏是否胜利bool isDeadGame(); // 判断是否和棋
};
#endif // GAMEMODEL_H

3.informationwindow.h

#ifndef INFORMATIONWINDOW_H
#define INFORMATIONWINDOW_H#include <QWidget>
#include <QPushButton>
#include <QLabel>
#include <QSqlTableModel>
#include <QTableView>
#include <QPaintEvent>class informationwindow : public QWidget
{Q_OBJECT
public:explicit informationwindow(QWidget *parent = nullptr);QPushButton a;void cout();QString NAME;QString  win;QString  lose;QString  name;QString  handle;QString  sex;signals:
public slots:
private:QLabel *label1 = new QLabel(this);QLabel *label2 = new QLabel(this);QLabel *label3 = new QLabel(this);QLabel *label4 = new QLabel(this);QLabel *label5 = new QLabel(this);QLabel *label6 = new QLabel(this);
protected://重写绘图事件//如果在窗口绘图,必须在绘图事件里实现//绘图事件内部自动调用,窗口需要重绘的时候(状态改变)void paintEvent(QPaintEvent *);
};#endif // INFORMATIONWINDOW_H

4.mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include "GameModel.h"
#include <QPushButton>
#include "subwindow.h" //子窗口头文件
#include "informationwindow.h"
#include "rankwindow.h"
#include <Qpair>class MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = 0);~MainWindow();QPushButton b3;//void mySlot();void changeWin();void dealsub(QString);QString NAME;int color=0;int giveup=0;int Returns=0;protected:// 绘制void paintEvent(QPaintEvent *event);// 监听鼠标移动情况,方便落子void mouseMoveEvent(QMouseEvent *event);// 实际落子void mouseReleaseEvent(QMouseEvent *event);private:GameModel *game; // 游戏指针GameType game_type; // 存储游戏类型int clickPosRow, clickPosCol; // 存储将点击的位置void initGame();void checkGame(int y, int x);subwindow subwin; //子窗口informationwindow infwin;rankwindow rankwin;QLabel *currentTimeLabel; // 先创建一个QLabel对象QTime *time;QTimer *timer;int a[1000][2];int nows=0;private slots:void chessOneByPerson(); // 人执行void chessOneByAI(); // AI下棋void initPVPGame();void initPVEGame();void showinf();void showrank();void exit();void backdeepwood();void backwood();void backgraywood();void backorangewood();void Giveup();void pause();void Return();void exland();//void Helpwindow();void time_update(); //时间更新槽函数,状态栏显示时间signals:/*信号必须有signals关键字来声明* 信号没有返回值,但可以有参数* 信号就是函数的声明,只需声明,无需定义*/void mySignal(QString);};#endif // MAINWINDOW_H

5.rankwindow.h

#ifndef TANKWINDOW_H
#define TANKWINDOW_H#include <QWidget>
#include <QPushButton>
#include <QLabel>
#include <QSqlTableModel>
#include <QTableView>
#include <QPaintEvent>class rankwindow : public QWidget
{Q_OBJECT
public:explicit rankwindow(QWidget *parent = nullptr);signals:public slots:protected://重写绘图事件//如果在窗口绘图,必须在绘图事件里实现//绘图事件内部自动调用,窗口需要重绘的时候(状态改变)void paintEvent(QPaintEvent *);
};#endif // TANKWINDOW_H

6.registerwindow.h

#ifndef REGISTERWINDOW_H
#define REGISTERWINDOW_H#include <QWidget>
#include <QPushButton>
#include <qlineedit.h>class registerwindow : public QWidget
{Q_OBJECT
public:explicit registerwindow(QWidget *parent = nullptr);void sendregitslot();void sendreturnslot();QLineEdit *pNormalLineEdit1 = new QLineEdit(this);QLineEdit *pNormalLineEdit2 = new QLineEdit(this);QLineEdit *pNormalLineEdit3 = new QLineEdit(this);QLineEdit *pPasswordLineEdit1 = new QLineEdit(this);QLineEdit *pPasswordLineEdit2 = new QLineEdit(this);protected://重写绘图事件//如果在窗口绘图,必须在绘图事件里实现//绘图事件内部自动调用,窗口需要重绘的时候(状态改变)void paintEvent(QPaintEvent *);signals:void regitSignal();public slots:private:QPushButton d;QPushButton e;
};#endif // REGISTERWINDOW_H

7.subwindow.h

#ifndef SUBWINDOW_H
#define SUBWINDOW_H
#include <QWidget>
#include <QPushButton>
#include <qlineedit.h>
#include "registerwindow.h"
#include <QPaintEvent>class subwindow : public QWidget
{Q_OBJECT
public:explicit subwindow(QWidget *parent = nullptr);void sendSlot();void subwindow::on_pushButton_2_clicked();QLineEdit *pNormalLineEdit = new QLineEdit(this);QLineEdit *pPasswordLineEdit = new QLineEdit(this);void changwin();void dealSlot();protected://重写绘图事件//如果在窗口绘图,必须在绘图事件里实现//绘图事件内部自动调用,窗口需要重绘的时候(状态改变)void paintEvent(QPaintEvent *);signals:/*信号必须有signals关键字来声明* 信号没有返回值,但可以有参数* 信号就是函数的声明,只需声明,无需定义*/void mySignal(QString);
public slots:private:QPushButton b;QPushButton c;registerwindow regist;
};#endif // SUBWINDOW_H

8.GameModel.cpp

#include <utility>
#include <stdlib.h>
#include <time.h>  //设置下棋的时间
#include "GameModel.h"
#include <QWidget>GameModel::GameModel()
{}void GameModel::startGame(GameType type)
{gameType = type;// 初始棋盘gameMapVec.clear();for (int i = 0; i < kBoardSizeNum; i++){std::vector<int> lineBoard;for (int j = 0; j < kBoardSizeNum; j++)lineBoard.push_back(0);gameMapVec.push_back(lineBoard);}// 如果是AI模式,需要初始化评分数组if (gameType == BOT){scoreMapVec.clear();for (int i = 0; i < kBoardSizeNum; i++){std::vector<int> lineScores;for (int j = 0; j < kBoardSizeNum; j++)lineScores.push_back(0);scoreMapVec.push_back(lineScores);}}// 己方下为true,对方下位falseplayerFlag = true;
}void GameModel::updateGameMap(int row, int col)
{if (playerFlag)gameMapVec[row][col] = 1;elsegameMapVec[row][col] = -1;// 换手playerFlag = !playerFlag;
}void GameModel::actionByPerson(int row, int col)
{updateGameMap(row, col);
}void GameModel::actionByAI(int &clickRow, int &clickCol)
{// 计算评分calculateScore();// 从评分中找出最大分数的位置int maxScore = 0;std::vector<std::pair<int, int>> maxPoints;for (int row = 1; row < kBoardSizeNum; row++)for (int col = 1; col < kBoardSizeNum; col++){// 前提是这个坐标是空的if (gameMapVec[row][col] == 0){if (scoreMapVec[row][col] > maxScore)          // 找最大的数和坐标{maxPoints.clear();maxScore = scoreMapVec[row][col];maxPoints.push_back(std::make_pair(row, col));}else if (scoreMapVec[row][col] == maxScore)     // 如果有多个最大的数,都存起来maxPoints.push_back(std::make_pair(row, col));}}// 随机落子,如果有多个点的话srand((unsigned)time(0));int index = rand() % maxPoints.size();std::pair<int, int> pointPair = maxPoints.at(index);clickRow = pointPair.first; // 记录落子点clickCol = pointPair.second;updateGameMap(clickRow, clickCol);
}// 最关键的计算评分函数
void GameModel::calculateScore()
{// 统计玩家或者电脑连成的子int personNum = 0; // 玩家连成子的个数int botNum = 0; // AI连成子的个数int emptyNum = 0; // 各方向空白位的个数// 清空评分数组scoreMapVec.clear();for (int i = 0; i < kBoardSizeNum; i++){std::vector<int> lineScores;for (int j = 0; j < kBoardSizeNum; j++)lineScores.push_back(0);scoreMapVec.push_back(lineScores);}// 计分(此处是完全遍历,其实可以用bfs或者dfs加减枝降低复杂度,通过调整权重值,调整AI智能程度以及攻守风格)for (int row = 0; row < kBoardSizeNum; row++)for (int col = 0; col < kBoardSizeNum; col++){// 空白点就算if (row > 0 && col > 0 &&gameMapVec[row][col] == 0){// 遍历周围八个方向for (int y = -1; y <= 1; y++)for (int x = -1; x <= 1; x++){// 重置personNum = 0;botNum = 0;emptyNum = 0;// 原坐标不算if (!(y == 0 && x == 0)){// 每个方向延伸4个子// 对玩家白子评分(正反两个方向)for (int i = 1; i <= 4; i++){if (row + i * y > 0 && row + i * y < kBoardSizeNum &&col + i * x > 0 && col + i * x <kBoardSizeNum &&gameMapVec[row + i * y][col + i * x] == 1) // 玩家的子{personNum++;}else if (row + i * y > 0 && row + i * y < kBoardSizeNum &&col + i * x > 0 && col + i * x < kBoardSizeNum && gameMapVec[row + i * y][col + i * x] == 0) // 空白位{emptyNum++;break;}else            // 出边界break;}for (int i = 1; i <= 4; i++){if (row - i * y > 0 && row - i * y < kBoardSizeNum &&
col - i * x > 0 && col - i * x < kBoardSizeNum &&gameMapVec[row - i * y][col - i * x] == 1) // 玩家的子 {personNum++;}else if (row - i * y > 0 && row - i * y < kBoardSizeNum &&col - i * x > 0 && col - i * x < kBoardSizeNum && gameMapVec[row - i * y][col - i * x] == 0) // 空白位 {emptyNum++;break;}else            // 出边界break;}if (personNum == 1)                      // 杀二scoreMapVec[row][col] += 10;else if (personNum == 2)                 // 杀三{if (emptyNum == 1)scoreMapVec[row][col] += 30;else if (emptyNum == 2)scoreMapVec[row][col] += 40;}else if (personNum == 3)                 // 杀四{// 量变空位不一样,优先级不一样if (emptyNum == 1)scoreMapVec[row][col] += 60;else if (emptyNum == 2)scoreMapVec[row][col] += 110;}else if (personNum == 4)                 // 杀五scoreMapVec[row][col] += 10100;// 进行一次清空emptyNum = 0;// 对AI黑子评分for (int i = 1; i <= 4; i++){if (row + i * y > 0 && row + i * y < kBoardSizeNum &&col + i * x > 0 && col + i * x < kBoardSizeNum &&gameMapVec[row + i * y][col + i * x] == 1) // 玩家的子{botNum++;}else if (row + i * y > 0 && row + i * y < kBoardSizeNum && col + i * x > 0 && col + i * x < kBoardSizeNum &&gameMapVec[row +i * y][col + i * x] == 0) // 空白位 {emptyNum++;break;}else            // 出边界break;}for (int i = 1; i <= 4; i++){if (row - i * y > 0 && row - i * y < kBoardSizeNum &&col - i * x > 0 && col - i * x < kBoardSizeNum &&gameMapVec[row - i * y][col - i * x] == -1) // AI的子{botNum++;
}else if (row - i * y > 0 && row - i * y < kBoardSizeNum &&col - i * x > 0 && col - i * x < kBoardSizeNum && gameMapVec[row - i * y][col - i * x] == 0) // 空白位{emptyNum++;break;}else            // 出边界break;
}if (botNum == 0)                      // 普通下子scoreMapVec[row][col] += 5;else if (botNum == 1)                 // 活二scoreMapVec[row][col] += 10;else if (botNum == 2){if (emptyNum == 1)                // 死三scoreMapVec[row][col] += 25;else if (emptyNum == 2)scoreMapVec[row][col] += 50;  // 活三}else if (botNum == 3){if (emptyNum == 1)                // 死四scoreMapVec[row][col] += 55;else if (emptyNum == 2)scoreMapVec[row][col] += 100; // 活四}else if (botNum >= 4)scoreMapVec[row][col] += 10000;   // 活五}}}}
}bool GameModel::isWin(int row, int col)
{// 横竖斜四种大情况,每种情况都根据当前落子往后遍历5个棋子,有一种符合就算赢// 水平方向for (int i = 0; i < 5; i++){// 往左5个,往右匹配4个子,20种情况if (col - i > 0 &&col - i + 4 < kBoardSizeNum &&gameMapVec[row][col - i] == gameMapVec[row][col - i + 1] &&gameMapVec[row][col - i] == gameMapVec[row][col - i + 2] &&gameMapVec[row][col - i] == gameMapVec[row][col - i + 3] &&gameMapVec[row][col - i] == gameMapVec[row][col - i + 4])return true;}// 竖直方向(上下延伸4个)for (int i = 0; i < 5; i++){if (row - i > 0 &&row - i + 4 < kBoardSizeNum &&gameMapVec[row - i][col] == gameMapVec[row - i + 1][col] &&gameMapVec[row - i][col] == gameMapVec[row - i + 2][col] &&gameMapVec[row - i][col] == gameMapVec[row - i + 3][col] &&gameMapVec[row - i][col] == gameMapVec[row - i + 4][col])return true;}// 左斜方向for (int i = 0; i < 5; i++){if (row + i < kBoardSizeNum &&row + i - 4 > 0 &&col - i > 0 &&col - i + 4 < kBoardSizeNum &&gameMapVec[row + i][col - i] == gameMapVec[row + i - 1][col - i + 1] &&gameMapVec[row + i][col - i] == gameMapVec[row + i - 2][col - i + 2] &&gameMapVec[row + i][col - i] == gameMapVec[row + i - 3][col - i + 3] &&gameMapVec[row + i][col - i] == gameMapVec[row + i - 4][col - i + 4])return true;}// 右斜方向for (int i = 0; i < 5; i++){if (row - i > 0 &&row - i + 4 < kBoardSizeNum &&col - i > 0 &&col - i + 4 < kBoardSizeNum &&gameMapVec[row - i][col - i] == gameMapVec[row - i + 1][col - i + 1] &&gameMapVec[row - i][col - i] == gameMapVec[row - i + 2][col - i + 2] &&gameMapVec[row - i][col - i] == gameMapVec[row - i + 3][col - i + 3] &&gameMapVec[row - i][col - i] == gameMapVec[row - i + 4][col - i + 4])return true;}return false;
}bool GameModel::isDeadGame()
{// 所有空格全部填满for (int i = 1; i < kBoardSizeNum; i++)for (int j = 1; j < kBoardSizeNum; j++){if (!(gameMapVec[i][j] == 1 || gameMapVec[i][j] == -1))return false;}return true;
}

9.informationwindow.cpp

#include "informationwindow.h"
#include <QDebug>
#include <QPushButton>
#include <subwindow.h>
#include <QSqlQuery>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QMessageBox>
#include<QTimer>
#include <QLabel>
#include <QSqlTableModel>
#include <QTableView>
#include <QPainter>
#include <QPen>informationwindow::informationwindow(QWidget *parent) : QWidget(parent)
{a.setParent(this);a.setText("clike");connect(&a,&QPushButton::clicked,this,&informationwindow::cout);a.move(100,100);/*QTimer *timer=new QTimer;connect(timer, &QTimer::timeout, this, [&](){//5秒调用一次,想干啥都行//假设按钮是pushButtona.click();});timer->start(100);
*/a.hide();this->setWindowTitle("Personal Information");resize(500,500);
}void informationwindow::cout(){qDebug()<<QSqlDatabase::drivers();//添加MYSQL数据库QSqlDatabase db=QSqlDatabase::addDatabase("QMYSQL"); //数据库对象//连接数据库db.setHostName("127.0.0.1"); //数据库服务器IPdb.setUserName("root"); //数据库用户名db.setPassword("holdworld000312"); //数据库密码db.setDatabaseName("slimes"); //使用哪个数据库if(!db.open()){QMessageBox::information(this, "连接结果", "连接数据库失败!");return;}QString sq=QStringLiteral("select *from wuziqi_user where id=1");QSqlQuery sqlquery=QSqlQuery(db);sqlquery.exec(sq);NAME = "";while (sqlquery.next()){NAME.append(sqlquery.value(1).toString());}win = "";QString sq5=QStringLiteral("select *from wuziqi_info where handle='%1' ").arg(NAME);QSqlQuery sqlquery5=QSqlQuery(db);sqlquery5.exec(sq5);while (sqlquery5.next()){win.append(sqlquery5.value(3).toString());}handle = "";QString sq1=QStringLiteral("select *from wuziqi_info where handle='%1' ").arg(NAME);QSqlQuery sqlquery1=QSqlQuery(db);sqlquery1.exec(sq1);while (sqlquery1.next()){handle.append(sqlquery1.value(1).toString());}lose = "";QString sq2=QStringLiteral("select *from wuziqi_info where handle='%1' ").arg(NAME);QSqlQuery sqlquery2=QSqlQuery(db);sqlquery2.exec(sq2);while (sqlquery2.next()){lose.append(sqlquery2.value(4).toString());}name = "";QString sq3=QStringLiteral("select *from wuziqi_info where handle='%1' ").arg(NAME);QSqlQuery sqlquery3=QSqlQuery(db);sqlquery3.exec(sq3);while (sqlquery3.next()){name.append(sqlquery3.value(5).toString());}sex = "";QString sq4=QStringLiteral("select *from wuziqi_info where handle='%1' ").arg(NAME);QSqlQuery sqlquery4=QSqlQuery(db);sqlquery4.exec(sq4);while (sqlquery4.next()){sex.append(sqlquery4.value(6).toString());}resize(500,500);qDebug()<< NAME<<handle<<win<<lose<<name<<sex;}void informationwindow::paintEvent(QPaintEvent *){QPainter p2;  //创建画家对象p2.begin(this); //指定当前窗口为绘图设备//绘图操作//画背景图p2.drawPixmap(0,0,width(),height(), QPixmap("../Image/u=3720865353,2633372586&fm=26&gp=0.jpg"));//QPainter p(this);if( sex == "men"){QPainter p;  //创建画家对象p.begin(this); //指定当前窗口为绘图设备//绘图操作//画背景图p.drawPixmap(100,100,100,100, QPixmap("../Image/7D016817BF7BEE8D56116FCBA333DBFB.jpg"));}if( sex == "women"){QPainter p1;  //创建画家对象p1.begin(this);//指定当前窗口为绘图设备//绘图操作//画背景图p1.drawPixmap(100,100,100,100, QPixmap("../Image/776CC876C0FAD440626034DE13CD5866.jpg"));}
}

10.main.cpp

#include "mainwindow.h"
#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);MainWindow w;//w.show();return a.exec();
}

11.mainwindow.cpp

#include <QPainter>
#include <QTimer>
#include <QMouseEvent>
#include <QMessageBox>
#include <QMenuBar>
#include <QMenu>
#include <QAction>
#include <QDebug>  //打印
#include <math.h>
#include "mainwindow.h"
#include <QPushButton>
#include <QWidget>
#include <QPen>
#include <QBrush>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QStatusBar>
#include <QLabel>
#include <QDateTime>const int kBoardMargin = 30; // 棋盘边缘空隙
const int kRadius = 15; // 棋子半径
const int kMarkSize = 6; // 落子标记边长
const int kBlockSize = 40; // 格子的大小
const int kPosDelta = 20; // 鼠标点击的模糊距离上限const int kAIDelay = 700; // AI下棋的思考时间// -------------------- //MainWindow::MainWindow(QWidget *parent): QMainWindow(parent)
{setWindowTitle("wuziqi");//等于this->setWindowTitle("boss");//显示子窗口subwin.show();//处理子窗口的信号void(subwindow::*funSignal)(QString)=&subwindow::mySignal;connect(&subwin,funSignal, this, &MainWindow::dealsub);//让窗口大小不变resize(500, 500);// 设置棋盘大小setFixedSize(kBoardMargin * 2 + kBlockSize * kBoardSizeNum, kBoardMargin * 2 + kBlockSize * kBoardSizeNum);//setStyleSheet("background-color:yellow;");// 开启鼠标hover功能,这两句一般要设置window的setMouseTracking(true);//    centralWidget()->setMouseTracking(true);// 添加游戏菜单QMenu *gameMenu = menuBar()->addMenu(tr("Game")); // menuBar默认是存在的,直接加菜单就可以了QAction *actionPVP = new QAction("Person VS Person", this);connect(actionPVP, SIGNAL(triggered()), this, SLOT(initPVPGame()));gameMenu->addAction(actionPVP);gameMenu->addSeparator(); //添加分割线QAction *actionPVE = new QAction("Person VS Computer", this);connect(actionPVE, SIGNAL(triggered()), this, SLOT(initPVEGame()));gameMenu->addAction(actionPVE);//添加信息菜单QMenu *gameMenuset = menuBar()->addMenu(tr("setting")); // menuBar默认是存在的,直接加菜单就可以了QAction *actionPVPinf = new QAction("information(&A)", this);connect(actionPVPinf, SIGNAL(triggered()),this ,SLOT(showinf()));gameMenuset->addAction(actionPVPinf);//添加排行榜QAction *actionPVPrank = new QAction("rank(&B)", this);connect(actionPVPrank, SIGNAL(triggered()),this ,SLOT(showrank()));gameMenuset->addAction(actionPVPrank);//添加换背景栏QMenu *actionPVPback = new QMenu("background(&C)", this);//connect(actionPVPback, SIGNAL(triggered()),this ,SLOT(showrank()));gameMenuset->addMenu(actionPVPback);//添加退出登陆QAction *actionPVPexland = new QAction("Exit landing(&D)", this);connect(actionPVPexland, SIGNAL(triggered()),this ,SLOT(exland()));gameMenuset->addAction(actionPVPexland);//添加深木色的背景QAction *actionPVPdeepwood = new QAction("deepwood", this);connect(actionPVPdeepwood, SIGNAL(triggered()),this ,SLOT(backdeepwood()));actionPVPback->addAction(actionPVPdeepwood);//添加浅木色的背景QAction *actionPVPwood = new QAction("lightwood", this);connect(actionPVPwood, SIGNAL(triggered()),this ,SLOT(backwood()));actionPVPback->addAction(actionPVPwood);//添加灰木色的背景QAction *actionPVPgraywood = new QAction("graywood", this);connect(actionPVPgraywood, SIGNAL(triggered()),this ,SLOT(backgraywood()));actionPVPback->addAction(actionPVPgraywood);//添加橙木色的背景QAction *actionPVPorangewood = new QAction("orangewood", this);connect(actionPVPorangewood, SIGNAL(triggered()),this ,SLOT(backorangewood()));actionPVPback->addAction(actionPVPorangewood);QMenu *gameMenuoper = menuBar()->addMenu(tr("operation")); // menuBar默认是存在的,直接加菜单就可以了//认输QAction *actionPVPgiveup = new QAction("give up(&E)", this);connect(actionPVPgiveup, SIGNAL(triggered()),this ,SLOT(Giveup()));gameMenuoper->addAction(actionPVPgiveup);//暂停QAction *actionPVPpause = new QAction("pause(&F)", this);connect(actionPVPpause, SIGNAL(triggered()),this ,SLOT(pause()));gameMenuoper->addAction(actionPVPpause);//悔棋QAction *actionPVPreturn = new QAction("return(&G)", this);connect(actionPVPreturn, SIGNAL(triggered()),this ,SLOT(Return()));gameMenuoper->addAction(actionPVPreturn);//帮助//QAction *actionPVPhelp = new QAction("help(&H)", this);//connect(actionPVPhelp, SIGNAL(triggered()),this ,SLOT(Helpwindow()));//gameMenuoper->addAction(actionPVPhelp);//添加退出QAction *actionPVPexit = new QAction("exit(&I)", this);connect(actionPVPexit, SIGNAL(triggered()),this ,SLOT(exit()));gameMenuoper->addAction(actionPVPexit);// 开始游戏initGame();//setWindowTitle("-五子棋-");//状态栏currentTimeLabel = new QLabel; // 创建QLabel控件QStatusBar *sBar = statusBar();sBar->addWidget(new QLabel("time:",this));sBar->addWidget(currentTimeLabel);timer = new QTimer(this);time = new QTime(0,0,0);timer->start(1000); //每隔1000ms发送timeout的信号connect(timer, SIGNAL(timeout()),this,SLOT(time_update()));
}void MainWindow::time_update()
{//time->addSecs(1);*time=time->addSecs(1);//QDateTime current_time =  new QDateTime(0,0,0);QString timestr = time->toString("hh:mm:ss"); //设置显示的格式currentTimeLabel->setText(timestr); //设置label的文本内容为时间
}//void MainWindow::Helpwindow(){//    helpwin.show();
//}void MainWindow::exland(){this->hide();subwin.show();
}void MainWindow::Return(){Returns=1;
}void MainWindow::pause(){timer->stop();QMessageBox::StandardButton btnValue = QMessageBox::information(this, "pause", "The game is paused.");timer->start();
}void MainWindow::backwood(){color=0;
}void MainWindow::backdeepwood(){color=1;
}void MainWindow::backgraywood(){color=2;
}void MainWindow::backorangewood(){color=3;
}void MainWindow::Giveup(){giveup=1;time->setHMS(0,0,0);
}//退出
void MainWindow::exit(){this->close();
}//显示排行榜
void MainWindow::showrank(){rankwin.show();
}//显示个人信息
void MainWindow::showinf(){infwin.show();infwin.a.click();
}void MainWindow::changeWin(){//子窗口显示subwin.show();//本窗口隐藏this->hide();
}void MainWindow::dealsub(QString str){NAME = str;qDebug()<<NAME;//子窗口显示subwin.hide();//本窗口隐藏this->show();time->setHMS(0,0,0);
}MainWindow::~MainWindow()
{if (game){delete game;game = nullptr;}
}void MainWindow::initGame()
{// 初始化游戏模型game = new GameModel;initPVPGame();
}void MainWindow::initPVPGame()
{game_type = PERSON;game->gameStatus = PLAYING;game->startGame(game_type);time->setHMS(0,0,0);update();
}void MainWindow::initPVEGame()
{game_type = BOT;game->gameStatus = PLAYING;game->startGame(game_type);time->setHMS(0,0,0);update();
}void MainWindow::paintEvent(QPaintEvent *event)
{//QPainter p(this);QPainter p;  //创建画家对象p.begin(this); //指定当前窗口为绘图设备//绘图操作//画背景图if(color == 0)p.drawPixmap(0,0,width(),height(), QPixmap("../Image/u=3967820435,4109070133&fm=26&gp=0.jpg"));if(color == 1)p.drawPixmap(0,0,width(),height(), QPixmap("../Image/u=867276353,2609607622&fm=72.jpg"));if(color == 2)p.drawPixmap(0,0,width(),height(), QPixmap("../Image/u=1985406695,1258431003&fm=11&gp=0_WPS图片.jpg"));if(color == 3)p.drawPixmap(0,0,width(),height(), QPixmap("../Image/u=3606751862,1869919184&fm=26&gp=0.jpg"));QPainter painter(this);// 绘制棋盘painter.setRenderHint(QPainter::Antialiasing, true); // 抗锯齿
//    QPen pen; // 调整线条宽度
//    pen.setWidth(2);
//    painter.setPen(pen);for (int i = 0; i < kBoardSizeNum + 1; i++){painter.drawLine(kBoardMargin + kBlockSize * i, kBoardMargin, kBoardMargin + kBlockSize * i, size().height() - kBoardMargin);painter.drawLine(kBoardMargin, kBoardMargin + kBlockSize * i, size().width() - kBoardMargin, kBoardMargin + kBlockSize * i);}QBrush brush;brush.setStyle(Qt::SolidPattern);// 绘制落子标记(防止鼠标出框越界)if (clickPosRow > 0 && clickPosRow < kBoardSizeNum &&clickPosCol > 0 && clickPosCol < kBoardSizeNum &&game->gameMapVec[clickPosRow][clickPosCol] == 0){if (game->playerFlag)brush.setColor(Qt::white);elsebrush.setColor(Qt::black);painter.setBrush(brush);painter.drawRect(kBoardMargin + kBlockSize * clickPosCol - kMarkSize / 2, kBoardMargin + kBlockSize * clickPosRow - kMarkSize / 2, kMarkSize, kMarkSize);}if(Returns==1){game->gameMapVec[a[nows][0]][a[nows][1]]=0;nows--;Returns=0;}// 绘制棋子for (int i = 0; i < kBoardSizeNum; i++)for (int j = 0; j < kBoardSizeNum; j++){if (game->gameMapVec[i][j] == 1){brush.setColor(Qt::white);painter.setBrush(brush);painter.drawEllipse(kBoardMargin + kBlockSize * j - kRadius, kBoardMargin + kBlockSize * i - kRadius, kRadius * 2, kRadius * 2);}else if (game->gameMapVec[i][j] == -1){brush.setColor(Qt::black);painter.setBrush(brush);painter.drawEllipse(kBoardMargin + kBlockSize * j - kRadius, kBoardMargin + kBlockSize * i - kRadius, kRadius * 2, kRadius * 2);}}if(giveup == 1){QString str = "black player";giveup = 0;QMessageBox::StandardButton btnValue = QMessageBox::information(this, "congratulations", str + " win!");//打印QT支持的数据库驱动qDebug()<<QSqlDatabase::drivers();//添加MYSQL数据库QSqlDatabase db=QSqlDatabase::addDatabase("QMYSQL"); //数据库对象//连接数据库db.setHostName("127.0.0.1"); //数据库服务器IPdb.setUserName("root"); //数据库用户名db.setPassword("holdworld000312"); //数据库密码db.setDatabaseName("slimes"); //使用哪个数据库if(!db.open()){QMessageBox::information(this, "连接结果", "连接数据库失败!");return;}//获得数据库中win,lise的值QString  win;QString  lose;QString sq=QStringLiteral("select *from wuziqi_info where handle='%1' ").arg(NAME);QSqlQuery sqlquery=QSqlQuery(db);sqlquery.exec(sq);while (sqlquery.next()){win.append(sqlquery.value(3).toString());}QString sq1=QStringLiteral("select *from wuziqi_info where handle='%1' ").arg(NAME);QSqlQuery sqlquery1=QSqlQuery(db);sqlquery1.exec(sq1);while (sqlquery1.next()){lose.append(sqlquery1.value(4).toString());}//qDebug()<<win;qDebug()<<lose;//默认用户为白棋,输if(str == "black player"){int newlose = lose.toInt()+1;QSqlQuery query;query.prepare("update wuziqi_info set lose=? where handle=?");query.addBindValue(newlose);query.addBindValue(NAME);query.exec();}// 重置游戏状态,否则容易死循环if (btnValue == QMessageBox::Ok){game->startGame(game_type);game->gameStatus = PLAYING;}}else{if (clickPosRow > 0 && clickPosRow < kBoardSizeNum &&clickPosCol > 0 && clickPosCol < kBoardSizeNum &&(game->gameMapVec[clickPosRow][clickPosCol] == 1 ||game->gameMapVec[clickPosRow][clickPosCol] == -1)){if (game->isWin(clickPosRow, clickPosCol) && game->gameStatus == PLAYING){qDebug() << "win";game->gameStatus = WIN;QString str;if (game->gameMapVec[clickPosRow][clickPosCol] == 1)str = "white player";else if (game->gameMapVec[clickPosRow][clickPosCol] == -1)str = "black player";QMessageBox::StandardButton btnValue = QMessageBox::information(this, "congratulations", str + " win!");time->setHMS(0,0,0);//打印QT支持的数据库驱动qDebug()<<QSqlDatabase::drivers();//添加MYSQL数据库QSqlDatabase db=QSqlDatabase::addDatabase("QMYSQL"); //数据库对象//连接数据库db.setHostName("127.0.0.1"); //数据库服务器IPdb.setUserName("root"); //数据库用户名db.setPassword("holdworld000312"); //数据库密码db.setDatabaseName("slimes"); //使用哪个数据库if(!db.open()){QMessageBox::information(this, "连接结果", "连接数据库失败!");return;}//获得数据库中win,lise的值QString  win;QString  lose;QString sq=QStringLiteral("select *from wuziqi_info where handle='%1' ").arg(NAME);QSqlQuery sqlquery=QSqlQuery(db);sqlquery.exec(sq);while (sqlquery.next()){win.append(sqlquery.value(3).toString());}QString sq1=QStringLiteral("select *from wuziqi_info where handle='%1' ").arg(NAME);QSqlQuery sqlquery1=QSqlQuery(db);sqlquery1.exec(sq1);while (sqlquery1.next()){lose.append(sqlquery1.value(4).toString());}//qDebug()<<win;//qDebug()<<lose;//默认用户为白棋,赢if(str == "white player"){int newwin = win.toInt()+1;QSqlQuery query;query.prepare("update wuziqi_info set win=? where handle=?");query.addBindValue(newwin);query.addBindValue(NAME);query.exec();}//默认用户为白棋,输if(str == "black player"){int newlose = lose.toInt()+1;QSqlQuery query;query.prepare("update wuziqi_info set lose=? where handle=?");query.addBindValue(newlose);query.addBindValue(NAME);query.exec();}// 重置游戏状态,否则容易死循环if (btnValue == QMessageBox::Ok){game->startGame(game_type);game->gameStatus = PLAYING;}}
}// 判断死局if (game->isDeadGame()){QMessageBox::StandardButton btnValue = QMessageBox::information(this, "oops", "dead game!");if (btnValue == QMessageBox::Ok){game->startGame(game_type);game->gameStatus = PLAYING;}}}
}void MainWindow::mouseMoveEvent(QMouseEvent *event)
{// 通过鼠标的hover确定落子的标记int x = event->x();int y = event->y();// 棋盘边缘不能落子if (x >= kBoardMargin + kBlockSize / 2 &&x < size().width() - kBoardMargin &&y >= kBoardMargin + kBlockSize / 2 &&y < size().height()- kBoardMargin){// 获取最近的左上角的点int col = x / kBlockSize;int row = y / kBlockSize;int leftTopPosX = kBoardMargin + kBlockSize * col;int leftTopPosY = kBoardMargin + kBlockSize * row;// 根据距离算出合适的点击位置,一共四个点,根据半径距离选最近的clickPosRow = -1; // 初始化最终的值clickPosCol = -1;int len = 0; // 计算完后取整就可以了// 确定一个误差在范围内的点,且只可能确定一个出来len = sqrt((x - leftTopPosX) * (x - leftTopPosX) + (y - leftTopPosY) * (y - leftTopPosY));if (len < kPosDelta){clickPosRow = row;clickPosCol = col;}len = sqrt((x - leftTopPosX - kBlockSize) * (x - leftTopPosX - kBlockSize) + (y - leftTopPosY) * (y - leftTopPosY));if (len < kPosDelta){clickPosRow = row;clickPosCol = col + 1;}len = sqrt((x - leftTopPosX) * (x - leftTopPosX) + (y - leftTopPosY - kBlockSize) * (y - leftTopPosY - kBlockSize));if (len < kPosDelta){clickPosRow = row + 1;clickPosCol = col;}len = sqrt((x - leftTopPosX - kBlockSize) * (x - leftTopPosX - kBlockSize) + (y - leftTopPosY - kBlockSize) * (y - leftTopPosY - kBlockSize));if (len < kPosDelta){clickPosRow = row + 1;clickPosCol = col + 1;}}// 存了坐标后也要重绘update();
}void MainWindow::mouseReleaseEvent(QMouseEvent *event)
{// 人下棋,并且不能抢机器的棋if (!(game_type == BOT && !game->playerFlag)){chessOneByPerson();// 如果是人机模式,需要调用AI下棋if (game->gameType == BOT && !game->playerFlag){// 用定时器做一个延迟QTimer::singleShot(kAIDelay, this, SLOT(chessOneByAI()));}}}void MainWindow::chessOneByPerson()
{// 根据当前存储的坐标下子// 只有有效点击才下子,并且该处没有子if (clickPosRow != -1 && clickPosCol != -1 && game->gameMapVec[clickPosRow][clickPosCol] == 0){nows++;game->actionByPerson(clickPosRow, clickPosCol);a[nows][0]=clickPosRow;a[nows][1]=clickPosCol;// 重绘update();}
}void MainWindow::chessOneByAI()
{game->actionByAI(clickPosRow, clickPosCol);update();
}

12.rankwindow.cpp

#include "rankwindow.h"
#include <QDebug>
#include <QPushButton>
#include <subwindow.h>
#include <QSqlQuery>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QMessageBox>
#include<QTimer>
#include <QLabel>
#include <QSqlTableModel>
#include <QTableView>
#include <QPainter>
#include <QPen>
rankwindow::rankwindow(QWidget *parent) : QWidget(parent)
{}void rankwindow::paintEvent(QPaintEvent *){QPainter p;  //创建画家对象p.begin(this); //指定当前窗口为绘图设备//绘图操作//画背景图p.drawPixmap(0,0,width(),height(), QPixmap("../Image/u=4069830077,209421225&fm=26&gp=0.jpg"));}

13.registerwindow.cpp

#include "registerwindow.h"
#include <qstring.h>
#include <QLabel>
#include <QLineEdit.h>
#include <QDebug>
#include <QMessageBox>
#include <QVariantList>
#include <QSqlDatabase>
#include <qsqltablemodel.h>
#include <qsqlquery.h>
#include <qlabel.h>
#include <QPainter>
#include <QPen>
#include <QBrush>registerwindow::registerwindow(QWidget *parent) : QWidget(parent)
{setWindowTitle("注册界面");d.setParent(this);d.setText("注册");d.move(300,300);resize(500, 500);connect(&d, &QPushButton::clicked, this, &registerwindow::sendregitslot);e.setParent(this);e.setText("返回登陆");e.move(400,300);connect(&e, &QPushButton::clicked, this, &registerwindow::sendreturnslot);pNormalLineEdit1->setPlaceholderText("handle");pPasswordLineEdit1->setPlaceholderText("Password");pPasswordLineEdit2->setPlaceholderText("Password");pNormalLineEdit1->move(150,100);pPasswordLineEdit1->move(150,125);pPasswordLineEdit2->move(150,150);// 设置显示效果pNormalLineEdit1->setEchoMode(QLineEdit::Normal);pPasswordLineEdit1->setEchoMode(QLineEdit::Password);pPasswordLineEdit2->setEchoMode(QLineEdit::Password);pNormalLineEdit2->setPlaceholderText("name");pNormalLineEdit3->setPlaceholderText("sex");pNormalLineEdit2->move(150,175);pNormalLineEdit3->move(150,200);// 设置显示效果pNormalLineEdit2->setEchoMode(QLineEdit::Normal);pNormalLineEdit3->setEchoMode(QLineEdit::Normal);QString data6;data6="账号:";QLabel *label6 = new QLabel(this);label6->setText(QString(data6));label6->move(50,100);QString data7;data7="密码:";QLabel *label7 = new QLabel(this);label7->setText(QString(data7));label7->move(50,128);QString data8;data8="重新确认密码:";QLabel *label8 = new QLabel(this);label8->setText(QString(data8));label8->move(50,154);QString data9;data9="姓名:";QLabel *label9 = new QLabel(this);label9->setText(QString(data9));label9->move(50,180);QString data10;data10="性别(men/women):";QLabel *label10 = new QLabel(this);label10->setText(QString(data10));label10->move(27,205);
}void  registerwindow::sendreturnslot(){emit regitSignal();
}void registerwindow::sendregitslot(){//打印QT支持的数据库驱动qDebug()<<QSqlDatabase::drivers();//添加MYSQL数据库QSqlDatabase db=QSqlDatabase::addDatabase("QMYSQL"); //数据库对象//连接数据库db.setHostName("127.0.0.1"); //数据库服务器IPdb.setUserName("root"); //数据库用户名db.setPassword("holdworld000312"); //数据库密码db.setDatabaseName("slimes"); //使用哪个数据库if(!db.open()){QMessageBox::information(this, "连接结果", "连接数据库失败!");return;}QString handle=pNormalLineEdit1->text();QString passwd1=pPasswordLineEdit1->text();QString passwd2=pPasswordLineEdit2->text();QString name=pNormalLineEdit2->text();QString sex=pNormalLineEdit3->text();if(passwd1!=passwd2){QMessageBox::information(this, "warning","密码不一致.");pNormalLineEdit1->clear();pPasswordLineEdit1->clear();pPasswordLineEdit2->clear();}else if (handle== '\0' || passwd1=='\0'){QMessageBox::information(this, "warning","密码/账号不能为空.");pNormalLineEdit1->clear();pPasswordLineEdit1->clear();pPasswordLineEdit2->clear();}else{QString str = QString("select *from wuziqi_info where handle = '%1'").arg(handle);QSqlQuery query;query.exec(str);int o=0;while (query.next()){o=1;}if(o==1){QMessageBox::information(this, "Warning", " Account already exists ");pNormalLineEdit1->clear();pPasswordLineEdit1->clear();pPasswordLineEdit2->clear();}else{QMessageBox::information(this, "login", " login was successful ");QString str=QString("insert into wuziqi_info(handle, passwd,  win, lose, name, sex) values('%1','%2', 0 , 0 ,'%3','%4')").arg(handle).arg(passwd1).arg(name).arg(sex);QSqlQuery query;query.exec(str);//textEdit->setText("插入成功");pNormalLineEdit1->clear();pPasswordLineEdit1->clear();pPasswordLineEdit2->clear();emit regitSignal();}}
}void registerwindow::paintEvent(QPaintEvent *){//QPainter p(this);QPainter p;  //创建画家对象p.begin(this); //指定当前窗口为绘图设备//绘图操作//画背景图p.drawPixmap(0,0,width(),height(), QPixmap("../Image/u=1869757711,2217152015&fm=26&gp=0.jpg"));}

14.subwindow.cpp

#include "subwindow.h"
#include <qstring.h>
#include <QLabel>
#include <QLineEdit.h>
#include <QDebug>
#include <QMessageBox>
#include <QVariantList>
#include <QSqlDatabase>
#include <qsqltablemodel.h>
#include <qfont.h>
#include <QPainter>
#include <QPen>
#include <QBrush>
#include <qsqlquery.h>subwindow::subwindow(QWidget *parent) : QWidget(parent)
{QString data4;data4="Handle/Email:";QLabel *label4 = new QLabel(this);label4->setText(QString(data4));label4->move(15,255);QString data5;data5="Password:";QLabel *label5 = new QLabel(this);label5->setText(QString(data5));label5->move(15,293);pNormalLineEdit->setPlaceholderText("Normal");pPasswordLineEdit->setPlaceholderText("Password");pNormalLineEdit->move(125,250);pPasswordLineEdit->move(125,290);// 设置显示效果pNormalLineEdit->setEchoMode(QLineEdit::Normal);pPasswordLineEdit->setEchoMode(QLineEdit::Password);this->setWindowTitle("登陆界面");b.setParent(this);b.setText("Login");b.move(320,300);connect(&b, &QPushButton::clicked, this, &subwindow::sendSlot);c.setParent(this);c.setText("Register");c.move(320,350);connect(&c, &QPushButton::released, this, &subwindow::changwin);QString data;data="抵制不良游戏,拒绝盗版游戏;";QLabel *label = new QLabel(this);label->setText(QString(data));label->move(25,350);QString data1;data1="注意自我保护,谨防受骗上当;";QLabel *label1 = new QLabel(this);label1->setText(QString(data1));label1->move(25,375);QString data2;data2="适度游戏益脑,沉迷游戏伤身;";QLabel *label2 = new QLabel(this);label2->setText(QString(data2));label2->move(25,400);QString data3;data3="合理安排时间,享受健康生活;";QLabel *label3 = new QLabel(this);label3->setText(QString(data3));label3->move(25,425);//让窗口大小不变resize(500, 460);//处理registerwindow的信号connect(&regist,&registerwindow::regitSignal, this ,&subwindow::dealSlot);}void subwindow::dealSlot(){//registerwindow隐藏regist.hide();//subwindow显示this->show();
}void subwindow::changwin(){//registerwindow显示regist.show();//subwindow隐藏this->hide();
}void subwindow::sendSlot()
{//打印QT支持的数据库驱动qDebug()<<QSqlDatabase::drivers();//添加MYSQL数据库QSqlDatabase db=QSqlDatabase::addDatabase("QMYSQL"); //数据库对象//连接数据库db.setHostName("127.0.0.1"); //数据库服务器IPdb.setUserName("root"); //数据库用户名db.setPassword("holdworld000312"); //数据库密码db.setDatabaseName("slimes"); //使用哪个数据库if(!db.open()){QMessageBox::information(this, "连接结果", "连接数据库失败!");return;}QString handle=pNormalLineEdit->text();QString passwd=pPasswordLineEdit->text();QSqlTableModel model;model.setTable("wuziqi_info");model.setFilter(tr("handle = '%1' and passwd = '%2'").arg(handle).arg(passwd));model.select();if(model.rowCount() == 1){QString NAME = handle;// 表示密码验证正确,登陆成功// ...... 显示登录后的状态QMessageBox::information(this, "Login", "登录成功!");QSqlQuery query1;query1.prepare("DELETE  From wuziqi_user where id=1");if(!query1.exec())//如果成功执行则返回1,未执行则为零qDebug()<<"fail";QString sex = "";QString sq4=QStringLiteral("select *from wuziqi_info where handle='%1' ").arg(NAME);QSqlQuery sqlquery4=QSqlQuery(db);sqlquery4.exec(sq4);while (sqlquery4.next()){sex.append(sqlquery4.value(6).toString());}QString str=QString("insert into wuziqi_user(id,handle,sex) values(1,'%1','%2')").arg(handle).arg(sex);QSqlQuery query;query.exec(str);emit mySignal(NAME);}else{QMessageBox::information(this, "Warning", "用户名或密码错误,请重新输入!");pNormalLineEdit->clear();pPasswordLineEdit->clear();}
}void subwindow::on_pushButton_2_clicked()
{close();
}void subwindow::paintEvent(QPaintEvent *){//QPainter p(this);QPainter p;  //创建画家对象p.begin(this); //指定当前窗口为绘图设备//绘图操作//画背景图p.drawPixmap(0,0,width(),height(), QPixmap("../Image/u=4105832563,1730732419&fm=26&gp=0_WPS图片.jpg"));QPainter p1;  //创建画家对象p1.begin(this);//指定当前窗口为绘图设备//绘图操作//画背景图p1.drawPixmap(0,-30,250,300, QPixmap("../Image/614356656556334208.png"));
}

QT五子棋游戏课设及源码(连接mysql数据库含打开并运行程序的教程)相关推荐

  1. 计算机毕业设计Java高校排课管理系统(源码+系统+mysql数据库+lw文档)

    计算机毕业设计Java高校排课管理系统(源码+系统+mysql数据库+lw文档) 计算机毕业设计Java高校排课管理系统(源码+系统+mysql数据库+lw文档) 本源码技术栈: 项目架构:B/S架构 ...

  2. 计算机毕业设计Java疫情网课管理系统(源码+系统+mysql数据库+Lw文档)

    计算机毕业设计Java疫情网课管理系统(源码+系统+mysql数据库+Lw文档) 计算机毕业设计Java疫情网课管理系统(源码+系统+mysql数据库+Lw文档) 本源码技术栈: 项目架构:B/S架构 ...

  3. 计算机毕业设计Java游戏资讯网站(源码+系统+mysql数据库+Lw文档)

    计算机毕业设计Java游戏资讯网站(源码+系统+mysql数据库+Lw文档) 计算机毕业设计Java游戏资讯网站(源码+系统+mysql数据库+Lw文档) 本源码技术栈: 项目架构:B/S架构 开发语 ...

  4. 计算机毕业设计java+ssm游戏光盘租赁系统(源码+系统+mysql数据库+Lw文档)

    项目介绍 游戏是很多人茶前饭后消遣的方式之一,但是很多时候人们因为网络等原因不能够下载到自己喜欢的游戏,或者有的游戏根本不提供网络下载,这个时候就需要游戏光盘来进行安装等操作了,但是游戏光盘一般拷贝之 ...

  5. 计算机毕业设计之Android的游戏账号交易平台APP(源码+系统+mysql数据库+Lw文档)

    随着互联网与智能手机的普及,手游市场规模迅速扩大.在节奏不断加快的城市中,越来越多的人选择在工作之余用手机游戏放松自己,减轻压力.而且手机游戏成本低,更受到欢迎.所以游戏交易平台的推出则可以增强用户游 ...

  6. 计算机毕业设计Android的游戏资讯APP设计(源码+系统+mysql数据库+Lw文档)

    随着科技进步,电子产品发展迅速,诸如手机电脑等电子产品更新换代很快,电子产品在人们的生活中已经成为不可缺少的一部分了,所以App的开发越来越重要.新闻类的app也有很多,像微博,知乎这些,为了方便用户 ...

  7. [含课设报告+源码等]基于JSP实现的飞机票售票管理系统[包运行成功]

    下载:https://download.csdn.net/download/ll6666668/64026192 项目介绍: [含课设报告+源码等]基于JSP实现的飞机票售票管理系统[包运行成功][含 ...

  8. 计算机毕业设计Java教务排课系统(源码+系统+mysql数据库+lw文档)

    计算机毕业设计Java教务排课系统(源码+系统+mysql数据库+lw文档) 计算机毕业设计Java教务排课系统(源码+系统+mysql数据库+lw文档) 本源码技术栈: 项目架构:B/S架构 开发语 ...

  9. 计算机毕业设计JavaSteam游戏平台系统(源码+系统+mysql数据库+lw文档)

    计算机毕业设计JavaSteam游戏平台系统(源码+系统+mysql数据库+lw文档) 计算机毕业设计JavaSteam游戏平台系统(源码+系统+mysql数据库+lw文档) 本源码技术栈: 项目架构 ...

最新文章

  1. windows 技巧篇-查看文件夹被那个进程占用,文件夹占用解除方法
  2. 计数信号量的原理与创建
  3. Linux运行Java出现“Exception in thread main java.lang.OutOfMemoryError: Java heap space”报错...
  4. python idea控制台中文乱码_python 解决cv2绘制中文乱码问题
  5. CL_CRM_PRODIL_EXTENSION
  6. 【PHP 扩展开发】Zephir 基础篇
  7. orabbix监控oracle11g,zabbix利用orabbix监控oracle(详细配置图解)
  8. 微型计算机中外储存器比内储存器,计算机笔试复习题集共23页.doc
  9. 四级口语计算机对话,四级英语口语对话常用的句子
  10. 三元组相加获得target
  11. html 多个mp3,HTML5 audio 如何实现播放多个MP3音频
  12. php程序员 软考考什么好,软考考什么好_软考哪个好考_软考哪个更容易考 - 希赛网...
  13. linux addr2line使用手册,addr2line 命令使用方法
  14. 安装VC 6.0,出现 DOSX.EX must be in your AUTOEXEC.NT的信息
  15. MySQL编程:将查询到的字段赋值给变量
  16. MODIS下载、处理全流程记录
  17. 视频消重入门级,学会这个你基本就能靠搬运维持生活自媒体视频如何消重?批量处理去重消重去水印去logo...
  18. 有哪些好用的python在线编程环境?
  19. 知乎上40个有趣回复,很精辟!
  20. 用‘+‘替换字符串中的所有空格[复制]

热门文章

  1. 「 SLAM lesson-2.3 」SLAM数学描述、运动方程、观测方程
  2. Greenplum实战-gpstop gpstart集群命令
  3. Vins_mono重力对齐理解
  4. 计算机弹音乐百度百科,音乐术语
  5. 牛客网——综合错题集
  6. 新装修的房子怎样知道含不含有甲醛?斐讯悟空M1告诉你
  7. python多线程请求接口_python多线程实现http请求
  8. 又一年没有中国队的世界杯,你还会熬夜打call吗?网友的回答亮了
  9. codeforces(D2. Coffee and Coursework (Hard Version))二分答案
  10. 正点原子第四期环境搭建