动态范围匹配逻辑实现

简介: 动态范围匹配逻辑实现

分享一个动态范围匹配逻辑的实现

import java.util.*;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;


public class GameMatchmaking {
    public static int initialSkillRange = 100; // 初始技能匹配范围
    public static int skillRangeExpansion = 100; // 每次扩大的技能范围
    public static int expansionPeriod = 1; // 扩大技能范围的周期(秒)

    public static void main(String[] args) throws Exception {

        MatchmakingSystem matchmakingSystem = new MatchmakingSystem(5, 10, initialSkillRange);

        matchmakingSystem.addPlayerToMatchmaking(new Player("PlayerA", 1000));
        matchmakingSystem.addPlayerToMatchmaking(new Player("PlayerB", 1200));
        matchmakingSystem.addPlayerToMatchmaking(new Player("PlayerC", 1400));
        matchmakingSystem.addPlayerToMatchmaking(new Player("PlayerD", 1600));
        matchmakingSystem.addPlayerToMatchmaking(new Player("PlayerE", 1800));

        matchmakingSystem.addPlayerToMatchmaking(new Player("PlayerF", 2000));
        matchmakingSystem.addPlayerToMatchmaking(new Player("PlayerG", 2000));
        matchmakingSystem.addPlayerToMatchmaking(new Player("PlayerH", 2000));
        matchmakingSystem.addPlayerToMatchmaking(new Player("PlayerI", 2000));
        matchmakingSystem.addPlayerToMatchmaking(new Player("PlayerJ", 2000));

        matchmakingSystem.addPlayerToMatchmaking(new Player("PlayerK", 12000));
        matchmakingSystem.addPlayerToMatchmaking(new Player("PlayerL", 12000));
        matchmakingSystem.addPlayerToMatchmaking(new Player("PlayerM", 12000));
        matchmakingSystem.addPlayerToMatchmaking(new Player("PlayerN", 12000));

        Thread.sleep(30000);
        matchmakingSystem.addPlayerToMatchmaking(new Player("PlayerO", 12000));

        // ... 添加更多玩家

        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            System.out.println("Shutting down matchmaking system...");
            matchmakingSystem.shutdown();
        }));

        // 模拟玩家进入房间后退出
        Thread.sleep(5000); // 等待一段时间以允许匹配发生
        matchmakingSystem.removePlayerFromMatchmaking(new Player("PlayerC", 1400));
        matchmakingSystem.reMatchPlayer(new Player("PlayerC", 1400));
        Thread.sleep(5000); // 等待一段时间以允许匹配发生
        matchmakingSystem.removePlayerFromMatchmaking(new Player("PlayerC", 1400));
        matchmakingSystem.reMatchPlayer(new Player("PlayerC", 1400));
        Thread.sleep(5000); // 等待一段时间以允许匹配发生
        matchmakingSystem.removePlayerFromMatchmaking(new Player("PlayerC", 1400));
        matchmakingSystem.reMatchPlayer(new Player("PlayerC", 1400));
    }

    public static class Player {
        private final String name;
        private final int skillLevel;

        public Player(String name, int skillLevel) {
            this.name = name;
            this.skillLevel = skillLevel;
        }

        public String getName() {
            return name;
        }

        public int getSkillLevel() {
            return skillLevel;
        }

        @Override
        public String toString() {
            return "Player{name='" + name + "', skillLevel=" + skillLevel + '}';
        }

    }

    public static class Room {
        private static int nextRoomId = 1; // 静态变量用于生成唯一的房间ID
        private final int roomId;
        private final int minPlayers;
        private final int maxPlayers;
        private final List<PlayerMatchInfo> players;
        private int avgSkillLevel; // 用于存储房间平均技能水平

        public Room(int minPlayers, int maxPlayers) {
            this.roomId = nextRoomId++;
            this.players = new LinkedList<>();
            this.minPlayers = minPlayers;
            this.maxPlayers = maxPlayers;
            this.avgSkillLevel = 0;
        }

        public boolean addPlayer(PlayerMatchInfo playerMatchInfo) {
            if (players.size() < maxPlayers) {
                players.add(playerMatchInfo);
                updateAverageSkillLevel();
                System.out.println(playerMatchInfo.getPlayer() +
                        " has joined the room [" + getRoomId() + "]. Current room size: " + players.size() +
                        ", avgSkillLevel is " + this.avgSkillLevel);
                return true;
            }
            return false;
        }

        public boolean removePlayer(Player player) {
            PlayerMatchInfo toRemove = null;
            for (PlayerMatchInfo pmi : players) {
                if (Objects.equals(pmi.getPlayer().getName(), player.getName())) {
                    toRemove = pmi;
                    break;
                }
            }

            if (toRemove != null) {
                players.remove(toRemove);
                updateAverageSkillLevel();
                System.out.println(player.getName() + " has left the room [" + getRoomId() + "]. Current room size: " + players.size());
                return true;
            }

            return false;
        }

        public int getRoomId() {
            return roomId;
        }

        private void updateAverageSkillLevel() {
            if (players.isEmpty()) {
                avgSkillLevel = 0;
                return;
            }
            avgSkillLevel = players.stream().mapToInt(pmi -> pmi.getPlayer().getSkillLevel()).sum() / players.size();
        }

        public boolean isPlayerCompatible(PlayerMatchInfo playerMatchInfo) {
            if (players.isEmpty()) {
                return true; // 如果房间为空,则任何玩家都可以加入
            }
            return players.stream().allMatch(pmi -> pmi.isWithinRange(playerMatchInfo));
        }

        public boolean isReadyToStart() {
            return players.size() >= minPlayers;
        }

        public boolean isFull() {
            return players.size() == maxPlayers;
        }

        public List<Player> getPlayers() {
            return players.stream().map(PlayerMatchInfo::getPlayer).collect(Collectors.toList());
        }
    }

    public static class PlayerMatchInfo {
        private static final int MAX_SKILL_RANGE = Integer.MAX_VALUE; // 最大技能范围
        private final Player player;
        private final long timeAdded;
        private int skillRange;
        private int exitCount; // Track the number of times player exits a room
        private long lastExitTime; // Track the last exit time
        private int lastRoomId; // Track the last room player exited

        public PlayerMatchInfo(Player player, int initialSkillRange) {
            this.player = player;
            this.timeAdded = System.currentTimeMillis();
            this.skillRange = initialSkillRange;
            this.exitCount = 0;
            this.lastExitTime = 0;
            this.lastRoomId = -1; // Initialize with an invalid room ID
        }

        public void updateSkillRange() {
            var beforeSkillRange = this.skillRange;
            long timeElapsed = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis() - timeAdded);
            this.skillRange = (int) Math.min(this.skillRange + skillRangeExpansion * (timeElapsed / expansionPeriod), MAX_SKILL_RANGE);
            System.out.println("Skill range for " + player.getName() + " has been updated from " + beforeSkillRange + " to " + this.skillRange);
        }

        public Player getPlayer() {
            return player;
        }

        public int getSkillRange() {
            return skillRange;
        }

        public int getLastRoomId() {
            return lastRoomId;
        }

        public boolean isWithinRange(PlayerMatchInfo other) {
            // 技能差异 ≤ 两位的技能容差范围最大值
            return Math.abs(player.getSkillLevel() - other.player.getSkillLevel()) <= Math.max(skillRange, other.skillRange);
        }

        public void recordExit(int roomId) {
            if (this.getLastRoomId() == roomId) {
                this.exitCount++;
            } else {
                this.exitCount = 1;
            }
            this.lastExitTime = System.currentTimeMillis();
            this.lastRoomId = roomId;
        }

        public boolean canJoinRoom(Room room) {
            if (this.getLastRoomId() != room.getRoomId()) {
                return true;
            }
            // 如果玩家在同一个房间退出两次,并且距离上次退出不足一分钟,则不能加入
            return this.exitCount < 2 || (System.currentTimeMillis() - this.lastExitTime) > 60000;
        }
    }

    public static class MatchmakingSystem {
        private final int minTeamSize;
        private final int maxPlayers;
        private final ScheduledExecutorService executorService;
        private final Map<String, PlayerMatchInfo> playerInfoMap = new HashMap<>();
        private final Queue<PlayerMatchInfo> matchmakingQueue;
        private final List<Room> rooms;
        private final int skillRange;

        public MatchmakingSystem(int minTeamSize, int maxPlayers, int initialSkillRange) {
            this.matchmakingQueue = new ConcurrentLinkedQueue<>();
            this.rooms = Collections.synchronizedList(new ArrayList<>());
            this.minTeamSize = minTeamSize;
            this.maxPlayers = maxPlayers;
            this.skillRange = initialSkillRange;
            this.executorService = Executors.newSingleThreadScheduledExecutor();
            executorService.scheduleAtFixedRate(this::tryToMatchPlayers, 0, 1, TimeUnit.SECONDS); // 每秒检查一次
        }


        public PlayerMatchInfo getPlayerMatchInfo(Player player) {
            return playerInfoMap.computeIfAbsent(player.getName(), k -> new PlayerMatchInfo(player, skillRange));
        }

        public void reMatchPlayer(Player player) {
            PlayerMatchInfo playerInfo = getPlayerMatchInfo(player);
            removePlayerFromMatchmaking(player);
            matchmakingQueue.removeIf(pmi -> Objects.equals(pmi.getPlayer().getName(), player.getName()));
            matchmakingQueue.add(playerInfo);
            System.out.println(player.getName() + " is looking for a match...");
            tryToMatchPlayers();
        }

        public void removePlayerFromMatchmaking(Player player) {
            PlayerMatchInfo playerInfo = playerInfoMap.get(player.getName());
            if (playerInfo != null) {
                for (Room room : rooms) {
                    if (room.removePlayer(player)) {
                        playerInfo.recordExit(room.getRoomId());
                        matchmakingQueue.remove(playerInfo);
                        break;
                    }
                }
            }
        }

        public void addPlayerToMatchmaking(Player player) {
            PlayerMatchInfo playerInfo = getPlayerMatchInfo(player);
            // 添加到匹配队列
            matchmakingQueue.add(playerInfo);
            System.out.println(player.getName() + " is looking for a match...");
            tryToMatchPlayers();
        }

        private void tryToMatchPlayers() {
            if (matchmakingQueue.isEmpty()) {
                return;
            }

            // Update skill ranges
            matchmakingQueue.forEach(PlayerMatchInfo::updateSkillRange);

            List<PlayerMatchInfo> playersToMatch = new ArrayList<>(matchmakingQueue);
            Iterator<PlayerMatchInfo> iterator = playersToMatch.iterator();

            while (iterator.hasNext()) {
                PlayerMatchInfo playerToMatch = iterator.next();
                Room suitableRoom = findSuitableRoom(playerToMatch);

                if (suitableRoom != null) {
                    suitableRoom.addPlayer(playerToMatch);
                    matchmakingQueue.remove(playerToMatch);
                    iterator.remove();
                    if (suitableRoom.isReadyToStart()) {
                        System.out.println("Room [" + suitableRoom.getRoomId() + "] " + suitableRoom.getPlayers().stream().map(Player::getName).toList() + " is ready to start the game!");
                    }
                }
            }

            // 如果没有合适的房间,尝试创建新的房间
            if (!playersToMatch.isEmpty()) {
                List<PlayerMatchInfo> potentialTeam = findPotentialTeam(playersToMatch);
                if (potentialTeam != null) {
                    Room room = new Room(minTeamSize, maxPlayers);
                    potentialTeam.forEach(pmi -> {
                        room.addPlayer(pmi);
                        matchmakingQueue.remove(pmi);
                    });
                    rooms.add(room);
                    System.out.println("Room " + room.getPlayers().stream().map(Player::getName).toList() + " is ready to start the game!");
                }
            }
        }

        private Room findSuitableRoom(PlayerMatchInfo playerToMatch) {
            for (Room room : rooms) {
                if (!room.isFull() &&
                        // 是否相互匹配
                        room.isPlayerCompatible(playerToMatch) &&
                        // 是否冷却时间内
                        playerToMatch.canJoinRoom(room)) {
                    return room;
                }
            }
            return null;
        }

        private List<PlayerMatchInfo> findPotentialTeam(List<PlayerMatchInfo> players) {
            if (players.size() < minTeamSize) {
                return null;
            }

            for (int i = 0; i <= players.size() - minTeamSize; i++) {
                List<PlayerMatchInfo> potentialTeam = players.subList(i, i + minTeamSize);
                if (isTeamCompatible(potentialTeam)) {
                    return new ArrayList<>(potentialTeam);
                }
            }
            return null;
        }

        private boolean isTeamCompatible(List<PlayerMatchInfo> team) {
            if (team.isEmpty()) {
                return false;
            }
            var avgSkill = team.stream().mapToInt(p -> p.getPlayer().getSkillLevel()).average().orElse(0.0);
            // 如果当前匹配队列中的玩家匹配值的平均值,减去玩家的技能水平(得到自己与平均值的差异),小于玩家的匹配值容差,则认为是合适的队伍
            return team.stream().allMatch(p -> Math.abs(avgSkill - p.getPlayer().getSkillLevel()) <= p.getSkillRange());
        }

        public void shutdown() {
            executorService.shutdown();
        }
    }
}

