C++项目:在线五子棋对战网页版--匹配对战模块开发

玩家匹配是根据自己的天梯分数进行匹配的,而服务器中将玩家天梯分数分为三个档次:

1. 普通:天梯分数小于2000分
2. 高手:天梯分数介于2000~3000分之间
3. 大神:天梯分数大于3000分

当玩家进行对战匹配时,服务器会根据档次,将玩家送到不同档次的匹配队列当中。共有3个匹配队列,分别是普通队列、高手队列和大神队列,每一条队列由单独的线程去控制。因此,匹配对战模块,需要由两个类,一个类是匹配队列的类,另外一个是管理匹配队列的类。

匹配队列类

当玩家进行匹配对战的请求后,服务器会将玩家添加至相应的匹配队列当中,匹配成功后,会从匹配队列中移除该玩家,而在匹配成功前,玩家可能会中止匹配。因此,匹配队列应该包含的功能有入队、出队、和移除指定玩家,玩家处在的位置可能是队列的中间,因此,匹配队列采用的是双向循环链表。在匹配过程中,如果暂时为达到匹配玩家个数,该线程会进入阻塞等待状态,因此需要实现的功能还有阻塞等待的方法,获取队列元素个数、判断队列是否为空的方法。

template<class T>
class match_queue
{
private:/*由于可能要删除中间数据,因此使用双向链表,而不使用队列*/std::list<T> _list;//保证线程安全std::mutex _mutex;//使用条件变量实现阻塞,在队列中元素个数小于2的时候进行阻塞std::condition_variable _cond;
public:/*入队*/void push(T& data){std::unique_lock<std::mutex> lock(_mutex);_list.push_back(data);/*每次有玩家进入匹配队列后,唤醒线程*/_cond.notify_all();}/*出队*/bool pop(T& data){std::unique_lock<std::mutex> lock(_mutex);if(_list.empty()==true){return false;}data = _list.front();_list.pop_front();return true;}/*移除指定元素*/void remove(T& data){std::unique_lock<std::mutex> lock(_mutex);_list.remove(data);}/*获取队列元素个数*/int size(){std::unique_lock<std::mutex> lock(_mutex);return _list.size();}/*判断队列是否为空*/bool empty(){std::unique_lock<std::mutex> lock(_mutex);return _list.empty();}/*阻塞等待*/void wait(){std::unique_lock<std::mutex> lock(_mutex);_cond.wait(lock);}};

匹配队列管理类

在匹配队列管理类中,创建三个线程,每一个线程分别管理着每一条匹配队列:

普通线程管理普通队列,高手线程管理高手队列,大神线程管理大神队列。

而管理的方法是:实现匹配对战:当玩家数量小于2时,线程继续阻塞。大于2时,将两个玩家出队,然后将玩家添加到房间,最后对玩家进行一个匹配成功的响应。

