package com.nju.edu.eval.service.serviceImpl; import cn.seecoder.codejudge.client.JudgeDTO; import cn.seecoder.codejudge.client.JudgeResult; import cn.seecoder.codejudge.client.JudgeResultType; import cn.seecoder.judgement.dto.StudentAnswerDTO; import cn.seecoder.judgement.vo.JudgedAnswersVO; import com.nju.edu.eval.data.dao.ExamDao; import com.nju.edu.eval.data.dao.RecordDao; import com.nju.edu.eval.data.dao.ScoreDao; import com.nju.edu.eval.data.dao.UserDao; import com.nju.edu.eval.data.entity.Exam; import com.nju.edu.eval.data.entity.QuestionRecord; import com.nju.edu.eval.data.entity.Score; import com.nju.edu.eval.data.entity.User; import com.nju.edu.eval.exception.MyServiceException; import com.nju.edu.eval.exception.ThirdPartyServiceException; import com.nju.edu.eval.manager.JudgeManager; import com.nju.edu.eval.manager.QuestionManager; import com.nju.edu.eval.model.vo.judge.CodeJudgeVO; import com.nju.edu.eval.model.vo.judge.ObjectiveJudgeResOfExerciseVO; import com.nju.edu.eval.model.vo.judge.ObjectiveJudgeResVO; import com.nju.edu.eval.model.vo.judge.ObjectiveJudgeVO; import com.nju.edu.eval.model.vo.logdata.AnswerDTO; import com.nju.edu.eval.model.vo.logdata.ExamRecordLog; import com.nju.edu.eval.model.vo.question.CompleteQuestionVO; import com.nju.edu.eval.publicdatas.enums.CodeJudgeResultType; import com.nju.edu.eval.service.JudgeService; import com.nju.edu.eval.util.LogTracingUtil; import com.nju.edu.logTracking.enums.SeecSystem; import org.apache.logging.log4j.LogBuilder; import org.slf4j.Logger; import org.springframework.stereotype.Service; import java.util.*; import java.util.stream.Collectors; /** * @author mars */ @Service public class JudgeServiceImpl implements JudgeService { private final JudgeManager judgeManager; private final QuestionManager questionManager; private final ScoreDao scoreDao; private final RecordDao recordDao; private final ExamDao examDao; private final UserDao userDao; public JudgeServiceImpl(JudgeManager judgeManager, QuestionManager questionManager, ScoreDao scoreDao, RecordDao recordDao, ExamDao examDao, UserDao userDao) { this.judgeManager = judgeManager; this.questionManager = questionManager; this.scoreDao = scoreDao; this.recordDao = recordDao; this.examDao = examDao; this.userDao = userDao; } @Override public ObjectiveJudgeResVO judgeObjectiveQuestionAnswers(Integer userId, Integer examId, ObjectiveJudgeVO objectiveJudgeVO) { try { // 提交给判题系统 JudgedAnswersVO judgedAnswersVO = judgeManager.judgeObjectiveQuestionAnswers(userId, objectiveJudgeVO); User user = userDao.findById(userId).orElse(null); Exam exam = examDao.findById(examId).orElse(null); Score score = scoreDao.findByUserIdAndExamId(userId, examId); Date currentTime = new Date(); if (score == null) { score = new Score(user, exam); } score.setSubmitTime(currentTime); scoreDao.save(score); List records = score.getRecords(); // 存储用以打日志的错题集 List err = new ArrayList<>(); double curScore = 0.0; // 存储用户提交的记录 for (Map.Entry entry : objectiveJudgeVO.getRecords().entrySet()) { // 获得该题满分 assert exam != null; String questionId = entry.getKey(); double scoreOfQuestion = exam.getQuestionAndScore().get(questionId); // 看该题是否正确 boolean isTrue = judgedAnswersVO.getAnswers().get(questionId).getCorrect(); // 填入错题集 try { if (!isTrue) err.add(new AnswerDTO(questionId, scoreOfQuestion)); }catch (Exception e) { LogTracingUtil.logSimple("smart error"); } double actualScore = isTrue ? scoreOfQuestion : 0; curScore += actualScore; QuestionRecord questionRecord = new QuestionRecord(user, exam, entry.getKey(), score, (String) entry.getValue().getAnswer(), actualScore, currentTime); records.add(questionRecord); } double maxScore = Math.max(score.getScore() - score.getObjectiveScore() + curScore, score.getScore()); score.setObjectiveScore(Math.max(curScore, score.getObjectiveScore())); score.setScore(maxScore); scoreDao.save(score);; // 提交记录日志 try { LogTracingUtil.logRecord(new ExamRecordLog(examId, userId, currentTime, curScore, err)); }catch (Exception e) { LogTracingUtil.logSimple("smart error"); } return new ObjectiveJudgeResVO(judgedAnswersVO.getSubmitAt(), judgedAnswersVO.getSubmitNumber()); } catch (ThirdPartyServiceException exception) { throw new MyServiceException(exception.getCode(), exception.getMessage()); } } @Override public JudgeResult judgeCodeQuestionAnswers(Integer userId, Integer examId, String questionId, CodeJudgeVO codeJudgeVO) { try { JudgeDTO judgeDTO = new JudgeDTO(); judgeDTO.setCode(codeJudgeVO.getCode()); judgeDTO.setLanguage(codeJudgeVO.getLanguage()); CompleteQuestionVO question = questionManager.getQuestionById(questionId).get(); judgeDTO.setMemoryLimit(question.getMemoryLimit()); judgeDTO.setInputList(question.getInputOutputMapping().entrySet().stream().map(Map.Entry::getKey).collect(Collectors.toList())); judgeDTO.setOutputList(question.getInputOutputMapping().entrySet().stream().map(Map.Entry::getValue).collect(Collectors.toList())); JudgeResult judgeResult = judgeManager.judgeCodeQuestionAnswers(judgeDTO); CodeJudgeResultType message = CodeJudgeResultType.values()[JudgeResultType.ACCEPT.ordinal()]; for (JudgeResult.Item item : judgeResult.getResultList()) { if (item.getResult() != JudgeResultType.ACCEPT) { message = CodeJudgeResultType.values()[item.getResult().ordinal()]; break; } } User user = userDao.findById(userId).orElse(null); Exam exam = examDao.findById(examId).orElse(null); Score score = scoreDao.findByUserIdAndExamId(userId, examId); Date currentTime = new Date(); if (score == null) { score = new Score(user, exam); } score.setSubmitTime(currentTime); scoreDao.save(score); List records = score.getRecords(); // 获得上一次用户提交的代码分数,如果没有,那就是0 double preScore = 0.0; QuestionRecord previousRecord = recordDao.findFirstByUserIdAndExamIdAndQuestionIdOrderByActualScore(userId, examId, questionId); if (previousRecord != null) { preScore = previousRecord.getActualScore(); } double curScore = 0.0; // 存储用户提交的记录 // 获得该题满分 double scoreOfQuestion = exam.getQuestionAndScore().get(questionId); // 遍历OJ结果,如果该测试用例AC则得分 int accecptedNum = 0; for (JudgeResult.Item item: judgeResult.getResultList()) { if (item.getResult() == JudgeResultType.ACCEPT) { accecptedNum++; } } // 获得该题满分 curScore = ((double) accecptedNum / judgeResult.getResultList().size()) * scoreOfQuestion; QuestionRecord questionRecord = new QuestionRecord(user, exam, questionId, score, judgeDTO.getCode(), curScore, currentTime); questionRecord.setMessage(message); records.add(questionRecord); // 更新成绩报告中的分数,通过减去该题最高得分来获得 double maxScore = Math.max(score.getScore() - preScore + curScore, score.getScore()); score.setScore(maxScore); scoreDao.save(score); // 提交记录日志 List err = new ArrayList<>(); if (curScore != scoreOfQuestion) err.add(new AnswerDTO(questionId, scoreOfQuestion)); LogTracingUtil.logRecord(new ExamRecordLog(examId, userId, currentTime, curScore, err)); return judgeResult; } catch (ThirdPartyServiceException exception) { throw new MyServiceException(exception.getCode(), exception.getMessage()); } } @Override public ObjectiveJudgeResOfExerciseVO judgeObjectiveQuestionAnswersOfExercise(Integer userId, ObjectiveJudgeVO objectiveJudgeVO) { try { // 提交给判题系统 JudgedAnswersVO judgedAnswersVO = judgeManager.judgeObjectiveQuestionAnswers(userId, objectiveJudgeVO); Map result = new HashMap<>(); User user = userDao.findById(userId).orElse(null); Date currentTime = new Date(); double curScore = 0.0; // 存储用户提交的记录 for (Map.Entry entry : objectiveJudgeVO.getRecords().entrySet()) { // 获得该题满分 String questionId = entry.getKey(); // 看该题是否正确 boolean isTrue = judgedAnswersVO.getAnswers().get(questionId).getCorrect(); result.put(questionId, isTrue); } return new ObjectiveJudgeResOfExerciseVO(result); } catch (ThirdPartyServiceException exception) { throw new MyServiceException(exception.getCode(), exception.getMessage()); } } @Override public JudgeResult judgeCodeQuestionAnswersOfExercise(Integer userId, String questionId, CodeJudgeVO codeJudgeVO) { try { JudgeDTO judgeDTO = new JudgeDTO(); judgeDTO.setCode(codeJudgeVO.getCode()); judgeDTO.setLanguage(codeJudgeVO.getLanguage()); CompleteQuestionVO question = questionManager.getQuestionById(questionId).get(); judgeDTO.setMemoryLimit(question.getMemoryLimit()); judgeDTO.setInputList(question.getInputOutputMapping().entrySet().stream().map(Map.Entry::getKey).collect(Collectors.toList())); judgeDTO.setOutputList(question.getInputOutputMapping().entrySet().stream().map(Map.Entry::getValue).collect(Collectors.toList())); JudgeResult judgeResult = judgeManager.judgeCodeQuestionAnswers(judgeDTO); return judgeResult; } catch (ThirdPartyServiceException exception) { throw new MyServiceException(exception.getCode(), exception.getMessage()); } } }