package com.mathapp.problemGenerators; import com.mathapp.models.Equation; import com.mathapp.models.Operator; import java.util.*; import java.util.stream.Collectors; import java.util.stream.IntStream; /** * 抽象题目生成器(模板方法模式)。 * 提供了生成题目的通用流程和创建基础四则运算的核心方法。 */ public abstract class AbstractProblemGenerator implements IProblemGenerator { protected final Random random = new Random(); protected static final int MIN_OPERAND_VALUE = 1; protected static final int MAX_OPERAND_VALUE = 100; protected static final int MIN_OPERANDS_COUNT = 2; protected static final int MAX_OPERANDS_COUNT = 5; private static final Operator[] AVAILABLE_OPERATORS = { Operator.ADD, Operator.SUBTRACT, Operator.MULTIPLY, Operator.DIVIDE }; /** * 此方法定义了生成指定数量不重复题目的标准流程。 */ @Override public final List generate(int count, Set existingProblems) { List newProblems = new ArrayList<>(count); int attempts = 0; final int maxAttempts = count * 10; // 防止无限循环 while (newProblems.size() < count && attempts < maxAttempts) { Equation newProblem = createProblem(); if (!existingProblems.contains(newProblem.toNormalizedString())) { newProblems.add(newProblem); existingProblems.add(newProblem.toNormalizedString()); } attempts++; } return newProblems; } /** * (模板方法) 子类必须实现此方法以提供具体的题目生成逻辑。 */ protected abstract Equation createProblem(); /** * (核心辅助方法) 创建一个基础的四则运算题目。 */ protected Equation createBaseArithmeticProblem(boolean nonNegativeOnly) { int operandCount = getRandomNumber(MIN_OPERANDS_COUNT, MAX_OPERANDS_COUNT); List operands = new ArrayList<>(); List operators = new ArrayList<>(); operands.add(String.valueOf(getRandomNumber(MIN_OPERAND_VALUE, MAX_OPERAND_VALUE))); for (int i = 0; i < operandCount - 1; i++) { Operator operator = AVAILABLE_OPERATORS[random.nextInt(AVAILABLE_OPERATORS.length)]; addOperandAndOperator(operands, operators, operator, nonNegativeOnly); } addParentheses(operands, operators); return new Equation(operands, operators); } protected int getRandomNumber(int min, int max) { return random.nextInt(max - min + 1) + min; } private void addOperandAndOperator(List operands, List operators, Operator operator, boolean nonNegativeOnly) { int nextOperand; int lastOperand = Integer.parseInt(operands.get(operands.size() - 1).replaceAll("[()]", "")); if (operator == Operator.SUBTRACT && nonNegativeOnly) { nextOperand = getRandomNumber(MIN_OPERAND_VALUE, lastOperand); } else if (operator == Operator.DIVIDE) { List divisors = findDivisors(lastOperand); int divisor = divisors.get(random.nextInt(divisors.size())); int quotient = lastOperand / divisor; operands.set(operands.size() - 1, String.valueOf(divisor * quotient)); nextOperand = divisor; } else { nextOperand = getRandomNumber(MIN_OPERAND_VALUE, MAX_OPERAND_VALUE); } operands.add(String.valueOf(nextOperand)); operators.add(operator); } private void addParentheses(List operands, List operators) { if (operators.size() > 1 && random.nextBoolean()) { int pos = random.nextInt(operators.size()); Operator op = operators.get(pos); if (op == Operator.ADD || op == Operator.SUBTRACT) { operands.set(pos, "(" + operands.get(pos)); operands.set(pos + 1, operands.get(pos + 1) + ")"); } } } private List findDivisors(int number) { if (number == 0) return Collections.singletonList(1); int absNumber = Math.abs(number); return IntStream.rangeClosed(1, absNumber) .filter(i -> absNumber % i == 0) .boxed() .collect(Collectors.toList()); } }