Переглянути джерело

feat(game): 优化跑道分配算法

- 实现动态生成最优跑道分配顺序,从中间向两侧展开
- 添加按空位规则的智能分配机制(空8道>空1道>空7道>空2道)
- 集成队列和集合数据结构支持层序遍历算法
- 添加调试日志记录生成的跑道顺序
- 重构运动员分配逻辑使用优化后的道次顺序
zhou 3 місяців тому
батько
коміт
61d88e9f9a

+ 80 - 1
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/service/impl/GameEventGroupServiceImpl.java

@@ -383,7 +383,30 @@ public class GameEventGroupServiceImpl implements IGameEventGroupService {
                     log.warn("每组人数({})超过道数({}),将限制为道数", personsPerGroup, groupInfo.getTrackNum());
                     personsPerGroup = groupInfo.getTrackNum();
                 }
-                for (int track = 1; track <= personsPerGroup; track++) {
+
+                int personsPerGroupInt = personsPerGroup.intValue();
+
+                // 实际可用的道次数量
+                int actualTrackNum = groupInfo.getTrackNum().intValue();
+
+                // 动态生成最优分配顺序:从中间开始,按照空位规则(空8道>空1道>空7道>空2道)
+                List<Integer> optimalTrackOrder = generateOptimalTrackOrder(actualTrackNum);
+
+                // 根据实际道数和需要人数调整分配顺序
+                List<Integer> tracksToAssign = new ArrayList<>();
+                for (Integer track : optimalTrackOrder) {
+                    if (track <= actualTrackNum && tracksToAssign.size() < personsPerGroupInt) {
+                        tracksToAssign.add(track);
+                    }
+                }
+
+                // 确保我们只分配需要的人数,多余的道次留空
+                if (tracksToAssign.size() > personsPerGroupInt) {
+                    tracksToAssign = tracksToAssign.subList(0, personsPerGroupInt);
+                }
+
+                // 按优化的道次顺序分配运动员
+                for (Integer track : tracksToAssign) {
                     // 寻找可用的运动员
                     GameAthleteVo selectedAthlete = null;
                     int athleteIndex = 0;
@@ -559,4 +582,60 @@ public class GameEventGroupServiceImpl implements IGameEventGroupService {
 
         return result;
     }
+
+    /**
+     * 动态生成最优跑道分配顺序
+     * 根据任意道数,先填所有组的中间道,然后填比中间道小1的道,再填比中间道大1的道,以此类推
+     * @param totalTracks 总道数
+     * @return 最优分配顺序的道次列表
+     */
+    private List<Integer> generateOptimalTrackOrder(int totalTracks) {
+        List<Integer> result = new ArrayList<>();
+        if (totalTracks <= 0) {
+            return result;
+        }
+
+        // 如果是1道,直接返回
+        if (totalTracks == 1) {
+            result.add(1);
+            log.debug("为{}道生成的最优跑道顺序: {}", totalTracks, result);
+            return result;
+        }
+
+        // 计算中间位置
+        int middle = totalTracks / 2 + 1;
+
+        // 从中间向两侧展开,先左后右(小的道次优先)
+        // 使用队列来按层序存储道次
+        Queue<Integer> queue = new LinkedList<>();
+        Set<Integer> visited = new HashSet<>();
+
+        // 将中间位置作为起点加入队列
+        queue.offer(middle);
+        visited.add(middle);
+
+        while (!queue.isEmpty()) {
+            int current = queue.poll();
+            result.add(current);
+
+            // 先添加比当前道小1的道次(如果存在且未访问)
+            int left = current - 1;
+            if (left >= 1 && !visited.contains(left)) {
+                queue.offer(left);
+                visited.add(left);
+            }
+
+            // 再添加比当前道大1的道次(如果存在且未访问)
+            int right = current + 1;
+            if (right <= totalTracks && !visited.contains(right)) {
+                queue.offer(right);
+                visited.add(right);
+            }
+        }
+
+        // 记录生成的跑道顺序
+        log.debug("为{}道生成的最优跑道顺序: {}", totalTracks, result);
+
+        return result;
+    }
 }