2.6.C++项目:网络版五子棋对战之数据管理模块-游戏房间管理模块的设计

在这里插入图片描述

文章目录

  • 一、意义
  • 二、功能
  • 三、作用
  • 四、游戏房间类基本框架
  • 五、游戏房间管理类基本框架
  • 七、游戏房间类代码
  • 八、游戏房间管理类代码

一、意义

对匹配成功的玩家创建房间,建立起一个小范围的玩家之间的关联关系!
房间里一个玩家产生的动作将会广播给房间里的其他用户。

二、功能

将这些房间管理起来,以便于进行房间生命周期的控制!

三、作用

  • 游戏房间类:
    // 实现两个部分:
    // 1. 房间的设计
    // 2. 房间管理的设置
    // 游戏房间的设计:
    // 管理的数据,处理房间中产生的动作
    // 1. 房间的ID
    // 2. 房间的状态(决定了一个玩家退出房间时所作的动作)
    // 3. 房间中玩家的数量(决定了玩家什么时候销毁)
    // 4. 白棋玩家id
    // 5. 黑棋玩家id
    // 6. 用户信息表的句柄(当玩家胜利/失败的时候更新用户数据)
    // 7. 棋盘信息(二维数组)
    // 房间中产生的动作:
    // 1. 下棋
    // 2. 聊天
    // 不管是什么动作,只要是合理的,都要广播给房间里的其他用户!
  • 游戏房间管理类:
    // Restful 风格的网络通信接口设计:
    // 房间管理:
    // 1. 创建房间 (两个玩家对战匹配完成了,为他们创造一个房间,需要传入两个玩家的用户id)
    // 2. 查找房间 (通过房间id查找房间信息,通过用户id查找房间所在信息)
    // 3. 销毁房间 (根据房间id销毁房间,房间中所有用户退出了,销毁房间)
    // 需要管理的数据:
    // 1. 数据管理模块句柄
    // 2. 在线用户管理模块句柄
    // 3. 房间id分配计数器
    // 4. 互斥锁
    // using room_ptr = std::shared_ptr; 房间信息的空间使用shared_ptr进行管理,释放了我们还操作,访问错误!
    // 5. unordered_map<room_id,room_ptr> 房间信息管理(建立起房间id与房间信息的映射关系)
    // 6. unordered_map<room_id,user_id> 房间id与用户id的关联关系管理! 通过用户id找到所在房间id,再去查找房间信息!
    // 7. 房间中所有用户退出了,销毁房间。

四、游戏房间类基本框架

typedef enum { GAME_START, GAME_OVER }room_statu;
class room {private:// 1. 房间的ID// 2. 房间的状态(决定了一个玩家退出房间时所作的动作)// 3. 房间中玩家的数量(决定了玩家什么时候销毁)// 4. 白棋玩家id// 5. 黑棋玩家id// 6. 用户信息表的句柄(当玩家胜利/失败的时候更新用户数据)// 7. 棋盘信息(二维数组)uint64_t _room_id;room_statu _statu;int _player_count;uint64_t _white_id;uint64_t _black_id;user_table *_tb_user; online_manager *_online_user;std::vector<std::vector<int>> _board;public:room()~room()/*处理下棋动作*/room_statu statu();int player_count();void add_white_user(uint64_t uid);void add_black_user(uint64_t uid);uint64_t get_white_user();uint64_t get_black_user();void handle_chess(Json::Value &req);/*处理聊天动作*/Json::Value handle_chat(Json::Value &req);/*处理玩家退出房间动作*/void handle_exit(uint64_t uid);/*将指定的信息广播给房间中所有玩家*/void broadcast(Json::Value &rsp);
};

五、游戏房间管理类基本框架

