QT vs2017《五子棋》人机对战项目

一年了。一年前,自己学习qt语言时,顺便写了一个五子棋的小项目,个人感觉,这个五子棋项目还算挺大型的,整个项目代码量加起来可能有1w行,现在分享出来给有需要的朋友,参考借鉴。

项目包括实现功能:背景音乐、悔棋、链接MySQL进行存档和读档操作、删库跑路(也就是删除所有存档)、最小化系统托盘、游戏声音调节、人机对战算法等!


一、游戏截图

下面是游戏截图:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

GIF演示:
在这里插入图片描述

在这里插入图片描述

麻雀虽小五脏俱全!


二、项目代码

这是项目文件:
在这里插入图片描述

项目源码代码
https://download.csdn.net/download/cpp_learner/76123482

需要自己创建一个名为gobang的数据库,并创建表gather_table_name
创建表MySQL语句:create table gather_table_name(id int PRIMARY KEY AUTO_INCREMENT, table_name varchar(128) NOT NULL, save_time timestamp NOT NULL);
在这里插入图片描述
gather_table_name表存储的是所有存档的档名,通过这些档名就可以获取对应存档的表名,就可以读取里面的数据了。

创建好后,再修改代码中自己的数据库账户和密码即可连接成功,就可以实现存档和读档的功能了!


三、项目大致讲解

1. Qt_Gobang类

这是主窗体类!用于下棋的,判断“五子连珠”也是在这里实现的!

“五子连珠”的判断思路:
我们的棋盘每个下棋点都是有固定的坐标的,且每个点间隔50像素。
所以,当鼠标点击时,获取该点的坐标,从此位置开始向左、向右、向上、向下、向左上、向右下、向右上、向右下进行统计是否有五个相同的棋子,
有即使“五子连珠”,可以结束棋盘了!

例如:
在这里插入图片描述

如图2-4,从中间空着这那个点开始统计,假设我们即将要将黑色的棋子下在空这个哪里,首先向上统计,发现只有一个,加上自身也就只有两个,不够,那么先记录已经有两个相同的棋子了,然后开始向下统计,发现有三个,刚好与两个相加为5个,符合“五子连珠”于是乎结束棋盘。
如果竖着的方向统计不够,那么就开始其他方向的统计!

不知道这样讲听懂了没有呢?
下面是判断五子连珠的代码:

这里我是通过switch的方式,然后通过循环进行判断操作的!

// 触发检测“五子连珠”的槽方法
void Qt_Gobang::on_Ninth_Game() {
	RESULT result = RESULT::No;

    result = doDetectionNinth_Game();
    if (result == RESULT::Yes) {
        m_victoryFlags = true;
		this->update();
        m_startGame = false;    // 胜利后,棋盘锁上,防止玩家再次点击棋盘下棋

		// 计时全部停止,倒计时清零
		m_pBlackChessStepTime->stop();
		m_pWhiteChessStepTime->stop();
		m_pTotalTime->stop();
		emit blackChessSucceed();
		emit whiteChessSucceed();
    }
}



// “五子连珠”执行判断标志
static int caseIndex = 1;
// 黑棋白棋“五子连珠”统计
static int ninth_gameCount = 1;
// 棋子统计辅助(ij)
static int chessCount = 1;
// 判断统计黑白棋子的标志,0统计黑棋,1统计白棋
static int black_white = 1;	

RESULT Qt_Gobang::doDetectionNinth_Game() {
    RESULT result = RESULT::Working;
    caseIndex = 1;
    ninth_gameCount = 1;
    chessCount = 1;
	black_white = 1;

	// 新下的一个棋子为黑色,则赋值0进行黑色棋子统计
	if (m_chessRecords.lastKey() % 2 == 0) {
		black_white = 0;
	}


    do {
        result = detectionNinth_Game();
    } while (result == RESULT::Working);

    return result;
}

/*
 * case 1:  左
 * case 10: 右
 * case 2:  上
 * case 20: 下
 * case 3:  左上
 * case 30: 右下
 * case 4:  右上
 * case 40: 左下
 */


