package com.mathlearning.model; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Random; import java.util.Set; public abstract class BaseQuestionGenerator { protected Random random = new Random(); public abstract Question generateQuestion(int index); protected void generateOperands(int[] operands, int min, int max) { for (int i = 0; i < operands.length; i++) { operands[i] = random.nextInt(max - min + 1) + min; } } protected void generateOperations(int[] operations, int operationTypes) { for (int i = 0; i < operations.length; i++) { operations[i] = random.nextInt(operationTypes); } } protected void appendOperator(StringBuilder sb, int operation) { switch (operation) { case 0: sb.append(" + "); break; case 1: sb.append(" - "); break; case 2: sb.append(" × "); break; case 3: sb.append(" ÷ "); break; } } protected boolean isValidAnswer(double answer) { return !(answer < 0 || Double.isNaN(answer) || Double.isInfinite(answer)); } protected double calculateExpression(double[] values, int[] operations) { List numbers = new ArrayList<>(); List ops = new ArrayList<>(); for (double value : values) numbers.add(value); for (int operation : operations) ops.add(operation); processMultiplicationAndDivision(numbers, ops); return processAdditionAndSubtraction(numbers, ops); } protected double calculateWithoutParentheses(int[] operands, int[] operations) { double[] doubleOperands = new double[operands.length]; for (int i = 0; i < operands.length; i++) { doubleOperands[i] = operands[i]; } return calculateExpression(doubleOperands, operations); } protected double calculateWithoutParentheses(List numbers, List ops) { double[] doubleNumbers = new double[numbers.size()]; for (int i = 0; i < numbers.size(); i++) { doubleNumbers[i] = numbers.get(i); } int[] intOps = new int[ops.size()]; for (int i = 0; i < ops.size(); i++) { intOps[i] = ops.get(i); } return calculateExpression(doubleNumbers, intOps); } private void processMultiplicationAndDivision(List numbers, List ops) { for (int i = 0; i < ops.size(); i++) { int op = ops.get(i); if (op == 2 || op == 3) { double left = numbers.get(i); double right = numbers.get(i + 1); double result = performOperation(left, right, op); numbers.set(i, result); numbers.remove(i + 1); ops.remove(i); i--; } } } private double processAdditionAndSubtraction(List numbers, List ops) { double result = numbers.get(0); for (int i = 0; i < ops.size(); i++) { int op = ops.get(i); double nextNum = numbers.get(i + 1); result = performOperation(result, nextNum, op); } return Math.round(result * 100) / 100.0; } private double performOperation(double left, double right, int operation) { switch (operation) { case 0: return left + right; case 1: return left - right; case 2: return left * right; case 3: if (right == 0) return Double.NaN; return left / right; default: return left; } } protected Question generateOptions(String questionText, double answer, String level) { String[] options = new String[4]; Set usedValues = new HashSet<>(); boolean isIntegerAnswer = (answer == (int) answer); String correctAnswer = formatAnswer(answer); options[0] = correctAnswer; usedValues.add(correctAnswer); generateWrongOptions(options, usedValues, answer, isIntegerAnswer); shuffleArray(options); int correctIndex = findCorrectIndex(options, correctAnswer); return new Question(questionText, options, correctIndex, level); } private void generateWrongOptions( String[] options, Set usedValues, double answer, boolean isIntegerAnswer) { for (int i = 1; i < 4; i++) { String wrongAnswer; int attempts = 0; do { double wrongValue = generateWrongValue(answer, isIntegerAnswer); wrongAnswer = formatAnswer(wrongValue); attempts++; } while (usedValues.contains(wrongAnswer) && attempts < 20); options[i] = wrongAnswer; usedValues.add(wrongAnswer); } } private double generateWrongValue(double answer, boolean isIntegerAnswer) { double offset = (random.nextDouble() * 5) + 1; if (isIntegerAnswer) { int intAnswer = (int) answer; int intOffset = random.nextInt(10) + 1; double wrongValue = random.nextBoolean() ? intAnswer + intOffset : Math.max(1, intAnswer - intOffset); return (int) wrongValue; } else { double wrongValue = random.nextBoolean() ? answer + offset : answer - offset; return Math.round(wrongValue * 100) / 100.0; } } private String formatAnswer(double answer) { return (answer == (int) answer) ? String.valueOf((int) answer) : String.format("%.2f", answer); } private void shuffleArray(String[] array) { for (int i = array.length - 1; i > 0; i--) { int j = random.nextInt(i + 1); String temp = array[i]; array[i] = array[j]; array[j] = temp; } } private int findCorrectIndex(String[] options, String correctAnswer) { for (int i = 0; i < options.length; i++) { if (options[i].equals(correctAnswer)) return i; } return 0; } }