Bläddra i källkod

refactor(game): 优化比赛分组逻辑和性别验证

- 移除不必要的导入和初始化接口
- 修复性别比较逻辑,使用正确的枚举值比较
- 重构分组分配算法,改进道次分配顺序
- 使用final变量解决lambda表达式中的变量引用问题
- 优化日志输出,添加中间位置计算日志
- 简化代码结构,移除冗余注释和变量声明
zhou 3 månader sedan
förälder
incheckning
963f3157fd

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

@@ -15,9 +15,7 @@ import org.dromara.system.domain.bo.GameTeamBo;
 import org.dromara.system.domain.vo.*;
 import org.dromara.system.service.*;
 import org.springframework.stereotype.Service;
-import org.springframework.context.annotation.Lazy;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.InitializingBean;
 import org.dromara.system.domain.bo.GameEventGroupBo;
 import org.dromara.system.domain.constant.GameEventConstant;
 import org.dromara.system.domain.constant.ProjectClassification;
@@ -348,8 +346,8 @@ public class GameEventGroupServiceImpl implements IGameEventGroupService {
                         .findFirst();
                     if (StringUtils.isNotBlank(groupInfo.getMemberGender())) {
                         if (!groupInfo.getMemberGender().equals(
-                            athlete.getGender() != null ? athlete.getGender().toString() : null)) {
-                            return false;
+                            athlete.getGender() != null ? athlete.getGender() : null)) {
+                            return groupInfo.getMemberGender().equals(mixGender.orElse(null));
                         }
                     }
 
