动态范围匹配逻辑实现

2023-12-17 10:48:21 浏览数 (2)

生活的全部意义在于无穷地探索尚未知道的东西,在于不断地增加更多的知识。——左拉

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

代码语言:javascript复制
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范围的玩家

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

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

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

代码语言:javascript复制
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!

0 人点赞