Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Iterative Development of a Java Quiz Assessment System

Tech 1

The development process of the quiz assessment system spans three distinct phases, evolving from basic question-answer validation to a comprehensive exam management tool supporting multiple papers, student registration, and dynamic content modification.

Phase 1: Basic Question-Answer Validation

The initial implementation focuses on establishing the core object-oriented structure. The system reads a set number of questions, followed by a list of answers. The primary logic involves parsing specific input formats (e.g., #N:, #Q:, #A:) and comparing submitted answers against standard answers.

The design utilizes a Question class to encapsulate the problem statement and the correct answer. An ExamPaper acts as a container, while an AnswerSheet handles the logic of storing user responses and performing comparisons.

Core Implementation:

import java.util.*;

class QuizItem {
    private final int id;
    private final String content;
    private final String correctAnswer;

    public QuizItem(int id, String content, String correctAnswer) {
        this.id = id;
        this.content = content;
        this.correctAnswer = correctAnswer;
    }

    public boolean validate(String response) {
        return correctAnswer.equalsIgnoreCase(response.trim());
    }

    public String getContent() { return content; }
    public int getId() { return id; }
}

class SubmissionHandler {
    private final Map<Integer, QuizItem> questionBank = new HashMap<>();
    private final List<String> userResponses = new ArrayList<>();

    public void loadQuestion(int id, String content, String answer) {
        questionBank.put(id, new QuizItem(id, content, answer));
    }

    public void recordResponse(String response) {
        userResponses.add(response.trim());
    }

    public void processResults() {
        StringBuilder output = new StringBuilder();
        List<Boolean> outcomes = new ArrayList<>();
        
        // Iterate assuming user responses map to questions 1 to N sequentially
        int index = 0;
        for (int qId = 1; qId <= userResponses.size(); qId++) {
            QuizItem item = questionBank.get(qId);
            String answer = userResponses.get(index++);
            
            output.append(item.getContent()).append(" ~").append(answer).append("\n");
            outcomes.add(item.validate(answer));
        }

        System.out.print(output);
        for (int i = 0; i < outcomes.size(); i++) {
            System.out.print(outcomes.get(i) + (i < outcomes.size() - 1 ? " " : ""));
        }
    }
}

public class QuizApp {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        SubmissionHandler handler = new SubmissionHandler();
        
        int count = Integer.parseInt(sc.nextLine().trim());
        for (int i = 0; i < count; i++) {
            String line = sc.nextLine();
            // Parsing logic simplified for brevity
            String[] tokens = line.split("#N:| #Q:| #A:");
            handler.loadQuestion(Integer.parseInt(tokens[1].trim()), tokens[2].trim(), tokens[3].trim());
        }
        
        String line;
        while (!(line = sc.nextLine()).equals("end")) {
            Arrays.stream(line.split("#A:")).filter(s -> !s.trim().isEmpty()).forEach(handler::recordResponse);
        }
        handler.processResults();
    }
}

Phase 2: Multi-Paper and Scoring Logic

The second iteration introduces complexity by decoupling questions from specific exam instances. A TestPaper class is introduced to define a specific set of questions and their associated point values. The system now supports multiple papers, identifies papers where the total score does not equal 100, and calculates scores based on correct answers.

