package com.personalproject.model; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * 表示用户的考试会话. */ public final class ExamSession { private final String username; private final DifficultyLevel difficultyLevel; private final List questions; private final List userAnswers; private final LocalDateTime startTime; private int currentQuestionIndex; /** * 创建新的考试会话. * * @param username 考生的用户名 * @param difficultyLevel 考试的难度级别 * @param questions 考试题目列表 */ public ExamSession(String username, DifficultyLevel difficultyLevel, List questions) { if (username == null || username.trim().isEmpty()) { throw new IllegalArgumentException("Username cannot be null or empty"); } if (difficultyLevel == null) { throw new IllegalArgumentException("Difficulty level cannot be null"); } if (questions == null || questions.isEmpty()) { throw new IllegalArgumentException("Questions list cannot be null or empty"); } this.username = username; this.difficultyLevel = difficultyLevel; this.questions = List.copyOf(questions); // 题目的不可变副本 this.userAnswers = new ArrayList<>(Collections.nCopies(questions.size(), -1)); this.startTime = LocalDateTime.now(); this.currentQuestionIndex = 0; } /** * 获取考生的用户名. * * @return 用户名 */ public String getUsername() { return username; } /** * 获取考试的难度级别. * * @return 考试难度级别 */ public DifficultyLevel getDifficultyLevel() { return difficultyLevel; } /** * 获取考试中的题目列表. * * @return 不可修改的题目列表 */ public List getQuestions() { return questions; } /** * 获取用户对各题的作答. * * @return 答案索引列表(-1 表示未选择) */ public List getUserAnswers() { return List.copyOf(userAnswers); // 返回副本以防止被修改 } /** * 获取当前题目的索引. * * @return 当前题目索引 */ public int getCurrentQuestionIndex() { return currentQuestionIndex; } /** * 为当前题目记录用户的答案. * * @param answerIndex 选中答案的索引 */ public void setAnswer(int answerIndex) { if (currentQuestionIndex < 0 || currentQuestionIndex >= questions.size()) { throw new IllegalStateException("No valid question at current index"); } int optionCount = questions.get(currentQuestionIndex).getOptions().size(); if (answerIndex < 0 || answerIndex >= optionCount) { throw new IllegalArgumentException("Invalid answer index"); } userAnswers.set(currentQuestionIndex, answerIndex); } /** * 跳转到下一题. * * @return 若成功跳转则返回 true,若已是最后一题则返回 false */ public boolean goToNextQuestion() { if (currentQuestionIndex < questions.size() - 1) { currentQuestionIndex++; return true; } return false; } /** * 返回上一题. * * @return 若成功返回则返回 true,若已是第一题则返回 false */ public boolean goToPreviousQuestion() { if (currentQuestionIndex > 0) { currentQuestionIndex--; return true; } return false; } /** * 检查考试是否完成(所有题目已作答或到达最后一题). * * @return 若考试已完成则返回 true,否则返回 false */ public boolean isComplete() { return userAnswers.stream().allMatch(answer -> answer != -1); } /** * 获取当前题目. * * @return 当前的测验题 */ public QuizQuestion getCurrentQuestion() { if (currentQuestionIndex < 0 || currentQuestionIndex >= questions.size()) { throw new IllegalStateException("No valid question at current index"); } return questions.get(currentQuestionIndex); } /** * 获取指定题目的用户答案. * * @param questionIndex 题目索引 * @return 用户答案的索引(未选择时为 -1) */ public int getUserAnswer(int questionIndex) { if (questionIndex < 0 || questionIndex >= questions.size()) { throw new IllegalArgumentException("Question index out of bounds"); } return userAnswers.get(questionIndex); } /** * 计算得分百分比. * * @return 0-100 范围内的得分百分比 */ public double calculateScore() { int correctCount = 0; for (int i = 0; i < questions.size(); i++) { QuizQuestion question = questions.get(i); int userAnswer = userAnswers.get(i); if (userAnswer != -1 && question.isAnswerCorrect(userAnswer)) { correctCount++; } } return questions.isEmpty() ? 0.0 : (double) correctCount / questions.size() * 100.0; } /** * 获取考试中的题目总数. * * @return 题目总数 */ public int getTotalQuestions() { return questions.size(); } /** * 检查指定题目是否已作答. * * @param questionIndex 题目索引 * @return 若已作答则返回 true,否则返回 false */ public boolean hasAnswered(int questionIndex) { if (questionIndex < 0 || questionIndex >= questions.size()) { throw new IllegalArgumentException("Question index out of bounds"); } return userAnswers.get(questionIndex) != -1; } /** * 获取考试开始时间. * * @return 开始时间 */ public LocalDateTime getStartTime() { return startTime; } /** * 获取答对的题目数量. * * @return 正确题目数量 */ public int getCorrectAnswersCount() { int correctCount = 0; for (int i = 0; i < questions.size(); i++) { QuizQuestion question = questions.get(i); int userAnswer = userAnswers.get(i); if (userAnswer != -1 && question.isAnswerCorrect(userAnswer)) { correctCount++; } } return correctCount; } /** * 获取答错的题目数量. * * @return 错误题目数量 */ public int getIncorrectAnswersCount() { int totalAnswered = 0; int correctCount = 0; for (int i = 0; i < questions.size(); i++) { int userAnswer = userAnswers.get(i); if (userAnswer != -1) { totalAnswered++; QuizQuestion question = questions.get(i); if (question.isAnswerCorrect(userAnswer)) { correctCount++; } } } return totalAnswered - correctCount; } }