C++ Easyx 三子棋
目录
思路
框架编辑
读取操作
数据操作
绘制画面
游戏的数据结构
用二维数组来模拟棋盘格
赢的情况
平局情况
Code
代码细节部分
(1)初始化棋盘格
(2) 初始化棋子类型编辑
事件处理部分
落子
框架内代码的完善
数据处理框架代码的完善
检查是否赢了 (函数)
绘制图形框架代码的完善
绘制棋盘网格(函数)
绘制棋子 (函数)
绘制提示信息 (函数)
DBUG
优化
代码托管
三子棋/Test.cpp · 孙鹏宇/孙鹏宇的第一个仓库 - 码云 - 开源中国 (gitee.com)
思路
我们遵循先框架,后思路得的思路
框架
首先是读取操作:
读取操作
读取鼠标单击之后的信息

接下来是数据操作:
数据操作
我们只需要对游戏胜负进行判断
胜的清空:一条线三颗棋子都一样
平的情况:棋格全部填满还未分出胜负。
游戏结束时使用弹出告诉玩家游戏结果,然后退出主循环。
绘制画面
我们使用line函数绘制一个3*3的棋盘格:


x玩家时使用line函数对角线画两个线,轮到O玩家落子时时使用cirlce函数画个圆:

游戏的数据结构
用二维数组来模拟棋盘格
棋盘内容为字符串,初始化为‘-'

赢的情况
我们对赢得情况进行穷举:
一共有八种
平局情况
如果9个网格均被棋子填满却没有获胜的一方,那么就是平局:
Code
写代码同样遵循先框架再细节的原则:
我们先把上面的内容转化为代码:
框架:
#include<easyx.h>
#include<iostream>
using namespace std;//处理数据// //检测玩家是否赢了
bool Checkwin(char str)
{}
//检测是否平局
bool Checkavg(char str)
{}//绘制图像
//
//绘制棋盘格
void DrawBorad()
{}
//绘制棋子
void DrawPiece()
{}
//绘制提示信息
void DrawTipText()
{}
int main()
{initgraph(60,600);//绘制窗口bool flag = true;//退出主循环的标识列ExMessage msg;//存储消息BeginBatchDraw();//渲染缓冲区//主循环while (flag){//读取操作while(peekmessage(&msg))//读取消息{//读取到的细节如何处理稍息再说}cleardevice();//清屏//重新绘图DrawBorad();DrawPiece();DrawTipText();FlushBatchDraw();//刷新缓冲区}EndBatchDraw();//刷新缓冲区return 0;
}
代码细节部分
如果 x玩家赢了,我们可以用MessageBox()函数弹出了一个框,显示x玩家赢了:

代码如下:
同样的,O玩家获胜的情况和平局的情况也写一下:

设置两个全局
(1)初始化棋盘格
(2) 初始化棋子类型
事件处理部分
用msg来表示鼠标的位置:
怎么把鼠标的位置映射到数组下标呢?我们绘制的棋盘格的大小为600x600,分成三等份之后每个格子的大小为200x200:
所以我们求横坐标可以有这样一个公式:
代码为:
落子
(1)首先判断是否可以落子
(2) 落完子之后要切换下次落子的棋子类型

框架内代码的完善
把之前只写了框架没写实现的函数补全:

数据处理框架代码的完善
检查是否赢了 (函数)
按照我们之前列的八种赢的情况写:
Checkavg()函数
用两个for循环来遍历棋盘格中每一个元素,如果还有空格没有落子就返回false代表没有平局,最后如果没有返回false说明平局了,返回true:

绘制图形框架代码的完善
绘制棋盘网格(函数)
棋盘格的网格其实就是四条线:
我们可以通过图形绘制相关函数->line()函数来绘制:

首先棋盘格总大小是600x600,每个小格子是200x200:


