From a94b1ac3b0dce24cd80675347c552fd38aee2249 Mon Sep 17 00:00:00 2001 From: joylink_zhangsai <1021828630@qq.com> Date: Fri, 26 Aug 2022 17:10:32 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=9E=E8=AE=AD=E8=AF=84=E5=88=86=E8=A7=84?= =?UTF-8?q?=E5=88=99=E4=BD=BF=E7=94=A8=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../services/training2/Training2Service.java | 41 ++++-- .../cbtc/training2/ScoringRule2.java | 123 ++++++++++++++++-- .../simulation/cbtc/training2/Training2.java | 29 ++++- .../vo/client/training2/ExpressionVO.java | 4 + .../vo/client/training2/ScoringRuleVO.java | 12 +- 5 files changed, 182 insertions(+), 27 deletions(-) diff --git a/src/main/java/club/joylink/rtss/services/training2/Training2Service.java b/src/main/java/club/joylink/rtss/services/training2/Training2Service.java index a2985823f..cf4700f52 100644 --- a/src/main/java/club/joylink/rtss/services/training2/Training2Service.java +++ b/src/main/java/club/joylink/rtss/services/training2/Training2Service.java @@ -14,9 +14,7 @@ import club.joylink.rtss.simulation.cbtc.exception.SimulationException; import club.joylink.rtss.simulation.cbtc.exception.SimulationExceptionType; import club.joylink.rtss.simulation.cbtc.member.MemberManager; import club.joylink.rtss.simulation.cbtc.script.ScriptBO; -import club.joylink.rtss.simulation.cbtc.training2.Operation2; -import club.joylink.rtss.simulation.cbtc.training2.Step2; -import club.joylink.rtss.simulation.cbtc.training2.Training2; +import club.joylink.rtss.simulation.cbtc.training2.*; import club.joylink.rtss.util.JsonUtils; import club.joylink.rtss.vo.AccountVO; import club.joylink.rtss.vo.LoginUserInfoVO; @@ -33,12 +31,14 @@ import org.springframework.util.StringUtils; import java.time.LocalDateTime; import java.time.temporal.ChronoUnit; +import java.util.List; import java.util.Objects; import java.util.function.Consumer; @Service public class Training2Service { - public static final String JOB_NAME = "Training2"; + public static final String EXECUTE_JOB_NAME = "Training2"; + public static final String SCORING_JOB_NAME = "Training2Scoring"; public static final int RATE = 1000; @Autowired @@ -134,10 +134,26 @@ public class Training2Service { atsOperationDispatcher.execute(simulation, step.getSimulationMember(), simOperation2.getOperationType().name(), simOperation2.getParams()); } - public void loadTraining(long id, Simulation simulation) { - DraftTraining2WithBLOBs draftTraining2 = new DraftTraining2WithBLOBs(); - Training2 training2 = new Training2(draftTraining2, simulation); - simulation.addJobIfAbsent(JOB_NAME, () -> this.run(simulation), RATE); + /** + * 评分监视 + */ + public void scoringMonitor(Simulation simulation) { + Training2 training2 = simulation.getTraining2(); + List scoringRules = training2.getScoringRules(); + if (CollectionUtils.isEmpty(scoringRules)) + return; + for (ScoringRule2 scoringRule : scoringRules) { + for (ScoringRule2.Detail durativeDetail : scoringRule.getDurativeDetails()) { + if (durativeDetail.getDeduct() != null) //已经被判定的不用再监视 + continue; + Expression condition = durativeDetail.getCondition(); + if (condition != null) { + if (condition.getValue(boolean.class)) { + durativeDetail.setDeduct(true); + } + } + } + } } /** @@ -223,10 +239,11 @@ public class Training2Service { groupSimulationService.loadScenes(simulation.getId(), training2.getBgSceneJson()); } // 增加任务 - if (simulation.getJobMap().containsKey(JOB_NAME)) { - simulation.removeJob(JOB_NAME); + if (simulation.getJobMap().containsKey(EXECUTE_JOB_NAME)) { + simulation.removeJob(EXECUTE_JOB_NAME); } - simulation.addJobIfAbsent(JOB_NAME, () -> this.run(simulation), RATE); + simulation.addJobIfAbsent(EXECUTE_JOB_NAME, () -> this.run(simulation), RATE); + simulation.addJobIfAbsent(SCORING_JOB_NAME, () -> this.scoringMonitor(simulation), RATE); training2.start(mode); simulationLifeCycleService.resume(simulation); } @@ -246,7 +263,9 @@ public class Training2Service { if (training2 == null) { throw new SimulationException(SimulationExceptionType.Invalid_Operation, "实训数据不存在"); } + simulation.removeJob(SCORING_JOB_NAME); //移除打分监视任务 training2.finish(); + training2.mark(); // 暂停仿真 simulationLifeCycleService.pause(simulation); } diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/training2/ScoringRule2.java b/src/main/java/club/joylink/rtss/simulation/cbtc/training2/ScoringRule2.java index 7583e6dcd..9cb7c37fa 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/training2/ScoringRule2.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/training2/ScoringRule2.java @@ -3,14 +3,17 @@ package club.joylink.rtss.simulation.cbtc.training2; import club.joylink.rtss.simulation.cbtc.member.SimulationMember; import lombok.AllArgsConstructor; import lombok.Getter; +import lombok.Setter; +import org.springframework.util.CollectionUtils; +import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; /** * 评分规则 */ @Getter -@AllArgsConstructor public class ScoringRule2 { /** * 评分规则应用于该成员 @@ -27,20 +30,110 @@ public class ScoringRule2 { */ private List details; + /** + * 最终得分 + */ + private Float finalScore; + + public ScoringRule2(SimulationMember member, Float fullMarks, List details) { + this.member = member; + this.fullMarks = fullMarks; + this.details = details; + } + + public List getDurativeDetails() { + if (CollectionUtils.isEmpty(details)) { + return new ArrayList<>(); + } else { + return details.stream() + .filter(detail -> Detail.Type.DURATIVE.equals(detail.getType())) + .collect(Collectors.toList()); + } + } + + public float mark(boolean allStepCompletion) { + if (finalScore != null) + return finalScore; + + if (CollectionUtils.isEmpty(details)) { //没有打分细则,则实训完成给满分,否则0分 + return allStepCompletion ? fullMarks : 0f; + } else { + double deductedPoints = details.stream() + .peek(detail -> { + if (detail.getDeduct() == null) { //未作出判定 + if (detail.isDurative()) { + detail.setDeduct(false); + } else { + if (detail.getCondition() != null) { + detail.setDeduct(detail.getCondition().getValue(boolean.class)); + } else { + detail.setDeduct(!detail.isCompletion()); + } + } + } + }) + .mapToDouble(detail -> Boolean.TRUE.equals(detail.getDeduct()) ? detail.getScore() : 0) + .sum(); + float finalScore = (float) (fullMarks - deductedPoints); + this.finalScore = finalScore < 0 ? 0 : finalScore; + return finalScore; + } + } + @Getter @AllArgsConstructor public static class Detail { private Type type; + private ElementType elementType; + + /** + * 扣分分值 + */ private float score; + /** + * 满足该条件则扣分 + */ private Expression condition; + /** + * null 未判定;true 扣分;false 不扣分; + */ + @Setter + private Boolean deduct; + + public Detail(Type type, ElementType elementType, float score, Expression condition) { + this.type = type; + this.elementType = elementType; + this.score = score; + this.condition = condition; + } + public Object getElement() { return null; } + public boolean isDurative() { + return Type.DURATIVE.equals(type); + } + + public boolean isCompletion() { + return true; + } + public enum Type { + /** + * 触发式的 + */ + TRIGGERED, + /** + * 持续性的 + */ + DURATIVE, + } + + public enum ElementType { /** * 操作 */ @@ -56,11 +149,11 @@ public class ScoringRule2 { } } - public static class Operation2Detail extends Detail{ + public static class Operation2Detail extends Detail { private Operation2 element; - public Operation2Detail(Type type, Operation2 element, float score, Expression condition) { - super(type, score, condition); + public Operation2Detail(Type type, ElementType elementType, Operation2 element, float score, Expression condition) { + super(type, elementType, score, condition); this.element = element; } @@ -68,19 +161,29 @@ public class ScoringRule2 { public Object getElement() { return element; } + + @Override + public boolean isCompletion() { + return element.isCompletion(); + } } - public static class Step2Detail extends Detail{ - private Step2 element; + public static class Step2Detail extends Detail { + private Step2 step; - public Step2Detail(Type type, Step2 element, float score, Expression condition) { - super(type, score, condition); - this.element = element; + public Step2Detail(Type type, ElementType elementType, Step2 step, float score, Expression condition) { + super(type, elementType, score, condition); + this.step = step; } @Override public Object getElement() { - return element; + return step; + } + + @Override + public boolean isCompletion() { + return step.isCompletion(); } } } diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/training2/Training2.java b/src/main/java/club/joylink/rtss/simulation/cbtc/training2/Training2.java index fe55256a3..4d67f3b9a 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/training2/Training2.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/training2/Training2.java @@ -3,6 +3,7 @@ package club.joylink.rtss.simulation.cbtc.training2; import club.joylink.rtss.entity.training2.DraftTraining2WithBLOBs; import club.joylink.rtss.exception.BusinessExceptionAssertEnum; import club.joylink.rtss.simulation.cbtc.Simulation; +import club.joylink.rtss.simulation.cbtc.member.SimulationMember; import club.joylink.rtss.simulation.cbtc.script.ScriptBO; import club.joylink.rtss.util.JsonUtils; import club.joylink.rtss.vo.client.training2.ExpressionVO; @@ -11,10 +12,11 @@ import club.joylink.rtss.vo.client.training2.ScoringRuleVO; import club.joylink.rtss.vo.client.training2.Step2VO; import lombok.Getter; import lombok.Setter; +import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; import java.time.LocalDateTime; -import java.util.List; +import java.util.*; import java.util.stream.Collectors; @Getter @@ -151,6 +153,31 @@ public class Training2 { return step2; } + public List getSteps(SimulationMember simulationMember) { + if (CollectionUtils.isEmpty(steps)) { + return new ArrayList<>(); + } else { + return steps.stream() + .filter(step2 -> Objects.equals(simulationMember, step2.getSimulationMember())) + .collect(Collectors.toList()); + } + } + + /** + * 打分 + * @return k-memberId v-分数 + */ + public Map mark() { + Map map = new HashMap<>(); + if (!CollectionUtils.isEmpty(scoringRules)) { + for (ScoringRule2 scoringRule : scoringRules) { + boolean allStepCompletion = getSteps(scoringRule.getMember()).stream().allMatch(Step2::isCompletion); + map.put(scoringRule.getMember().getId(), scoringRule.mark(allStepCompletion)); + } + } + return map; + } + public enum Type { SINGLE, SCENE, diff --git a/src/main/java/club/joylink/rtss/vo/client/training2/ExpressionVO.java b/src/main/java/club/joylink/rtss/vo/client/training2/ExpressionVO.java index f7ad1e35e..2ab3aee77 100644 --- a/src/main/java/club/joylink/rtss/vo/client/training2/ExpressionVO.java +++ b/src/main/java/club/joylink/rtss/vo/client/training2/ExpressionVO.java @@ -30,4 +30,8 @@ public class ExpressionVO implements ValuableVO { } return new Expression(operator, vs); } + + public static Expression convert2BO(ExpressionVO expressionVO, SimulationDataRepository repository) { + return expressionVO == null ? null : expressionVO.convert2BO(repository); + } } diff --git a/src/main/java/club/joylink/rtss/vo/client/training2/ScoringRuleVO.java b/src/main/java/club/joylink/rtss/vo/client/training2/ScoringRuleVO.java index 25c16639b..e49ef8bbf 100644 --- a/src/main/java/club/joylink/rtss/vo/client/training2/ScoringRuleVO.java +++ b/src/main/java/club/joylink/rtss/vo/client/training2/ScoringRuleVO.java @@ -57,6 +57,8 @@ public class ScoringRuleVO { public static class DetailVO { private ScoringRule2.Detail.Type type; + private ScoringRule2.Detail.ElementType elementType; + /** * 被评分的元素的id(操作、步骤、实训) */ @@ -73,17 +75,17 @@ public class ScoringRuleVO { private ExpressionVO condition; public ScoringRule2.Detail convert2BO(Training2 training2, SimulationDataRepository repository) { - switch (type) { + switch (elementType) { case O: Operation2 operation2 = training2.getOperation(Integer.parseInt(elementId)); - return new ScoringRule2.Operation2Detail(type, operation2, score, condition.convert2BO(repository)); + return new ScoringRule2.Operation2Detail(type, elementType, operation2, score, ExpressionVO.convert2BO(condition, repository)); case S: Step2 step2 = training2.getStep(Integer.parseInt(elementId)); - return new ScoringRule2.Step2Detail(type, step2, score, condition.convert2BO(repository)); + return new ScoringRule2.Step2Detail(type, elementType, step2, score, ExpressionVO.convert2BO(condition, repository)); case T: - return new ScoringRule2.Detail(type, score, condition.convert2BO(repository)); + return new ScoringRule2.Detail(type, elementType, score, ExpressionVO.convert2BO(condition, repository)); default: - throw new IllegalStateException("Unexpected value: " + type); + throw new IllegalStateException("Unexpected value: " + elementType); } } }