Input parsing becomes more robust, handling different line prefixes (#T:, #S:). The logic handles missing answers by defaulting to null and ignoring surplus answers.

Revised Class Structure:

class PaperDefinition {
    private final String paperId;
    private final LinkedHashMap<String, Integer> questionScoreMap = new LinkedHashMap<>(); // QuestionID -> Points

    public PaperDefinition(String paperId) { this.paperId = paperId; }

    public void addQuestion(String qId, int points) {
        questionScoreMap.put(qId, points);
    }

    public int calculateTotal() {
        return questionScoreMap.values().stream().mapToInt(Integer::intValue).sum();
    }
    
    public Set<String> getQuestionIds() { return questionScoreMap.keySet(); }
    public int getScore(String qId) { return questionScoreMap.getOrDefault(qId, 0); }
    public String getId() { return paperId; }
}

class GradingEngine {
    private final List<QuizItem> questionPool;
    private final List<PaperDefinition> papers;
    private final List<String[]> submissions; // PaperID + Answers

    public GradingEngine(List<QuizItem> qPool, List<PaperDefinition> pList, List<String[]> subs) {
        this.questionPool = qPool;
        this.papers = pList;
        this.submissions = subs;
    }

    public void run() {
        // Check total scores
        for (PaperDefinition p : papers) {
            if (p.calculateTotal() != 100) {
                System.out.println("alert: full score of test paper" + p.getId() + " is not 100 points");
            }
        }

        // Process each submission
        for (String[] sub : submissions) {
            String pId = sub[0];
            PaperDefinition paper = papers.stream().filter(p -> p.getId().equals(pId)).findFirst().orElse(null);
            
            if (paper == null) {
                System.out.println("The test paper number does not exist");
                continue;
            }

            List<Integer> scores = new ArrayList<>();
            int total = 0;
            Iterator<String> answerIter = Arrays.stream(sub).skip(1).iterator();

            for (String qId : paper.getQuestionIds()) {
                String userAns = answerIter.hasNext() ? answerIter.next() : "answer is null";
                QuizItem item = questionPool.stream().filter(q -> q.getId().equals(qId)).findFirst().orElse(null);

                if (item == null) continue; // Logic for non-existent questions handled in Phase 3

                boolean correct = item.validate(userAns);
                System.out.println(item.getContent() + "~" + userAns + "~" + correct);
                
                int pts = correct ? paper.getScore(qId) : 0;
                scores.add(pts);
                total += pts;
            }
            System.out.println(scores.toString().replaceAll("[\\[\\],]", "") + "~" + total);
        }
    }
}

Phase 3: Student Management and Dynamic Modification

The final iteration adds administrative features: student information storage, question deletion, and strict format validation. The system must now handle input errors graceful and prioritize output logic: missing answers take precedence over deleted questions, which in turn take precedence over non-existent questions.

A Student class is introduced. The main controller logic is enhanced to handle regex validation for input lines. When a question is deleted (#D:N-xx), it remains in the system but scores zero and displays an "invalid" message.

Enhanced Logic:

class StudentRecord {
    String id;
    String name;
    public StudentRecord(String id, String name) { this.id = id; this.name = name; }
}

public class ExamSystem {
    private static final List<QuizItem> questions = new ArrayList<>();
    private static final List<PaperDefinition> papers = new ArrayList<>();
    private static final List<StudentRecord> students = new ArrayList<>();
    private static final Set<String> deletedQuestions = new HashSet<>();

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        List<String> rawInputs = new ArrayList<>();
        
        while (sc.hasNextLine()) {
            String line = sc.nextLine().trim();
            if (line.equals("end")) break;
            rawInputs.add(line);
        }

        parseInputs(rawInputs);
        processExams();
    }

    private static void parseInputs(List<String> lines) {
        // Logic to sort and parse lines based on prefixes #N, #T, #X, #S, #D
        // Includes Regex validation: e.g., "#N:[0-9]+\\s#Q:.+\\s#A:.+"
        for (String line : lines) {
            if (line.startsWith("#D:N-")) {
                deletedQuestions.add(line.substring(5));
            } 
            // ... other parsing logic similar to previous phases
        }
    }

    private static void processExams() {
        // Output alerts for paper totals
        // Iterate through submissions
        // For each answer:
        // 1. Check if answer is missing -> "answer is null"
        // 2. Check if question ID is in deletedQuestions -> "the question X invalid~0"
        // 3. Check if question exists -> "non-existent question~0"
        // 4. Else compare and score
    }
}

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.