#ifndef __M__MATCHER_H__
#define __M__MATCHER_H__
#include<list>
#include <mutex>
#include <condition_variable>
#include "room.hpp"template<class T>
class match_queue
{
private:/*由于可能要删除中间数据,因此使用双向链表,而不使用队列*/std::list<T> _list;//保证线程安全std::mutex _mutex;//使用条件变量实现阻塞,在队列中元素个数小于2的时候进行阻塞std::condition_variable _cond;
public:/*入队*/void push(T& data){std::unique_lock<std::mutex> lock(_mutex);_list.push_back(data);/*每次有玩家进入匹配队列后,唤醒线程*/_cond.notify_all();}/*出队*/bool pop(T& data){std::unique_lock<std::mutex> lock(_mutex);if(_list.empty()==true){return false;}data = _list.front();_list.pop_front();return true;}/*移除指定元素*/void remove(T& data){std::unique_lock<std::mutex> lock(_mutex);_list.remove(data);}/*获取队列元素个数*/int size(){std::unique_lock<std::mutex> lock(_mutex);return _list.size();}/*判断队列是否为空*/bool empty(){std::unique_lock<std::mutex> lock(_mutex);return _list.empty();}/*阻塞等待*/void wait(){std::unique_lock<std::mutex> lock(_mutex);_cond.wait(lock);}
};class matcher
{
private:/*普通队列*/match_queue<uint64_t> _q_normal;/*高手队列*/match_queue<uint64_t> _q_hight;/*大神队列*/match_queue<uint64_t> _q_super;/*普通线程*/std::thread _th_normal;/*高手线程*/std::thread _th_hight;/*大神线程*/std::thread _th_super;room_manager *_rm;user_table *_ut;online_manager *_om;
private:void handle_match(match_queue<uint64_t>& mq){while(1){/*判断队列中玩家个数是否大于2*/while(mq.size()<2){mq.wait();}/*大于2,将两个玩家出队*/uint64_t uid1,uid2;bool ret = mq.pop(uid1);if(ret==false){continue;}ret = mq.pop(uid2);if(ret==false){continue;}/*两个玩家出队后,获取对应的通信连接,然后判断是否依然连接在线*/wsserver_t::connection_ptr conn1 = _om->get_conn_from_hall(uid1);if(conn1.get()==nullptr){this->add(uid1);continue;}wsserver_t::connection_ptr conn2 = _om->get_conn_from_hall(uid2);if(conn2.get()==nullptr){this->add(uid2);continue;}/*获取连接后,为他们创建房间并且添加进房间*/room_ptr rp = _rm->create_room(uid1,uid2);if(rp.get()==nullptr){this->add(uid1);this->add(uid2);continue;}/*将信息返回*/Json::Value resp;resp["optype"] = "match_success";resp["result"] = true;std::string body;json_util::serialize(resp,body);conn1->send(body);conn2->send(body);}}void _th_normal_entry(){return handle_match(_q_normal);}void _th_hight_entry(){return handle_match(_q_hight);}void _th_super_entry(){return handle_match(_q_super);}
public:matcher(room_manager *rm,user_table* ut,online_manager* om):_rm(rm),_ut(ut),_om(om),_th_normal(std::thread(&matcher::_th_normal_entry,this)),_th_hight(std::thread(&matcher::_th_hight_entry,this)),_th_super(std::thread(&matcher::_th_super_entry,this)){DLOG("游戏匹配模块初始化完毕...");}bool add(uint64_t uid){/*根据uid,获取到玩家的信息*/Json::Value user;bool ret = _ut->select_by_id(uid,user);if(ret==false){DLOG("获取玩家:%d 信息失败",uid);return false;}int score = user["score"].asInt();if(score < 2000){_q_normal.push(uid);}else if(score>=2000 && score < 3000){_q_normal.push(uid);}else{_q_normal.push(uid);}return true;}bool del(uint64_t uid){Json::Value user;bool ret = _ut->select_by_id(uid,user);if(ret==false){DLOG("获取玩家:%d 信息失败",uid);return false;}int score = user["score"].asInt();if(score<2000){_q_normal.remove(uid);}else if(score>=2000 && score<3000){_q_hight.remove(uid);}else{_q_super.remove(uid);}return true;}};#endif

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[分享]STM32G070 串口 乱码 解决方法

硬件 NUCLEO-G070RB 工具 cubemx 解决方法 7bit 改为 8bit printf 配置方法 添加头文件 #include <stdio.h> 添加重定向代码 #ifdef __GNUC__#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)#else#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)#endi…

并发多线程篇

线程的基础知识 面试题1&#xff1a;线程与进程的区别&#xff1f; 面试题2&#xff1a;并行和并发有什么区别&#xff1f; 面试题3&#xff1a;创建线程的方式有哪些&#xff1f; 面试题 4&#xff1a;runnable 和 callable 有什么区别&#xff1f; 面试题5&#xff1a;线程…

Postgresql源码(110)分析dsm动态共享内存分配与共享内存mq实例(dsm/toc接口备忘录)

相关 《Postgresql源码&#xff08;90&#xff09;共享内存申请CreateSharedMemoryAndSemaphores》 《Linux内存映射函数mmap与匿名内存块》 《Linux共享内存与子进程继承》 dsm/toc使用备忘 用dsm框架的流程 评估共享内存大小&#xff1a;多次用shm_toc_estimate_chunk、shm…

Git 快速入门

Git 快速入门 文章目录 Git 快速入门一、代码托管平台&#xff08;远程仓库&#xff09;二、安装Git三、Git的命令实践Git 的四个区域Git 管理代码的3个场景Git 工作区的理念Git 工作区的生命周期Git 版本回退Git 文件重命名Git查看版本提交日志Git StashGit分支Git标签 四、创…

Nginx与docker配置安装

目录&#xff1a; Nginx的安装配置&#xff1a; 1、安装依赖包&#xff1a; 2、下载Nginx安装包&#xff1a; 3、解压Nginx压缩包&#xff1a; 4、配置Nginx编译环境&#xff1a; 5、编译并安装Nginx&#xff1a; 6、安装完Nginx后&#xff0c;可以切换到Nginx的安装目录…

【TypeScript】TS接口interface类型(三)

【TypeScript】TS接口interface类型&#xff08;三&#xff09; 【TypeScript】TS接口interface类型&#xff08;三&#xff09;一、接口类型二、实践使用2.1 常规类型2.2 设置属性只读 readonly2.3 设置索引签名2.4 设置可选属性2.5 函数类型接口 一、接口类型 TypeScript中的…

