实训评分规则使用逻辑

This commit is contained in:
joylink_zhangsai 2022-08-26 17:10:32 +08:00
parent 7669f34480
commit a94b1ac3b0
5 changed files with 182 additions and 27 deletions

View File

@ -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.exception.SimulationExceptionType;
import club.joylink.rtss.simulation.cbtc.member.MemberManager; import club.joylink.rtss.simulation.cbtc.member.MemberManager;
import club.joylink.rtss.simulation.cbtc.script.ScriptBO; import club.joylink.rtss.simulation.cbtc.script.ScriptBO;
import club.joylink.rtss.simulation.cbtc.training2.Operation2; import club.joylink.rtss.simulation.cbtc.training2.*;
import club.joylink.rtss.simulation.cbtc.training2.Step2;
import club.joylink.rtss.simulation.cbtc.training2.Training2;
import club.joylink.rtss.util.JsonUtils; import club.joylink.rtss.util.JsonUtils;
import club.joylink.rtss.vo.AccountVO; import club.joylink.rtss.vo.AccountVO;
import club.joylink.rtss.vo.LoginUserInfoVO; import club.joylink.rtss.vo.LoginUserInfoVO;
@ -33,12 +31,14 @@ import org.springframework.util.StringUtils;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.function.Consumer; import java.util.function.Consumer;
@Service @Service
public class Training2Service { 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; public static final int RATE = 1000;
@Autowired @Autowired
@ -134,10 +134,26 @@ public class Training2Service {
atsOperationDispatcher.execute(simulation, step.getSimulationMember(), simOperation2.getOperationType().name(), simOperation2.getParams()); 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<ScoringRule2> 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()); groupSimulationService.loadScenes(simulation.getId(), training2.getBgSceneJson());
} }
// 增加任务 // 增加任务
if (simulation.getJobMap().containsKey(JOB_NAME)) { if (simulation.getJobMap().containsKey(EXECUTE_JOB_NAME)) {
simulation.removeJob(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); training2.start(mode);
simulationLifeCycleService.resume(simulation); simulationLifeCycleService.resume(simulation);
} }
@ -246,7 +263,9 @@ public class Training2Service {
if (training2 == null) { if (training2 == null) {
throw new SimulationException(SimulationExceptionType.Invalid_Operation, "实训数据不存在"); throw new SimulationException(SimulationExceptionType.Invalid_Operation, "实训数据不存在");
} }
simulation.removeJob(SCORING_JOB_NAME); //移除打分监视任务
training2.finish(); training2.finish();
training2.mark();
// 暂停仿真 // 暂停仿真
simulationLifeCycleService.pause(simulation); simulationLifeCycleService.pause(simulation);
} }

View File