绘制棋子 (函数)
(1)绘制棋子,首先用二维数组遍历一下棋盘,如果要落的棋子是'O',那就在棋格中间画圆。
(2)棋盘中心的求法:一个小格子长宽200x200,中心坐标为左上角坐标+100:
(3)画圆的方法:
(4)当棋子为'x'时就按小格子对角线画两条线
(5)对角线点求法:如下图
(6)画对角线的方法:
(7)如果不是'O'或者',那就什么都不用做。
(8)代码:
绘制提示信息 (函数)
适用settextcolor()函数将提示文本设高亮:

outtextxy()函数用来在窗口指定位置输出提示信息:

code:
DBUG
这样三子棋基本功能就做好了,但是有bug:
(1)闪退
(2)闪退过程中可以看见我们画的棋盘,发现棋盘网格线条错位:
原因:
(1)绘制棋盘时手误
(2)闪退的原因是我们在判断是否平局用的else,没设条件,此刻没输值就直接平局了(只要不是'O',‘x’就直接平局了),这显示不是我们要的,我们想要的是棋盘满了还没赢才平局,因此我们应该引用checkagv()函数。

修改:
修改完之后运行:
发现有两个错误
(1)鼠标左键不用点击,就可以落子
(2)落子位置和我们鼠标落点位置不配置

鼠标左键不用点击,就可以落子的原因:
应该选择ExMessage的WM_LBUTTONDOWN表实列,我选成第一个了:
落子位置不配置的原因:
(1)切换棋子类型应该包含在可以落子的前提下,如果不能落子也就没必要切换棋子类型了:
修改之后:
(2)
二维数组是按照横纵坐标系的:
但是我们的窗口确是纵横坐标系:

错误:

修改:
交互功能正常,但是渲染功能有问题,最后一颗棋子不会显示:
原因:
我们把重新绘图放在判断胜负的后面,当玩家赢了的时候会执行flag=fale,此时会执行重新绘图。
当再次循环时,flag因为false,所以退出循环。也就是绘图只执行了一次,一闪而过。

我们把绘图放到胜负判断之前,这样即便是不再进入循环,也是最后一次落子的下一次绘图不会显示,而最后一次落子的绘图会显示在当前窗口。

正常运行:

