2.8.C++项目:网络版五子棋对战之对战玩家匹配管理模块的设计

news2024/11/18 15:30:29

在这里插入图片描述

文章目录

  • 一、意义
  • 二、功能
  • 三、设计
  • 四、阻塞队列
    • (一)功能
    • (二)框架
    • (三)代码
  • 五、匹配管理
    • (一)功能
    • (二)设计
    • (三)框架
    • (四)代码

一、意义

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

  1. 青铜:天梯分数小于2000分
  2. 白银:天梯分数介于2000~3000分之间
  3. 黄金:天梯分数大于3000分
    而实现玩家匹配的思想非常简单,为不同的档次设计各自的匹配队列,当⼀个队列中的玩家数量大于等于2的时候,则意味着同一档次中,有2个及以上的⼈要进行实战匹配,则出队队列中的前两个用户,相当于队首2个玩家匹配成功,这时候为其创建房间,并将两个用户信息加入房间中。

二、功能

  1. 将所有玩家,根据得分,分为三个档次!
    score < 2000;
    score >= 2000 && score < 3000;
    score >= 3000;
  2. 为三个不同档次创建三个不同的匹配队列!
  3. 如果有玩家想要进行对战匹配,根据玩家分数,将玩家的id,加到指定的队列中!
  4. 当一个队列中元素数量 >= 2,则表示有两个玩家要进行匹配,匹配成功
  5. 出对队列中的前两个元素,为这两个玩家创建房间!
  6. 给匹配成功的玩家,发送匹配响应,对战匹配成功!

三、设计

// 设计:
// 1. 设计一个匹配队列 —— 阻塞队列
// 2. 匹配管理
// 因为匹配队列有三个,因此创建三个线程,阻塞等待指定队列中的玩家数量>=2;

四、阻塞队列

(一)功能

// 设计一个阻塞队列:(目的是为了实现玩家匹配队列)
// 功能:
// 1. 入队数据
// 2. 出队数据
// 3. 移除指定的数据
// 4. 线程安全
// 5. 获取队列元素个数
// 6. 阻塞接
// 7. 判断队列是否为空

(二)框架

template <class T>
class match_queue {
private:
    /*用链表而不直接使用queue是因为我们有中间删除数据的需要*/
    std::list<T> _list;
    /*实现线程安全*/
    std::mutex _mutex;
    /*这个条件变量主要为了阻塞消费者,后边使用的时候:队列中元素个数<2则阻塞*/
    std::condition_variable _cond;
public:
    match_queue();
    ~match_queue();
     /*入队数据,并唤醒线程*/
    bool push(const T& data);
    /*出队数据*/
    bool pop(const T& data);
     /*获取元素个数*/
    int size();
     /*阻塞线程*/
    void wait();
    /*判断是否为空*/
    bool empty();
    /*移除指定的数据*/
    void remove();
};

(三)代码

#include "util.hpp"
#include "online.hpp"
#include "db.hpp"
#include "room.hpp"
#include <list>
#include <mutex>
#include <condition_variable>

#ifndef __M_MATCHER_H__
#define __M_MATCHER_H__
template <class T>
class match_queue {
private:
    /*用链表而不直接使用queue是因为我们有中间删除数据的需要*/
    std::list<T> _list;
    /*实现线程安全*/
    std::mutex _mutex;
    /*这个条件变量主要为了阻塞消费者,后边使用的时候:队列中元素个数<2则阻塞*/
    std::condition_variable _cond;
public:
   /*获取元素个数*/
        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);
        }
        /*入队数据,并唤醒线程*/
        void push(const 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);
        }
};

五、匹配管理

(一)功能

  1. 添加用户到匹配队列
  2. 线程入口函数
    判断指定队列是否热人数大于二
    出对队列中的前两个元素
    创建房间,将两个用户信息添加到房间中
    向两个玩家发送对战匹配成功的消息!
  3. 从匹配队列移除用户

(二)设计

  1. 三个不同档次的队列
  2. 三个线程分别对三个队列中的玩家进行匹配
  3. 房间管理模块的句柄
  4. 在线用户管理模块的句柄
  5. 数据管理模块——用户表的句柄

(三)框架

