当前位置: 首页 > news >正文

项目实战--网页五子棋(匹配模块)(5)

上期我们实现了websocket后端的大部分代码,这期我们实现具体的匹配逻辑

1. 定义Mather类

我们新建一个Matcher类用来实现匹配逻辑

@Component
public class Matcher {
    //每个匹配队列代表不同的段位,这里约定每一千分为一个段位
    private ArrayList<Queue<User>> matchQueueList = new ArrayList<>();
    @Autowired
    private ObjectMapper objectMapper;
    @Autowired
    private OnlineUserManager onlineUserManager;
    public Matcher() {
        //暂定三个段位
        for(int i = 0; i < 3; i++) {
            matchQueueList.add(new LinkedList<>());
        }
    }
    public void add(User user) {
        int index = Math.min(user.getScore() / 3, 2);
        Queue<User> queue = matchQueueList.get(index);
        //对操作的队列加锁保证线程安全
        synchronized (queue) {
            queue.offer(user);
            queue.notify();
        }
        System.out.println("用户 " + user.getUsername() + " 加入了 " + index + "号 队列");
    }

    public void remove(User user) {
        int index = Math.min(user.getScore() / 3, 2);
        Queue<User> queue = matchQueueList.get(index);
        synchronized (queue) {
            queue.remove(user);
        }
        System.out.println("把用户 " + user.getUsername() + " 从 " + index + "号 队列中删除");
    }
}

2.修改websocket后端代码

    //接收到请求后执行
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        User user = (User) session.getAttributes().get("user");
        MatchRequest request = objectMapper.readValue(message.getPayload(), MatchRequest.class);
        MatchResponse response = new MatchResponse();
        if(request.getMessage().equals("startMatch")) {
            //开始匹配,把用户加入匹配队列
            matcher.add(user);
            response.setOk(true);
            response.setMessage("startMatch");
        }else if(request.getMessage().equals("stopMatch")) {
            //取消匹配,从匹配队列中移除用户
            matcher.remove(user);
            response.setOk(true);
            response.setMessage("stopMatch");
        }else{
            response.setOk(false);
            response.setErrMsg("非法请求");
        }
        //返回响应
        session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
    }

由于存在在匹配中途断开连接的情况,所有我们还要在断开连接代码中增加退出队列的代码进行:

    //连接异常时执行
    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        //连接异常断开,玩家下线
        try {
            User user = (User)session.getAttributes().get("user");
            //防止重复登录时删除正常登录的在线信息
            if(onlineUser.getFromHall(user.getId()).equals(session)) {
                onlineUser.exitGameHall(user.getId());
                System.out.println("用户:" + user.getUsername() + " 已下线");
            }
            //用户可能还在匹配队列中
            matcher.remove(user);
        }catch (NullPointerException e) {
            e.printStackTrace();
            MatchResponse response = new MatchResponse();
            response.setOk(false);
            response.setErrMsg("用户未登录");
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
        }
    }
    //连接正常断开后执行
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        //连接正常断开,玩家下线
        try {
            User user = (User)session.getAttributes().get("user");

            //防止重复登录时删除正常登录的在线信息
            if(onlineUser.getFromHall(user.getId()).equals(session)) {
                onlineUser.exitGameHall(user.getId());
                System.out.println("用户:" + user.getUsername() + " 已下线");
            }
            //用户可能还在匹配队列中
            matcher.remove(user);

        }catch (NullPointerException e) {
            e.printStackTrace();
            MatchResponse response = new MatchResponse();
            response.setOk(false);
            response.setErrMsg("用户未登录");
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
        }
    }

3. 实现匹配功能

3.1 创建线程扫描队列

我们为每个匹配队列创建一个线程,用来实现匹配功能,我们在构造方法中创建线程:

    public Matcher() {
        //暂定三个段位
        for(int i = 0; i < 3; i++) {
            matchQueueList.add(new LinkedList<>());
        }

        //每个队列创建一个线程扫描完成匹配功能
        for(Queue<User> q : matchQueueList) {
            Thread t = new Thread(()->{
                while(true) {
                    //调用handlerMatch()完成匹配功能
                    handlerMatch(q);
                }
            });
        }
    }
3.2 实现handlerMatch()方法进行匹配
public void handlerMatch(Queue<User> matchQueue) {
        try {
            //对操作的队列加锁保证线程安全
            synchronized (matchQueue) {
                //1.检测队列中是否有两个元素
                while(matchQueue.size() < 2) {
                    matchQueue.wait();
                }

                //2.从队列中取出两个玩家
                User user1 = matchQueue.poll();
                User user2 = matchQueue.poll();

                //3.获取到两个玩家的会话信息
                WebSocketSession session1 = onlineUserManager.getFromHall(user1.getId());
                WebSocketSession session2 = onlineUserManager.getFromHall(user2.getId());

                //4.todo 把两个玩家放到一个游戏房间中

                //5.给用户返回匹配成功的响应
                MatchResponse response = new MatchResponse();
                response.setOk(true);
                response.setMessage("success");
                String json = objectMapper.writeValueAsString(response);
                session1.sendMessage(new TextMessage(json));
                session2.sendMessage(new TextMessage(json));
            }
        }catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }

    }

游戏房间功能我们下一期再实现。

相关文章:

  • 【网络安全 | 漏洞挖掘】Stripe 子系统 TaxJar 的 ATO 漏洞挖掘之旅
  • 【第五节】C++设计模式(创建型模式)-Prototype(原型)模式
  • 【NLP 23、预训练语言模型】
  • 码率和采样率
  • UE_C++ —— Gameplay Modules
  • C++和OpenGL实现3D游戏编程【连载23】——几何着色器和法线可视化
  • 白帽黑客系列教程之Windows驱动开发(64位环境)入门教程(六)
  • Pytorch实现论文:基于多尺度融合生成对抗网络的水下图像增强
  • Python常见面试题的详解20
  • Starlink卫星动力学系统仿真建模第十讲-基于SMC和四元数的卫星姿态控制示例及Python实现
  • Hot100 贪心算法
  • Blob转Base64
  • 火绒终端安全管理系统V2.0网络防御功能介绍
  • VMware17下Ubuntu22.04设置本地共享文件夹
  • 大白话Vue2和Vue3 组件通信,方式有哪些,都有什么区别?
  • Linux System V - 消息队列与责任链模式
  • Web前端开发——HTML基础
  • Java 基本数据类型
  • 【虚拟仪器技术】labview操作指南和虚拟仪器技术习题答案(一)
  • SpringBoot两种方式接入DeepSeek
  • 设计公司企业文化/杭州seo网站推广排名
  • 广州网站建设方案/怎样交换友情链接
  • 网站开发费用如何记账/搜收录批量查询
  • 开发网页的常用软件/网站的优化和推广方案
  • 网站制作的地方/seo快速排名代理
  • 网站导航广告怎么做/宁波seo费用