昨晚双12通宵值班,无聊的时候玩了几局五子棋,然后对这个匹配的功能产生了兴趣,想了想我们平时玩的LOL 5V5对战的匹配,想用自己的想法简单实现一下这个对战匹配功能。

MatchService接口

public interface MatchService {/*** 加入到对应的池中** @param person*/void join(UserMatch person);/*** 批量加入到对应的池中(拉好友一起队列)** @param persons*/void batchJoin(List<UserMatch> persons);/*** 匹配出段位相同的几个人,放到本地缓存里** @param peopleNumber*/void match(UserMatch person, int peopleNumber);/*** 查询本地缓存里的数据,返回给前端** @param userId* @return*/List<UserMatch> findMatch(Long userId, int peopleNumber);/*** 用户取消队列,要把这个用户从池里删除,其他已经被锁的用户继续匹配** @param userId*/void cancel(Long userId);
}

枚举类

/*** 段位枚举*/
public enum LevelEnum {BRONZE("bronze", "青铜"),SILVER("silver", "白银"),GOLD("gold", "黄金"),PLATINUM("platinum", "白金"),DIAMONDS("diamonds", "钻石"),KING("king", "王者"),;private String code;private String value;public static LevelEnum getByCode(String code) {if (StringUtils.isBlank(code)) {return null;}for (LevelEnum level : values()) {if (org.apache.commons.lang3.StringUtils.equals(code, level.getCode())) {return level;}}return null;}LevelEnum(String code, String value) {this.code = code;this.value = value;}public String getCode() {return code;}public String getValue() {return value;}
}

UserMatch实体类

@Data
public class UserMatch {/*** 用户ID*/private Long userId;/*** 段位*/private LevelEnum level;/*** 是否锁住,当被用户匹配到之后则锁住,不让其他线程再来找该用户*/private volatile boolean lock = false;
}

用CommonMap当做正在队列中的池

public class CommonMap  {public static Map<LevelEnum, List<UserMatch>>  map = new ConcurrentHashMap<>();}

匹配成功之后把数据存起来返回给前端,利用本地缓存LoadingCache,这里是配置LoadingCacheConfiguration