using room_ptr = std::shared_ptr<room>;class room_manager {private:uint64_t _next_rid;std::mutex _mutex;user_table *_tb_user;online_manager *_online_user;std::unordered_map<uint64_t, room_ptr> _rooms;std::unordered_map<uint64_t, uint64_t> _users;room_manager();~room_manager();//为两个用户创建房间,并返回房间的智能指针管理对象room_ptr create_room(uint64_t uid1, uint64_t uid2);/*通过房间ID获取房间信息*/room_ptr get_room_by_rid(uint64_t rid);/*通过用户ID获取房间信息*/room_ptr get_room_by_uid(uint64_t uid);/*通过房间ID销毁房间*/void remove_room(uint64_t rid);/*删除房间中指定用户,如果房间中没有用户了,则销毁房间,用户连接断开时被调用*/void remove_room_user(uint64_t uid);
};

七、游戏房间类代码

#ifndef __M_ROOM_H__
#define __M_ROOM_H__
#include "util.hpp"
#include "logger.hpp"
#include "online.hpp"
#include "db.hpp"
#define BOARD_ROW 15
#define BOARD_COL 15
#define CHESS_WHITE 1
#define CHESS_BLACK 2
typedef enum { GAME_START, GAME_OVER }room_statu;
class room {private:// 1. 房间的ID// 2. 房间的状态(决定了一个玩家退出房间时所作的动作)// 3. 房间中玩家的数量(决定了玩家什么时候销毁)// 4. 白棋玩家id// 5. 黑棋玩家id// 6. 用户信息表的句柄(当玩家胜利/失败的时候更新用户数据)// 7. 棋盘信息(二维数组)uint64_t _room_id;room_statu _statu;int _player_count;uint64_t _white_id;uint64_t _black_id;user_table *_tb_user; online_manager *_online_user;std::vector<std::vector<int>> _board;private: bool five(int row, int col, int row_off, int col_off, int color) {//row和col是下棋位置,  row_off和col_off是偏移量,也是方向int count = 1;int search_row = row + row_off;int search_col = col + col_off;while(search_row >= 0 && search_row < BOARD_ROW &&search_col >= 0 && search_col < BOARD_COL &&_board[search_row][search_col] == color) {//同色棋子数量++count++;//检索位置继续向后偏移search_row += row_off;search_col += col_off;}search_row = row - row_off;search_col = col - col_off;while(search_row >= 0 && search_row < BOARD_ROW &&search_col >= 0 && search_col < BOARD_COL &&_board[search_row][search_col] == color) {//同色棋子数量++count++;//检索位置继续向后偏移search_row -= row_off;search_col -= col_off;}return (count >= 5);}uint64_t check_win(int row, int col, int color) {// 从下棋位置的四个不同方向上检测是否出现了5个及以上相同颜色的棋子(横行,纵列,正斜,反斜)if (five(row, col, 0, 1, color) || five(row, col, 1, 0, color) ||five(row, col, -1, 1, color)||five(row, col, -1, -1, color)) {//任意一个方向上出现了true也就是五星连珠,则设置返回值return color == CHESS_WHITE ? _white_id : _black_id;}return 0;}public:room(uint64_t room_id, user_table *tb_user, online_manager *online_user):_room_id(room_id), _statu(GAME_START), _player_count(0),_tb_user(tb_user), _online_user(online_user),_board(BOARD_ROW, std::vector<int>(BOARD_COL, 0)){DLOG("%lu 房间创建成功!!", _room_id);}~room() {DLOG("%lu 房间销毁成功!!", _room_id);}uint64_t id() { return _room_id; }room_statu statu() { return _statu; }int player_count() { return _player_count; }void add_white_user(uint64_t uid) { _white_id = uid; _player_count++;}void add_black_user(uint64_t uid) {_black_id = uid; _player_count++; }uint64_t get_white_user() { return _white_id; }uint64_t get_black_user() { return _black_id; }// 处理下棋动作Json::Value handle_chess(Json::Value &req) {Json::Value json_resp = req;// 2. 判断房间中两个玩家是否都在线,任意一个不在线,就是另一方胜利。int chess_row = req["row"].asInt();int chess_col = req["col"].asInt();uint64_t cur_uid = req["uid"].asUInt64();if (_online_user -> is_in_game_room(_white_id) == false) {json_resp["result"] = true;json_resp["reason"] = "运气真好!对方掉线,不战而胜!";json_resp["winner"] = (Json::UInt64)_black_id;return json_resp;}if (_online_user->is_in_game_room(_black_id) == false) {json_resp["result"] = true;json_resp["reason"] = "运气真好!对方掉线,不战而胜!";json_resp["winner"] = (Json::UInt64)_white_id;return json_resp;}// 3. 获取走棋位置,判断当前走棋是否合理(位置是否已经被占用)if (_board[chess_row][chess_col] != 0) {json_resp["result"] = false;json_resp["reason"] = "当前位置已经有了其他棋子!";return json_resp;}int cur_color = cur_uid == _white_id ? CHESS_WHITE : CHESS_BLACK;_board[chess_row][chess_col] = cur_color;// 4. 判断是否有玩家胜利(从当前走棋位置开始判断是否存在五星连珠)uint64_t winner_id = check_win(chess_row, chess_col, cur_color);if (winner_id != 0) {json_resp["reason"] = "五星连珠,您获胜了!";}json_resp["result"] = true;json_resp["winner"] = (Json::UInt64)winner_id;return json_resp;}/*处理聊天动作*/Json::Value handle_chat(Json::Value &req) {Json::Value json_resp = req;// 检查消息中是否包含敏感词std::string msg = req["message"].asString();size_t pos = msg.find("sb");if (pos != std::string::npos) {json_resp["result"] = false;json_resp["reason"] = "消息中包含敏感词,不能发送!";return json_resp;}//广播消息---返回消息json_resp["result"] = true;return json_resp;}/*处理玩家退出房间动作*/void handle_exit(uint64_t uid) {//如果是下棋中退出,则对方胜利,否则下棋结束了退出,则是正常退出Json::Value json_resp;if (_statu == GAME_START) {uint64_t winner_id = (Json::UInt64)(uid == _white_id ? _black_id : _white_id);json_resp["optype"] = "put_chess";json_resp["result"] = true;json_resp["reason"] = "对方掉线,不战而胜!";json_resp["room_id"] = (Json::UInt64)_room_id;json_resp["uid"] = (Json::UInt64)uid;json_resp["row"] = -1;json_resp["col"] = -1;json_resp["winner"] = (Json::UInt64)winner_id;uint64_t loser_id = winner_id == _white_id ? _black_id : _white_id;_tb_user->win(winner_id);_tb_user->lose(loser_id);_statu = GAME_OVER;broadcast(json_resp);}//房间中玩家数量--_player_count--;return;}void handle_request(Json::Value &req) {//1. 校验房间号是否匹配Json::Value json_resp;uint64_t room_id = req["room_id"].asUInt64();if (room_id != _room_id) {json_resp["optype"] = req["optype"].asString();json_resp["result"] = false;json_resp["reason"] = "房间号不匹配!";return broadcast(json_resp);}//2. 根据不同的请求类型调用不同的处理函数if (req["optype"].asString() == "put_chess") {json_resp = handle_chess(req);if (json_resp["winner"].asUInt64() != 0) {uint64_t winner_id = json_resp["winner"].asUInt64();uint64_t loser_id = winner_id == _white_id ? _black_id : _white_id;_tb_user->win(winner_id);_tb_user->lose(loser_id);_statu = GAME_OVER;}}else if (req["optype"].asString() == "chat") {json_resp = handle_chat(req);}else {json_resp["optype"] = req["optype"].asString();json_resp["result"] = false;json_resp["reason"] = "未知请求类型";}std::string body;json_util::serialize(json_resp, body);DLOG("房间-广播动作: %s", body.c_str());return broadcast(json_resp);}/*将指定的信息广播给房间中所有玩家*/void broadcast(Json::Value &rsp) {//1. 对要响应的信息进行序列化,将Json::Value中的数据序列化成为json格式字符串std::string body;json_util::serialize(rsp, body);//2. 获取房间中所有用户的通信连接//3. 发送响应信息wsserver_t::connection_ptr wconn = _online_user->get_conn_from_room(_white_id);if (wconn.get() != nullptr) {wconn->send(body);}else {DLOG("房间-白棋玩家连接获取失败");}wsserver_t::connection_ptr bconn = _online_user->get_conn_from_room(_black_id);if (bconn.get() != nullptr) {bconn->send(body);}else {DLOG("房间-黑棋玩家连接获取失败");}return;}
};

