C++项目:在线五子棋对战网页版--房间管理模块

2023-10-13 11:31:46 浏览数 (1)

房间管理模块 

房间管理模块,就是对每一间游戏房间进行管理,因此我首先需要先创建出一个房间类,实现了房间类的功能,再去创建房间管理的类,从而实现房间管理的类的功能。

房间类主要是对匹配成对的玩家建立一个小范围的关联关系,⼀个房间中任意⼀个用户发生的任何动作,都会被广播给房间中的其他用户。

房间中的两个主要动作:下棋和聊天。

游戏房间包含了房间id,玩家数量,房间状态、黑棋白棋玩家的id,以及棋盘,在线用户管理和数据模块管理的指针等字段。在游戏房间中,需要实现的是处理下棋动作、处理聊天动作和处理玩家退出房间的动作,以及将动作处理广播给房间的所有玩家的方法,已经判断下棋后是否五星连珠,胜利的方法。

将处理下棋的动作、处理聊天的动作和处理玩家退出房间的动作交给了总处理方法,通过请求的类型来分别处理不同的业务请求。

房间类

成员变量

成员变量均为私有。对于在线用户管理类的对象和数据模块管理类的对象,我们使用指针定义出来。因为在后续的房间管理类中,依然需要用到相同的在线管理类的对象和数据模块管理类的对象,使用指针可以避免拷贝,提供程序的效率。

代码语言:javascript复制
/*棋盘的大小为15*15*/
#define BOARD_ROW 15
#define BOARD_COL 15
/*1代表白棋玩家,2代表黑棋玩家*/
#define CHESS_WHITE 1
#define CHESS_BLACK 2
/*定义房间状态:游戏开始,游戏结束*/
typedef enum{GAME_START, GAME_OVER}room_status;
/*房间类中,一个房间,需要有的信息是:房间的id,房间的状态,房间玩家数量,玩家的id(黑白棋),在线用户管理,数据模块管理*/
class room
{   
private:
    uint64_t _room_id;/*房间id*/
    room_status _statu;/*房间状态*/
    uint64_t player_count;/*玩家数量*/
    uint64_t _white_id;/*白棋玩家的id*/
    uint64_t _black_id;/*黑棋玩家的id*/
    user_table* _tb_user;/*数据模块管理*/
    online_manager* _online_user;/*在线用户管理*/
    std::vector<vector<int>> _board;/*棋盘*/
public:
};
成员方法
私有成员方法

私有成员方法中,有两个成员方法,一个是判断是否五星连珠的方法,一个是判断输赢的方法。其实这两个方法是结合起来使用的,也就是说,在判断输赢的方法中,是需要调用判断是否五星连珠的方法的。

首先,判断是否五星连珠的方法:从当前位置开始,分正方向和反方向去寻找连续相同颜色棋子的数量,一开始数量是1个,也就是当前位置的棋子。然后先从正方向去寻找,找到一个,计数 1,直到走出棋盘或者颜色不一样,该方向结束。然后反方向寻找,同样的方法,将所有连续的相同颜色棋子个数加起来,最后返回即可。

代码语言:javascript复制
    /*判断是否五星连珠的方法,参数为:当前棋子的坐标,棋子后续的偏移量,也就是方向,然后是棋子的颜色*/
    /**/
    bool five(int row,int col,int row_off,int col_off,int color)
    {
        int cnt = 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)
        {
            /*同色棋子加1*/
            cnt  ;
            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) 
        {
            //同色棋子数量  
            cnt  ;
            //检索位置继续向后偏移
            search_row -= row_off;
            search_col -= col_off;
        }
        return (cnt>=5);
    }

判断输赢的方法:

其实判断输赢,无非就是每下一步棋子,然后就进行判断,去四个方向上寻找是否出现五星连珠,如果是,则赢,返回赢家的id,如果没有,游戏继续。

代码语言:javascript复制
uint64_t check_win(nt 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;
    }
公有成员方法
1.构造函数和析构函数

对于房间中的信息,需要进行初始化的有房间的id,房间的玩家数量,房间状态,在线用户管理对象和数据模块管理对象,以及棋盘。

代码语言:javascript复制
    room(uint64_t room_id, user_table *tb_user, online_manager *online_user)
        :_room_id(room_id),_tb_user(tb_user),_online_user(online_user)
        ,_statu(GAME_START),_player_count(0),_board(BOARD_ROW, std::vector<int>(BOARD_COL, 0))
    {
        DLOG("%lu 房间创建成功!!", _room_id);
    }
    ~room()
    {
        DLOG("%lu 房间销毁成功!!", _room_id);
    }
