《QT实用小工具·六十九》基于QT开发的五子棋AI游戏

1、概述
源码放在文章末尾

该项目实现了五子棋对战AI,可以享受和AI下棋的快乐,项目实现思路如下:
博弈树

●Alpha-Beta剪枝(性能提高较大)

●启发式搜索(性能提高较大)

●落子区域限制(性能提高较大)

●Zobrist哈希(性能小幅提升)

●Qt多线程计算避免界面卡死

●小概率走法剔除

仅进行Alpha-Beta剪枝+落子区域限制,思考两层,计算量在3k-9k,2s内计算完毕;思考四层,计算量在9k-20w,2s~20min内计算完毕.

+启发式搜索,思考两层,思考两层,计算量在900-2k,1s内计算完毕;思考四层,计算量在3k-3w,2s~20s内计算完毕.

+小概率走法剔除,思考两层,思考两层,计算量在24-60,1s内计算完毕;思考5层,计算量在2k-3k,1s内计算完毕;思考7层,计算量在8k-3w,2min~10min内计算完毕

项目界面图如下所示:
在这里插入图片描述
项目部分代码如下所示:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QPainter>
#include <QPen>
#include <QDebug>
#include <QMouseEvent>
#include <QString>
#include <vector>
#include <QMessageBox>
#include <random>
#include <ctime>
#include <map>
#include <cmath>
#include <algorithm>
#include <QThread>
#include <QTime>
#include <unordered_map>
#define QOUT qDebug()

enum patternID{
  LongLink=0,
  Active4,
  Sleep4,
  Active3,
  Sleep3,
  Active2,
  Sleep2,
  Dead4,
  Dead3,
  Dead2
};

struct step{
  int x;
  int y;
  bool nowWhite;
  int score;
  step(int xx=0,int yy=0,bool nw=true){
    x=xx;
    y=yy;
    nowWhite=nw;
  }
};


struct pattern{
  std::vector<QString> whitePattern;
  std::vector<QString> blackPattern;
  int id;
  int whiteScore;
  int blackScore;
  void clear(){
    whitePattern.clear();
    blackPattern.clear();
  }
};

namespace Ui {
  class MainWindow;
}

class MainWindow;
class AI:public QObject{
  Q_OBJECT
public:
  AI();
  AI(MainWindow *p):parentWindow(p){}
  int count;
private:
  MainWindow* parentWindow;

public slots:
  void getAINextStep();
 public:

  int getChessScore(int chess[15][15],int leftEdge=0,int rightEdge=14,int upEdge=0,int downEdge=14);
  int getLineScore(QString,int whitePatternNum[10],int blackPatternNum[15]);
  std::vector<step> getPossibleSteps(int chess[15][15],bool white,int leftEdge=0,int rightEdge=14,int upEdge=0,int downEdge=14);
  int alpha_beta(int chess[15][15], int depth, int alpha, int beta);
  bool calculateScore(std::vector<step>& possibleSteps,int chess[15][15]);
  void deleteUselessStep(std::vector<step>& possibleSteps,int chess[15][15]);
  bool reserveKillStep(std::vector<step>& possibleSteps,int chess[15][15]);
  signals:
  void stepReady();
};


class MainWindow : public QMainWindow
{
  Q_OBJECT
friend class AI;
public:
  explicit MainWindow(QWidget *parent = 0);
  ~MainWindow();
  void paintEvent(QPaintEvent *e);
  void mousePressEvent(QMouseEvent *e);
  void keyPressEvent(QKeyEvent *e);
public slots:
  void handleAIStep();
signals:
  void AIShouldMove();
private:
  QThread AIThread;
  bool gameOver;
  int searchDepth;//搜索深度,应当是偶数
  int killStepSearchDepth;
  int stepAlreadyMade;//已经走的步数
  Ui::MainWindow *ui;
  const int gap=20;
  constexpr static int boxNum=14;
  const int boxWidth=gap*boxNum;
  const int startX=30;
  const int startY=30;
  bool nowWhite;//记录当前是否是白子 白色=1 黑色=2
  int gomoku[boxNum+1][boxNum+1];
  int gomokuForPaint[boxNum+1][boxNum+1];
  bool judge(int x,int y,bool nowWhite);
  bool judge(int chess[15][15],int x, int y, bool nowWhite);
  int steps;//用于设定搜索范围的步数
  int AINextX;
  int AINextY;
  bool AIIsThinking;
  std::vector<pattern> patterns;//储存算分的模式
  std::vector<pattern> lightPatterns;//排序走法用的模式
  int zobristHash;

