4 #4

Merged
hnu202326010305 merged 5 commits from develop into main 5 days ago

@ -1,148 +1,347 @@
import java.util.List; import java.util.ArrayList;
import java.util.Random; import java.util.List;
import java.util.Random;
/**
* /**
*/ *
public class BracketManager { */
private static final Random RANDOM = new Random(); public class BracketManager {
private static final Random RANDOM = new Random();
/**
* /**
* 3 -> 80% 1 20%0 *
* 4 -> 90% 1 10%2 * 3 -> 80% 1 20%0
* 5 -> 50% 1 50%2 * 4 -> 90% 1 10%2
*/ * 5 -> 50% 1 50%2
public int decideParenthesesPairs(int numCount) { */
return switch (numCount) { private int decideParenthesesPairs(int numCount) {
case 3 -> RANDOM.nextDouble() < 0.8 ? 1 : 0; return switch (numCount) {
case 4 -> RANDOM.nextDouble() < 0.9 ? 1 : 2; case 3 -> RANDOM.nextDouble() < 0.6 ? 1 : 0;
case 5 -> RANDOM.nextDouble() < 0.5 ? 1 : 2; case 4 -> RANDOM.nextDouble() < 0.8 ? 1 : 2;
default -> 0; case 5 -> RANDOM.nextDouble() < 0.5 ? 1 : 2;
}; default -> 0;
} };
}
// 添加括号
public String addParentheses(String expression, int pairs, List<Integer> numPositions) { // 添加括号
String[] tokens = expression.split(" "); public String addNestedParentheses(String expression) {
int numCount = numPositions.size(); List<Integer> numPositions = getNumPositions(expression);
boolean[] markLeft = new boolean[numCount]; int pairs = decideParenthesesPairs(numPositions.size());
boolean[] markRight = new boolean[numCount];
String result;
generateBracketPositions(numCount, numPositions, pairs, tokens, markLeft, markRight); if (pairs == 1) {
String result = insertBrackets(tokens, markLeft, markRight); result = addParentheses(expression, 1, numPositions);
return validateParentheses(result) ? result : expression; } else if (pairs == 2) {
} String first = addParentheses(expression, 1, numPositions);
String second = addParallelOutside(first);
//计算生成括号的位置 if (!second.equals(first)) {
private void generateBracketPositions(int numCount, List<Integer> numPositions, int pairs, String[] tokens, result = second;
boolean[] markLeft, boolean[] markRight) { } else {
int attempts = 0; result = addNestedInside(first);
for (int p = 0; p < pairs && attempts < 50; p++, attempts++) { }
boolean placed = false; } else {
for (int tries = 0; tries < 50 && !placed; tries++) { result = expression;
int start = RANDOM.nextInt(numCount - 1); }
int end = start + 1 + RANDOM.nextInt(numCount - start - 1);
if (end >= numCount) end = numCount - 1; result = fixLeftParenthesisSpacing(result);
return result;
// 20%概率尝试嵌套在已有括号内部 }
if (RANDOM.nextDouble() < 0.2) {
for (int i = 0; i < numCount; i++) { // 并列括号
if (markLeft[i]) { private String addParallelOutside(String expression) {
start = i; String result = expression;
end = i + RANDOM.nextInt(numCount - i); List<Integer> numPositions = getNumPositions(expression);
break; List<int[]> innerRanges = getInnerBracketRanges(expression);
}
} // 找到未被第一层括号覆盖的段落
} List<int[]> outerRanges = new ArrayList<>();
int lastEnd = -1;
if (canPlaceBracket(start, end, markLeft, markRight, numPositions, tokens)) { for (int[] range : innerRanges) {
markLeft[start] = true; if (range[0] - 1 > lastEnd + 1) {
markRight[end] = true; outerRanges.add(new int[]{lastEnd + 1, range[0] - 1});
placed = true; }
} lastEnd = range[1];
} }
} if (lastEnd + 1 < numPositions.size()) {
} outerRanges.add(new int[]{lastEnd + 1, numPositions.size() - 1});
}
//检测添加括号的合法性
private boolean canPlaceBracket(int start, int end, boolean[] markLeft, boolean[] markRight, boolean added = false;
List<Integer> numPositions, String[] tokens) { for (int[] range : outerRanges) {
if (isOuterMostBracket(start, end, markLeft.length)) return false; String outerExpr = extractTokens(result, range[0], range[1]);
if (isInvalidOverlap(start, end, markLeft, markRight)) return false; List<Integer> outerNumPos = getNumPositions(outerExpr);
return isValidBracketRange(tokens, numPositions, start, end); int outerPairs = decideParenthesesPairs(outerNumPos.size());
} if (outerPairs > 0) {
String newOuterExpr = addParentheses(outerExpr, outerPairs, outerNumPos);
//避免最外层括号 result = replaceTokens(result, range[0], range[1], newOuterExpr);
private boolean isOuterMostBracket(int start, int end, int numCount) { added = true;
return start == 0 && end == numCount - 1; }
} }
//允许嵌套但禁止交叉 return added ? result : expression;
private boolean isInvalidOverlap(int start, int end, boolean[] markLeft, boolean[] markRight) { }
for (int i = start; i <= end; i++) {
// start/end可重合内部禁止已有左右括号 // 嵌套括号
if ((i != start && markLeft[i]) || (i != end && markRight[i])) return true; private String addNestedInside(String expression) {
} String result = expression;
return false; List<int[]> innerRanges = getInnerBracketRanges(expression);
} for (int[] range : innerRanges) {
String innerExpr = extractTokens(result, range[0], range[1]);
//检测括号是否有意义(优先级) List<Integer> innerNumPos = getNumPositions(innerExpr);
private boolean isValidBracketRange(String[] tokens, List<Integer> numPositions, int start, int end) { int innerPairs = decideParenthesesPairs(innerNumPos.size());
int opStart = numPositions.get(start) + 1; String newInnerExpr = addParentheses(innerExpr, innerPairs, innerNumPos);
int opEnd = numPositions.get(end) - 1; result = replaceTokens(result, range[0], range[1], newInnerExpr);
String firstOp = null; }
boolean hasHigherOuterOp = false; return result;
}
for (int i = opStart; i <= opEnd; i += 2) {
if (!isNumber(tokens[i])) { // 添加括号核心逻辑
if (firstOp == null) firstOp = tokens[i]; private String addParentheses(String expression, int pairs, List<Integer> numPositions) {
else if (isDifferentPriority(firstOp, tokens[i])) { String[] tokens = expression.split(" "); // 按空格拆分
hasHigherOuterOp = true; int numCount = numPositions.size();
break; boolean[] markLeft = new boolean[numCount]; // 左括号标记
} boolean[] markRight = new boolean[numCount]; // 右括号标记
}
} generateBracketPositions(numCount, numPositions, pairs, tokens, markLeft, markRight); // 生成括号位置
return hasHigherOuterOp || firstOp == null; String result = insertBrackets(tokens, markLeft, markRight); // 插入括号
} return validateParentheses(result) ? result : expression; // 验证括号匹配,非法返回原表达式
}
//比较运算符优先级
private boolean isDifferentPriority(String op1, String op2) { // 生成括号位置
int p1 = (op1.equals("+") || op1.equals("-")) ? 1 : 2; private void generateBracketPositions(int numCount, List<Integer> numPositions, int pairs, String[] tokens,
int p2 = (op2.equals("+") || op2.equals("-")) ? 1 : 2; boolean[] markLeft, boolean[] markRight) {
return p1 != p2; int attempts = 0;
} for (int p = 0; p < pairs && attempts < 50; p++, attempts++) {
boolean placed = false;
//插入操作 for (int tries = 0; tries < 50 && !placed; tries++) {
private String insertBrackets(String[] tokens, boolean[] markLeft, boolean[] markRight) { int start = RANDOM.nextInt(numCount - 1); // 随机起始数字索引
StringBuilder sb = new StringBuilder(); int end = start + 1 + RANDOM.nextInt(numCount - start - 1); // 随机结束数字索引
int numIndex = 0; if (end >= numCount) {
for (String token : tokens) { end = numCount - 1;
if (isNumber(token)) { }
if (markLeft[numIndex]) sb.append("( ");
sb.append(token); // 40%概率尝试嵌套在已有括号内部
if (markRight[numIndex]) sb.append(" )"); if (RANDOM.nextDouble() < 0.4) {
numIndex++; for (int i = 0; i < numCount; i++) {
} else { if (markLeft[i]) {
sb.append(" ").append(token).append(" "); start = i;
} end = i + RANDOM.nextInt(numCount - i);
} break;
return sb.toString(); }
} }
}
//检查括号是否缺失
private boolean validateParentheses(String expr) { // 检查是否合法
int balance = 0; if (canPlaceBracket(start, end, markLeft, markRight, numPositions, tokens)) {
for (char c : expr.toCharArray()) { markLeft[start] = true;
if (c == '(') balance++; markRight[end] = true;
if (c == ')') balance--; placed = true;
if (balance < 0) return false; }
} }
return balance == 0; }
} }
private boolean isNumber(String token) { // 检查括号是否可以放置
try { Integer.parseInt(token); return true; } private boolean canPlaceBracket(int start, int end, boolean[] markLeft, boolean[] markRight,
catch (NumberFormatException e) { return false; } List<Integer> numPositions, String[] tokens) {
} if (isOuterMostBracket(start, end, markLeft.length)) {
} return false;
}
if (isInvalidOverlap(start, end, markLeft, markRight)) {
return false;
}
return isValidBracketRange(tokens, numPositions, start, end);
}
// 避免最外层括号
private boolean isOuterMostBracket(int start, int end, int numCount) {
return start == 0 && end == numCount - 1;
}
// 避免交叉括号,允许嵌套
private boolean isInvalidOverlap(int start, int end, boolean[] markLeft, boolean[] markRight) {
for (int i = start; i <= end; i++) {
if ((i != start && markLeft[i]) || (i != end && markRight[i])) {
return true;
}
}
return false;
}
// 检查括号区间内部最小优先级是否小于相邻外部运算符优先级
private boolean isValidBracketRange(String[] tokens, List<Integer> numPositions, int start, int end) {
int opStart = numPositions.get(start) + 1;
int opEnd = numPositions.get(end) - 1;
// 找到括号内部最低优先级运算符
int minPriInside = Integer.MAX_VALUE;
for (int i = opStart; i <= opEnd; i++) {
if (i < 0 || i >= tokens.length) {
continue;
}
String t = tokens[i];
if (t.equals("(") || t.equals(")")) {
continue;
}
if (!isNumber(t)) {
int p = getPrecedence(t);
if (p > 0) minPriInside = Math.min(minPriInside, p);
}
}
if (minPriInside == Integer.MAX_VALUE) {
return false;
}
int leftPri = getAdjacentOpPrecedence(tokens, numPositions.get(start) - 1);
int rightPri = getAdjacentOpPrecedence(tokens, numPositions.get(end) + 1);
if (leftPri == -1 && rightPri == -1) {
return false;
}
return (leftPri != -1 && minPriInside < leftPri) || (rightPri != -1 && minPriInside < rightPri);
}
// 获取相邻运算符优先级
private int getAdjacentOpPrecedence(String[] tokens, int idx) {
if (idx < 0 || idx >= tokens.length) return -1;
String t = tokens[idx];
if (t.equals("(") || t.equals(")") || isNumber(t)) return -1;
return getPrecedence(t);
}
// 运算符优先级
private int getPrecedence(String op) {
return switch (op) {
case "+", "-" -> 1;
case "*", "/" -> 2;
default -> 0;
};
}
// 插入括号
private String insertBrackets(String[] tokens, boolean[] markLeft, boolean[] markRight) {
StringBuilder sb = new StringBuilder();
int numIndex = 0;
for (String token : tokens) {
if (isNumber(token)) {
if (markLeft[numIndex]) {
sb.append("(").append(" ");
}
sb.append(token);
if (markRight[numIndex]) {
sb.append(" ").append(")");
}
numIndex++;
} else {
sb.append(" ").append(token).append(" ");
}
}
return sb.toString();
}
// 验证括号匹配
private boolean validateParentheses(String expr) {
int balance = 0;
for (char c : expr.toCharArray()) {
if (c == '(') {
balance++;
}
if (c == ')') {
balance--;
}
if (balance < 0) {
return false;
}
}
return balance == 0;
}
// 判断是否为数字
private boolean isNumber(String token) {
try {
Integer.parseInt(token);
return true;
} catch (NumberFormatException e) {
return false;
}
}
// 获取表达式中数字位置
private List<Integer> getNumPositions(String expr) {
String[] tokens = expr.split(" ");
List<Integer> positions = new ArrayList<>();
for (int i = 0; i < tokens.length; i++) {
if (isNumber(tokens[i])) {
positions.add(i);
}
}
return positions;
}
// 获取第一层括号内部 token 范围
private List<int[]> getInnerBracketRanges(String expr) {
List<int[]> ranges = new ArrayList<>();
String[] tokens = expr.split(" ");
int balance = 0, start = -1;
for (int i = 0; i < tokens.length; i++) {
if (tokens[i].equals("(")) {
if (balance == 0) {
start = i;
}
balance++;
} else if (tokens[i].equals(")")) {
balance--;
if (balance == 0 && start != -1) {
ranges.add(new int[]{start + 1, i - 1});
}
}
}
return ranges;
}
// 提取指定范围 token
private String extractTokens(String expr, int start, int end) {
String[] tokens = expr.split(" ");
StringBuilder sb = new StringBuilder();
for (int i = start; i <= end; i++) {
if (i > start) sb.append(" ");
sb.append(tokens[i]);
}
return sb.toString();
}
// 替换指定范围 token
private String replaceTokens(String expr, int start, int end, String replacement) {
String[] tokens = expr.split(" ");
StringBuilder sb = new StringBuilder();
for (int i = 0; i < tokens.length; i++) {
if (i == start) {
sb.append(replacement);
i = end;
} else {
if (!sb.isEmpty()) {
sb.append(" ");
}
sb.append(tokens[i]);
}
}
return sb.toString();
}
//修正左括号后" "缺失
private String fixLeftParenthesisSpacing(String expr) {
StringBuilder sb = new StringBuilder();
char[] chars = expr.toCharArray();
for (int i = 0; i < chars.length; i++) {
char c = chars[i];
sb.append(c);
if (c == '(') {
if (i + 1 < chars.length && chars[i + 1] != ' ') {
sb.append(' ');
}
}
}
return sb.toString();
}
}

