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

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

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

1. 定义Mather类

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

@Component
public class Matcher {//每个匹配队列代表不同的段位,这里约定每一千分为一个段位private ArrayList<Queue<User>> matchQueueList = new ArrayList<>();@Autowiredprivate ObjectMapper objectMapper;@Autowiredprivate 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后端代码

    //接收到请求后执行@Overrideprotected 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)));}

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

    //连接异常时执行@Overridepublic 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)));}}//连接正常断开后执行@Overridepublic 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();}}

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

相关文章:

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

上期我们实现了websocket后端的大部分代码&#xff0c;这期我们实现具体的匹配逻辑 1. 定义Mather类 我们新建一个Matcher类用来实现匹配逻辑 Component public class Matcher {//每个匹配队列代表不同的段位,这里约定每一千分为一个段位private ArrayList<Queue<User…...

mysql 迁移到人大金仓数据库

我是在windows上安装了客户端工具 运行数据库迁移工具 打开 在浏览器输入http://localhost:54523/ 账号密码都是kingbase 添加mysql源数据库连接 添加人大金仓目标数据库 添加好的两个数据库连接 新建迁移任务 选择数据库 全选 迁移中 如果整体迁移不过去可以单个单个或者几个…...

uniapp 网络请求封装(uni.request 与 uView-Plus)

一、背景 在开发项目中&#xff0c;需要经常与后端服务器进行交互&#xff1b;为了提高开发效率和代码维护性&#xff0c;以及降低重复性代码&#xff0c;便对网络请求进行封装统一管理。 二、创建环境文件 2.1、根目录新建utils文件夹&#xff0c;utils文件夹内新建env.js文…...

计算机网络与通讯知识总结

计算机网络与通讯知识总结 基础知识总结 1)FTP:文件传输 SSH:远程登录 HTTP:网址访问 2)‌交换机 定义‌:一种基于MAC地址实现局域网(LAN)内数据高速转发的网络设备,可为接入设备提供独享通信通道‌。 -‌ 核心功能‌: 1.数据链路层(OSI第二层)工作,通过MAC地址…...

DPVS-2:单臂负载均衡测试

上一篇编译安装了DPVS&#xff0c;这一篇开启DPVS的负载均衡测试 &#xff1a; 单臂 FULL NAT模式 拓扑-单臂 单臂模式 DPVS 单独物理机 CLINET&#xff0c;和两个RS都是另一个物理机的虚拟机&#xff0c;它们网卡都绑定在一个桥上br0 &#xff0c; 二层互通。 启动DPVS …...

open webui 部署 以及解决,首屏加载缓慢,nginx反向代理访问404,WebSocket后端服务器链接失败等问题

项目地址&#xff1a;GitHub - open-webui/open-webui: User-friendly AI Interface (Supports Ollama, OpenAI API, ...) 选择了docker部署 如果 Ollama 在您的计算机上&#xff0c;请使用以下命令 docker run -d -p 3000:8080 --add-hosthost.docker.internal:host-gatewa…...

交通物联网:概念、历史、现状与展望

交通物联网&#xff1a;概念、历史、现状与展望 李升伟 李昱均 一、概念 交通物联网&#xff08;Internet of Vehicles, IoV&#xff09;是物联网&#xff08;IoT&#xff09;在交通领域的延伸&#xff0c;旨在通过信息传感设备&#xff0c;实现车、路、人、云之间的全方位连…...

如何实现应用程序与中间件的类进行隔离

以下是一些可以实现类似阿里巴巴 Pandora 功能的框架和工具&#xff0c;这些项目可以帮助你实现类隔离以及中间件和应用的 JAR 包隔离&#xff1a; 1. Pandora Boot Pandora Boot 是阿里巴巴开源的一个基于 Pandora 的轻量级隔离容器&#xff0c;用于管理第三方包&#xff0c…...

MySQL 数据库基础

