当前位置: 首页 > news >正文

150行代码写一个Qt井字棋游戏

照例先演示一下:

QT井字棋游戏,可以悔棋。

会在鼠标箭头处跟随一个下棋方的小棋子图标。

棋盘和棋子是自己画的,可以自行在对应的代码处更换自己喜欢的图片,不过要注意尺寸兼容。

以棋会友:

井字棋最关键的就是下棋了,我们需要重写窗口的鼠标点击事件,并且根据坐标进行判断。

如果鼠标点击的范围在棋盘里,那么就接着判断此处能否下棋(是否已经有棋子在这个地方了)。

我这里下棋的逻辑是拿一个3*3的vector来缓存下棋状态 ,0为没棋,1为白棋,2为黑棋。

只需要更新缓存更新绘图事件,让绘图事件按照缓存来重绘即可达到下棋的效果 。

每次下棋之后,轮到对方下棋(白棋下完黑棋下),需要将记录谁下棋的标志更新。

为了悔棋的功能,还需要将下棋的坐标存在一个vector里。

void TTT::mousePressEvent(QMouseEvent* e){  //按下鼠标int x = e->x(), y = e->y();if (x >= 65 && x <= 490 && y>=115 && y<=540 ) { //是否在棋盘范围内x -= 65, y -= 115;    //经过测试计算得到的结果,因为棋盘在中间,因此需要减去这些像素值才可以准确判断点击位置对应的缓存位置x /= 140, y /= 140;    //获取对应的缓存下标if (cache[x][y] == 0) { //如果该位置没有棋子就下棋if (iswhite) cache[x][y] = 1;else cache[x][y] = 2;    iswhite = !iswhite;    //更新下棋方last.push_back(vector<int>{x,y});    //添加缓存,用于悔棋check();    //检测是否赢棋以及和棋update();   //手动调用绘图事件}}
}

并且还需要检测落完子之后有没有人赢棋以及是否和棋。

重写一个函数用于检测,因为井字棋是3*3的比较简单,赢棋的情况就8种,所以直接用8条if来判断(试过用for循环来检测,结果还不如8条if来的简洁)。

void TTT::check(){  //检测是否赢棋已经是否和棋bool iswin = false;if (cache[0][0] == cache[0][1] && cache[0][0] == cache[0][2] && cache[0][0] != 0) iswin = true;if (cache[1][0] == cache[1][1] && cache[1][0] == cache[1][2] && cache[1][0] != 0) iswin = true;if (cache[2][0] == cache[2][1] && cache[2][0] == cache[2][2] && cache[2][0] != 0) iswin = true;if (cache[0][0] == cache[1][0] && cache[0][0] == cache[2][0] && cache[0][0] != 0) iswin = true;if (cache[0][1] == cache[1][1] && cache[0][1] == cache[2][1] && cache[0][1] != 0) iswin = true;if (cache[0][2] == cache[1][2] && cache[0][2] == cache[2][2] && cache[0][2] != 0) iswin = true;if (cache[0][0] == cache[1][1] && cache[0][0] == cache[2][2] && cache[0][0] != 0) iswin = true;if (cache[0][2] == cache[1][1] && cache[0][2] == cache[2][0] && cache[0][2] != 0) iswin = true;if (iswin) {    //如果有人赢棋QString who;if (cache[(*(last.end() - 1))[0]][(*(last.end() - 1))[1]] == 1) {   //根据最后一个落子是谁来判断谁赢棋who = QString::fromLocal8Bit("白棋");}else {who = QString::fromLocal8Bit("黑棋");}//弹出提示框,是否继续游戏int check=QMessageBox::question(this, who+QString::fromLocal8Bit("赢了"), who+QString::fromLocal8Bit("赢了,是否重新开始"));if (check == QMessageBox::Yes) {//如果继续游戏,则清空下棋记录,恢复棋盘清空,更新绘图事件cache = { {0,0,0},{0,0,0},{0,0,0} };last.clear();update();return;}//不继续游戏就退出程序.exit(0);}for (int i = 0; i < 3; i++) {   //判断是否和棋,只要有一个地方是0(没下棋)就是没和棋,直接returnfor (int j = 0; j < 3; j++) {if (cache[i][j] == 0) return;}}//弹出提示框,和棋,是否继续游戏,逻辑和上面赢棋的逻辑一样int check = QMessageBox::question(this, QString::fromLocal8Bit("和棋"), QString::fromLocal8Bit("和棋,是否重新开始"));if (check == QMessageBox::Yes) {cache = { {0,0,0},{0,0,0},{0,0,0} };last.clear();update();return;}exit(0);
}

