C++五子棋(三)——判断鼠标有效点击
分析
在鼠标左键点击时,我们不能让新棋子在已有棋子的位置落下,同时我们还要让棋子在规定位置落下——棋盘线的交点处。
功能实现
创建数据类型
- 创建头文件chessData.h和源文件chessData.cpp
- 在chessData.cpp和main.cpp中分别引用头文件chessData.h
#include "chessData.h"
- 将之前在main.cpp中写的棋盘数据剪贴到chessData.h中
const float BLOCKSIZE = 67.4;
const int BLOCK_GRAD_SIZE = 13;
- 在chessData.h中定义常量 POS_OFFSET,即鼠标有效点击距离上限
const int POS_OFFSET = BLOCKSIZE * 0.4;
- 在chessData.h定义结构体 ChessData
struct ChessData{
//储存当前游戏棋盘的情况,空白为0,黑棋为1,白棋为-1
int chessMap[BLOCK_GRAD_SIZE][BLOCK_GRAD_SIZE];
//储存各点的评分情况,用于之后的AI走棋
int scoreMap[BLOCK_GRAD_SIZE][BLOCK_GRAD_SIZE];
bool playFlag; //表示下棋放,true黑棋,false白棋(AI)
};
- 在main.cpp中添加全局变量game
ChessData game;
初始化数据类型
- 在chessData.h中添加函数声明
void initChessData(ChessData*);
- 在chessData.cpp
void initChessData(ChessData *data){
if(!data) return;
memset(data->chessMap,0,sizeof(data->chessMap));
memset(data->scoreMap,0,sizeof(data->scoreMap));
data->playFlag = true;
}
判断有效点击
算法原理
实现
- 在main.cpp中添加全局变量
int clickPosRow, clickPosCol; //用于储存点击位置
- 定义函数clickBoard()
//有效点击返回true,无效点击返回false
//MOUSEMSG为鼠标信息类型
bool clickBoard(MOUSEMSG msg){
//(鼠标点击坐标 - 边界长度)/ 格宽 = 行(列)数
//计算列数并取整
int col = (msg.x - MARGIN_X) / BLOCKSIZE;
//计算行数取整
int row = (msg.y - MARGIN_Y) / BLOCKSIZE;
//计算棋子正确坐标,即格子左上角棋子应在的棋盘格线交点处坐标
int leftTopPosX = MARGIN_X + BLOCKSIZE * col;
int leftTopPosY = MARGIN_Y + BLOCKSIZE * row;
}
- 在文件最上方引用头文件math.h用于后期计算
#include <math.h>
- 之后要判断棋子应在四个交点中具体哪一点上,这里我们用一个do-while循环。继续添加clickBoard()函数的定义
int len; //用于计算两点见的距离(根据中学所学两点间距离公式)
int selectPos = false; //作为返回值
do{
//左上角
len = sqrt((msg.x - leftTopPosX)*(msg.x - leftTopPosX) + (y - leftTopPosY)*(msg.y - leftTopPosY));
if(len < POS_OFFSET){
clickPosRow = row;
clickPosCol = col;
if ( game.chessMap[clickPosRow][clickPosCol] == 0 ){
selectPos = true;
}
break;
}
//右上角
len = sqrt((msg.x - leftTopPosX - BLOCKSIZE)*(msg.x - leftTopPosX - BLOCKSIZE) + (y - leftTopPosY)*(msg.y - leftTopPosY));
if(len < POS_OFFSET){
clickPosRow = row;
clickPosCol = col + 1;
if ( game.chessMap[clickPosRow][clickPosCol] == 0 ){
selectPos = true;
}
break;
}
//左下角
len = sqrt((msg.x - leftTopPosX)*(msg.x - leftTopPosX) + (y - leftTopPosY - BLOCKSIZE)*(msg.y - leftTopPosY - BLOCKSIZE));
if(len < POS_OFFSET){
clickPosRow = row + 1;
clickPosCol = col;
if ( game.chessMap[clickPosRow][clickPosCol] == 0 ){
selectPos = true;
}
break;
}
//右下角
len = sqrt((msg.x - leftTopPosX - BLOCKSIZE)*(msg.x - leftTopPosX - BLOCKSIZE) + (y - leftTopPosY - BLOCKSIZE)*(msg.y - leftTopPosY - BLOCKSIZE));
if(len < POS_OFFSET){
clickPosRow = row + 1;
clickPosCol = col + 1;
if ( game.chessMap[clickPosRow][clickPosCol] == 0 ){
selectPos = true;
}
break;
}
}while(0);
return selectPos;
更新底层数据
- chessData.h
void updateGameMap(ChessData* data, int row, int col);
- chessData.cpp
void updateGameMap(ChessData* data, int row, int col){
if(!data) return;
if(data->playFlag){
data->chessMap[row][col] = 1;
}else{
data->chessMap[row][col] = -1;
}
data->playFlag = !data->playFlag; //换下棋方
}
- main.cpp
//玩家走棋
void manGo(){
chessDown(clickPosRow,clickPosCol,CHESS_BLACK);
updateGameMap(&game, clickPosRow, clickPosCol);
}
C++五子棋(三)——判断鼠标有效点击的更多相关文章
- unity3D基础学习 通过判断鼠标点击的是否是目标物体,物体旋转,滑动滚轮缩放拉近视角
贴代码: 摄像机的拉近视角代码: public Transform target; public float minFov = 15f; public float maxFov = 7 ...
- GDI画图,判断鼠标点击点在某一画好的多边形、矩形、图形里
Region.IsVisible方法 简单方便准确 private bool CheckPntInPoly(Point[] points, Point pnt) { || pnt == Point.E ...
- js 如何判断鼠标点击事件还是js代码调用
<html> <head> <meta http-equiv="Content-Type" content="text/html; char ...
- 精通Web Analytics 2.0 (5) 第三章:点击流分析的奇妙世界:指标
精通Web Analytics 2.0 : 用户中心科学与在线统计艺术 第三章:点击流分析的奇妙世界:指标 新的Web Analytics 2.0心态:搞定它.新的闪亮系列工具:是的.准备好了吗?当然 ...
- C#之在treeview中鼠标点击的所选的节点触发事件
一.背景 如下图所示,我想实现通过鼠标点击treeview的根节点,然后在文本框控件中显示鼠标点击的节点号. 二.程序实现 因为是要通过鼠标点击才发生的事情,所以这属于一个事件,需要触发才行,刚开始不 ...
- 【Unity3D】简单常用的功能实现1——鼠标点击实现移动
[鼠标点击实现移动] 第一步,在要移动的GameObject的Inspector面板中添加角色控制器组件并调整参数. 参数的调整可以依照Scene面板,如下图的绿色线框(角色控制器组件是一种胶囊形状的 ...
- JS判断鼠标进入容器方向的方法和分析window.open新窗口被拦截的问题
1.鼠标进入容器方向的判定 判断鼠标从哪个方向进入元素容器是一个经常碰到的问题,如何来判断呢?首先想到的是:获取鼠标的位置,然后经过一大堆的if..else逻辑来确定.这样的做法比较繁琐,下面介绍两种 ...
- JS判断鼠标移入元素的方向
最终效果 这里的关键主要是判断鼠标是从哪个方向进入和离开的 $("li").on("mouseenter mouseleave",function(e) { v ...
- Matlab判断鼠标移动
set(gcf,'WindowButtonMotionFcn',@get_cur_positon); 其中第二项是判断鼠标移动的属性参数,第三项为回调函数 et. main.m clear;clc;s ...
随机推荐
- 通过PROFINET网络实现SINAMICS 120的PN IO OPC通讯,起动及调速控制 | OPC通讯
1 概述 TCP/IP 通讯的传输时间可能太长,并且该时间具有不确定性,无法满足生产自动化领域的要求.因此,在进行时间要求苛刻的IO 有效载荷数据通讯时,PROFINET IO 不使用TCP/IP,而 ...
- 【原创】浅谈指针(十一)alloca函数
前言 好几天没写了,最近网课,事情也比较多,今天多写点东西. 目录 前言 alloca函数 1.简介 2.反汇编看alloca 3.手工调用alloca函数 4.注意事项 alloca函数 1.简介 ...
- HMS Core机器学习服务图像超分能力,基于深度学习提升新闻阅读体验
在移动端阅读资讯时,人们对高分辨率.高质量的图像要求越来越高.但受限于网络流量.存储.图片源等诸多因素,用户无法便捷获得高质量图片.移动端显示设备的高分辨率图片获得问题亟待解决.不久前,HMS Cor ...
- 为MySQL加锁?
在日常操作中,UPDATE.INSERT.DELETE InnoDB会自动给涉及的数据集加排他锁,一般的 SELECT 一般是不加任何锁的.我们可以使用以下方式显示的为 SELECT 加锁. 共享锁: ...
- vue自定义指令?
除核心指令之外的指令, 使用directive进行注册. 指令自定义钩子函数: bind, inserted, update, componentUpdated, unbind
- Linux 中进程有哪几种状态?在 ps 显示出来的信息中,分别用什么符号表示的?
(1)不可中断状态:进程处于睡眠状态,但是此刻进程是不可中断的.不可中断,指进程不响应异步信号. (2)暂停状态/跟踪状态:向进程发送一个 SIGSTOP 信号,它就会因响应该信号 而进入 TASK_ ...
- SpringAOP 失效解决方案、Spring事务失效
SpringAOP 失效解决方案 SpringAOP是基于代理来对目标方法进行增强,但是有的时候又会出现"增强无效"的情况,比如在@Transactional下的某类中的方法内调用 ...
- Delete、truncate、drop都是删除语句,它们有什么分别?
delete 属于DML语句,删除数据,保留表结构,需要commit,可以回滚,如果数据量大,很慢. truncate 属于DDL语句,删除所有数据,保留表结构,自动commit,不可以回滚,一次全部 ...
- kafka的message格式是什么样的?
一个Kafka的Message由一个固定长度的header和一个变长的消息体body组成 header部分由一个字节的magic(文件格式)和四个字节的CRC32(用于判断body消息体是否正常)构成 ...
- 如何在 spring 中启动注解装配?
默认情况下,Spring 容器中未打开注解装配.因此,要使用基于注解装配,我们 必须通过配置 <context:annotation-config/> 元素在 Spring 配置文件 中启 ...