八、游戏房间管理类代码

using room_ptr = std::shared_ptr<room>;class room_manager {
private:uint64_t _next_rid;std::mutex _mutex;user_table *_tb_user;online_manager *_online_user;std::unordered_map<uint64_t, room_ptr> _rooms;std::unordered_map<uint64_t, uint64_t> _users;
public:/*初始化房间ID计数器*/room_manager(user_table *ut, online_manager *om):_next_rid(1), _tb_user(ut), _online_user(om) {DLOG("房间管理模块初始化完毕!");}~room_manager() { DLOG("房间管理模块即将销毁!"); }//为两个用户创建房间,并返回房间的智能指针管理对象room_ptr create_room(uint64_t uid1, uint64_t uid2) {// 两个用户在游戏大厅中进行对战匹配,匹配成功后创建房间// 1. 校验两个用户是否都还在游戏大厅中,只有都在才需要创建房间。if (_online_user->is_in_game_hall(uid1) == false) {DLOG("用户:%lu 不在大厅中,创建房间失败!", uid1);return room_ptr();}if (_online_user->is_in_game_hall(uid2) == false) {DLOG("用户:%lu 不在大厅中,创建房间失败!", uid2);return room_ptr();}// 2. 创建房间,将用户信息添加到房间中std::unique_lock<std::mutex> lock(_mutex);room_ptr rp(new room(_next_rid,_tb_user,_online_user));rp->add_white_user(uid1);rp->add_black_user(uid2);//3. 将房间信息管理起来_rooms.insert(std::make_pair(_next_rid, rp));_users.insert(std::make_pair(uid1, _next_rid));_users.insert(std::make_pair(uid2, _next_rid));_next_rid++;//4. 返回房间信息return rp;}/*通过房间ID获取房间信息*/room_ptr get_room_by_rid(uint64_t rid) {std::unique_lock<std::mutex> lock(_mutex);auto it = _rooms.find(rid);if (it == _rooms.end()) {return room_ptr();}return it->second;}/*通过用户ID获取房间信息*/room_ptr get_room_by_uid(uint64_t uid) {std::unique_lock<std::mutex> lock(_mutex);//1. 通过用户ID获取房间IDauto uit = _users.find(uid);if (uit == _users.end()) {return room_ptr();}uint64_t rid = uit->second;//2. 通过房间ID获取房间信息auto rit = _rooms.find(rid);if (rit == _rooms.end()) {return room_ptr();}return rit->second;}/*通过房间ID销毁房间*/void remove_room(uint64_t rid) {//因为房间信息,是通过shared_ptr在_rooms中进行管理,因此只要将shared_ptr从_rooms中移除//则shared_ptr计数器==0,外界没有对房间信息进行操作保存的情况下就会释放//1. 通过房间ID,获取房间信息room_ptr rp = get_room_by_rid(rid);if (rp.get() == nullptr)return ;//2. 通过房间信息,获取房间中所有用户的IDuint64_t uid1 = rp->get_white_user();uint64_t uid2 = rp->get_black_user();//3. 移除房间管理中的用户信息std::unique_lock<std::mutex> lock(_mutex);_users.erase(uid1);_users.erase(uid2);//4. 移除房间管理信息_rooms.erase(rid);}/*删除房间中指定用户,如果房间中没有用户了,则销毁房间,用户连接断开时被调用*/void remove_room_user(uint64_t uid) {room_ptr rp = get_room_by_rid(uid);if (rp.get() == nullptr)return ;rp->handle_exit(uid);if (rp->player_count() == 0) {remove_room(rp->id());}return ;}
};#endif

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

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