  std::unordered_map<int,int> scoreCache;
  bool debug;

  int basicScore[15][15]={
    { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
    { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 },
    { 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0 },
    { 0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0 },
    { 0, 1, 2, 3, 4, 4, 4, 4, 4, 4, 4, 3, 2, 1, 0 },
    { 0, 1, 2, 3, 4, 5, 5, 5, 5, 5, 4, 3, 2, 1, 0 },
    { 0, 1, 2, 3, 4, 5, 6, 6, 6, 5, 4, 3, 2, 1, 0 },
    { 0, 1, 2, 3, 4, 5, 6, 7, 6, 5, 4, 3, 2, 1, 0 },
    { 0, 1, 2, 3, 4, 5, 6, 6, 6, 5, 4, 3, 2, 1, 0 },
    { 0, 1, 2, 3, 4, 5, 5, 5, 5, 5, 4, 3, 2, 1, 0 },
    { 0, 1, 2, 3, 4, 4, 4, 4, 4, 4, 4, 3, 2, 1, 0 },
    { 0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0 },
    { 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0 },
    { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 },
    { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } };
  int zobristWhite[15][15];
  int zobristBlack[15][15];
  int XStack[250];//从1开始算
  int YStack[250];//从1开始算
  void initPattern();//初始化算分模式
public slots:
  void restartGame();
  void regret();

};

#endif // MAINWINDOW_H

源码下载

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/666068.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

香港云服务器好还是国内的好?

香港云服务器与国内云服务器各有其优点和缺点&#xff0c;选择哪种类型的云服务器主要取决于业务需求、用户群体、网络需求以及成本考虑。以下是对两者进行详细比较的内容。 首先&#xff0c;从网络速度和稳定性来看&#xff0c;香港云服务器具有独特的优势。由于香港是全球数据…

vue-Dialog 自定义title样式

展示结果 vue代码 <el-dialog :title"title" :visible.sync"classifyOpen" width"500px" :showClose"false" class"aboutDialog"> <el-form :model"classifyForm" :rules"classifyRules">…

移动电商服务器单点部署

知识图谱 任务一&#xff1a;Web服务器部署 1.知识结构 2.WEB服务器的介绍 Web服务器一般指网站服务器&#xff0c;是指驻留于因特网上提供某种特定类型计算机的程序&#xff0c;Web服务器可以向浏览器等Web客户端提供文档&#xff0c;也可以放置网站文件&#xff0c;让全世界…

红外超声波雷达测距(water)

文章目录 一 RS-232二 RS485三 Modbus四 stm32多路超声波测距4.1 设计方案4.2 代码 参考资料总结 实验要求 一. 采用stm32F103和HC-SR04超声波模块&#xff0c; 使用标准库或HAL库 定时器中断&#xff0c;完成1或2路的超声波障碍物测距功能。 1&#xff09;测试数据包含噪声&am…

Rasa.3X中使用lookup实现对实体的抽取

rasa3.6的DIETClassifier实体提取器不准确&#xff0c;使用RegexEntityExtractor的实体提取器替换。在实战过程解决以下两个问题&#xff1a; 1、RegexEntityExtractor实体提取器的应用 首先在domain.yml中明确对应的实体以及意图&#xff1a; version: "3.0" ent…

数据治理(三)-平台架构

数据治理大致分为两类&#xff0c;一种贴合业务&#xff0c;特殊情况特殊治理&#xff1b;另外一种平台型治理&#xff0c;不考虑具体业务。本文从一个平台数据架构师视角去理解数据治理。 1.什么是治理 数据管理治理 数据治理的职能是指导其他所有的数据管理职能。数据治理的…

CMake的原理与使用方法

一.为什么需要CMake&#xff0c;什么是CMake 1.由于各种make工具遵循不同的规范和标准&#xff0c;所执行的Makefile格式也不同&#xff0c;例如 GNU Make &#xff0c;QT 的 qmake &#xff0c;微软的 MS nmake&#xff0c;BSD Make&#xff08;pmake&#xff09;&#xff0c;…

【JAVA入门】Day06 - 字符串

【JAVA入门】Day06 - 字符串 文章目录 【JAVA入门】Day06 - 字符串一、API二、字符串2.1 创建 String 对象的方式2.2 字符串内存模型 三、字符串的相关操作3.1 字符串的比较3.2 遍历字符串3.3 统计字符出现次数3.4 拼接字符串3.5 字符串反转 四、StringBuilder3.1 构造方法3.2 …

束测后台实操文档2-OpenWrt

束测后台实操文档1-PVE、PBS 上面文&#xff0c;把proxmox装好并添加好PBS上的镜像存储空间后&#xff0c;还原已经做好的镜像基本上就可以在已有的镜像下开展工作了。 调试的PVE环境一般两个网口&#xff0c;一个外网wan&#xff0c;一个子网lan&#xff0c;虚拟机一般在lan…

体验Photoshop:无需下载,直接在浏览器编辑图片

搜索Photoshop时&#xff0c;映入眼帘的是PS软件下载&#xff0c;自学PS软件需要多长时间&#xff0c;学PS软件有必要报班吗...PS软件的设计功能很多&#xff0c;除了常见的图像处理功能外&#xff0c;还涉及图形、文本、视频、出版等。不管你是平面设计师&#xff0c;UI/UX设计…

可变参数

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 在Python中&#xff0c;还可以定义可变参数。可变参数也称不定长参数&#xff0c;即传入函数中的实际参数可以是任意多个。 定义可变参数时&#xf…

植物大战僵尸杂交版破解C++实现

文章目录 前言准备工作&#xff1a;基地址与偏移UI界面设计和绑定项目模板总览图生成与实现信号处理1、阳光值更新:BTN12、三种钱币值更新:BTN2-BTN43、冷却刷新:BTN54、锁定阳光&#xff1a;check15、无冷却&#xff1a;check26、OnTimer&#xff08;&#xff09;和OnClose&am…

Linux上传文件

在finalshell中连接的Linux系统中&#xff0c;输入命令rz然后选择windows中的文件即可。

透视茅台股东大会三大关键词:稳定、竞争力、创新

执笔 | 尼 奥 编辑 | 扬 灵 “让我们携手共同致力于茅台的稳定、健康、可持续发展。”上任刚满一个月的贵州茅台党委书记、董事长张德芹&#xff0c;在5月29日的贵州茅台酒股份有限公司2023年度股东大会上迎来首秀。 张德芹在40多分钟脱稿演讲与30多分钟互动环节中&#x…

TiDB学习9:Ti Cloud简介

目录 1. 为什么选择TiDB 2. 多租户 3. TiDB架构 4. 什么是TiDB Cloud 5. TiDB Cloud Provider Region 6. TiDB Cloud 入门 6.1 在浏览器中打开TiDB Cloud 6.2 创建您的账户 6.3 Developer Tier 与Dedicated Tier 6.3.1 Developer Tier 6.3.2 Dedicated Tier 6.3.2.…

项目纪实 | 版本升级操作get!GreatDB分布式升级过程详解

某客户项目现场&#xff0c;因其业务系统要用到数据库新版本中的功能特性&#xff0c;因此考虑升级现有数据库版本。在升级之前&#xff0c;万里数据库项目团队帮助客户在本地测试环境构造了相同的基础版本&#xff0c;导入部分生产数据&#xff0c;尽量复刻生产环境进行升级&a…

【NVM】nvm常用命令,切换node版本命令

nvm常用的命令&#xff0c;切换node版本命令 nvm 查看支持安装的node版本 nvm list available nvm安装指定版本node nvm install 版本号 例如&#xff1a;nvm install 10.24.1 nvm查看本机安装所有node版本 nvm list nvm切换node版本 nvm use 10.24.1 检测当前node版本 node -…

玄机平台应急响应—Linux日志分析

1、前言 啥是日志呢&#xff0c;日志就是字面意思&#xff0c;用来记录你干了啥事情。日志大体可以分为网站日志和系统日志&#xff0c;网站日志呢就是记录哪个用户在哪里什么时候干了啥事&#xff0c;以及其它的与网站相关的事情。系统日志呢&#xff0c;就是记录你的电脑系统…

动态分配函数参数用二级指针的作用

文章目录 前言一、案例 前言 在一些情况下&#xff0c;我们需要在函数内部动态地分配内存来存储结构体&#xff0c;并且需要在函数外部访问该结构体。在这种情况下&#xff0c;可以使用二级指针作为函数参数来实现动态内存分配&#xff0c;并且在函数外部使用指针访问结构体。…

12V转19V4A升压恒压WT3207

12V转19V4A升压恒压WT3207 WT3207是款高效的PWM升压控制器&#xff0c;采用SO-8封装设计。该控制器经过优化以适应低输入电压应用&#xff0c;具有从5V至36V的广泛输入电压范围&#xff0c;适用于需要提高12V、15V和19V系统电压的场合&#xff0c;特别是对于两节或三节锂离子电…