落子无悔:

悔棋这个功能我是后面大致都写完了才想加上去的,然后窗口的大小,棋子的大小,棋盘的大小以及他们的坐标位置我都设计完了,没地方再插一个按钮来悔棋了,所以我直接加在了菜单栏里。

我们在下棋的时候就有把每一步下棋的坐标存起来,想要悔棋的话,我们只需要把最后一个下棋的落子坐标取出,把棋盘缓存中对应的位置改为0(没下棋),然后在更新绘图事件即可。

不要忘了把下棋方再改回去,并且把下棋记录的最后一个删去。

void TTT::initMenubar() {  //初始化菜单栏QMenuBar* qb = new QMenuBar(this);QMenu* item = new QMenu(QString::fromLocal8Bit("选项"), this);QAction* restart = new QAction(QString::fromLocal8Bit("重新开始"), this);QAction* revoke = new QAction(QString::fromLocal8Bit("悔棋"), this);connect(restart, &QAction::triggered, [=]() {   //重新开始//清空下棋记录,恢复棋盘初始状态,更新绘图事件cache = { {0,0,0},{0,0,0},{0,0,0} };last.clear();update();});connect(revoke, &QAction::triggered, [=]() {    //悔棋if (last.size() > 0) {  //如果有下棋记录才能悔棋//将最后一个下棋的位置设为0(没下棋),并且需要把下棋方再变回去(取个反),再把最后一个下棋记录删去cache[(*(last.end() - 1))[0]][(*(last.end() - 1))[1]] = 0;iswhite = !iswhite;last.pop_back();update();}});item->addAction(restart);item->addAction(revoke);QMenu* about = new QMenu(QString::fromLocal8Bit("关于"), this);QAction* me = new QAction(QString::fromLocal8Bit("我"), this);QAction* help = new QAction(QString::fromLocal8Bit("帮助"), this);QAction* quit = new QAction(QString::fromLocal8Bit("退出"), this);quit->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q));connect(quit, &QAction::triggered, this, &QMainWindow::close);connect(me, &QAction::triggered, [=] {QMessageBox::information(this, QString::fromLocal8Bit("这里是折途"), QString::fromLocal8Bit("bilibili:折途想要敲代码/折途想要长高高\nCSDN:折途\n微信公众号:折途想要敲代码"));});connect(help, &QAction::triggered, [=] {QMessageBox::information(this, QString::fromLocal8Bit("使用帮助"), QString::fromLocal8Bit("井字棋游戏 TicTacToe(TTT)"));});about->addAction(me);about->addAction(help);about->addAction(quit);qb->addMenu(about);qb->addMenu(item);qb->setFixedHeight(50);this->setMenuBar(qb);
}

脑袋跟着屁股走:

脑袋跟着屁股走,棋子跟着鼠标走。

从开头的动图可以看出鼠标剪头所指有下棋方的棋子小图标,要做到这个就需要重写窗口的鼠标移动事件,每次鼠标移动我们都更新鼠标的坐标,然后重写调用绘图事件,在相应的位置画上小棋子。

如果直接重写鼠标移动事件函数的话只有在鼠标点击的时候才会调用,我们需要在加上构造函数的开头加上行代码用于设置跟踪鼠标:

setMouseTracking(true);     //设置跟踪获取鼠标坐标,用于更改鼠标指向的棋子

然后重写鼠标移动事件:

void TTT::mouseMoveEvent(QMouseEvent* e){   //实时获取鼠标坐标,用于修改鼠标指向的小图标mouse[0] = e->x();mouse[1] = e->y();update();
}

然后剩下就是绘图事件的工作了。

绘图:

其实要绘的图不多,一个是棋盘,一个是下的棋子,另一个就是跟着鼠标的棋子小图标。

