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

这篇具有很好参考价值的文章主要介绍了2.6.C++项目:网络版五子棋对战之数据管理模块-游戏房间管理模块的设计。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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

一、意义

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

二、功能

将这些房间管理起来,以便于进行房间生命周期的控制!文章来源地址https://www.toymoban.com/news/detail-720818.html

三、作用

  • 游戏房间类:
    // 实现两个部分:
    // 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获取房间ID
            auto 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. 通过房间信息,获取房间中所有用户的ID
            uint64_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

到了这里,关于2.6.C++项目:网络版五子棋对战之数据管理模块-游戏房间管理模块的设计的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C++在线五子棋对战(网页版)项目:websocket协议

    目标:认识理解websocket协议、websocket切换过程和websocket协议格式。认识和学会使用websocketpp库常用接口。了解websocketpp库搭建服务器流程,认识和学会使用websocketpp库bin接口,最后使用websocketpp库搭建服务器。 平时我们在逛某宝,点击商品查看商品信息,从HTTP角度来看,就是客

    2024年02月13日
    浏览(35)
  • C++项目:在线五子棋对战网页版--数据模块开发

    数据管理模块,基于mysql数据库进行数据管理以及封装数据管理模块实现数据库访问。因此,在数据库中,我需要为每一张表创建出对应类,通过类实例化的对象来访问这张数据库表中的数 据,这样的话当我们要访问哪张表的时候,使⽤哪个类实例化的对象即可。 那么在五子

    2024年02月13日
    浏览(27)
  • 基于FPGA(basys3)的双人对战人机对战五子棋(vivado)课程设计项目

    目录 主界面显示与选择模式 双人对战 人机对战 胜利界面显示 部分源码 VGA显示器显示图片,显示图片利用Block Memory Generator将图片像素点储存在RAM里面。 效果图:(防止侵权打了马赛克)  通过开发板上的按键进行模式选择,模式确定 双人对战就是采用简单的存数组的办法

    2024年01月18日
    浏览(31)
  • 网页版Java(Spring/Spring Boot/Spring MVC)五子棋项目(四)对战模块

    匹配成功返回数据 1. message消息类别 2. ok 3. reson 4. 房间id 5. 双方id 6.白色玩家 一个类记录房间中的信息(房间id,两个用户id,是否为白棋) 信息提示框 处理匹配API 初始化游戏(棋盘,下一个棋子,接受棋子处理响应,判断是否结束) 1. 客户端连接到游戏房间后, 服务器返回

    2024年02月13日
    浏览(38)
  • 在线五子棋对战

    目录   数据管理模块(数据库设计) 前端界面模块 业务处理模块 会话管理模块网络通信模块(session,cookie) 在线管理模块 房间管理模块 用户匹配模块 项目扩展 数据库中有可能存在很多张表,每张表中管理的数据⼜有不同,要进⾏的数据操作也各不相同,因此我们可以为每⼀

    2024年02月14日
    浏览(35)
  • 在线五子棋对战 --- 人机对战的实现

    要增添一个人机对战的模块, 最大的难点就是如何让人机知道下在什么位置是最好的, 不仅要具备进攻的能力, 还需要具备防守的能力. 这里当人机第一次走的时候, 采用标准开局, 下子在最中间. 当玩家走了之后, 人机就需要去判定下在什么位置合理. 这里采用的是评分表的方法

    2024年02月05日
    浏览(31)
  • 基于Python的五子棋人机对战

    在之前的博文基于tkinter的五子棋游戏中使用tkinter做了一个简单的五子棋游戏,只能实现人人对战,后来想着加上人机对战的功能。 不过,最初想想还是挺麻烦的,计算机怎么评估当前的棋局,找到最佳或者较佳的落子点呢,脑子真是越来越不灵光了。站在巨人的肩膀上,科

    2024年02月04日
    浏览(31)
  • C++ 实现对战AI五子棋

     个人主页: 日刷百题 系列专栏 : 〖C/C++小游戏〗 〖Linux〗 〖数据结构〗   〖 C语言 〗 🌎 欢迎各位 → 点赞 👍+ 收藏 ⭐️+ 留言 📝  ​ ​      为了能够快速上手一门语言,我们往往在学习了基本语法后,采用写一个小项目的方式来加深理解语言的语法及运用,本文采

    2024年02月03日
    浏览(44)
  • python实现五子棋-人机对战/人人对战(动图演示+源码分享)

    大家好,我是梦执,对梦执着。希望能和大家共同进步!   五子棋对战-所有文件文末自取 前言 人人对战 动态演示 源码分享 cheackboard.py 人人对战.py 导入模块 设置棋盘和棋子参数 局内字体设置 落子循坏体 画棋盘 画棋子 运行框返回落子坐标 执行文件 人机对战 动态演示

    2023年04月08日
    浏览(43)
  • JAVA五子棋手机网络对战游戏的设计与实现(源代码+论文)

    在现代社会中,手机及其它无线设备越来越多的走进普通老百姓的工作和生活。 随着3G技术的普及与应用,基于Java开发的软件在手机上的使用非常的广泛,手机增值服务的内容也是越来越多,对丰富人们的生活内容、提供快捷的资讯起着不可忽视的作用。 本文基于J2ME技术,以

    2024年02月09日
    浏览(28)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包