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

在这里插入图片描述

一、意义

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

  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,技术人又向前迈进一步。 心怀梦想,坚守技术,技术人的脚下之路,也将更加坚定。 在今天这个日子,祝福所有的技术人节日快乐!

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值