class matcher {
    private:
        /*普通选手匹配队列*/
        match_queue<uint64_t> _q_normal;
        /*高手匹配队列*/
        match_queue<uint64_t> _q_high;
        /*大神匹配队列*/
        match_queue<uint64_t> _q_super;
        /*对应三个匹配队列的处理线程*/
        std::thread _th_normal;
        std::thread _th_high;
        std::thread _th_super;

        room_manager *_rm;
        user_table *_ut;
        online_manager *_om;
    private:
        void th_normal_entry() { 
            return handle_match(_q_normal); 
        }
        void th_high_entry() { 
            return handle_match(_q_high); 
        }
        void th_super_entry() { 
            return handle_match(_q_super); 
        }
    public:
        matcher(room_manager *rm, user_table *ut, online_manager *om);
        bool add(uint64_t uid);
        bool del(uint64_t uid);
};

(四)代码

// 匹配管理:
// 1. 三个不同档次的队列
// 2. 三个线程分别对三个队列中的玩家进行匹配
// 3. 房间管理模块的句柄
// 4. 在线用户管理模块的句柄
// 5. 数据管理模块——用户表的句柄
// 功能:
// 1. 添加用户到匹配队列
// 2. 线程入口函数
//     判断指定队列是否热人数大于二
//     出对队列中的前两个元素
//     创建房间,将两个用户信息添加到房间中
//     向两个玩家发送对战匹配成功的消息!
// 3. 从匹配队列移除用户

class matcher {
    private:
        /*普通选手匹配队列*/
        match_queue<uint64_t> _q_normal;
        /*高手匹配队列*/
        match_queue<uint64_t> _q_high;
        /*大神匹配队列*/
        match_queue<uint64_t> _q_super;
        /*对应三个匹配队列的处理线程*/
        std::thread _th_normal;
        std::thread _th_high;
        std::thread _th_super;