相关文章

基本的爬虫工作原理

爬虫是一种自动化程序&#xff0c;能够模拟人类的浏览行为&#xff0c;从网络上获取数据。爬虫的工作原理主要包括网页请求、数据解析和数据存储等几个步骤。本文将详细介绍爬虫的基本工作原理&#xff0c;帮助读者更好地理解和应用爬虫技术。 首先&#xff0c;爬虫的第一步是…

I/O模型之非阻塞IO

简介 五种IO模型   阻塞IO   非阻塞IO   信号驱动IO   IO多路转接    异步IO 代码书写 非阻塞IO 再次理解IO 什么是IO&#xff1f;什么是高效的IO&#xff1f; 为了理解后面的一个问题&#xff0c;我们首先要再重新理解一下什么是IO 在之前的网络介绍中&#xff…

如何使用Flutter开发执行操作系统shell命令的工具

简介 Flutter是一种由Google开发的移动应用程序开发框架&#xff0c;它允许开发人员使用单个代码库构建高性能、高质量的移动体验。而Android终端命令行工具则允许用户在Android手机上运行类似于Linux的操作系统命令。本文的目的是介绍如何在Flutter应用中开发一个Android终端命…

CUDA学习笔记(二)CUDA简介

本篇博文转载于https://www.cnblogs.com/1024incn/tag/CUDA/&#xff0c;仅用于学习。 CUDA是并行计算的平台和类C编程模型&#xff0c;我们能很容易的实现并行算法&#xff0c;就像写C代码一样。只要配备的NVIDIA GPU&#xff0c;就可以在许多设备上运行你的并行程序&#xf…

