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

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.lryc.cn/news/116107.html

相关文章:

  • ssh 连接断开,正在执行的shell脚本也被中断了
  • UML 用例图,类图,时序图,活动图
  • Java 面试题2023
  • 【CSS3】CSS3 动画 ④ ( 使用动画制作地图热点图 )
  • 命令模式(Command)
  • Dapper 微型orm的光
  • Mysql随心记--第一篇
  • 使用dockerfile安装各种服务组件
  • 如何简单的无人直播
  • 【基于HBase和ElasticSearch构建大数据实时检索项目】
  • ProComponent 用法学习
  • 巨人互动|Google海外户Google Analytics的优缺点是什么?
  • MySQL数据库的操作
  • 人工智能行业岗位一览
  • 《Linux运维实战:Docker基础总结》
  • Clash 意外退出后 chrome / google 谷歌 浏览器无法连接互联网
  • 89 | Python人工智能篇 —— 深度学习算法 Keras 实现 MNIST分类
  • 每天一道leetcode:剑指 Offer 32 - III. 从上到下打印二叉树 III(中等广度优先遍历)
  • day10 快速排序 方法重载 和 方法递推
  • Qt 6. 其他类调用Ui中的控件
  • PHP 的不同版本(src 版、nts 版和 win 版)之间的区别和共同点。
  • 3 vue的if语法
  • python基础3——流程控制
  • kubernetes中最小组件——Pod
  • C++ 友元
  • Vulkan 绘制显示设计
  • Linux性能分析工具介绍(一)--cpu及功耗相关工具介绍
  • 智能财务分析的无冕之王-奥威BI数据可视化工具
  • .NET 应用程序 部署
  • Linux CentOS安装NVIDIA GPU驱动程序和NVIDIA CUDA工具包