@Configuration
public class LoadingCacheConfiguration {private static final int EXPIRE_SECONDS = 60;@Beanpublic LoadingCache<Long, List<UserMatch>> myCacheStorage() {return CacheBuilder.newBuilder().concurrencyLevel(10).maximumSize(3000).expireAfterWrite(EXPIRE_SECONDS, TimeUnit.SECONDS).build(new CacheLoader<Long, List<UserMatch>>() {@Overridepublic List<UserMatch> load(Long name) throws Exception {//在这里可以初始化加载数据的缓存信息,读取数据库中信息或者是加载文件中的某些数据信息return null;}});}
}

实现类:MatchServiceImpl

@Service
public class MatchServiceImpl implements MatchService {@Resourceprivate LoadingCache<Long, List<UserMatch>> cache;@Overridepublic void join(UserMatch person) {if (CommonMap.map.containsKey(person.getLevel())) {CommonMap.map.get(person.getLevel()).add(person);} else {List<UserMatch> list = new ArrayList<>();list.add(person);CommonMap.map.put(person.getLevel(), list);}}@Overridepublic void batchJoin(List<UserMatch> persons) {persons.forEach(person -> {join(person);});}/*** 1、多个用户可以同时去调接口匹配,所以用线程池去处理每一个请求* 2、当一个用户被一个线程拿到,就要在池里删除掉(用个锁标识),保证别人不会再拿到这个用户* 3、当池里只有一个用户,但是我需要匹配4个用户,那我就要先把符合的用户拿到,再去监听池里满足情况的用户,新加入满足的再拿过来* 4、当调取消接口的话,要把拿到的用户全部放在池里去,取消的用户要从池里删除** @param person* @param peopleNumber* @return*/@Overridepublic void match(UserMatch person, int peopleNumber) {ExecutorUtils.execute(() -> {List<UserMatch> newUserList = new ArrayList<>();while (newUserList.size() < peopleNumber + 1) {try {Thread.sleep(5);} catch (InterruptedException e) {e.printStackTrace();}//该用户已经被其他线程匹配到if (person.isLock()) {return;}//所有这个段位的用户List<UserMatch> matchList = CommonMap.map.get(person.getLevel());//先过滤掉目前已经锁上的用户matchList = matchList.stream().filter(userMatch -> !userMatch.isLock()).collect(Collectors.toList());if (matchList.size() == 0 || matchList == null) {continue;}Random random = new Random();//选出peopleNumber个用户出来for (int i = 0; i < peopleNumber; i++) {if (matchList.size() == 0 || matchList == null) {continue;}int index = random.nextInt(matchList.size());UserMatch userMatch = matchList.get(index);if (userMatch.isLock()) {continue;}if (newUserList.contains(userMatch)) {userMatch.setLock(true);matchList.remove(index);continue;}userMatch.setLock(true);newUserList.add(userMatch);matchList.remove(index);if (newUserList.size() == peopleNumber + 1) {break;}}}newUserList.forEach(newUser -> {cache.put(newUser.getUserId(), newUserList);});});}@Overridepublic List<UserMatch> findMatch(Long userId, int peopleNumber) {try {List<UserMatch> userMatches = cache.get(userId);if (userMatches != null && userMatches.size() == peopleNumber + 1) {return userMatches;}return null;} catch (Exception e) {return new ArrayList<>(1);}}/*** 木有写,你们可以自己思考下* @param person*/@Overridepublic void cancel(UserMatch person) {}
}

测试controller

@RestController
public class TestMatchController {@Resourceprivate MatchService matchService;@RequestMapping("/testMatch")public void testMatch() {List<UserMatch> persons = new ArrayList<>();UserMatch person = new UserMatch();person.setUserId(123L);person.setLevel(LevelEnum.getByCode("bronze"));persons.add(person);UserMatch person1 = new UserMatch();person1.setUserId(234L);person1.setLevel(LevelEnum.getByCode("bronze"));persons.add(person1);UserMatch person2 = new UserMatch();person2.setUserId(345L);person2.setLevel(LevelEnum.getByCode("bronze"));persons.add(person2);UserMatch person3 = new UserMatch();person3.setUserId(000L);person3.setLevel(LevelEnum.getByCode("gold"));persons.add(person3);UserMatch person4 = new UserMatch();person4.setUserId(111L);person4.setLevel(LevelEnum.getByCode("gold"));persons.add(person4);UserMatch person5 = new UserMatch();person5.setUserId(222L);person5.setLevel(LevelEnum.getByCode("gold"));persons.add(person5);matchService.batchJoin(persons);}@RequestMapping("/testMatch1")public void testMatch1() {List<UserMatch> persons = new ArrayList<>();UserMatch person = new UserMatch();person.setUserId(1231L);person.setLevel(LevelEnum.getByCode("bronze"));persons.add(person);UserMatch person1 = new UserMatch();person1.setUserId(2341L);person1.setLevel(LevelEnum.getByCode("bronze"));persons.add(person1);UserMatch person2 = new UserMatch();person2.setUserId(3451L);person2.setLevel(LevelEnum.getByCode("bronze"));persons.add(person2);UserMatch person3 = new UserMatch();person3.setUserId(0001L);person3.setLevel(LevelEnum.getByCode("gold"));persons.add(person3);UserMatch person4 = new UserMatch();person4.setUserId(1111L);person4.setLevel(LevelEnum.getByCode("gold"));persons.add(person4);UserMatch person5 = new UserMatch();person5.setUserId(2221L);person5.setLevel(LevelEnum.getByCode("gold"));persons.add(person5);matchService.batchJoin(persons);}@RequestMapping("/match")public void match(Long userId, String code) {UserMatch person = new UserMatch();person.setUserId(userId);person.setLevel(LevelEnum.getByCode(code));matchService.match(person, 4);}@RequestMapping("/find")public List<UserMatch> find(Long userId, int peopleNumber) {return matchService.findMatch(userId, peopleNumber);}}

1、启动项目

2、http://localhost:8080/testMatch 先初始化几条数据进行,代码里是三个黄铜、三个黄金的用户

3、http://localhost:8080/match?userId=123&code=bronze 当用户点击 LOL里开始队列时,调join接口(这里我们用第一步的初始化数据代替了)和match接口 (你可以debug)

4、第三步的时候可以发现,我要匹配四个黄铜队友,但是第二步里初始化的池中只有3个用户,所以代码里会继续对池里的数据进行实时查询(你依然可以debug,这样观察的更明显);

5、http://localhost:8080/testMatch1 执行这个接口,再往池中新增几个刚刚点击开始队列的用户,断点f9,然后这些新用户会被上面第四步的线程读取到,再把符合条件的两个黄铜用户拉过来,凑成了五个人,放进本地缓存里。

6、http://localhost:8080/find?userId=123&peopleNumber=4 前端点击队列之后,就立即轮训该接口获取匹配到的用户。

我的测试结果为:

这个是我即兴的一次撸码,代码写的简单或不完善还请多担待,只是为了增加对事情的思考。谢谢~

LOL根据用户段位进行匹配相关推荐

  1. python给用户打标签_python用户评论标签匹配的解决方法

    我们观察用户评论发现:属性词往往和情感词伴随出现,原因是用户通常会在描述属性时表达情感,属性是情感表达的对象.还发现:属性词和专用情感词基本都是名词或形容词(形谓词). 算法流程图如下: 评论数据如下 ...

  2. UI设计师的段位和匹配能力

    作为UI设计师,可以说大多数同学心里都有一个大厂梦,也时不时会奇怪,同为设计师,工作年限也相差不大,为什么职级不一样.工资更不一样? 这里就为大家总结了一份UI设计师大厂职级判断标准,大家可以对照一下 ...

  3. 大数据【企业级360°全方位用户画像】匹配型标签开发

    写在前面: 博主是一名大数据的初学者,昵称来源于<爱丽丝梦游仙境>中的Alice和自己的昵称.作为一名互联网小白,写博客一方面是为了记录自己的学习历程,一方面是希望能够帮助到很多和自己一样 ...

  4. 飞桨框架2.0RC新增模型保存、加载方案,与用户场景完美匹配,更全面、更易用

    通过一段时间系统的课程学习,算法攻城狮张同学对于飞桨框架的使用越来越顺手,于是他打算在企业内尝试使用飞桨进行AI产业落地. 但是AI产业落地并不是分秒钟的事情,除了专业技能过硬,熟悉飞桨的使用外,在落 ...

  5. 网易严选高段位的“超级用户”数据运营法则

    产品总价值=活跃用户规模╳单个用户价值–异常用户损失 本文分享三点: 用户增长的三件事: 用户增长的指标体系: 用户增长的策略工具. 用户增长的三件事 1. 识别真实的增长 假如有两个产品:产品一在春 ...

  6. Android获取手机联系人匹配用户表并按字母A-Z排序展示

    1.前言 最近在做公司项目的时候遇到一个添加手机联系人的需求,主要有以下几个功能点: 读取联系人:读取用户手机上的通讯录里的联系人列表 好友排序:按照拼音顺序对好友进行排序,兼容英文数字符号等 字母索 ...

  7. Android获取手机联系人匹配用户表并按字母A Z排序展示

    1.前言 最近在做公司项目的时候遇到一个添加手机联系人的需求,主要有以下几个功能点: 读取联系人:读取用户手机上的通讯录里的联系人列表 好友排序:按照拼音顺序对好友进行排序,兼容英文数字符号等 字母索 ...

  8. 简析王者荣耀的匹配机制

    本文以王者荣耀为主体,结合多款MOBA类游戏,对其匹配机制进行的一些猜想, 1.匹配机制的基础 分别从why.who.how三个角度简析. 1.1Why 王者荣耀有实战对抗模式,娱乐模式,排位赛模式等 ...

  9. 有道围棋 AI:智能匹配儿童棋力的良师益友

    1 背景 有道纵横是网易有道旗下专为4-8岁孩子量身打造的在线少儿围棋产品,于2019年启动,自研了全国首部在线交互式围棋动漫课程,从孩子的理解力和喜好出发,采用直播互动的课程形式将围棋知识变得简单有 ...

最新文章

  1. java获取当前方法
  2. 2020-11-23(dll注入方法)
  3. 20 万、50 万、100 万年薪的算法工程师在能力素质模型上有哪些差距?
  4. MySQL三层逻辑架构
  5. opencv配置_Opencv在vs2012下的配置
  6. 坚持早起21天,每月多赚1000+ (文末有惊喜)
  7. VNCServer在Linux下设置
  8. TensorFlow第七步再试牛刀-自编BP代码解Mnist
  9. mysql bin log 255_解析MYSQL BINLOG 二进制格式(4)--TABLE_MAP_EVENT
  10. nodejs后端office转pdf
  11. UE4-(蓝图)第一百二十课 贴花(蓝图生成示例开枪生成弹孔)
  12. bzoj3939 [Usaco2015 Feb]Cow Hopscotch
  13. Linux下安装与配置aMule电驴
  14. Linux - 如何查看Ubuntu系统的版本信息
  15. oracle to_char函数格式,oracle 中to_char函数的用法
  16. 游戏解说是咋制作的?怎么给视频添加有趣的剧情配音?
  17. 超级详细易懂的GhostNet解析
  18. 为2017年出生的孩子免费取名字,孩子起名要注意的问题
  19. 微信小程序搜索功能!附:小程序前端+PHP后端 1
  20. 2022年起重机械指挥操作证考试题模拟考试平台操作

热门文章

  1. CollectionUtils.removeAll和集合的removeAll区别及代码实现
  2. css hover变成手_如何用CSS设置连接鼠标在上面是变成手型
  3. 最新版eclipse支持java8
  4. 2023年第十五届华中杯赛题B 题 小学数学应用题相似性度量及难度评估
  5. 玩家心理角度分析《英雄无敌三》
  6. 经验原石_哔哩哔哩(b站)手机版经验原石怎么样获得?在哪里使用?有期限吗?...
  7. MySQL 新增表中的数据为另外一个或多个表的数据(业务场景:创建关系表,复制旧表数据到新表)
  8. JavaScript【十一】2022.5.23第十三周
  9. Project2013 界面目录清单
  10. Python处理PDF——PyMuPDF中图像的使用(2)