@@ -373,44 +371,48 @@ public class GameEventGroupServiceImpl implements IGameEventGroupService {
             // 分组结果
             Map<String, GameAthleteVo> groupResult = new HashMap<>();
 
-            // 按组别和道次分配运动员
-            for (int groupIndex = 1; groupIndex <= groupInfo.getIncludeGroupNum(); groupIndex++) {
-                final int currentGroupIndex = groupIndex; // 创建final变量用于lambda表达式
-                // 每组分配 personNum 个运动员,但不超过 trackNum
-                Long personsPerGroup = groupInfo.getPersonNum() != null ? groupInfo.getPersonNum() : groupInfo.getTrackNum();
-                // 如果每组人数超过道数,限制为道数(否则无法显示)
-                if (personsPerGroup > groupInfo.getTrackNum()) {
-                    log.warn("每组人数({})超过道数({}),将限制为道数", personsPerGroup, groupInfo.getTrackNum());
-                    personsPerGroup = groupInfo.getTrackNum();
-                }
+            // 实际可用的道次数量
+            int actualTrackNum = groupInfo.getTrackNum().intValue();
 
-                int personsPerGroupInt = personsPerGroup.intValue();
+            // 总组数
+            int totalGroups = groupInfo.getIncludeGroupNum().intValue();
 
-                // 实际可用的道次数量
-                int actualTrackNum = groupInfo.getTrackNum().intValue();
+            // 每组分配人数
+            Long personsPerGroup = groupInfo.getPersonNum() != null ? groupInfo.getPersonNum() : groupInfo.getTrackNum();
+            if (personsPerGroup > groupInfo.getTrackNum()) {
+                log.warn("每组人数({})超过道数({}),将限制为道数", personsPerGroup, groupInfo.getTrackNum());
+                personsPerGroup = groupInfo.getTrackNum();
+            }
+            int personsPerGroupInt = personsPerGroup.intValue();
 
-                // 动态生成最优分配顺序:从中间开始,按照空位规则(空8道>空1道>空7道>空2道)
-                List<Integer> optimalTrackOrder = generateOptimalTrackOrder(actualTrackNum);
+            // 动态生成最优分配顺序:从中间开始,按照空位规则(空最大道>空最小道>空次大道>空次小道)
+            List<Integer> optimalTrackOrder = generateOptimalTrackOrder(actualTrackNum);
 
-                // 根据实际道数和需要人数调整分配顺序
-                List<Integer> tracksToAssign = new ArrayList<>();
-                for (Integer track : optimalTrackOrder) {
-                    if (track <= actualTrackNum && tracksToAssign.size() < personsPerGroupInt) {
-                        tracksToAssign.add(track);
-                    }
+            // 根据需要分配的人数过滤道次
+            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);
-                }
+            // 确保我们只分配需要的人数,多余的道次留空
+            if (tracksToAssign.size() > personsPerGroupInt) {
+                tracksToAssign = tracksToAssign.subList(0, personsPerGroupInt);
+            }
 
-                // 按优化的道次顺序分配运动员
-                for (Integer track : tracksToAssign) {
+            // 空位规则应用于列(道次)而非行(组别)
+            // 对每个道次,按组别顺序分配运动员
+            for (Integer track : tracksToAssign) {
+                // 对当前道次,按组别顺序分配
+                for (int groupIndex = 1; groupIndex <= totalGroups; groupIndex++) {
                     // 寻找可用的运动员
                     GameAthleteVo selectedAthlete = null;
                     int athleteIndex = 0;
 
+                    // 创建final局部变量,用于lambda表达式中引用
+                    final int finalGroupIndex = groupIndex;
+
                     while (athleteIndex < shuffledAthletes.size() && selectedAthlete == null) {
                         GameAthleteVo candidateAthlete = shuffledAthletes.get(athleteIndex);
 
@@ -421,16 +423,15 @@ public class GameEventGroupServiceImpl implements IGameEventGroupService {
                         }
 
                         // 只有项目属于团体项目才检查同一组中是否已有同一队伍的运动员
-                        // 个人项目(classification="0")不限制同一队伍,团体项目(classification="1")才限制
                         boolean isValidCandidate = true;
                         if (project != null && ProjectClassification.TEAM.getValue().equals(project.getClassification())) {
-                            // 团体项目:检查同一组中是否已有同一队伍的运动员,避免同一队伍在同一组中重复分配
+                            // 团体项目:检查同一组中是否已有同一队伍的运动员
                             boolean hasSameTeamInGroup = groupResult.entrySet().stream()
                                 .anyMatch(entry -> {
                                     String[] keyParts = entry.getKey().split("-");
                                     if (keyParts.length >= 1) {
                                         String existingGroup = keyParts[0];
-                                        return existingGroup.equals(String.valueOf(currentGroupIndex)) &&
+                                        return existingGroup.equals(String.valueOf(finalGroupIndex)) &&
                                                entry.getValue().getTeamId() != null &&
                                                entry.getValue().getTeamId().equals(candidateAthlete.getTeamId());
                                     }
@@ -439,10 +440,9 @@ public class GameEventGroupServiceImpl implements IGameEventGroupService {
                             if (hasSameTeamInGroup) {
                                 isValidCandidate = false;
                                 log.debug("第{}组拒绝运动员{}:团体项目中同一组不能有同一队伍({})的运动员",
-                                    currentGroupIndex, candidateAthlete.getAthleteCode(), candidateAthlete.getTeamId());
+                                    finalGroupIndex, candidateAthlete.getAthleteCode(), candidateAthlete.getTeamName());
                             }
                         }
-                        // 个人项目(classification="0"或null):允许同一组中有同一队伍的运动员,不进行队伍限制检查
 
                         if (isValidCandidate) {
                             selectedAthlete = candidateAthlete;
@@ -455,10 +455,10 @@ public class GameEventGroupServiceImpl implements IGameEventGroupService {
 
                     // 如果找到了合适的运动员,分配到当前组和道次
                     if (selectedAthlete != null) {
-                        String key = currentGroupIndex + "-" + track;
+                        String key = finalGroupIndex + "-" + track;
                         groupResult.put(key, selectedAthlete);
                         log.debug("分配成功 - 第{}组第{}道: 运动员编号={}, 姓名={}, 队伍={}",
-                            currentGroupIndex, track, selectedAthlete.getAthleteCode(),
+                            finalGroupIndex, track, selectedAthlete.getAthleteCode(),
                             selectedAthlete.getName(), selectedAthlete.getTeamName());
                     } else {
                         // 检查是否有可用但未分配的运动员
@@ -467,10 +467,10 @@ public class GameEventGroupServiceImpl implements IGameEventGroupService {
                             .count();
                         if (availableCount > 0) {
                             log.warn("第{}组第{}道未找到合适的运动员,但仍有{}个符合条件的运动员未分配",
-                                currentGroupIndex, track, availableCount);
+                                finalGroupIndex, track, availableCount);
                         } else {
                             log.warn("第{}组第{}道未找到合适的运动员,所有符合条件的运动员都已被分配",
-                                currentGroupIndex, track);
+                                finalGroupIndex, track);
                         }
                     }
                 }
@@ -499,10 +499,6 @@ public class GameEventGroupServiceImpl implements IGameEventGroupService {
                 log.info("  所有符合条件的运动员都已成功分配");
             } else {
                 // 计算需要的道次总数(每组人数 × 组数,但不超过道数)
-                int personsPerGroup = groupInfo.getPersonNum() != null &&
-                    groupInfo.getPersonNum() <= groupInfo.getTrackNum()
-                        ? groupInfo.getPersonNum().intValue()
-                        : groupInfo.getTrackNum().intValue();
                 Long totalTracksNeeded = groupInfo.getIncludeGroupNum() * personsPerGroup;
 
                 for (GameAthleteVo athlete : unassignedAthletes) {
@@ -603,7 +599,8 @@ public class GameEventGroupServiceImpl implements IGameEventGroupService {
         }
 
         // 计算中间位置
-        int middle = totalTracks / 2 + 1;
+        int middle = totalTracks%2==0 ? totalTracks / 2 : (totalTracks + 1) / 2;
+        log.info("为{}道生成中间位置: {}", totalTracks, middle);
 
         // 从中间向两侧展开,先左后右(小的道次优先)
         // 使用队列来按层序存储道次