2.获取房间各种信息的方法

获取房间id、获取房间状态、获取房间玩家数量,添加玩家成为白棋或黑棋玩家,获取白棋、黑棋玩家id。

代码语言:javascript复制
    uint64_t get_rid(){ return _room_id; }/*获取房间id*/
    uint64_t get_white_user(){ return _white_id; }/*获取白棋玩家id*/
    uint64_t get_black_user(){ return _black_id; }/*获取黑棋玩家id*/
    room_status statu(){ return _statu; }/*获取房间状态*/
    int player_count(){ return _player_count; }/*获取玩家数量*/
    void add_white_user(uint64_t uid){ _white_id = uidl; _player_count  ; }/*添加白棋玩家到房间中*/
    void add_black_user(uint64_t uid){ _black_id = uid; _player_count  ; }/*添加黑棋玩家到房间中*/
3.处理下棋动作

流程:

下棋动作分有3种情况:

①在下棋过程中,对手掉线,那么不战而胜

②在下棋的过程中,位置已经被占用

③下完棋子后,判断是否五星连珠,如果是,则胜利,胜利或失败后的操作交由总处理方法去处理。

代码语言:javascript复制
    /*处理下棋动作*/
    Json::Value handle_chess(Json::Value& req)
    {
        /*在下棋动作,分几种情况进行处理
        1.一方掉线,那么另一方不战而胜
        2.在下棋的时候,棋子的位置已经被占用,提示玩家重新选择下棋位置
        3.一方下完棋子后,判断是否五星连珠,如果是,则胜利*/

        /*首先,创建一个用于响应的Json*/
        Json::Value resp_json = req;/*直接拷贝req的数据,因为req的数据中已经有了下棋玩家的一些数据*/
        /*进行判断,双方是否都在线,如果一方掉线,那么另一方不战而胜*/
        if(_online_user.is_in_game_room(_white_id)==false)/*白棋玩家掉线*/
        {
            resp_json["result"] = true;
            resp_json["reason"] = "对方掉线,不战而胜!";
            resp_json["winner"] = (Json::UInt64)_black_id;
            return resp_json;
        }
        if(_online_user.is_in_game_room(_black_id)==false)/*黑棋玩家掉线*/
        {
            resp_json["result"] = true;
            resp_json["reason"] = "对方掉线,不战而胜!";
            resp_json["winner"] = (Json::UInt64)_white_id;
            return resp_json;
        }
        /*双方在线*/
        /*获取走棋的位置,判断当前走棋是否合理(位置是否已经被占用)*/
        int chess_row = req["row"].asInt();//当前下棋的位置
        int chess_col = req["col"].asInt();//当前下棋的位置
        uint64_t cur_uid = req["uid"].asUInt64();//当前下棋的玩家
        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;//下棋
        /*下完棋后需要判断是否有玩家胜利(从当前走棋位置开始判断是否存在五星连珠)*/
        uint64_t winner_id = check_win(chess_row,chess_col,cur_color);
        if (winner_id != 0)/*如果返回来不为0,说明游戏结束*/
        {
            json_resp["reason"] = "五星连珠,战无敌!";
        }
        json_resp["result"] = true;
        json_resp["winner"] = (Json::UInt64)winner_id;
        return json_resp;
    }
4.处理聊天动作

流程:

①接收到聊天信息,获取聊天信息

②然后检测聊天信息中是否有敏感词,如果有,则表示不能发送

③如果没有,则发送

代码语言:javascript复制
    /*处理聊天动作*/
    Json::Value handle_chat(Json::Value& req)
    {
        /*处理聊天动作很简单,就是查看聊天消息中有没有敏感词*/
        Json::Value resp_json = req;
        /*获取其中的信息*/
        std::string msg = req["message"].asString();
        size_t pos = msg.find("垃圾");
        if(pos != std::string::npos)
        {
            resp_json["result"] = false;
            resp_json["reason"] = "消息中包含了敏感词,不能发送";
            return resp_json;
        }
        resp_json["result"] = true;
        return resp_json;
    }
5.处理玩家退出房间动作

流程:

玩家退出房间,有两种情况,第一种是在游戏对战中退出,第二种是游戏结束后正常退出

①游戏对战中退出,即房间状态为GAME_START,那么先获取胜利者的id和失败者的id,即黑棋还是白棋的id,然后交由数据管理模块去进行数据的更新,然后将房间信息返回。

②如果是正常退出,那么房间玩家数量减一下就

0 人点赞