这里每一位玩家都有一个技能水平skillLevel,在玩家进入匹配后会随着时间动态扩大匹配范围区间,例如技能水平为1000的玩家一开始是匹配900~1100范围区间的玩家,然后过了1秒变为能匹配到800~1200范围的玩家

当五位玩家都相互满足范围区间时,这五位玩家组成一个房间

房间会继续接受玩家加入,直到满足最大人数十

这是这个逻辑的日志输出:

Connected to the target VM, address: '127.0.0.1:49327', transport: 'socket'
20:50:14.891 [main] DEBUG reactor.util.Loggers - Using Slf4j logging framework
20:50:14.893 [main] DEBUG reactor.core.publisher.Hooks - Enabling stacktrace debugging via onOperatorDebug
PlayerA is looking for a match...
Skill range for PlayerA has been updated from 100 to 100
PlayerB is looking for a match...
Skill range for PlayerA has been updated from 100 to 100
Skill range for PlayerB has been updated from 100 to 100
PlayerC is looking for a match...
Skill range for PlayerA has been updated from 100 to 100
Skill range for PlayerB has been updated from 100 to 100
Skill range for PlayerC has been updated from 100 to 100
PlayerD is looking for a match...
Skill range for PlayerA has been updated from 100 to 100
Skill range for PlayerB has been updated from 100 to 100
Skill range for PlayerC has been updated from 100 to 100
Skill range for PlayerD has been updated from 100 to 100
PlayerE is looking for a match...
Skill range for PlayerA has been updated from 100 to 100
Skill range for PlayerB has been updated from 100 to 100
Skill range for PlayerC has been updated from 100 to 100
Skill range for PlayerD has been updated from 100 to 100
Skill range for PlayerE has been updated from 100 to 100
PlayerF is looking for a match...
Skill range for PlayerA has been updated from 100 to 100
Skill range for PlayerB has been updated from 100 to 100
Skill range for PlayerC has been updated from 100 to 100
Skill range for PlayerD has been updated from 100 to 100
Skill range for PlayerE has been updated from 100 to 100
Skill range for PlayerF has been updated from 100 to 100
PlayerG is looking for a match...
Skill range for PlayerA has been updated from 100 to 100
Skill range for PlayerB has been updated from 100 to 100
Skill range for PlayerC has been updated from 100 to 100
Skill range for PlayerD has been updated from 100 to 100
Skill range for PlayerE has been updated from 100 to 100
Skill range for PlayerF has been updated from 100 to 100
Skill range for PlayerG has been updated from 100 to 100
PlayerH is looking for a match...
Skill range for PlayerA has been updated from 100 to 100
Skill range for PlayerB has been updated from 100 to 100
Skill range for PlayerC has been updated from 100 to 100
Skill range for PlayerD has been updated from 100 to 100
Skill range for PlayerE has been updated from 100 to 100
Skill range for PlayerF has been updated from 100 to 100
Skill range for PlayerG has been updated from 100 to 100
Skill range for PlayerH has been updated from 100 to 100
PlayerI is looking for a match...
Skill range for PlayerA has been updated from 100 to 100
Skill range for PlayerB has been updated from 100 to 100
Skill range for PlayerC has been updated from 100 to 100
Skill range for PlayerD has been updated from 100 to 100
Skill range for PlayerE has been updated from 100 to 100
Skill range for PlayerF has been updated from 100 to 100
Skill range for PlayerG has been updated from 100 to 100
Skill range for PlayerH has been updated from 100 to 100
Skill range for PlayerI has been updated from 100 to 100
PlayerJ is looking for a match...
Skill range for PlayerA has been updated from 100 to 100
Skill range for PlayerB has been updated from 100 to 100
Skill range for PlayerC has been updated from 100 to 100
Skill range for PlayerD has been updated from 100 to 100
Skill range for PlayerE has been updated from 100 to 100
Skill range for PlayerF has been updated from 100 to 100
Skill range for PlayerG has been updated from 100 to 100
Skill range for PlayerH has been updated from 100 to 100
Skill range for PlayerI has been updated from 100 to 100
Skill range for PlayerJ has been updated from 100 to 100
Player{name='PlayerF', skillLevel=2000} has joined the room [1]. Current room size: 1, avgSkillLevel is 2000
Player{name='PlayerG', skillLevel=2000} has joined the room [1]. Current room size: 2, avgSkillLevel is 2000
Player{name='PlayerH', skillLevel=2000} has joined the room [1]. Current room size: 3, avgSkillLevel is 2000
Player{name='PlayerI', skillLevel=2000} has joined the room [1]. Current room size: 4, avgSkillLevel is 2000
Player{name='PlayerJ', skillLevel=2000} has joined the room [1]. Current room size: 5, avgSkillLevel is 2000
Room [PlayerF, PlayerG, PlayerH, PlayerI, PlayerJ] is ready to start the game!
PlayerK is looking for a match...
Skill range for PlayerA has been updated from 100 to 100
Skill range for PlayerB has been updated from 100 to 100
Skill range for PlayerC has been updated from 100 to 100
Skill range for PlayerD has been updated from 100 to 100
Skill range for PlayerE has been updated from 100 to 100
Skill range for PlayerK has been updated from 100 to 100
PlayerL is looking for a match...
Skill range for PlayerA has been updated from 100 to 100
Skill range for PlayerB has been updated from 100 to 100
Skill range for PlayerC has been updated from 100 to 100
Skill range for PlayerD has been updated from 100 to 100
Skill range for PlayerE has been updated from 100 to 100
Skill range for PlayerK has been updated from 100 to 100
Skill range for PlayerL has been updated from 100 to 100
PlayerM is looking for a match...
Skill range for PlayerA has been updated from 100 to 100
Skill range for PlayerB has been updated from 100 to 100
Skill range for PlayerC has been updated from 100 to 100
Skill range for PlayerD has been updated from 100 to 100
Skill range for PlayerE has been updated from 100 to 100
Skill range for PlayerK has been updated from 100 to 100
Skill range for PlayerL has been updated from 100 to 100
Skill range for PlayerM has been updated from 100 to 100
PlayerN is looking for a match...
Skill range for PlayerA has been updated from 100 to 100
Skill range for PlayerB has been updated from 100 to 100
Skill range for PlayerC has been updated from 100 to 100
Skill range for PlayerD has been updated from 100 to 100
Skill range for PlayerE has been updated from 100 to 100
Skill range for PlayerK has been updated from 100 to 100
Skill range for PlayerL has been updated from 100 to 100
Skill range for PlayerM has been updated from 100 to 100
Skill range for PlayerN has been updated from 100 to 100
Skill range for PlayerA has been updated from 100 to 200
Skill range for PlayerB has been updated from 100 to 100
Skill range for PlayerC has been updated from 100 to 100
Skill range for PlayerD has been updated from 100 to 100
Skill range for PlayerE has been updated from 100 to 100
Skill range for PlayerK has been updated from 100 to 100
Skill range for PlayerL has been updated from 100 to 100
Skill range for PlayerM has been updated from 100 to 100
Skill range for PlayerN has been updated from 100 to 100
Skill range for PlayerA has been updated from 200 to 400
Skill range for PlayerB has been updated from 100 to 200
Skill range for PlayerC has been updated from 100 to 200
Skill range for PlayerD has been updated from 100 to 200
Skill range for PlayerE has been updated from 100 to 200
Skill range for PlayerK has been updated from 100 to 200
Skill range for PlayerL has been updated from 100 to 200
Skill range for PlayerM has been updated from 100 to 200
Skill range for PlayerN has been updated from 100 to 200
Player{name='PlayerE', skillLevel=1800} has joined the room [1]. Current room size: 6, avgSkillLevel is 1966
Room [1] [PlayerF, PlayerG, PlayerH, PlayerI, PlayerJ, PlayerE] is ready to start the game!
Skill range for PlayerA has been updated from 400 to 700
Skill range for PlayerB has been updated from 200 to 400
Skill range for PlayerC has been updated from 200 to 400
Skill range for PlayerD has been updated from 200 to 400
Skill range for PlayerK has been updated from 200 to 400
Skill range for PlayerL has been updated from 200 to 400
Skill range for PlayerM has been updated from 200 to 400
Skill range for PlayerN has been updated from 200 to 400
Player{name='PlayerD', skillLevel=1600} has joined the room [1]. Current room size: 7, avgSkillLevel is 1914
Room [1] [PlayerF, PlayerG, PlayerH, PlayerI, PlayerJ, PlayerE, PlayerD] is ready to start the game!
Skill range for PlayerA has been updated from 700 to 1100
Skill range for PlayerB has been updated from 400 to 700
Skill range for PlayerC has been updated from 400 to 700
Skill range for PlayerK has been updated from 400 to 700
Skill range for PlayerL has been updated from 400 to 700
Skill range for PlayerM has been updated from 400 to 700
Skill range for PlayerN has been updated from 400 to 700
Player{name='PlayerA', skillLevel=1000} has joined the room [1]. Current room size: 8, avgSkillLevel is 1800
Room [1] [PlayerF, PlayerG, PlayerH, PlayerI, PlayerJ, PlayerE, PlayerD, PlayerA] is ready to start the game!
Player{name='PlayerC', skillLevel=1400} has joined the room [1]. Current room size: 9, avgSkillLevel is 1755
Room [1] [PlayerF, PlayerG, PlayerH, PlayerI, PlayerJ, PlayerE, PlayerD, PlayerA, PlayerC] is ready to start the game!
Skill range for PlayerB has been updated from 700 to 1100
Skill range for PlayerK has been updated from 700 to 1100
Skill range for PlayerL has been updated from 700 to 1100
Skill range for PlayerM has been updated from 700 to 1100
Skill range for PlayerN has been updated from 700 to 1100
Player{name='PlayerB', skillLevel=1200} has joined the room [1]. Current room size: 10, avgSkillLevel is 1700
Room [1] [PlayerF, PlayerG, PlayerH, PlayerI, PlayerJ, PlayerE, PlayerD, PlayerA, PlayerC, PlayerB] is ready to start the game!
Skill range for PlayerK has been updated from 1100 to 1600
Skill range for PlayerL has been updated from 1100 to 1600
Skill range for PlayerM has been updated from 1100 to 1600
Skill range for PlayerN has been updated from 1100 to 1600
Skill range for PlayerK has been updated from 1600 to 2200
Skill range for PlayerL has been updated from 1600 to 2200
Skill range for PlayerM has been updated from 1600 to 2200
Skill range for PlayerN has been updated from 1600 to 2200
Skill range for PlayerK has been updated from 2200 to 2900
Skill range for PlayerL has been updated from 2200 to 2900
Skill range for PlayerM has been updated from 2200 to 2900
Skill range for PlayerN has been updated from 2200 to 2900
Skill range for PlayerK has been updated from 2900 to 3700
Skill range for PlayerL has been updated from 2900 to 3700
Skill range for PlayerM has been updated from 2900 to 3700
Skill range for PlayerN has been updated from 2900 to 3700
Skill range for PlayerK has been updated from 3700 to 4600
Skill range for PlayerL has been updated from 3700 to 4600
Skill range for PlayerM has been updated from 3700 to 4600
Skill range for PlayerN has been updated from 3700 to 4600
Skill range for PlayerK has been updated from 4600 to 5600
Skill range for PlayerL has been updated from 4600 to 5600
Skill range for PlayerM has been updated from 4600 to 5600
Skill range for PlayerN has been updated from 4600 to 5600
Skill range for PlayerK has been updated from 5600 to 6700
Skill range for PlayerL has been updated from 5600 to 6700
Skill range for PlayerM has been updated from 5600 to 6700
Skill range for PlayerN has been updated from 5600 to 6700
Skill range for PlayerK has been updated from 6700 to 7900
Skill range for PlayerL has been updated from 6700 to 7900
Skill range for PlayerM has been updated from 6700 to 7900
Skill range for PlayerN has been updated from 6700 to 7900
Skill range for PlayerK has been updated from 7900 to 9200
Skill range for PlayerL has been updated from 7900 to 9200
Skill range for PlayerM has been updated from 7900 to 9200
Skill range for PlayerN has been updated from 7900 to 9200
Skill range for PlayerK has been updated from 9200 to 10600
Skill range for PlayerL has been updated from 9200 to 10600
Skill range for PlayerM has been updated from 9200 to 10600
Skill range for PlayerN has been updated from 9200 to 10600
Skill range for PlayerK has been updated from 10600 to 12100
Skill range for PlayerL has been updated from 10600 to 12100
Skill range for PlayerM has been updated from 10600 to 12100
Skill range for PlayerN has been updated from 10600 to 12100
Skill range for PlayerK has been updated from 12100 to 13700
Skill range for PlayerL has been updated from 12100 to 13700
Skill range for PlayerM has been updated from 12100 to 13700
Skill range for PlayerN has been updated from 12100 to 13700
Skill range for PlayerK has been updated from 13700 to 15400
Skill range for PlayerL has been updated from 13700 to 15400
Skill range for PlayerM has been updated from 13700 to 15400
Skill range for PlayerN has been updated from 13700 to 15400
Skill range for PlayerK has been updated from 15400 to 17200
Skill range for PlayerL has been updated from 15400 to 17200
Skill range for PlayerM has been updated from 15400 to 17200
Skill range for PlayerN has been updated from 15400 to 17200
Skill range for PlayerK has been updated from 17200 to 19100
Skill range for PlayerL has been updated from 17200 to 19100
Skill range for PlayerM has been updated from 17200 to 19100
Skill range for PlayerN has been updated from 17200 to 19100
Skill range for PlayerK has been updated from 19100 to 21100
Skill range for PlayerL has been updated from 19100 to 21100
Skill range for PlayerM has been updated from 19100 to 21100
Skill range for PlayerN has been updated from 19100 to 21100
Skill range for PlayerK has been updated from 21100 to 23200
Skill range for PlayerL has been updated from 21100 to 23200
Skill range for PlayerM has been updated from 21100 to 23200
Skill range for PlayerN has been updated from 21100 to 23200
Skill range for PlayerK has been updated from 23200 to 25400
Skill range for PlayerL has been updated from 23200 to 25400
Skill range for PlayerM has been updated from 23200 to 25400
Skill range for PlayerN has been updated from 23200 to 25400
Skill range for PlayerK has been updated from 25400 to 27700
Skill range for PlayerL has been updated from 25400 to 27700
Skill range for PlayerM has been updated from 25400 to 27700
Skill range for PlayerN has been updated from 25400 to 27700
Skill range for PlayerK has been updated from 27700 to 30100
Skill range for PlayerL has been updated from 27700 to 30100
Skill range for PlayerM has been updated from 27700 to 30100
Skill range for PlayerN has been updated from 27700 to 30100
Skill range for PlayerK has been updated from 30100 to 32600
Skill range for PlayerL has been updated from 30100 to 32600
Skill range for PlayerM has been updated from 30100 to 32600
Skill range for PlayerN has been updated from 30100 to 32600
Skill range for PlayerK has been updated from 32600 to 35200
Skill range for PlayerL has been updated from 32600 to 35200
Skill range for PlayerM has been updated from 32600 to 35200
Skill range for PlayerN has been updated from 32600 to 35200
Skill range for PlayerK has been updated from 35200 to 37900
Skill range for PlayerL has been updated from 35200 to 37900
Skill range for PlayerM has been updated from 35200 to 37900
Skill range for PlayerN has been updated from 35200 to 37900
Skill range for PlayerK has been updated from 37900 to 40700
Skill range for PlayerL has been updated from 37900 to 40700
Skill range for PlayerM has been updated from 37900 to 40700
Skill range for PlayerN has been updated from 37900 to 40700
Skill range for PlayerK has been updated from 40700 to 43600
Skill range for PlayerL has been updated from 40700 to 43600
Skill range for PlayerM has been updated from 40700 to 43600
Skill range for PlayerN has been updated from 40700 to 43600
PlayerO is looking for a match...
Skill range for PlayerK has been updated from 43600 to 46600
Skill range for PlayerL has been updated from 43600 to 46600
Skill range for PlayerM has been updated from 43600 to 46600
Skill range for PlayerN has been updated from 43600 to 46600
Skill range for PlayerO has been updated from 100 to 100
Player{name='PlayerK', skillLevel=12000} has joined the room [2]. Current room size: 1, avgSkillLevel is 12000
Player{name='PlayerL', skillLevel=12000} has joined the room [2]. Current room size: 2, avgSkillLevel is 12000
Player{name='PlayerM', skillLevel=12000} has joined the room [2]. Current room size: 3, avgSkillLevel is 12000
Player{name='PlayerN', skillLevel=12000} has joined the room [2]. Current room size: 4, avgSkillLevel is 12000
Player{name='PlayerO', skillLevel=12000} has joined the room [2]. Current room size: 5, avgSkillLevel is 12000
Room [PlayerK, PlayerL, PlayerM, PlayerN, PlayerO] is ready to start the game!
PlayerC has left the room [1]. Current room size: 9
PlayerC is looking for a match...
Skill range for PlayerC has been updated from 700 to 4200
Player{name='PlayerC', skillLevel=1400} has joined the room [1]. Current room size: 10, avgSkillLevel is 1700
Room [1] [PlayerF, PlayerG, PlayerH, PlayerI, PlayerJ, PlayerE, PlayerD, PlayerA, PlayerB, PlayerC] is ready to start the game!
PlayerC has left the room [1]. Current room size: 9
PlayerC is looking for a match...
Skill range for PlayerC has been updated from 4200 to 8200
Skill range for PlayerC has been updated from 8200 to 12200
Player{name='PlayerC', skillLevel=1400} has joined the room [2]. Current room size: 6, avgSkillLevel is 10233
Room [2] [PlayerK, PlayerL, PlayerM, PlayerN, PlayerO, PlayerC] is ready to start the game!
PlayerC has left the room [2]. Current room size: 5
PlayerC is looking for a match...
Skill range for PlayerC has been updated from 12200 to 16700
Player{name='PlayerC', skillLevel=1400} has joined the room [1]. Current room size: 10, avgSkillLevel is 1700
Room [1] [PlayerF, PlayerG, PlayerH, PlayerI, PlayerJ, PlayerE, PlayerD, PlayerA, PlayerB, PlayerC] is ready to start the game!