优化
当我们的程序跑起来之后,查看任务管理器,发现我们的程序消耗内存空间特别大;
这是因为计算机在执行while循环时特别快,我们编写的主循环在顷刻间已经被执行了成千上万次。
因此,为了不避免的销毁,我们可以使用sleep()函数使循环休眠几毫秒。
我们可以在主循环开头写一个开始数获取GetTickCount(),主循环结束位置写一个结尾数获取GetTickCount()函数。
通过计算 二者落差 可以得到 该主循环实际运行所需要的 毫秒数,简称实需数。
如果我们想在60帧率下刷新,那么就让1000/60=16,16为我们的期望值。
如果 实需数 < 期望值,说明不用休眠。
否则,实需数-期望值= 休眠数。
代码托管
三子棋/Test.cpp · 孙鹏宇/孙鹏宇的第一个仓库 - 码云 - 开源中国 (gitee.com)
相关文章:
C++ Easyx 三子棋
目录 思路 框架编辑 读取操作 数据操作 绘制画面 游戏的数据结构 用二维数组来模拟棋盘格 赢的情况 平局情况 Code 代码细节部分 (1)初始化棋盘格 (2) 初始化棋子类型编辑 事件处理部分 落子 框架内代码的完善 数据处…...
[NAND Flash 2.1] NAND Flash 闪存改变了现代生活
依公知及经验整理,原创保护,禁止转载。 专栏 《深入理解NAND Flash》 <<<< 返回总目录 <<<< 1989年NAND闪存面世了,它曾经且正在改变了我们的日常生活。 NAND 闪存发明之所以伟大,是因为,…...
2015年五一杯数学建模B题空气污染问题研究解题全过程文档及程序
2015年五一杯数学建模 B题 空气污染问题研究 原题再现 近十年来,我国 GDP 持续快速增长,但经济增长模式相对传统落后,对生态平衡和自然环境造成一定的破坏,空气污染的弊病日益突出,特别是日益加重的雾霾天气已经干扰…...
java面试题,上楼梯有多少种方式
java面试题,上楼梯有多少种方式 题目:一个小孩上一个N级台阶的楼梯,他可以一次走1阶、2阶或3阶,那么走完N阶有多少种方式。 很自然的想法是使用递归: public class Test04 { public static int countWays(int n) {…...
8.HTTP工作原理
HTTP是什么 HTTP工作原理 HTTP协议的请求类型和响应状态码 总结 1.HTTP是什么 HTTP超文本传输协议就是在一个网络中上传下载文件的一套规则 2.HTTP工作原理 HTTP超文本传输协议的本质是TCP通信,链接—>请求—>响应—>断开 3.HTTP协议的请求类型和响应状…...
环境部署的学习笔记(Docker)
1 前言 在现场测试时,常常需要在现场机器上搭建开发环境,此时使用容器会是一个比较方便的途径; 2 常见的容器技术 2.1 Docker⭐️31k:目前使用最为广泛的容器技术 2.2 Nix⭐️13.8k:镜像文件占用会比Docker少 Chat…...
Navicat在分辨率不同的屏幕窗口显示大小不一致问题解决
1.主屏幕为2560*1600分辨率,能够显示较多数据连接 2.在第二屏幕分辨率低,字体变大,显示内容变少 解决办法: 1.右击navicat图标-属性 2.选择【兼容性】-在兼容性页面中选择**“更改高DPI设置”** 3…勾选“高DPI缩放替代”&a…...
通过代码搞明白JAVA中值传递和引用传递
public static void main(String[] args) {Map a new HashMap();a.put("a", 1);System.out.println(a "我在main中的值");aaa(a);System.out.println(a "我在main中的值");bbb(a);System.out.println(a "我在main中的值");int b …...
ambari 开启hdfs回收站机制
hdfs回收站类似于我们常用的windows中的回收站,被删除的文件会被暂时存储于此,和回收站相关的参数有两个: fs.trash.interval:默认值为0 代表禁用回收站,其他值为回收站保存文件时间,单位为分钟 fs.trash…...
服务器数据恢复—服务器重装系统导致逻辑卷发生改变的数据恢复案例
服务器数据恢复环境: 某品牌linux操作系统服务器,服务器中有4块SAS接口硬盘组建一组raid5阵列。服务器中存放的数据有数据库、办公文档、代码文件等。 服务器故障&检测: 服务器在运行过程中突然瘫痪,管理员对服务器进行了重装…...
软件工程之架构设计
从公众号转载,关注微信公众号掌握更多技术动态 --------------------------------------------------------------- 一、架构设计的目的 1.什么是复杂的软件项目 复杂的软件项目通常有两个特点: 需求不确定 技术复杂 技术的复杂性主要体现在四个方面…...
oracle java.sql.SQLException: Invalid column type: 1111
1.遇到的问题 org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.type.TypeException: Could not set parameters for mapping: ParameterMapping{propertyuuid, modeIN, javaTypeclass java.lang.String, jdbcTypenull, numericScalenull, r…...
Mac 浏览器下载的文件名总是「乱码」
如果可以实现记得点赞分享,谢谢老铁~ 本文所说的方法是在出现文件名乱码情况下,如何恢复文件名的正确中文名称,并非一劳永逸地避免乱码的出现。这是由于下载文件名称乱码的出现,往往是系统、浏览器、网站三方面因素共…...
Redis Reactor事件驱动模型源码
前置学习:Redis server启动源码-CSDN博客 1、Redis服务器启动的时候就会就一直在轮询。 // 运行事件处理器,一直到服务器关闭为止 aeSetBeforeSleepProc(server.el,beforeSleep); aeMain(server.el);// 服务器关闭,停止事件循环 aeDeleteEven…...
cv2.error: OpenCV(4.7.0)
运行hsv脚本报错: cv2.error: OpenCV(4.7.0) D:\a\opencv-python\opencv-python\opencv\modules\imgproc\src\color.cpp:182: error: (-215:Assertion failed) !_src.empty() in function cv::cvtColor 解决方案: 这个错误信息是在使用OpenCV的cvtColor函…...
10.vue3项目(十):spu管理页面的sku的新增和修改
目录 一、sku静态页面的搭建 1.思路分析 2.代码实现 3.效果展示...
Java LeetCode篇-深入了解二叉树经典解法(三种方式实现:获取二叉树的最大深度)
🔥博客主页: 【小扳_-CSDN博客】 ❤感谢大家点赞👍收藏⭐评论✍ 文章目录 1.0 对称二叉树 1.1 判断对称二叉树实现思路 1.2 代码实现:判断对称二叉树 2.0 二叉树的最大深度 2.1 使用递归实现获取二叉树的最大深度思路 2.2 代码实…...
Image Segmentation Using Deep Learning: A Survey
论文标题:Image Segmentation Using Deep Learning:A Survey作者:发表日期:阅读日期 :研究背景:scene understanding,medical image analysis, robotic perception, video surveillance, augmented reality, and image…...
可视化开源编辑器Swagger Editor本地部署并实现远程访问管理编辑文档
最近,我发现了一个超级强大的人工智能学习网站。它以通俗易懂的方式呈现复杂的概念,而且内容风趣幽默。我觉得它对大家可能会有所帮助,所以我在此分享。点击这里跳转到网站。 文章目录 Swagger Editor本地接口文档公网远程访问1. 部署Swagge…...
Java TCP协议实现一对一聊天与UDP协议实现群聊案例
JavaTCP协议实现一对一聊天与UDP协议实现群聊案例 1.TCP协议实现一对一聊天 1.1服务端运行结果 1.2客服端运行结果 1.3代码汇总 服务端 package twentyone;import java.io.IOException; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.…...
conda相比python好处
Conda 作为 Python 的环境和包管理工具,相比原生 Python 生态(如 pip 虚拟环境)有许多独特优势,尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处: 一、一站式环境管理:…...
iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘
美国西海岸的夏天,再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至,这不仅是开发者的盛宴,更是全球数亿苹果用户翘首以盼的科技春晚。今年,苹果依旧为我们带来了全家桶式的系统更新,包括 iOS 26、iPadOS 26…...
springboot 百货中心供应链管理系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,百货中心供应链管理系统被用户普遍使用,为方…...
label-studio的使用教程(导入本地路径)
文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...
K8S认证|CKS题库+答案| 11. AppArmor
目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作: 1)、切换集群 2)、切换节点 3)、切换到 apparmor 的目录 4)、执行 apparmor 策略模块 5)、修改 pod 文件 6)、…...
Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件
今天呢,博主的学习进度也是步入了Java Mybatis 框架,目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学,希望能对大家有所帮助,也特别欢迎大家指点不足之处,小生很乐意接受正确的建议&…...
STM32标准库-DMA直接存储器存取
文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA(Direct Memory Access)直接存储器存取 DMA可以提供外设…...
关键领域软件测试的突围之路:如何破解安全与效率的平衡难题
在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件,这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下,实现高效测试与快速迭代?这一命题正考验着…...
uniapp 开发ios, xcode 提交app store connect 和 testflight内测
uniapp 中配置 配置manifest 文档:manifest.json 应用配置 | uni-app官网 hbuilderx中本地打包 下载IOS最新SDK 开发环境 | uni小程序SDK hbulderx 版本号:4.66 对应的sdk版本 4.66 两者必须一致 本地打包的资源导入到SDK 导入资源 | uni小程序SDK …...
苹果AI眼镜:从“工具”到“社交姿态”的范式革命——重新定义AI交互入口的未来机会
在2025年的AI硬件浪潮中,苹果AI眼镜(Apple Glasses)正在引发一场关于“人机交互形态”的深度思考。它并非简单地替代AirPods或Apple Watch,而是开辟了一个全新的、日常可接受的AI入口。其核心价值不在于功能的堆叠,而在于如何通过形态设计打破社交壁垒,成为用户“全天佩戴…...

