浏览代码

组卷调整临时提交

mingfu 3 周之前
父节点
当前提交
95308aa25a
共有 1 个文件被更改,包括 215 次插入2 次删除
  1. 215 2
      ie-admin/src/main/java/com/ruoyi/web/service/PaperService.java

+ 215 - 2
ie-admin/src/main/java/com/ruoyi/web/service/PaperService.java

@@ -44,8 +44,23 @@ public class PaperService {
         this.questionsMapper = questionsMapper;
         this.learnQuestionsService = learnQuestionsService;
         this.learnDirectedKnowledgeMapper = learnDirectedKnowledgeMapper;
-        // buildSimulatedPaper(20154L, 11L);
         this.wishUniversitiesService = wishUniversitiesService;
+        // buildSimulatedPaper(20154L, 11L);
+        // test2();
+    }
+
+    public void test2() {
+        TestPaperVO.PaperDef paperDef = new TestPaperVO.PaperDef();
+        paperDef.setFillExclude(true);
+        paperDef.setKnowIds(Lists.newArrayList(1016L,1101L,1091L, 1103L));
+        List<TestPaperVO.TypeDef> typeDefList= Lists.newArrayList();
+        typeDefList.add(new TestPaperVO.TypeDef("判断题", "判断题", 20, 2));
+        typeDefList.add(new TestPaperVO.TypeDef("单选题", "单选题", 10, 1));
+        typeDefList.add(new TestPaperVO.TypeDef("多选题", "多选题", 10, 2));
+        paperDef.setTypes(typeDefList);
+        paperDef.setTotal(40L);
+        List<LearnPaperQuestion> questionList = getQuestionsByType(null, paperDef);
+        return;
     }
 
     public void test() {
@@ -114,6 +129,8 @@ public class PaperService {
             } else {
                 BeanUtils.copyProperties(lqs, qs, "title", "options", "parse", "answer1", "answer2");
             }
+            qs.setTotalScore(lqs.getScore());
+            qs.setScore(null);
             QuestionType qt = QuestionType.of(lqs.getQtpye());
             qs.setTypeId(qt.getVal());
             qs.setIsFavorite(lqs.isCollect());
@@ -123,6 +140,7 @@ public class PaperService {
                 qs.setState(answer.getState());
                 qs.setIsMark(answer.getMark());
                 qs.setIsNotKnow(answer.getNotKnow());
+                qs.setScore(answer.getScore());
             }
             if(StringUtils.isNotBlank(lqs.getTitle0())) { // 大题
                 PaperVO.QuestionAnswer qg = gropuMap.get(lqs.getTitle0());
@@ -229,6 +247,19 @@ public class PaperService {
         return paper;
     }
 
+    /**
+     * 按类型,知识点平均分配组卷
+     * @param studentId
+     * @param paperDef
+     * @return
+     */
+    public List<LearnPaperQuestion> getQuestionsByType(Long studentId, TestPaperVO.PaperDef paperDef) {
+        // 统计知识点+类型的有效数量 TODO 总量可以缓存
+        Map<String, KnowTypeAssign> knowTypeAssignMap = buildKnowTypeAssignMap(studentId, paperDef);
+        assignTypeFirstWithCount(paperDef, knowTypeAssignMap); // 知识优先,类型可变
+        return getQuestions(studentId, paperDef, knowTypeAssignMap);
+    }
+
     /**
      * 按知识点,题型平均分配组卷
      * @param studentId
@@ -243,6 +274,188 @@ public class PaperService {
         return getQuestions(studentId, paperDef, knowTypeAssignMap);
     }
 
+    private void assignTypeFirstWithCount(TestPaperVO.PaperDef paperDef, Map<String, KnowTypeAssign> knowTypeAssignMap) {
+        AtomicLong assignCount = new AtomicLong(0);
+        Map<Long, Long> knownAdjMap = Maps.newHashMap();
+        Map<String, Set<Long>> typeKnowIdMap = Maps.newHashMap();
+        Map<String, Long> typeFillCntMap = Maps.newHashMap();
+        Map<String, Long> typeMinCntMap = Maps.newHashMap();
+        // 所有知识点,正常补全一次,哪个知识点差多少先记录下
+        for(TestPaperVO.TypeDef typeDef : paperDef.getTypes()) {
+            Long avgKnowTypeCount = typeDef.getCount().longValue() / paperDef.getKnowIds().size();
+            if(avgKnowTypeCount.equals(0L)) {
+                avgKnowTypeCount = 1L;
+            }
+            assignCount.set(0);
+            for(Long knowId : paperDef.getKnowIds()) {
+                Long tmpMinKnowTypeCount = assignKnownCount(knowId, typeDef.getType(), knowTypeAssignMap, avgKnowTypeCount, paperDef.getFillExclude(), assignCount);
+                if (tmpMinKnowTypeCount > 0) {
+                    // 记录最小数
+                    Long minKnowTypeCount = typeMinCntMap.get(typeDef.getType());
+                    typeMinCntMap.put(typeDef.getType(), null == minKnowTypeCount ? tmpMinKnowTypeCount : Math.min(minKnowTypeCount, tmpMinKnowTypeCount));
+                    // 记录有效知识点
+                    Set<Long> knownIdSet = typeKnowIdMap.get(typeDef.getType());
+                    if(null == knownIdSet) {
+                        typeKnowIdMap.put(typeDef.getType(), Sets.newHashSet(knowId));
+                    } else {
+                        knownIdSet.add(knowId);
+                    }
+                } else if(tmpMinKnowTypeCount < 0) { // 差的个数移到下一类型,补充的类型也移到下一类型
+                    // 记录知识点差额
+                    Long lackCount = knownAdjMap.get(knowId);
+                    knownAdjMap.put(knowId, (null != lackCount ? lackCount : 0L) - tmpMinKnowTypeCount);
+                }
+            }
+            typeFillCntMap.put(typeDef.getType(), assignCount.get());
+        }
+        knownAdjMap.clear();
+        // 优先补充差的知识点
+        for(TestPaperVO.TypeDef typeDef : paperDef.getTypes()) {
+            assignCount.set(typeFillCntMap.get(typeDef.getType()));
+            Long lackTotal = typeDef.getCount().longValue();
+            Long minCount = typeMinCntMap.get(typeDef.getType());
+            Set<Long> knownIdSet = typeKnowIdMap.get(typeDef.getType());
+            do {
+                if(lackTotal <= assignCount.get()) {
+                    break;
+                }
+                Long needCount = lackTotal - assignCount.get();
+                Long avgKnowTypeCount = knownIdSet.size() > 0 ? Math.min(minCount, needCount / knownIdSet.size()) : 1;
+                if (avgKnowTypeCount <= 0L) {
+                    avgKnowTypeCount = 1L;
+                }
+                minCount = Long.MAX_VALUE;
+                Set<Long> validIdSet = Sets.newHashSet(knownIdSet);
+                knownIdSet.clear();
+                for(Long knowId : paperDef.getKnowIds()) {
+                    if(knownIdSet.size() > 0 && !validIdSet.contains(knowId)) {
+                        continue;
+                    }
+                    // Long lastLack = null; knownAdjMap.remove(knowId); null != lastLack ? lastLack + avgKnowTypeCount :
+                    Long knowTypeCount = avgKnowTypeCount;
+                    if (knowTypeCount > 0) {
+//                        Long oldCnt = assignCount.get();
+                        Long tmpMinKnowTypeCount = assignKnownCount(knowId, typeDef.getType(), knowTypeAssignMap, knowTypeCount, paperDef.getFillExclude(), assignCount);
+//                        Long fillCnt = oldCnt - assignCount.get();
+//                        if(fillCnt < 0) {
+//                            Long oldFill = knownAdjMap.get(knowId);
+//                            knownAdjMap.put(knowId, null == oldFill ? fillCnt : oldFill - fillCnt);
+//                        }
+                        if (tmpMinKnowTypeCount > 0) {
+                            minCount = Math.min(minCount, tmpMinKnowTypeCount);
+                            knownIdSet.add(knowId);
+                        } else if(tmpMinKnowTypeCount < 0) { // 差的个数移到下一类型,补充的类型也移到下一类型
+                            // knownAdjMap.put(knowId, -tmpMinKnowTypeCount);
+                        }
+                    } else if(knowTypeCount < 0) {
+                        // knownAdjMap.put(knowId, knowTypeCount);
+                    }
+                    if(lackTotal <= assignCount.get()) {
+                        break;
+                    }
+                }
+            } while(true);
+        }
+    }
+
+    private void assignTypeFirstWithCount2(TestPaperVO.PaperDef paperDef, Map<String, KnowTypeAssign> knowTypeAssignMap) {
+        Map<String, Set<Long>> typeKnownIdsMap = knowTypeAssignMap.values().stream().collect(Collectors.groupingBy(KnowTypeAssign::getType, Collectors.mapping(KnowTypeAssign::getKnowId, Collectors.toSet())));
+        Map<Long, Long> knownAdjMap = Maps.newHashMap();
+        AtomicLong assignCount = new AtomicLong(0);
+        Integer needCount = paperDef.getTypes().size();
+        Set<String> doneSet = Sets.newHashSet();
+        do {
+            for(TestPaperVO.TypeDef typeDef : paperDef.getTypes()) { // 每个类型,让所有知识先平均补充,补充的由后面填充
+                Long minKnowTypeCount = Long.MAX_VALUE;
+                // 首先按平均数量填充
+                assignCount.set(0L);
+                Long lackTotal = typeDef.getCount().longValue();
+                Set<Long> knownIdSet;
+                if(knownAdjMap.size() > 0) { // 先补充之前的同类型
+                    knownIdSet = Sets.newHashSet();
+                    for(Long knowId : paperDef.getKnowIds()) {
+                        Long lastLack = knownAdjMap.remove(knowId);
+                        Long knowTypeCount = null != lastLack ? lastLack : 0;
+                        if(knowTypeCount >= 0) {
+                            Long tmpMinKnowTypeCount = assignKnownCount(knowId, typeDef.getType(), knowTypeAssignMap, knowTypeCount, paperDef.getFillExclude(), assignCount);
+                            if (tmpMinKnowTypeCount > 0) {
+                                minKnowTypeCount = Math.min(minKnowTypeCount, tmpMinKnowTypeCount);
+                                knownIdSet.add(knowId);
+                            } else if(tmpMinKnowTypeCount < 0) { // 差的个数移到下一类型,补充的类型也移到下一类型
+                                knownAdjMap.put(knowId, -tmpMinKnowTypeCount);
+                            }
+                        } else if(knowTypeCount < 0) {
+                            knownAdjMap.put(knowId, knowTypeCount);
+                        }
+                    }
+                } else {
+                    knownIdSet = typeKnownIdsMap.get(typeDef.getType());
+                }
+                if(lackTotal <= assignCount.get()) {
+                    doneSet.add(typeDef.getType());
+                    continue;
+                }
+                Long avgKnowTypeCount = (lackTotal - assignCount.get()) / paperDef.getKnowIds().size();
+                if (avgKnowTypeCount <= 0L) {
+                    avgKnowTypeCount = 1L;
+                }
+                for(Long knowId : paperDef.getKnowIds()) {
+                    Long lastLack = knownAdjMap.remove(knowId);
+                    Long knowTypeCount = null != lastLack ? lastLack + avgKnowTypeCount : avgKnowTypeCount;
+                    if(knowTypeCount > 0) {
+                        Long tmpMinKnowTypeCount = assignKnownCount(knowId, typeDef.getType(), knowTypeAssignMap, knowTypeCount, paperDef.getFillExclude(), assignCount);
+                        if (tmpMinKnowTypeCount > 0) {
+                            minKnowTypeCount = Math.min(minKnowTypeCount, tmpMinKnowTypeCount);
+                            knownIdSet.add(knowId);
+                        } else if(tmpMinKnowTypeCount < 0) { // 差的个数移到下一类型,补充的类型也移到下一类型
+                            knownAdjMap.put(knowId, -tmpMinKnowTypeCount);
+                        }
+                    } else if(knowTypeCount < 0) {
+                        knownAdjMap.put(knowId, knowTypeCount);
+                    }
+                }
+                // 然后进行多级补充,多退少补
+                do {
+                    if(lackTotal <= assignCount.get()) {
+                        doneSet.add(typeDef.getType());
+                        break;
+                    }
+                    avgKnowTypeCount = Math.min(minKnowTypeCount, (lackTotal - assignCount.get()) / knownIdSet.size());
+                    if (avgKnowTypeCount <= 0L) {
+                        avgKnowTypeCount = 1L;
+                    }
+                    minKnowTypeCount = Long.MAX_VALUE;
+                    Set<Long> validIdSet = Sets.newHashSet(knownIdSet);
+                    knownIdSet.clear();
+                    for(Long knowId : paperDef.getKnowIds()) {
+                        if(!validIdSet.contains(knowId)) {
+                            continue;
+                        }
+                        Long lastLack = knownAdjMap.remove(knowId);
+                        Long knowTypeCount = null != lastLack ? lastLack + avgKnowTypeCount : avgKnowTypeCount;
+                        if (knowTypeCount > 0) {
+                            Long oldCnt = assignCount.get();
+                            Long tmpMinKnowTypeCount = assignKnownCount(knowId, typeDef.getType(), knowTypeAssignMap, knowTypeCount, paperDef.getFillExclude(), assignCount);
+                            Long fillCnt = oldCnt - assignCount.get();
+                            if(fillCnt < 0) {
+                                Long oldFill = knownAdjMap.get(knowId);
+                                knownAdjMap.put(knowId, null == oldFill ? fillCnt : oldFill - fillCnt);
+                            }
+                            if (tmpMinKnowTypeCount > 0) {
+                                minKnowTypeCount = Math.min(minKnowTypeCount, tmpMinKnowTypeCount);
+                                knownIdSet.add(knowId);
+                            } else if(tmpMinKnowTypeCount < 0) { // 差的个数移到下一类型,补充的类型也移到下一类型
+                                knownAdjMap.put(knowId, -tmpMinKnowTypeCount);
+                            }
+                        } else if(knowTypeCount < 0) {
+                            knownAdjMap.put(knowId, knowTypeCount);
+                        }
+                    }
+                } while(true);
+            }
+        } while(doneSet.size() < needCount);
+    }
+
     private void assignKnowFirst(TestPaperVO.PaperDef paperDef, Map<String, KnowTypeAssign> knowTypeAssignMap) {
         // 循环补充未做+已做,如果知识点总数不够时才填充其他知识点的
         Long lackTotal = paperDef.getTotal();
@@ -440,7 +653,7 @@ public class PaperService {
         } else if(lack < 0) {
             return -lack;
         }
-        return 0L;
+        return -lack;
     }
 
     /**