【肌电图信号分析】通道肌电图并查找收缩周期的数量、振幅、最大值和持续时间(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

arcgis宗地或者地块四至权利人信息提取教程

ARCGIS怎样将图斑四邻的名称及方位加入其属性表 以前曾发表过一篇《 如何把相邻图斑的属性添加在某个字段中》的个人心得,有些会员提出了进一步的要求,不但要相邻图斑的名称,还要求有方位,下面讲一下自己的做法。 基本思路是:连接相邻图斑质心,根据连线的角度确定相邻图斑…

dpkg: error: dpkg frontend lock is locked by another process

问题 在Ubuntu 系统终端用&#xff1a; dpkg -i xxxxxxxxxx.deb 安装软件包的时候&#xff0c;报错 dpkg: error: dpkg frontend lock is locked by another process 方案 找到这个锁文件的进程id lsof /var/lib/dpkg/lock-frontend 再kill 掉 sudo kill -9 PID 删除锁文件 …

SQL-每日一题【1164. 指定日期的产品价格】

题目 产品数据表: Products 写一段 SQL来查找在 2019-08-16 时全部产品的价格&#xff0c;假设所有产品在修改前的价格都是 10 。 以 任意顺序 返回结果表。 查询结果格式如下例所示。 示例 1: 解题思路 1.题目要求我们查找在 2019-08-16 时全部产品的价格&#xff0c;假设所…

处理nacos、tomcat、nginx日志增长过快问题

1.nacos日志清理 修改nacos-logback.xml 将日志级别改为error级&#xff0c;减少info级日志产生量 将<maxHistory>调整为2以下&#xff0c;将 <totalSizeCap>调整为2GB左右 比如&#xff1a; [rootiZ0jlapur4hqjezy8waee0Z logs]# ll -h total 2.1G -rw-r--r-…

[Securinets CTF Quals 2023] PolyLCG DigestiveV2

PolyLCG 第1个题是个LCG问题,通过一堆参数生成两个序列&#xff0c;如果flag位为1则输出x序列为0则输出 y序列 from random import randintxcoeff[2220881165502059873403292638352563283672047788097000474246472547036149880673794935190953317495413822516051735501183996…

设计实现数据库表扩展的7种方式

设计实现数据库表扩展的7种方式 在软件开发过程中&#xff0c;数据库是一项关键技术&#xff0c;用于存储、管理和检索数据。数据库表设计是构建健壮数据库系统的核心环节之一。然而&#xff0c;随着业务需求的不断演变和扩展&#xff0c;数据库表中的字段扩展变得至关重要。 …

[OnWork.Tools]系列 06-屏幕水印

简介 屏幕水印功能主要是在开会分享屏幕的时候在屏幕上增加水印 水印使用 水印启用和颜色设置 水印文字和大小设置 水印间距,透明度,角度调整

centos安装python3的多个版本

标题 原本安装了python3.6&#xff0c;但是又有一个项目需要py3.7&#xff0c;所以需要让两个版本共存 操作 1、下载py3.7 wget https://www.python.org/ftp/python/3.7.3/Python-3.7.3.tgz2、解压 tar -xzvf Python-3.7.3.tgz进入到文件夹 cd Python-3.7.33、安装 本人c…

day10 快速排序 方法重载 和 方法递推

方法重载 斐波拉契数列问题 使用重载思想解决 public static int method(int n){if (n 2 ){return 1 ;}return (n-1)*2method(n-1);}public static int f(int n){if (n 1){return 1;}if (n 2){return 2;}return f(n-1)f(n-2);} 快速排序 思维很简单&#xff0c;类似二…

【从零单排Golang】第十三话:使用WaitGroup等待多路并行的异步任务

在后端开发当中&#xff0c;经常会遇到这样的场景&#xff1a;请求给了批量的输入&#xff0c;对于每一个输入&#xff0c;我们都要给外部发请求等待返回&#xff0c;然后才能继续其它自己的业务逻辑。在这样的case下&#xff0c;如果每一个输入串行处理的话&#xff0c;那么很…

C语言进阶-4

1、常用位操作符 1.1、位与& (1)注意&#xff1a;位与符号是一个&&#xff0c;两个&&是逻辑与。 (2)真值表&#xff1a;1&00 1&11 0&00 0&10 (3)从真值表可以看出&#xff1a;位与操作的特点是&#xff0c;只有1和1位于结果为1&…

Zookeeper 面试题

一、ZooKeeper 基础题 1.1、Zookeeper 的典型应用场景 Zookeeper 是一个典型的发布/订阅模式的分布式数据管理与协调框架&#xff0c;开发人员可以使用它来进行分布式数据的发布和订阅。 通过对 Zookeeper 中丰富的数据节点进行交叉使用&#xff0c;配合 Watcher 事件通知机…

【java】【maven】【高级】MAVEN聚合继承属性等

目录 1、模块开发与设计 2、聚合 2、继承 3、属性 4、版本管理 5、资源配置 6、多环境配置 7、多环境开发配置 8、跳过测试 9、私服 前言&#xff1a;maven的高级使用包含分模块开发与设计、聚合、继承、属性、版本管理、资源配置、多环境配置、多环境开发配置、跳过…