void TTT::paintEvent(QPaintEvent* e){QPainter* p = new QPainter(this);QPixmap board;board.load(":/image/board.png");p->drawPixmap(50,100,board);//绘制已经下过的棋for (int i = 0; i < 3; i++) {for (int j = 0; j < 3; j++) {if (cache[i][j] != 0) {QPixmap piece;if (cache[i][j] == 1) piece.load(":/image/white.png");  //根据缓存的数值决定下什么颜色的棋else piece.load(":/image/black.png");p->drawPixmap(150*i+75,150*j+125,piece);    //下在格子里}}}  //修改鼠标坐标的指向的图片以及位置QPixmap mou;if (iswhite) {mou.load(":/image/white.png");}else {mou.load(":/image/black.png");}mou = mou.scaled(50, 50);p->drawPixmap(mouse[0] - 30, mouse[1] - 30, mou);   //让鼠标在图标的中间p->end();
}

免费领取完整代码:

完整的代码我已经上传到CSDN了,大家可以进入我的主页找到对应资源直接免费下载。

也可以关注我的微信公众号 折途想要敲代码  回复关键词“qt井字棋”免费下载完整代码。

我上传的是VS的完整工程文件,已经自己绘制的图片,如果小伙伴用的是QtCreater,可以直接把cpp和h的文件内容复制过去,再把资源文件配置一下就好啦。

相关文章:

150行代码写一个Qt井字棋游戏

照例先演示一下: QT井字棋游戏&#xff0c;可以悔棋。 会在鼠标箭头处跟随一个下棋方的小棋子图标。 棋盘和棋子是自己画的&#xff0c;可以自行在对应的代码处更换自己喜欢的图片&#xff0c;不过要注意尺寸兼容。 以棋会友&#xff1a; 井字棋最关键的就是下棋了&#xf…...

k8s概念-controller

Controller作用和分类 controller用于控制pod 参考: 工作负载资源 | Kubernetes 控制器主要分为: Deployments 部署无状态应用&#xff0c;控制pod升级,回退 ReplicaSet 副本集,控制pod扩容,裁减 ReplicationController(相当于ReplicaSet的老版本,现在建议使用Deployments…...

Gis入门,根据起止点和一个控制点计算二阶贝塞尔曲线(共三个控制点组成的线段转曲线)

前言 本章讲解如何在gis地图中使用起止点和一个控制点(总共三个控制点)生成二阶贝塞尔曲线。 三阶贝塞尔曲线请参考下一章《Gis入门,使用起止点和两个控制点生成三阶贝塞尔曲线(共四个控制点)》 贝塞尔曲线(Bezier curve)介绍 贝塞尔曲线(Bezier curve)是一种数学…...

第1集丨Vue 江湖 —— Hello Vue

目录 一、简介1.1 参考网址1.2 下载 二、Hello Vue2.1 创建页面2.2 安装Live Server插件2.4 安装 vue-devtools2.5 预览效果 一、简介 Vue&#xff08;读音 /vjuː/, 类似于 view&#xff09; 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是&#xff0c;Vue 被设…...

PCB制版技术

1、在头脑里形成一个原理图----现在就下载AD9盖版&#xff0c;诞生了一个问题&#xff0c;电路板去哪里买&#xff0c;买了怎么焊接电路和芯片&#xff0c;怎样流程化批量制作电子产品 1.1 形成一个PCB板&#xff0c;形成一个结构 1.2 焊接&#xff0c;嫁接&#xff0c;组装等 …...

大数据课程E7——Flume的Interceptor

文章作者邮箱&#xff1a;yugongshiyesina.cn 地址&#xff1a;广东惠州 ▲ 本章节目的 ⚪ 了解Interceptor的概念和配置参数&#xff1b; ⚪ 掌握Interceptor的使用方法&#xff1b; ⚪ 掌握Interceptor的Host Interceptor&#xff1b; ⚪ 掌握Interceptor的…...

P2P网络NAT穿透原理(打洞方案)

1.关于NAT NAT技术&#xff08;Network Address Translation&#xff0c;网络地址转换&#xff09;是一种把内部网络&#xff08;简称为内网&#xff09;私有IP地址转换为外部网络&#xff08;简称为外网&#xff09;公共IP地址的技术&#xff0c;它使得一定范围内的多台主机只…...

Gof23设计模式之桥接外观模式

1.概述 又名门面模式&#xff0c;是一种通过为多个复杂的子系统提供一个一致的接口&#xff0c;而使这些子系统更加容易被访问的模式。该模式对外有一个统一接口&#xff0c;外部应用程序不用关心内部子系统的具体的细节&#xff0c;这样会大大降低应用程序的复杂度&#xff0…...

