import java.util.Random; public class ElementaryQuestionStrategy implements QuestionStrategy { private final Random random = new Random(); private final String[] operators = {"+", "-", "*", "/"}; @Override public String generateQuestion() { int operandsCount = random.nextInt(4) + 2; // 操作数 2~5 StringBuilder sb = new StringBuilder(); // 生成运算符序列 String[] chosenOps = generateOperators(operandsCount); // 随机决定括号 int[] parentheses = decideParentheses(operandsCount, chosenOps); // 拼接表达式 buildExpression(sb, operandsCount, chosenOps, parentheses); return sb.toString(); } /** * 生成运算符序列 * 根据操作数数量,随机生成对应数量的运算符数组 * * @param operandsCount 操作数数量 * @return 随机生成的运算符数组,长度为操作数数量-1 */ private String[] generateOperators(int operandsCount) { String[] chosenOps = new String[operandsCount - 1]; for (int i = 0; i < operandsCount - 1; i++) { chosenOps[i] = operators[random.nextInt(operators.length)]; } return chosenOps; } /** * 决定是否需要括号,并返回括号的起始和结束位置 * 对于3个及以上操作数,随机决定是否添加括号,并检查括号是否有效 * * @param operandsCount 操作数数量 * @param chosenOps 运算符数组 * @return 包含开括号和闭括号位置的数组,格式为[openParenIndex, closeParenIndex],-1表示不添加括号 */ private int[] decideParentheses(int operandsCount, String[] chosenOps) { int openParenIndex = -1; int closeParenIndex = -1; if (operandsCount > 2 && random.nextBoolean()) { openParenIndex = random.nextInt(operandsCount - 1); closeParenIndex = random.nextInt(operandsCount - openParenIndex - 1) + openParenIndex + 1; // 如果括号包裹整个表达式,则不需要括号 if (openParenIndex == 0 && closeParenIndex == operandsCount - 1) { openParenIndex = -1; closeParenIndex = -1; } else { // 检查括号内的运算符优先级是否相同,如果相同则不需要括号 boolean samePrecedence = checkPrecedenceEquality(chosenOps, openParenIndex, closeParenIndex); if (samePrecedence) { openParenIndex = -1; closeParenIndex = -1; } } } return new int[]{openParenIndex, closeParenIndex}; } /** * 判断括号内的运算符优先级是否相同 * 用于决定是否需要添加括号(如果优先级都相同,则括号是冗余的) * * @param chosenOps 运算符数组 * @param openParenIndex 开括号位置 * @param closeParenIndex 闭括号位置 * @return 如果括号内所有运算符优先级相同则返回true,否则返回false */ private boolean checkPrecedenceEquality(String[] chosenOps, int openParenIndex, int closeParenIndex) { int precedence = getPrecedence(chosenOps[openParenIndex]); for (int i = openParenIndex; i < closeParenIndex; i++) { if (getPrecedence(chosenOps[i]) != precedence) { return false; } } return true; } /** * 构建数学表达式 * 根据操作数、运算符和括号位置,拼接完整的数学表达式 * * @param sb StringBuilder对象,用于构建表达式 * @param operandsCount 操作数数量 * @param chosenOps 运算符数组 * @param parentheses 括号位置数组,格式为[openParenIndex, closeParenIndex] */ private void buildExpression(StringBuilder sb, int operandsCount, String[] chosenOps, int[] parentheses) { int prevNum = random.nextInt(100) + 1; int openParenIndex = parentheses[0]; int closeParenIndex = parentheses[1]; // 处理第一个操作数可能的开括号 if (openParenIndex == 0) sb.append("("); sb.append(prevNum); // 处理最后一个操作数可能的闭括号 if (closeParenIndex == operandsCount - 1) sb.append(")"); // 构建剩余的操作数和运算符 for (int i = 1; i < operandsCount; i++) { String op = chosenOps[i - 1]; sb.append(" ").append(op).append(" "); // 根据运算符生成下一个操作数 int num = generateOperand(op, prevNum); // 添加括号(如果需要) if (i == openParenIndex) sb.append("("); sb.append(num); if (i == closeParenIndex) sb.append(")"); prevNum = num; // 更新上一个数字,供下一轮计算使用 } } /** * 生成每个操作数 * 确保生成的操作数符合题目要求,特别是减法不会导致负数结果 * * @param op 当前运算符 * @param prevNum 前一个操作数的值 * @return 生成的操作数 */ private int generateOperand(String op, int prevNum) { int num = random.nextInt(100) + 1; // 默认生成1-100之间的随机数 // 如果是减法运算符,确保不会出现负数结果 if (op.equals("-") && num > prevNum) { num = random.nextInt(prevNum) + 1; // 保证 num <= prevNum,避免负数结果 } return num; } private int getPrecedence(String op) { if (op.equals("+") || op.equals("-")) return 1; if (op.equals("*") || op.equals("/")) return 2; return 0; } }