RESULT Qt_Gobang::detectionNinth_Game() {
    RESULT result = RESULT::Working;

    switch (caseIndex) {
        case 1:
			if (m_pointIJ.y() - chessCount >= 0 && Recall(m_pointIJ.x(), m_pointIJ.y() - chessCount, black_white)) {
				ninth_gameCount++;	// “五子连珠”统计个数加一
				chessCount++;		// 辅助统计加一

				// “五子连珠”
				if (ninth_gameCount == 5) {
					result = RESULT::Yes;
				}
				break;
			}

			chessCount = 1;
			caseIndex = 10;
            break;

        case 10:
			if (m_pointIJ.y() + chessCount <= 14 && Recall(m_pointIJ.x(), m_pointIJ.y() + chessCount, black_white)) {
				ninth_gameCount++;
				chessCount++;

				if (ninth_gameCount == 5) {
					result = RESULT::Yes;
				}
				break;
			}

			chessCount = 1;
			caseIndex = 2;
			ninth_gameCount = 1;	// 每开始统计新的方向时,统计“五子连珠”个数赋值1
            break;

        case 2:
			if (m_pointIJ.x() - chessCount >= 0 && Recall(m_pointIJ.x() - chessCount, m_pointIJ.y(), black_white)) {
				ninth_gameCount++;
				chessCount++;

				if (ninth_gameCount == 5) {
					result = RESULT::Yes;
				}
				break;
			}

			chessCount = 1;
			caseIndex = 20;
            break;

        case 20:
			if (m_pointIJ.x() + chessCount <= 14 && Recall(m_pointIJ.x() + chessCount, m_pointIJ.y(), black_white)) {
				ninth_gameCount++;
				chessCount++;

				if (ninth_gameCount == 5) {
					result = RESULT::Yes;
				}
				break;
			}

			chessCount = 1;
			caseIndex = 3;
			ninth_gameCount = 1;
            break;

        case 3:
			if (m_pointIJ.x() - chessCount >= 0 && m_pointIJ.y() - chessCount >= 0 &&
				Recall(m_pointIJ.x() - chessCount, m_pointIJ.y() - chessCount, black_white)) {

				ninth_gameCount++;
				chessCount++;

				if (ninth_gameCount == 5) {
					result = RESULT::Yes;
				}
				break;
			}

			chessCount = 1;
			caseIndex = 30;
            break;

        case 30:
			if (m_pointIJ.x() + chessCount <= 14 && m_pointIJ.y() + chessCount <= 14 &&
				Recall(m_pointIJ.x() + chessCount, m_pointIJ.y() + chessCount, black_white)) {

				ninth_gameCount++;
				chessCount++;

				if (ninth_gameCount == 5) {
					result = RESULT::Yes;
				}
				break;
			}

			chessCount = 1;
			caseIndex = 4;
			ninth_gameCount = 1;
            break;

        case 4:
			if (m_pointIJ.x() - chessCount >= 0 && m_pointIJ.y() + chessCount <= 14 &&
				Recall(m_pointIJ.x() - chessCount, m_pointIJ.y() + chessCount, black_white)) {

				ninth_gameCount++;
				chessCount++;

				if (ninth_gameCount == 5) {
					result = RESULT::Yes;
				}
				break;
			}

			chessCount = 1;
			caseIndex = 40;
			break;

        case 40:
			if (m_pointIJ.x() + chessCount <= 14 && m_pointIJ.y() - chessCount >= 0 &&
				Recall(m_pointIJ.x() + chessCount, m_pointIJ.y() - chessCount, black_white)) {

				ninth_gameCount++;
				chessCount++;

				if (ninth_gameCount == 5) {
					result = RESULT::Yes;
				}
				break;
			}

			result = RESULT::No;
			break;
    }
    
    return result;
}

2. MyThread类

这是一个线程类,作用是(循环)播放音乐的,不知为什么,使用QMediaPlayer进行播放音乐,只能单曲循环,不能循环播放。
于是就想到了使用线程,每十秒钟进行播放一次,当音乐还有在播放时,再每十秒的播放一次是没有任何反应的,当音乐停止后再进行播放就会重新开始播放音乐。

然后就到了循环播放的效果,方便发很笨,但有效…

3. GameTime类

这是一个计时类,下棋计时用的!

4. ReadData类

这是一个读档的操作类。

从数据库中读取表gather_table_name中的所有数据,显示在QTableWidget中!

这样就可以显示当前有多少存档了,选择其中一项,点击读档,就会读取对应表的数据初始化棋盘!

5. SaveData类

这是一个存档的操作类。

简而言之就是存档,数据存档名字后,单击确定就会将档名存入gather_table_name表中,创建一个与档名相同的表,将当前棋盘的数据存进入。

6. Systray类

这是一个系统托盘类。

就是最小化,会显示在系统托盘哪里,然后会提示一下!

7. Ai_Chess类

这是一个人机算法类。

里面的代码和五子连珠类似。

算法思想:
通过遍历全盘坐标,找到符合对应机制的模块,进行加分统计,得到最高分的一个坐标,就将棋子下载哪里。

机制是什么?就是那些活四、冲四、活三、眠三等…具体自己上网看一下,如下图,我写一个简单的文档用于统计分的,在项目中页包含了此文档。
在这里插入图片描述

根据不同的分数机制,就可以控制ai的智能程度。

另外,调节音量大小也是在这个类中实现的。


四、总结

到此就讲解完了。
其实这个项目是在一年前写的,我也一年没有碰过了,都忘记的差不多了,只能讲个大概,代码已经上传,需要的自提回去慢慢研究吧!

  • 2
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cpp_learners

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值