@ -1,16 +1,22 @@
import java.nio.charset.StandardCharsets;
import java.util.Scanner; import java.util.Scanner;
/** /**
* *
*/ */
public class ExamSystem { public class ExamSystem {
private final Scanner scanner = new Scanner(System.in); private final Scanner scanner = new Scanner(System.in, StandardCharsets.UTF_8);
public Users login() { public Users login() {
Users users = null; Users users = null;
while (users == null) { while (users == null) {
System.out.print("请输入用户名和密码: "); System.out.print("请输入用户名和密码: ");
String input = scanner.nextLine(); String input = scanner.nextLine();
if (input.equals("-1")) {
System.out.println("exit");
System.exit(0);
}
String[] parts = input.split(" "); String[] parts = input.split(" ");
if (parts.length == 2) { if (parts.length == 2) {
users = Users.login(parts[0], parts[1]); users = Users.login(parts[0], parts[1]);

@ -17,18 +17,13 @@ public class JuniorProblem implements ProblemsGenerator {
do { do {
int numCount = RANDOM.nextInt(5) + 1; int numCount = RANDOM.nextInt(5) + 1;
expression = expressionBuilder.generateBasicExpression(numCount); expression = expressionBuilder.generateBasicExpression(numCount);
List<Integer> numPositions = expressionBuilder.getNumberPositions(expression);
if (RANDOM.nextDouble() < 0.8) { expression = bracketManager.addNestedParentheses(expression);
int pairs = bracketManager.decideParenthesesPairs(numCount);
if (pairs > 0) {
expression = bracketManager.addParentheses(expression, pairs, numPositions);
}
}
// 添加幂运算并检查添加是否成功 List<Integer> numPositions = expressionBuilder.getNumberPositions(expression);
expression = powerManager.addPowerOperations(expression, numPositions); expression = powerManager.addPowerOperations(expression, numPositions, null);
hasPower = expression.contains("^2") || expression.contains("√"); hasPower = expression.contains("^2") || expression.contains("√");
} while (expressionBuilder.hasDivideByZero(expression) || !hasPower); } while (expressionBuilder.hasDivideByZero(expression) || !hasPower);
return expression; return expression;

@ -1,95 +1,148 @@
import java.util.List; import java.util.List;
import java.util.Random; import java.util.ArrayList;
import java.util.Random;
/**
* public class PowerManager {
*/ private static final Random RANDOM = new Random();
public class PowerManager {
private static final Random RANDOM = new Random(); //添加一次幂运算,30%概率再加一次
public String addPowerOperations(String expression, List<Integer> numPositions,
// 普通幂运算 List<Integer> trigPositions) {
public String addPowerOperations(String expression, List<Integer> numPositions) { if (numPositions.isEmpty()) {
if (numPositions.isEmpty()) return expression; return expression;
}
String[] tokens = expression.split(" ");
int targetIndex = chooseTargetIndex(tokens, numPositions, null); String[] tokens = expression.split(" ");
if (targetIndex != -1) { addOnePower(tokens, numPositions, trigPositions);
tokens[targetIndex] = applyPower(tokens[targetIndex], tokens, targetIndex); if (RANDOM.nextDouble() < 0.3) {
} addOnePower(tokens, numPositions, trigPositions);
}
return String.join(" ", tokens);
} return String.join(" ", tokens);
}
// 避免加在 trig 已占用的位置,同时避免加在运算符右边
public String addPowerOperationsAvoid(String expression, List<Integer> numPositions, List<Integer> trigPositions) { // 添加一次幂运算,平方/根号各50%
if (numPositions.isEmpty()) return expression; private void addOnePower(String[] tokens, List<Integer> numPositions, List<Integer> trigPositions) {
if (RANDOM.nextBoolean()) {
String[] tokens = expression.split(" "); tryAddSquare(tokens, numPositions, trigPositions);
int targetIndex = chooseTargetIndex(tokens, numPositions, trigPositions); } else {
tryAddSqrt(tokens, numPositions, trigPositions);
if (targetIndex != -1) { }
tokens[targetIndex] = applyPower(tokens[targetIndex], tokens, targetIndex); }
}
// 添加平方
return String.join(" ", tokens); private void tryAddSquare(String[] tokens, List<Integer> numPositions,
} List<Integer> trigPositions) {
int target = chooseTargetIndex(tokens, numPositions, trigPositions, true);
// 选择合适的位置加幂运算 if (target != -1) {
private int chooseTargetIndex(String[] tokens, List<Integer> numPositions, List<Integer> avoidPositions) { tokens[target] = tokens[target] + "^2";
for (int tries = 0; tries < 20; tries++) { }
int idx = numPositions.get(RANDOM.nextInt(numPositions.size())); }
if ((avoidPositions == null || !avoidPositions.contains(idx)) && canApplyPower(tokens, idx)) { // 添加根号
return idx; private void tryAddSqrt(String[] tokens, List<Integer> numPositions,
} List<Integer> trigPositions) {
} int target = chooseTargetIndex(tokens, numPositions, trigPositions, false);
return -1; if (target != -1) {
} tokens[target] = "√" + tokens[target];
}
// 检查该位置是否可以加幂运算 }
private boolean canApplyPower(String[] tokens, int index) {
if (!isNumber(tokens[index])) return false; // 选择可插入位置
if (tokens[index].contains("^") || tokens[index].contains("√")) return false; // 避免重复幂运算 private int chooseTargetIndex(String[] tokens, List<Integer> numPositions,
List<Integer> trigPositions, boolean isSquare) {
// 不能加在运算符右边 List<Integer> candidates = new ArrayList<>();
if (index > 0) { for (int idx : numPositions) {
String prev = tokens[index - 1]; String token = tokens[idx];
if (prev.equals("/") || prev.equals("*") || prev.equals("+") || prev.equals("-")) {
return false; // 避免 trig 位置
} if (trigPositions != null && trigPositions.contains(idx)) {
} continue;
return true; }
} // 不能已有运算
if (token.contains("^") || token.contains("√")) {
// 应用平方或开方(根号放左括号左侧,平方放右括号右侧) continue;
private String applyPower(String token, String[] tokens, int index) { }
boolean useSqrt = RANDOM.nextBoolean(); // 括号匹配检查
if ((token.equals("(") || token.equals(")")) && !checkParenCanAdd(tokens, idx, isSquare)) {
if (useSqrt) { continue;
// 根号放在左括号左侧,如果前面是左括号,则放在括号左边 }
if (index > 0 && tokens[index - 1].equals(")")) {
return "√" + token; // 特殊情况,仍然放数字前 // 根号/平方合法性
} if (isSquare) {
if (index > 0 && tokens[index - 1].equals("(")) { if (isNumber(token) || token.equals(")")) {
return "√" + token; candidates.add(idx);
} }
return "√" + token; }
} else { if (!isSquare) {
// 平方放在右括号右侧,如果后面是右括号,则放在括号右边 if (isNumber(token) || token.equals("(")) {
if (index < tokens.length - 1 && tokens[index + 1].equals(")")) { candidates.add(idx);
return token + "^2"; }
} }
return token + "^2"; }
}
} if (candidates.isEmpty()) {
return -1;
private boolean isNumber(String token) { }
try { return candidates.get(RANDOM.nextInt(candidates.size()));
Integer.parseInt(token); }
return true;
} catch (NumberFormatException e) { // 检查括号匹配另一侧是否可以加运算
return false; private boolean checkParenCanAdd(String[] tokens, int index, boolean isSquare) {
} int match = findMatchingParen(tokens, index);
} if (match == -1) {
} return false;
}
// 检查匹配括号是否已加运算
if (tokens[match].contains("^") || tokens[match].contains("√")) {
return false;
}
// 左括号只能加根号,右括号只能加平方
if (isSquare && tokens[index].equals("(")) {
return false;
}
return isSquare || !tokens[index].equals(")");
}
// 找匹配括号
private int findMatchingParen(String[] tokens, int index) {
if (tokens[index].equals("(")) {
int depth = 0;
for (int i = index; i < tokens.length; i++) {
if (tokens[i].equals("(")) {
depth++;
} else if (tokens[i].equals(")")) {
depth--;
if (depth == 0) {
return i;
}
}
}
} else if (tokens[index].equals(")")) {
int depth = 0;
for (int i = index; i >= 0; i--) {
if (tokens[i].equals(")")) {
depth++;
} else if (tokens[i].equals("(")) {
depth--;
if (depth == 0) {
return i;
}
}
}
}
return -1;
}
private boolean isNumber(String token) {
try {
Integer.parseInt(token);
return true;
} catch (NumberFormatException e) {
return false;
}
}
}

@ -15,27 +15,27 @@ public class SeniorProblem implements ProblemsGenerator {
public String generate() { public String generate() {
String expression; String expression;
boolean hasTrig; boolean hasTrig;
do { do {
// 生成基础表达式并添加括号
int numCount = RANDOM.nextInt(5) + 1; int numCount = RANDOM.nextInt(5) + 1;
expression = expressionBuilder.generateBasicExpression(numCount); expression = expressionBuilder.generateBasicExpression(numCount);
List<Integer> numPositions = expressionBuilder.getNumberPositions(expression); expression = bracketManager.addNestedParentheses(expression);
if (RANDOM.nextDouble() < 0.8) { // 获取初始数字位置
int pairs = bracketManager.decideParenthesesPairs(numCount); List<Integer> numPositions = expressionBuilder.getNumberPositions(expression);
if (pairs > 0) {
expression = bracketManager.addParentheses(expression, pairs, numPositions);
}
}
// 添加三角函数并检查是否存在 // 添加三角函数并重新获取数字位置
expression = trigManager.addTrigOperations(expression, numPositions); expression = trigManager.addTrigOperations(expression, numPositions);
List<Integer> trigPositions = expressionBuilder.getNumberPositions(expression); List<Integer> numPositionsAfterTrig = expressionBuilder.getNumberPositions(expression);
hasTrig = expression.contains("sin") || expression.contains("cos") || expression.contains("tan");
// 40% 概率加幂运算,避免与 trig 重叠 // 判断是否包含三角函数
if (RANDOM.nextDouble() < 0.4) { hasTrig = expression.contains("sin") || expression.contains("cos") || expression.contains("tan");
expression = powerManager.addPowerOperationsAvoid(expression, numPositions, trigPositions); // 添加幂运算50%概率执行
if (RANDOM.nextDouble() < 0.5) {
expression = powerManager.addPowerOperations(expression, numPositionsAfterTrig, null);
} }
} while (expressionBuilder.hasDivideByZero(expression) || !hasTrig); } while (expressionBuilder.hasDivideByZero(expression) || !hasTrig);
return expression; return expression;

Loading…
Cancel
Save