|
|
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<QuizQuestion> questions;
|
|
|
private final List<Integer> userAnswers;
|
|
|
private final LocalDateTime startTime;
|
|
|
private int currentQuestionIndex;
|
|
|
|
|
|
/**
|
|
|
* 创建新的考试会话.
|
|
|
*
|
|
|
* @param username 考生的用户名
|
|
|
* @param difficultyLevel 考试的难度级别
|
|
|
* @param questions 考试题目列表
|
|
|
*/
|
|
|
public ExamSession(String username, DifficultyLevel difficultyLevel,
|
|
|
List<QuizQuestion> 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<QuizQuestion> getQuestions() {
|
|
|
return questions;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 获取用户对各题的作答.
|
|
|
*
|
|
|
* @return 答案索引列表(-1 表示未选择)
|
|
|
*/
|
|
|
public List<Integer> 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;
|
|
|
}
|
|
|
}
|