什么是马尔科夫随机场?

马尔科夫随机场&#xff0c;也称为马尔可夫网&#xff08;Markov Network&#xff09;&#xff0c;是一种概率图模型&#xff0c;用于表示随机变量之间的依赖关系。它是由若干个随机变量组成的无向图&#xff0c;其中节点代表随机变量&#xff0c;边代表它们之间的相互作用或依…

Node.js的crypto模块 加密

Node.js的crypto模块提供了许多加密和解密功能&#xff0c;包括对称加密、非对称加密、哈希函数等。在本篇文章中&#xff0c;我们将详细介绍Node.js的crypto模块的API、代码注释和举例。 加密和解密 对称加密 对称加密算法使用相同的密钥进行加密和解密&#xff0c;例如AES…

Android 13.0 进入recovery模式(等待用户选择recovery模式界面)进入自动恢复出厂设置模式

1.概述 在13.0的系统产品开发中,由于产品硬件有按钮,按钮执行恢复出厂设置功能,需要实现自动恢复出厂设置的功能,这就需要去掉等待输入recovery模式的相关代码,改成默认恢复出厂模式就实现这个功能了 2.进入recovery模式(等待用户选择recovery模式界面)进入自动恢复出厂设…

浅谈uniapp中开发安卓原生插件

其实官方文档介绍的比较清楚而且详细,但是有时候他太墨迹,你一下子找不到自己想要的,所以我总结了一下开发的提纲,也是为了自己方便下次使用。 1.第一步,下载官方提供的Android的示例工程,然后倒入UniPlugin-Hello-AS工程请在App离线SDK中查找,之后Android studio,编译运行项目…

自编efi文件测试vmware虚拟机如何进入UEFI环境

同事突然让帮忙编一下UEFI&#xff0c;之前完全没有接触过&#xff0c;在此粗鲁记录其过程。 UEFI的开源框架是edk2&#xff0c;开发环境配置起来还是有些麻烦&#xff0c;完全按照文档编译不过&#xff0c;经人帮助总算编译通过&#xff0c;但如何测试又是问题&#xff1b;网…