1. MySQL 数据库基础 在这一部分&#xff0c;我们将学习 MySQL 的基本概念和常见的数据库操作&#xff0c;帮助你掌握如何创建数据库、表&#xff0c;并进行数据的增、删、改操作。同时&#xff0c;我们还会探讨一些常见的错误示例及其原因&#xff0c;帮助你避免常见的陷阱。…...

微服务即时通信系统---(三)框架学习

目录 brpc RPC框架 核心概念 工作原理 介绍 安装 头文件包含和编译时指明库 类与接口介绍 日志输出类与接口 protobuf类与接口 Closure类 RpcController类 服务端类与接口 ServerOptions类 Server类 ClosureGuard类 HttpHeader类 Controller类 客户端类与…...

解决Spring Data JPA set值后自动更新到数据库问题

出现问题&#xff1a; 通过EntityManager查询出数据保存到对象中&#xff0c;但是向对象set值后就自动更新到数据库中去了。 Hibernate对象的三种状态 1、瞬时态&#xff1a;对象刚new出来&#xff0c;还未通过save方法保存到数据库&#xff0c;或通过游离态对象、持久化态对象…...

心理咨询小程序的未来发展

还在眼巴巴看着心理咨询行业的巨大蛋糕却无从下口&#xff1f;今天就来聊聊心理咨询小程序的无限潜力 据统计&#xff0c;全球超 10 亿人受精神心理问题困扰&#xff0c;国内心理健康问题也日益突出&#xff0c;心理咨询需求猛增。可传统心理咨询预约难&#xff0c;费用高&…...

STM32-智能台灯项目

一、项目需求 1. 红外传感器检测是否有人&#xff0c;有人的话实时检测距离&#xff0c;过近则报警&#xff1b;同时计时&#xff0c;超过固定时间则报警&#xff1b; 2. 按键 1 切换工作模式&#xff1a;智能模式、按键模式、远程模式&#xff1b; 3. 智能模式下&#xff0c;根…...

c# —— StringBuilder 类

StringBuilder 类是 C# 和其他一些基于 .NET Framework 的编程语言中的一个类&#xff0c;它位于 System.Text 命名空间下。StringBuilder 类表示一个可变的字符序列&#xff0c;它是为了提供一种比直接使用字符串连接操作更加高效的方式来构建或修改字符串。 与 C# 中的 stri…...

Linux 核心架构与组件(2025更新中)

‌一、Linux 核心架构与组件‌ ‌内核架构‌ ‌核心职责‌&#xff1a; 管理进程生命周期、内存分配、硬件驱动交互及文件系统操作。 模块化设计支持动态加载硬件驱动&#xff08;如modprobe加载内核模块&#xff09;&#xff0c;提升灵活性和扩展性。 ‌内存管理‌&#xff1a…...

Unity打包APK报错 using a newer Android Gradle plugin to use compileSdk = 35

Unity打包APK报错 using a newer Android Gradle plugin to use compileSdk 35 三个报错信息如下 第一个 WARNING:We recommend using a newer Android Gradle plugin to use compileSdk 35This Android Gradle plugin (7.1.2) was tested up to compileSdk 32This warning…...

陀螺匠·企业助手v1.8 产品介绍

陀螺匠企业助手是一套采用Laravel 9框架结合Swoole高性能协程服务与Vue.js前端技术栈构建的新型智慧企业管理与运营系统。该系统深度融合了客户管理、项目管理、审批流程自动化以及低代码开发平台&#xff0c;旨在为企业提供一站式、数字化转型的全方位解决方案&#xff0c;助力…...

文件包含-session2

[题目信息]&#xff1a; 题目名称题目难度文件包含-session22 [题目考点]&#xff1a; 由于网站功能需求&#xff0c;会让前端用户选择要包含的文件&#xff0c;而开发人员又没有对要包含的文件进行安全考虑&#xff0c;就导致攻击者可以通过修改文件的位置来让后台执行任意…...

GitHub免密操作与跨服务器通行:SSH密钥一站式配置指南