微服务性能分析工具 Pyroscope 初体验

Go 自带接口性能分析工具 pprof&#xff0c;较为常用的有以下 4 种分析&#xff1a; CPU Profiling: CPU 分析&#xff0c;按照一定的频率采集所监听的应用程序 CPU&#xff08;含寄存器&#xff09;的使用情况&#xff0c;可确定应用程序在主动消耗 CPU 周期时花费时间的位置…...

工作记录------单元测试(持续更新)

工作记录------单元测试 之前的工作中从来没有写过单元测试&#xff0c;新入职公司要求写单元测试&#xff0c; 个人觉得&#xff0c;作为程序员单元测试还是必须会写的 于此记录一下首次编写单元测试的过程。 首先引入单元测试相关的依赖 <dependency><groupId>…...

C#再windowForm窗体中绘画扇形并给其填充颜色

C#再windowForm窗体中绘画扇形并给其填充颜色 Graphics graphics this.CreateGraphics();graphics.SmoothingMode SmoothingMode.AntiAlias;int width this.Width;int height this.Height;h this.Height;w this.Width;Rectangle rct new Rectangle(0 - h / 6, 0 - h / 6…...

MBA拓展有感-见好就收,还是挑战到底?MBA拓展有感-见好就收,还是挑战到底?

今天看到新闻提到某位坚持了14年高考的同学滑档&#xff0c;让人心生感叹&#xff1a;无论在日常工作还是生活中&#xff0c;选择都是非常重要的。不由想起前段时间我参加研究生新生拓展时的一些感悟&#xff0c;和大家分享一下。 事情的起因是拓展活动中的一个分队竞技类的活…...

综合布线系统光缆分类及其特点?

综合布线系统光缆是一种用于数据传输和通信的电缆&#xff0c;常用于建筑物内部网络和通信系统的布线。光缆采用光纤作为传输介质&#xff0c;能够以光的形式传输大量数据&#xff0c;具有高带宽、低延迟、抗干扰等特点&#xff0c;适用于高速数据传输和长距离通信需求。 光缆…...

前端构建(打包)工具发展史

大多同学的前端学习路线&#xff1a;三件套框架慢慢延伸到其他&#xff0c;在这个过程中&#xff0c;有一个词出现的频率很高&#xff1a;webpack 。 作为一个很出名的前端构建工具我们在网上随便一搜&#xff0c;就会有各种教程&#xff1a;loader plugin entry吧啦吧啦。 但…...

【数据可视化】(一)数据可视化概述

目录 0.本章节概述 一、数据可视化 1、什么是数据可视化? 2、数据可视化的好处 3、数据可视化的用途 二、数据探索 1、数据相关工具的使用情景: 2、探索性查询 三、数据挑战 1、什么是数据挑战?...

GoogleLeNet Inception V2 V3

文章目录 卷积核分解第一步分解&#xff0c;对称分解第二步分解&#xff0c;非对称分解在Inception中的改造一般模型的参数节省量可能导致的问题 针对两个辅助分类起的改造特征图尺寸缩减Model Regularization via Label Smoothing——LSR问题描述&#xff0c;也就是LSR解决什么…...

【css】背景图片附着

属性&#xff1a;background-attachment 属性指定背景图像是应该滚动还是固定的&#xff08;不会随页面的其余部分一起滚动&#xff09;。 background-attachment: fixed&#xff1a;为固定&#xff1b; background-attachment: scroll为滚动 代码&#xff1a; <!DOCTYPE h…...

解决运行flutter doctor --android-licenses时报错

问题描述&#xff1a; 配置flutter环境时&#xff0c;会使用flutter doctor命令来检查运行flutter的相关依赖是否配好。能看到还差 Android license status unknown.未解决。 C:\Users\ipkiss.wu>flutter doctor Flutter assets will be downloaded from https://storage.…...

在使用Python爬虫时遇到503 Service Unavailable错误解决办法汇总

在进行Python爬虫的过程中&#xff0c;有时会遇到503 Service Unavailable错误&#xff0c;这意味着所请求的服务不可用&#xff0c;无法获取所需的数据。为了解决这个常见的问题&#xff0c;本文将提供一些解决办法&#xff0c;希望能提供实战价值&#xff0c;让爬虫任务顺利完…...