【T+】畅捷通T+增加会计科目提示执行超时已过期。

【问题描述】 在畅捷通T软件中&#xff0c; 增加会计科目的时候提示&#xff1a; 通过DataTable插入ext扩展表出错:执行超时已过期。 完成操作之前已超时或服务器未响应。 操作已被用户取消。 语句已终止。 【解决方法】 【方法一】 注销用户登录&#xff0c;回到软件登录界面…

FFmpeg和rtsp服务器搭建视频直播流服务

下面使用的是ubuntu的&#xff0c;window系统可以参考&#xff1a; 通过rtsp-simple-server和ffmpeg实现录屏并发布视频直播_rtsp simple server_病毒宇宇的博客-CSDN博客 一、安装rtsp-simple-server &#xff08;1&#xff09;下载rtsp-simple-server 下载地址&#xff1a;R…

1024啊啊啊啊啊啊

1024 程序员节快乐&#xff0c;没什么想发的&#xff0c;只是想要个1024胸章。

Kotlin中的Lambda表达式基本定义和使用

在Kotlin中&#xff0c;Lambda表达式是一种简洁的方式来定义匿名函数。Lambda表达式可以作为函数的实际参数或者返回值&#xff0c;使得函数成为高阶函数。本篇博客将介绍Lambda表达式的基本概念以及使用方法&#xff0c;并提供相关的示例代码。 Lambda表达式的基本概念 Lamb…

vsCode 格式化配置

学习目标&#xff1a; 基于 vsCode 配置格式化工具&#xff0c;提高&#xff08;React、Vue &#xff09;开发效率  1. vsCode 安装 prettier 插件并启用  2. 修改配置文件 setting.json setting.json 位置&#xff1a; 依次点击 替换内容&#xff1a;↓ {"git.enab…

智加科技与东风柳汽达成深度合作 自动驾驶重卡计划2024年初量产交付

&#xff08;2023年10月19日&#xff0c;苏州&#xff09;全球领先的重卡自动驾驶技术公司智加科技与东风柳汽宣布&#xff0c;双方共同开发的自动驾驶重卡H7计划2024年初实现量产交付。未来&#xff0c;双方将携手推出安全可靠、高性价比、性能卓越的自动驾驶重卡产品&#xf…

什么年代了,还在用FastQC?试试Falco吧

什么年代了&#xff0c;还在用FastQC&#xff1f;试试Falco吧 目前大部分的教程在质控上都是推荐的FastQC&#xff0c;然而它有一个不足&#xff0c;就是虽然名字上有一个Fast&#xff0c;但是它还不够Fast&#xff0c;真正的快&#xff0c;还得是Falco。 如何安装&#xff1…

STM32 HAL高级定时器正交编码模式案例

STM32 HAL高级定时器正交编码模式案例 &#x1f516;基于stm32F030RBT6单片机采用高级定时器1&#xff0c;编码器模式&#xff0c;测试EC11编码器。 &#x1f3ac;EC11测试效果&#xff1a; &#x1f33f;STM32定时器编码器有3种映射模式: ✨本次采用的是上面的模式3&#x…

postgresql14-模式的管理(三)

基本概念 postgresql成为数据库管理系统DBMS&#xff0c;在内存中以进程的形态运行起来成为一个实例&#xff0c;可管理多个database。 数据库databases&#xff1a;包含表、索引、视图、存储过程&#xff1b; 模式schema&#xff1a;多个对象组成一个模式&#xff0c;多个模…

2023年10月22日找工作面试交流遇到的基本问题

交叉编译解决的痛点问题 不同硬件体系结构之间的编译问题。嵌入式系统开发需要在主机上编写代码。提高效率和节省时间。软件移植和管理依赖关系。 不同硬件体系结构之间的编译问题&#xff1a;例如&#xff0c;你开发了一个针对Intel x86架构的应用程序&#xff0c;但想要在Ra…