@ -3,14 +3,17 @@ package club.joylink.rtss.simulation.cbtc.training2;
import club.joylink.rtss.simulation.cbtc.member.SimulationMember; import club.joylink.rtss.simulation.cbtc.member.SimulationMember;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
import lombok.Setter;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
/** /**
* 评分规则 * 评分规则
*/ */
@Getter @Getter
@AllArgsConstructor
public class ScoringRule2 { public class ScoringRule2 {
/** /**
* 评分规则应用于该成员 * 评分规则应用于该成员
@ -27,20 +30,110 @@ public class ScoringRule2 {
*/ */
private List<Detail> details; private List<Detail> details;
/**
* 最终得分
*/
private Float finalScore;
public ScoringRule2(SimulationMember member, Float fullMarks, List<Detail> details) {
this.member = member;
this.fullMarks = fullMarks;
this.details = details;
}
public List<Detail> 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 @Getter
@AllArgsConstructor @AllArgsConstructor
public static class Detail { public static class Detail {
private Type type; private Type type;
private ElementType elementType;
/**
* 扣分分值
*/
private float score; private float score;
/**
* 满足该条件则扣分
*/
private Expression condition; 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() { public Object getElement() {
return null; return null;
} }
public boolean isDurative() {
return Type.DURATIVE.equals(type);
}
public boolean isCompletion() {
return true;
}
public enum Type { 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; private Operation2 element;
public Operation2Detail(Type type, Operation2 element, float score, Expression condition) { public Operation2Detail(Type type, ElementType elementType, Operation2 element, float score, Expression condition) {
super(type, score, condition); super(type, elementType, score, condition);
this.element = element; this.element = element;
} }
@ -68,19 +161,29 @@ public class ScoringRule2 {
public Object getElement() { public Object getElement() {
return element; return element;
} }
@Override
public boolean isCompletion() {
return element.isCompletion();
}
} }
public static class Step2Detail extends Detail{ public static class Step2Detail extends Detail {
private Step2 element; private Step2 step;
public Step2Detail(Type type, Step2 element, float score, Expression condition) { public Step2Detail(Type type, ElementType elementType, Step2 step, float score, Expression condition) {
super(type, score, condition); super(type, elementType, score, condition);
this.element = element; this.step = step;
} }
@Override @Override
public Object getElement() { public Object getElement() {
return element; return step;
}
@Override
public boolean isCompletion() {
return step.isCompletion();
} }
} }
} }

View File

@ -3,6 +3,7 @@ package club.joylink.rtss.simulation.cbtc.training2;
import club.joylink.rtss.entity.training2.DraftTraining2WithBLOBs; import club.joylink.rtss.entity.training2.DraftTraining2WithBLOBs;
import club.joylink.rtss.exception.BusinessExceptionAssertEnum; import club.joylink.rtss.exception.BusinessExceptionAssertEnum;
import club.joylink.rtss.simulation.cbtc.Simulation; 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.simulation.cbtc.script.ScriptBO;
import club.joylink.rtss.util.JsonUtils; import club.joylink.rtss.util.JsonUtils;
import club.joylink.rtss.vo.client.training2.ExpressionVO; 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 club.joylink.rtss.vo.client.training2.Step2VO;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@Getter @Getter
@ -151,6 +153,31 @@ public class Training2 {
return step2; return step2;
} }
public List<Step2> 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<String, Float> mark() {
Map<String, Float> 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 { public enum Type {
SINGLE, SINGLE,
SCENE, SCENE,

View File

@ -30,4 +30,8 @@ public class ExpressionVO implements ValuableVO {
} }
return new Expression(operator, vs); return new Expression(operator, vs);
} }
public static Expression convert2BO(ExpressionVO expressionVO, SimulationDataRepository repository) {
return expressionVO == null ? null : expressionVO.convert2BO(repository);
}
} }

View File

@ -57,6 +57,8 @@ public class ScoringRuleVO {
public static class DetailVO { public static class DetailVO {
private ScoringRule2.Detail.Type type; private ScoringRule2.Detail.Type type;
private ScoringRule2.Detail.ElementType elementType;
/** /**
* 被评分的元素的id操作步骤实训 * 被评分的元素的id操作步骤实训
*/ */
@ -73,17 +75,17 @@ public class ScoringRuleVO {
private ExpressionVO condition; private ExpressionVO condition;
public ScoringRule2.Detail convert2BO(Training2 training2, SimulationDataRepository repository) { public ScoringRule2.Detail convert2BO(Training2 training2, SimulationDataRepository repository) {
switch (type) { switch (elementType) {
case O: case O:
Operation2 operation2 = training2.getOperation(Integer.parseInt(elementId)); 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: case S:
Step2 step2 = training2.getStep(Integer.parseInt(elementId)); 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: case T:
return new ScoringRule2.Detail(type, score, condition.convert2BO(repository)); return new ScoringRule2.Detail(type, elementType, score, ExpressionVO.convert2BO(condition, repository));
default: default:
throw new IllegalStateException("Unexpected value: " + type); throw new IllegalStateException("Unexpected value: " + elementType);
} }
} }
} }