        room_manager *_rm;
        user_table *_ut;
        online_manager *_om;
    private:
        void handle_match(match_queue<uint64_t> &mq) {
            while(1) {
                //1. 判断队列人数是否大于2,<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) { 
                    this->add(uid1); 
                    continue; 
                }
                //3. 校验两个玩家是否在线,如果有人掉线,则要吧另一个人重新添加入队列
                wsserver_t::connection_ptr conn1 = _om->get_conn_from_hall(uid1);
                if (conn1.get() == nullptr) {
                    this->add(uid2); 
                    continue;
                }
                wsserver_t::connection_ptr conn2 = _om->get_conn_from_hall(uid2);
                if (conn2.get() == nullptr) {
                    this->add(uid1); 
                    continue;
                }
                //4. 为两个玩家创建房间,并将玩家加入房间中
                room_ptr rp = _rm->create_room(uid1, uid2);
                if (rp.get() == nullptr) {
                    this->add(uid1);
                    this->add(uid2);
                    continue;
                }
                //5. 对两个玩家进行响应
                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_high_entry() { 
            return handle_match(_q_high); 
        }
        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_high(std::thread(&matcher::th_high_entry, this)),
            _th_super(std::thread(&matcher::th_super_entry, this)){
            DLOG("游戏匹配模块初始化完毕....");
        }
        bool add(uint64_t uid) {
            //根据玩家的天梯分数,来判定玩家档次,添加到不同的匹配队列
            // 1. 根据用户ID,获取玩家信息
            Json::Value user;
            bool ret = _ut->select_by_id(uid, user);
            if (ret == false) {
                DLOG("获取玩家:%d 信息失败!!", uid);
                return false;
            }
            int score = user["score"].asInt();
            // 2. 添加到指定的队列中
            if (score < 2000) {
                _q_normal.push(uid);
            }else if (score >= 2000 && score < 3000) {
                _q_high.push(uid);
            }else {
                _q_super.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();
            // 2. 添加到指定的队列中
            if (score < 2000) {
                _q_normal.remove(uid);
            }else if (score >= 2000 && score < 3000) {
                _q_high.remove(uid);
            }else {
                _q_super.remove(uid);
            }
            return true;
        }
};
#endif

今天是10月24日,一年一度的程序员节。 心之所向,一往无前,每跨越一次1024,技术人又向前迈进一步。 心怀梦想,坚守技术,技术人的脚下之路,也将更加坚定。 在今天这个日子,祝福所有的技术人节日快乐!

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

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

相关文章

GoLand设置Go Modules的Environment信息

在golang中&#xff0c;如果没有设置环境信息&#xff0c;就不会自动下载go.mod中设置的包&#xff0c;这时候&#xff0c;我们就需要设置一下环境信息 GOPROXYhttps://goproxy.cn,direct 图片如下&#xff1a;

【机器学习】集成学习Boosting

文章目录 集成学习BoostingAdaBoost梯度提升树GBDTXGBoostxgboost库sklearn APIxgboost库xgboost应用 集成学习 集成学习&#xff08;ensemble learning&#xff09;的算法主要包括三大类&#xff1a;装袋法&#xff08;Bagging&#xff09;&#xff0c;提升法&#xff08;Boo…

Python基础入门例程10-NP10 牛牛最好的朋友们

目录 描述 输入描述&#xff1a; 输出描述&#xff1a; 示例1 解答&#xff1a; 说明&#xff1a; 描述 牛牛有两个最好的朋友&#xff0c;他们的名字分别用input读入记录在两个字符串中&#xff0c;请使用字符串连接&#xff08;&#xff09;帮助牛牛将两个朋友的名字依…

大灰狼远程管理[SVIP3会员版]易语言源码

大灰狼远程管理[SVIP3会员版]易语言源码 下载地址&#xff1a;https://user.qzone.qq.com/512526231/main https://user.qzone.qq.com/3503787372/main

实验六:DHCP、DNS、Apache、FTP服务器的安装和配置

1. (其它) 掌握Linux下DHCP、DNS、Apache、FTP服务器的安装和配置&#xff0c;在Linux服务器上部署JavaWeb应用 完成单元八的实训内容。 1、安装 JDK 2、安装 MySQL 3、部署JavaWeb应用 安装jdk 教程连接&#xff1a;linux安装jdk8详细步骤-CSDN博客 Jdk来源&#xff1a;linu…

自动驾驶之—2D到3D升维

前言&#xff1a; 最近在学习自动驾驶方向的东西&#xff0c;简单整理一些学习笔记&#xff0c;学习过程中发现宝藏up 手写AI 3D卷积 3D卷积的作用&#xff1a;对于2DCNN&#xff0c;我们知道可以很好的处理单张图片中的信息&#xff0c;但是其对于视频这种由多帧图像组成的图…

分类预测 | MATLAB实现SSA-CNN-GRU-Attention数据分类预测(SE注意力机制)

分类预测 | MATLAB实现SSA-CNN-GRU-Attention数据分类预测&#xff08;SE注意力机制&#xff09; 目录 分类预测 | MATLAB实现SSA-CNN-GRU-Attention数据分类预测&#xff08;SE注意力机制&#xff09;分类效果基本描述模型描述程序设计参考资料 分类效果 基本描述 1.MATLAB实现…

【软考系统架构设计师】2021年系统架构师综合知识真题及解析

本文主要分享2021年下半年系统架构师综合知识历年真题以及本人在做题时的所思所想。题目序号有点混乱&#xff0c;可忽略 【01】.某计算机系统页面大小为4K&#xff0c;进程P1的页面变换表如下图所示&#xff0c;看P1要访问数据的逻辑地址为十六进制1B1AH,那么该逻辑地址经过变…

2023CPSE安博会倒计时1天!英码科技参展5大亮点抢先看~

第十九届中国国际社会公共安全博览会 暨全球数字城市产业博览会 距离开幕仅剩1天 英码科技将精彩亮相1号馆 展位号为&#xff1a;1A06 展会期间重点展示 创新性的国产AI智能硬件 AI技术服务以及热门的行业解决方案 2023CPSE安博会基本信息 展会时间&#xff1a;10月25-27日&am…

深度学习第四课

第九章 卷积神经网络解读 9.1 计算机视觉 目标分类 目标识别 64x64x312288 1000x1000x33000000 使用传统神经网络处理机器视觉面临的一个挑战是&#xff1a;数据的输入会非常大 一般的神经网络很难处理海量图像数据。解决这一问题的方法就是卷积神经网络 9.2 卷积运算 …

分代ZGC详解

ZGC&#xff08;Z Garbage Collector&#xff09;是Java平台上的一种垃圾收集器&#xff0c;它是由Oracle开发的&#xff0c;旨在解决大堆的低延迟垃圾收集问题。ZGC是一种并发的分代垃圾收集器&#xff0c;它主要针对具有大内存需求和低停顿时间要求的应用程序 分代ZGC收集器…

Vue的MVVM实现原理

目录 前言 用法 代码和效果图 效果图 理解 高质量的使用 前言 MVVM是Model-View-ViewModel的缩写&#xff0c;是一种软件架构设计模式。Vue.js实现了这种设计模式&#xff0c;通过双向数据绑定和虚拟DOM技术&#xff0c;使得数据和视图能够快速响应彼此的变化。了解Vue的…

标准库STM32F1_USART2_DMA接收发送数据源码分享直接复制能用

标准库STM32F1_USART2_DMA接收发送数据源码分享直接复制能用 STM32的DMA通道表&#xff1a; 现有一个小需求&#xff0c;使用STM32F1系列单片机做串口2的收发数据的功能&#xff0c;通过PC上的串口调试助手给单片机发一串数据&#xff0c;单片机收到数据后再给PC的串口调试助手…

selenium安装和python中基本使用

selenium安装和python中基本使用 背景下载和安装浏览器驱动115.xx版本之前驱动下载115.xx及之后的高版本驱动 配置浏览器驱动安装selenium使用selenium点击按钮搜索内容 背景 selenium 出现的初衷就是一个自动化测试工具&#xff0c;她可以打开浏览器&#xff0c;然后像用户一…

软件测试进阶篇----自动化测试脚本开发

自动化测试脚本开发 一、自动化测试用例开发 1、用例设计需要注意的点 2、设计一条测试用例 二、脚本开发过程中的技术 1、线性脚本开发 2、模块化脚本开发&#xff08;封装线性代码到方法或者类中。在需要的地方进行调用&#xff09; 3、关键字驱动开发&#xff1a;selen…

php 数组基础/练习

数组 练习在最后 数组概述 概述与定义 数组中存储键值对 数组实际上是一个有序映射 key-value&#xff0c;可将其当成真正的数组、列表&#xff08;向量&#xff09;、散列表、字典、集合、栈、队列等 数组中的元素可以是任意类型的数据对象&#xff08;可以嵌套数组&#…

AI作画使用指南

AI作画API使用文档请前往&#xff1a;https://blog.csdn.net/qq_48896417/article/details/132520804 一、定义 AI作画使用指南 二、形式 「公式」 图片主体&#xff0c;细节词&#xff0c;修饰词 细节词可以任意组合&#xff0c;修饰词可以限定一种风格&#xff0c;也可以…

永恒之蓝 ms17-010

文章目录 永恒之蓝 ms17-0101. 漏洞介绍1.1 影响版本1.2 漏洞原理 2. 信息收集2.1 主机扫描2.2 端口扫描 3. 漏洞探测4. 漏洞利用5. 特殊情况5.1 安装wine32环境5.2 安装攻击32位操作系统所用的的脚本 永恒之蓝 ms17-010 很久之前做过的永恒之蓝漏洞… 1. 漏洞介绍 永恒之蓝…

【STM32】RCC时钟模块(使用HAL库)

https://gitee.com/linhir-linhir/stm32-f103-c8/blob/master/STM32%E6%9C%80%E6%96%B0%E5%9B%BA%E4%BB%B6%E5%BA%93v3.5/Libraries/STM32F10x_StdPeriph_Driver/inc/stm32f10x_rcc.h STM32最新固件库v3.5/Libraries/CMSIS/CM3/DeviceSupport/ST/STM32F10x/system_stm32f10x.c…

Linux环境开发工具yum、makefile的使用 【Linux】

文章目录 Linux软件包管理器 - yumLinux下安装软件的方式yum查找软件包如何实现本地机器和云服务器之间的文件互传卸载软件Linux编译器 - gcc/g 程序的翻译过程1.预编译&#xff08;预处理&#xff09;2.编译&#xff08;生成汇编&#xff09;3.汇编&#xff08;生成机器可识别…