相关文章
|
4月前
|
负载均衡 应用服务中间件 API
location` 块的语法、匹配规则、配置示例及其应用场景
location` 块的语法、匹配规则、配置示例及其应用场景
44 2
|
5月前
|
算法 Unix Linux
|
5月前
|
开发框架 .NET C#
C# 10.0中的扩展属性与模式匹配:深入解析
【1月更文挑战第20天】C# 10.0引入了众多新特性,其中扩展属性与模式匹配的结合为开发者提供了更强大、更灵活的类型检查和代码分支能力。通过这一特性,开发者可以在不修改原始类的情况下,为其添加新的行为,并在模式匹配中利用这些扩展属性进行更精细的控制。本文将详细探讨C# 10.0中扩展属性与模式匹配的工作原理、使用场景以及最佳实践,帮助读者更好地理解和应用这一新功能。
判断两棵树是否完全一致
给你两棵二叉树的根节点 p 和 q ,编写一个函数来检验这两棵树是否相同。
111 0
|
前端开发
前端学习案例9-正则-非捕获反向引用
前端学习案例9-正则-非捕获反向引用
60 0
前端学习案例9-正则-非捕获反向引用
|
移动开发 JavaScript 算法
如何实现动态内容条件筛选
这两天看了一下后端给的接口文档,每一个都要求筛选,而且这个筛选还是多条件的,还是不能固定的,要求根据用户的输入然后筛选,我之前的实现大概是这样子,当用户想要筛选的时候就去检索条件,并输入相关的内容进行筛选
|
Java Maven Ruby
去掉复杂的逻辑计算,get一下Aviator吧
去掉复杂的逻辑计算,get一下Aviator吧
465 0
|
编译器 Scala 开发者
类型匹配的注意事项和细节 | 学习笔记
快速学习类型匹配的注意事项和细节
适配器模式:转换匹配,复用已有功能
适配器模式的本质是转换匹配,复用已有功能
844 0
适配器模式:转换匹配,复用已有功能