小研究 - 主动式微服务细粒度弹性缩放算法研究(一)

微服务架构已成为云数据中心的基本服务架构。但目前关于微服务系统弹性缩放的研究大多是基于服务或实例级别的水平缩放&#xff0c;忽略了能够充分利用单台服务器资源的细粒度垂直缩放&#xff0c;从而导致资源浪费。为此&#xff0c;本文设计了主动式微服务细粒度弹性缩放算法…...

【LeetCode】215.数组中的第K个最大元素

题目 给定整数数组 nums 和整数 k&#xff0c;请返回数组中第 k 个最大的元素。 请注意&#xff0c;你需要找的是数组排序后的第 k 个最大的元素&#xff0c;而不是第 k 个不同的元素。 你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。 示例 1: 输入: [3,2,1,5,6,4…...

MySQL学习记录:第七章 存储过程和函数

文章目录 第七章 存储过程和函数一、存储过程1、 创建语法*2、调用语法(1)空参列表(2)创建带in参数模式的存储过程,需终端运行(3)创建带out参数模式的存储过程,需终端运行(4)创建带inout参数模式的存储过程,需终端运行3、删除存储过程4、查看存储过程的信息二、函数…...

Docker中gitlab以及gitlab-runner的安装与使用

1、本文主要讲述如何使用Docker安装gitlab以及gitlab-runner&#xff0c;并且会讲述gitlab-runner如何使用 2、gitlab部分不需要修改过多的配置即可使用&#xff0c;本文未讲述https配置&#xff0c;如有需求&#xff0c;可自行百度 3、Docker如何安装可以自行百度 一、Docker安…...

一起学SF框架系列5.12-spring-beans-数据绑定dataBinding

数据绑定有助于将用户输入动态绑定到应用程序的域模型&#xff08;或用于处理用户输入的任何对象&#xff09;&#xff0c;主要用于web层&#xff0c;但实际可用于任何层。Spring提供了DataBinder来做到这一点&#xff0c;并提供了Validator进行数据验证&#xff0c;两者组成了…...

火热报名中 | 赛宁独家技术支持第七届“蓝帽杯”网络安全技能大赛

由公安部网络安全保卫局、教育部教育管理信息中心、中国教育协会指导&#xff0c;中国人民公安大学主办&#xff0c;奇安信科技集团股份有限公司协办&#xff0c;南京赛宁信息技术有限公司提供技术支持的2023第七届“蓝帽杯”全国大学生网络安全技能大赛于近日正式开启报名。 …...

无涯教程-jQuery - Ajax Tutorial函数

AJAX是用于创建交互式Web应用程序的Web开发技术。如果您了解JavaScript,HTML,CSS和XML,则只需花费一个小时即可开始使用AJAX。 为什么要学习Ajax? AJAX代表 A 同步 Ja vaScript和 X ML。 AJAX是一项新技术,可借助XML,HTML,CSS和Java Script创建更好,更快,更具交互性的Web应用…...

Android日志

Android中的日志工具类是Log&#xff08;android.util.Log&#xff09;&#xff0c;这个类中提供了如下5个方法来供我们打印日志。 Log.v()。用于打印那些最为琐碎的、意义最小的日志信息。对应级别verbose&#xff0c;是Android日志里面级别最低的一种。 Log.d()。用于打印一…...

【Golang 接口自动化08】使用标准库httptest完成HTTP请求的Mock测试

目录 前言 http包的HandleFunc函数 http.Request/http.ResponseWriter httptest 定义被测接口 测试代码 测试执行 总结 资料获取方法 前言 Mock是一个做自动化测试永远绕不过去的话题。本文主要介绍使用标准库net/http/httptest完成HTTP请求的Mock的测试方法。 可能有…...

SpringBoot自定义注解 + AOP+分布式Redis 防止重复提交

第一步 引入依赖pom.xml&#xff1a; <dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>3.16.3</version> <!-- 使用最新版本 --></dependency><dependency><groupId&g…...

3.yum安装分布式LNMP--剧本

文章目录 修改hosts创建剧本文件 修改hosts vim /etc/ansible/hosts[webservers] 192.168.242.67[dbservers] 192.168.242.68[phpservers] 192.168.242.69创建剧本文件 vim lnmp.yaml- name: nginx playhosts: webserversremote_user: rootvars:- http_port: 192.168.242.67:…...