作为开发者,与GitHub的安全交互和远程服务器的高效管理是日常工作的核心技能。本文将从零开始,教你如何配置GitHub的SSH密钥认证,并实现免密码远程登录Linux服务器。 一、为什么需要SSH密钥? 更安全的认证方式:相比传统密码,密钥认证几乎无法被暴力破解操作便捷性:免去每…...

PHP入门基础学习四(PHP基本语法)

运算符 运算符&#xff0c;专门用于告诉程序执行特定运算或逻辑操作的符号。根据运算符的作用&#xff0c;可以将PHP语言中常见的运算符分为9类 算数运算符&#xff1a; 是用来处理加减乘除运算的符号 也是最简单和最常用的运算符号 赋值运算符 1. 是一个二元运算符&#x…...

进程地址空间(比特课总结)

一、进程地址空间 1. 环境变量 1 &#xff09;⽤户级环境变量与系统级环境变量 全局属性&#xff1a;环境变量具有全局属性&#xff0c;会被⼦进程继承。例如当bash启动⼦进程时&#xff0c;环 境变量会⾃动传递给⼦进程。 本地变量限制&#xff1a;本地变量只在当前进程(ba…...

工业安全零事故的智能守护者:一体化AI智能安防平台

前言&#xff1a; 通过AI视觉技术&#xff0c;为船厂提供全面的安全监控解决方案&#xff0c;涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面&#xff0c;能够实现对应负责人反馈机制&#xff0c;并最终实现数据的统计报表。提升船厂…...

3.3.1_1 检错编码(奇偶校验码)

从这节课开始&#xff0c;我们会探讨数据链路层的差错控制功能&#xff0c;差错控制功能的主要目标是要发现并且解决一个帧内部的位错误&#xff0c;我们需要使用特殊的编码技术去发现帧内部的位错误&#xff0c;当我们发现位错误之后&#xff0c;通常来说有两种解决方案。第一…...

visual studio 2022更改主题为深色

visual studio 2022更改主题为深色 点击visual studio 上方的 工具-> 选项 在选项窗口中&#xff0c;选择 环境 -> 常规 &#xff0c;将其中的颜色主题改成深色 点击确定&#xff0c;更改完成...

【大模型RAG】Docker 一键部署 Milvus 完整攻略

本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装&#xff1b;只需暴露 19530&#xff08;gRPC&#xff09;与 9091&#xff08;HTTP/WebUI&#xff09;两个端口&#xff0c;即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...

cf2117E

原题链接&#xff1a;https://codeforces.com/contest/2117/problem/E 题目背景&#xff1a; 给定两个数组a,b&#xff0c;可以执行多次以下操作&#xff1a;选择 i (1 < i < n - 1)&#xff0c;并设置 或&#xff0c;也可以在执行上述操作前执行一次删除任意 和 。求…...

Keil 中设置 STM32 Flash 和 RAM 地址详解

文章目录 Keil 中设置 STM32 Flash 和 RAM 地址详解一、Flash 和 RAM 配置界面(Target 选项卡)1. IROM1(用于配置 Flash)2. IRAM1(用于配置 RAM)二、链接器设置界面(Linker 选项卡)1. 勾选“Use Memory Layout from Target Dialog”2. 查看链接器参数(如果没有勾选上面…...

JDK 17 新特性

#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持&#xff0c;不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的&#xff…...

C++使用 new 来创建动态数组

问题&#xff1a; 不能使用变量定义数组大小 原因&#xff1a; 这是因为数组在内存中是连续存储的&#xff0c;编译器需要在编译阶段就确定数组的大小&#xff0c;以便正确地分配内存空间。如果允许使用变量来定义数组的大小&#xff0c;那么编译器就无法在编译时确定数组的大…...

智能AI电话机器人系统的识别能力现状与发展水平

一、引言 随着人工智能技术的飞速发展&#xff0c;AI电话机器人系统已经从简单的自动应答工具演变为具备复杂交互能力的智能助手。这类系统结合了语音识别、自然语言处理、情感计算和机器学习等多项前沿技术&#xff0c;在客户服务、营销推广、信息查询等领域发挥着越来越重要…...