diff --git a/README.md b/README.md deleted file mode 100644 index 8f8370e..0000000 --- a/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# individual - diff --git a/doc/Documentation.md b/doc/Documentation.md new file mode 100644 index 0000000..f842c6a --- /dev/null +++ b/doc/Documentation.md @@ -0,0 +1,265 @@ +# **中小学数学卷子自动生成程序说明** +## 一、概述 +该项目是一个基于 Java 的中小学数学卷子自动生成系统,支持小学、初中和高中三个难度级别,具备用户登录、题目生成、查重、文件存储等功能。 +## 二、类 +### 1.Start - 程序入口类 +#### **功能:** +程序的启动入口,调用 Login 类启动登录流程。 + +#### **方法:** + +main(String[] args): 启动程序,创建 Login 实例并调用其 Main() 方法。 +### 2. Login - 用户登录类 +#### **功能:** + +处理用户登录、验证、权限管理和难度切换。 + +#### **方法:** + +Main(): 主登录循环,接收用户输入并验证。 + +initializeUserFile(): 初始化用户文件 users.txt,如果不存在则创建。 + +load(): 从 users.txt 加载用户信息到内存。 + +Prove(String username, String password): 验证用户名和密码。 + +Success(User user, Scanner scanner): 登录成功后进入题目生成流程。 + +Switch(QuestionManager questionManager, String input): 切换题目生成难度。 + +getRole(String role):将英文角色转换为中文显示。 +### 3. User - 用户信息类 +#### **功能:** + +封装用户的基本信息。 + +#### **属性:** + +username: 用户名 + +password: 密码 + +role: 角色(primary/junior/senior) + +#### **方法:** + +构造方法和 getter 方法 +### 4. QuestionManager - 题目管理器 +#### **功能:** + +管理题目生成、文件存储和用户目录。 + +#### **方法:** + +setRole(String role): 设置当前题目生成器(小学/初中/高中)。 + +createQuestionsDirectory(): 创建用户题目存储目录。 + +generateQuestions(int count): 生成指定数量的题目并保存到文件。 + +getCurrentRoleChinese(): 返回当前难度的中文名称。 + +getUserQuestionFiles(String username): 获取用户所有题目文件(用于查重)。 +### 5. QuestionGenerator - 题目生成器接口 +#### **功能:** + +定义题目生成器的基本行为。 + +#### **方法:** + +generateQuestion(): 生成一道题目。 + +normalizeQuestion(String question): 标准化题目格式用于比较。 + +generateOperator(String[] operators): 随机生成运算符。 + +isValidParentheses(String expression): 验证括号是否合法。 +### 6. AbstractQuestionGenerator - 抽象题目生成器 +#### **功能:** + +提供题目生成的通用方法和查重机制。 + +#### **方法:** + +setUsername(String username): 设置用户名并加载历史题目。 + +loadExistingQuestions(): 加载用户已生成的题目用于查重。 + +normalizeQuestion(String question): 去除空格标准化题目。 + +generateNumber(): 生成 1~100 的随机数。 + +isQuestionUnique(String question): 判断题目是否重复。 + +isValidParentheses(String expression): 验证括号是否合法且不冗余。 + +ensureBalancedParentheses(String expression): 确保括号成对出现。 +### 7. PrimaryQuestionGenerator - 小学题目生成器 +#### **功能:** + +生成小学难度题目,仅包含加减乘除和括号。 + +#### **方法:** + +generateQuestion(): 生成小学题目,支持括号和多个操作数。 + +addReasonableParentheses(String expression, int operandCount): 随机添加合理括号。 +### 8. JuniorQuestionGenerator - 初中题目生成器 +#### **功能:** + +生成初中难度题目,至少包含一个平方或开方运算。 + +#### **方法:** + +generateQuestion(): 生成初中题目,确保包含平方或开方。 + +AddSpecialOperator(...): 添加平方或开方运算符。 + +hasProperOperatorSpacing(String expression): 检查运算符间距是否合理。 +### 9. SeniorQuestionGenerator - 高中题目生成器 +#### **功能:** + +生成高中难度题目,至少包含一个三角函数(sin/cos/tan),支持嵌套。 + +#### **方法:** + +generateQuestion(): 生成高中题目,确保包含三角函数。 + +AddTrigOperator(...): 添加三角函数运算符。 + +ForceAddTrigOperator(...): 若未包含三角函数,则强制添加。 + +Revise(String expression): 调整括号位置,避免语法错误。 +## 三、流程 +### 1.登录流程 +(1)用户输入用户名和密码; + +(2)系统验证身份并显示角色; + +(3)用户选择生成题目数量或切换难度; + +(4)系统生成题目并保存到用户目录。 + +### 2.题目生成流程 +(1)根据难度选择对应的生成器; + +(2)生成操作数和运算符; + +(3)添加括号和特殊运算符(初中/高中); + +(4)查重和括号合法性检查; + +(5)保存到文件,格式为 年-月-日-时-分-秒.txt。 + +### 3.文件存储结构 + src + ├── questions/ + | └── 用户名/ + | ├── 2025-09-20-10-30-45.txt + | └── 2025-09-20-10-35-22.txt + └── users.txt + +### 4.难度特征 +|难度| 运算符类型| 特殊要求| +|:---:|:---|:---| +|小学| +, -, ×, ÷| 可含括号| +|初中| +, -, ×, ÷, ², √| 至少一个平方或开方| +|高中| +, -, ×, ÷, sin, cos, tan| 至少一个三角函数,可嵌套| +## 四、运行 +### 1. Linux bash +```bash +~/src$ javac *.java +~/src$ java Start +已创建users.txt +Loading... + +---------登录系统--------- +请输入用户名和密码(用空格隔开): +``` +或先生成jar: +```bash +~/src$ javac *.java +~/src$ jar -cfve main.jar Start *.class +已添加清单 +正在添加: AbstractQuestionGenerator.class(输入 = 4777) (输出 = 2649)(压缩了 44%) +正在添加: JuniorQuestionGenerator.class(输入 = 3654) (输出 = 2095)(压缩了 42%) +正在添加: Login.class(输入 = 5877) (输出 = 3401)(压缩了 42%) +正在添加: PrimaryQuestionGenerator.class(输入 = 2048) (输出 = 1203)(压缩了 41%) +正在添加: QuestionGenerator.class(输入 = 356) (输出 = 199)(压缩了 44%) +正在添加: QuestionManager.class(输入 = 4097) (输出 = 2204)(压缩了 46%) +正在添加: SeniorQuestionGenerator.class(输入 = 4577) (输出 = 2454)(压缩了 46%) +正在添加: Start.class(输入 = 308) (输出 = 238)(压缩了 22%) +正在添加: User.class(输入 = 1121) (输出 = 540)(压缩了 51%) +~/src$ java -jar main +Error: Unable to access jarfile main +~/src$ java -jar main.jar +已创建users.txt +Loading... + +---------登录系统--------- +请输入用户名和密码(用空格隔开): +``` +### 2.Windows cmd + +```cmd +D:\src>chcp 65001 +Active code page: 65001 + +D:\src>java Start.java +已创建users.txt +Loading... + +---------登录系统--------- +请输入用户名和密码(用空格隔开): +``` +或 +```cmd +D:\src>chcp 65001 +Active code page: 65001 + +D:\src>javac -encoding UTF-8 *.java + +D:\src>java Start +已创建users.txt +Loading... + +---------登录系统--------- +请输入用户名和密码(用空格隔开): +``` +或先生成jar: +```cmd +D:\src>chcp 65001 +Active code page: 65001 + +D:\src>javac -encoding UTF-8 *.java + +D:\src>jar cfve main.jar Start *.class +已添加清单 +正在添加: AbstractQuestionGenerator.class(输入 = 4777) (输出 = 2647)(压缩了 44%) +正在添加: JuniorQuestionGenerator.class(输入 = 3654) (输出 = 2095)(压缩了 42%) +正在添加: Login.class(输入 = 5877) (输出 = 3402)(压缩了 42%) +正在添加: PrimaryQuestionGenerator.class(输入 = 2048) (输出 = 1203)(压缩了 41%) +正在添加: QuestionGenerator.class(输入 = 356) (输出 = 199)(压缩了 44%) +正在添加: QuestionManager.class(输入 = 4097) (输出 = 2204)(压缩了 46%) +正在添加: SeniorQuestionGenerator.class(输入 = 4577) (输出 = 2454)(压缩了 46%) +正在添加: Start.class(输入 = 308) (输出 = 238)(压缩了 22%) +正在添加: User.class(输入 = 1121) (输出 = 539)(压缩了 51%) + +D:\src>java -jar main.jar +已创建users.txt +Loading... + +---------登录系统--------- +请输入用户名和密码(用空格隔开): +``` +### 3.Windows PowerShell +与cmd类似,只需将 +```cmd +D:\src>chcp 65001 +``` +换成 +```powershell +PS D:\src> [Console]::InputEncoding = [Console]::OutputEncoding = [System.Text.Encoding]::UTF8 +``` + diff --git a/src/AbstractQuestionGenerator.java b/src/AbstractQuestionGenerator.java new file mode 100644 index 0000000..7e39d09 --- /dev/null +++ b/src/AbstractQuestionGenerator.java @@ -0,0 +1,134 @@ +import java.io.*; +import java.util.HashSet; +import java.util.Random; +import java.util.Set; +import java.util.Stack; + +public abstract class AbstractQuestionGenerator implements QuestionGenerator { + + protected Random random = new Random(); + protected Set generatedQuestions = new HashSet<>(); + protected String username; + + // 设置用户名用于查重 + public void setUsername(String username) { + this.username = username; + loadExistingQuestions(); + } + + // 从文件中加载已存在的题目 + protected void loadExistingQuestions() { + if (username == null) return; + + File[] userFiles = QuestionManager.getUserQuestionFiles(username); + for (File file : userFiles) { + try (BufferedReader reader = new BufferedReader(new FileReader(file))) { + String line; + while ((line = reader.readLine()) != null) { + line = line.trim(); + if (!line.isEmpty() && line.matches("^\\d+\\. .+")) { + // 提取题目内容(去除题号) + String question = line.replaceFirst("^\\d+\\. ", ""); + String normalized = normalizeQuestion(question); + generatedQuestions.add(normalized); + } + } + } catch (IOException e) { + System.out.println("读取题目文件出错: " + e.getMessage()); + } + } + } + + // 标准化题目格式用于比较 + public String normalizeQuestion(String question) { + return question.replaceAll("\\s+", ""); + } + + protected String generateNumber() { + return String.valueOf(random.nextInt(100) + 1); + } + + public String generateOperator(String[] operators) { + return operators[random.nextInt(operators.length)]; + } + + protected boolean isQuestionUnique(String question) { + String normalized = normalizeQuestion(question); + return !generatedQuestions.contains(normalized); + } + + protected void addToGeneratedQuestions(String question) { + String normalized = normalizeQuestion(question); + generatedQuestions.add(normalized); + } + + + protected boolean hasBalancedParentheses(String expression) { + Stack stack = new Stack<>(); + for (char c : expression.toCharArray()) { + if (c == '(') { + stack.push(c); + } else if (c == ')') { + if (stack.isEmpty()) return false; + stack.pop(); + } + } + return stack.isEmpty(); + } + + public boolean isValidParentheses(String expression) { + expression = expression.replaceAll("\\s+", ""); + + if (!hasBalancedParentheses(expression)) { + return false; + } + + if (expression.startsWith("(") && expression.endsWith(")") && + hasBalancedParentheses(expression.substring(1, expression.length() - 1))) { + return false; + } + + String[] parts = expression.split("[+\\-×÷]"); + for (String part : parts) { + part = part.trim(); + if (part.startsWith("(") && part.endsWith(")")) { + String inside = part.substring(1, part.length() - 1); + if (isSimpleOperand(inside)) { + return false; + } + } + } + + return true; + } + + private boolean isSimpleOperand(String str) { + return str.matches("\\d+") || str.matches("√\\d+") || str.matches("\\d²+") || + str.matches("sin[\\d°]+") || str.matches("cos[\\d°]+") || str.matches("tan[\\d°]+") || + str.matches("sincos[\\d°]+") || str.matches("sintan[\\d°]+") || str.matches("cossin[\\d°]+") || + str.matches("costan[\\d°]+") || str.matches("tansin[\\d°]+") || str.matches("tancos[\\d°]+"); + } + + protected boolean hasOperator(String expression) { + return expression.contains("+") || expression.contains("-") || + expression.contains("×") || expression.contains("÷"); + } + + protected String ensureBalancedParentheses(String expression) { + int openCount = 0; + int closeCount = 0; + + for (char c : expression.toCharArray()) { + if (c == '(') openCount++; + if (c == ')') closeCount++; + } + + while (openCount > closeCount) { + expression += ")"; + closeCount++; + } + + return expression; + } + +} diff --git a/src/JuniorQuestionGenerator.java b/src/JuniorQuestionGenerator.java new file mode 100644 index 0000000..a72fbe3 --- /dev/null +++ b/src/JuniorQuestionGenerator.java @@ -0,0 +1,122 @@ +public class JuniorQuestionGenerator extends AbstractQuestionGenerator { + private static final String[] OPERATORS = {"+", "-", "×", "÷"}; + private static boolean h = false; + private static StringBuilder q; + + @Override + public String generateQuestion() { + int attempts = 0; + while (attempts < 100) { + attempts++; + + int operandCount = random.nextInt(5) + 1; // 1~5个操作数 + StringBuilder question = new StringBuilder(); + boolean hasSpecialOperator = false; + + AddSpecialOperator(operandCount, hasSpecialOperator, question); + hasSpecialOperator = h; + question = q; + + + String result = addReasonableParentheses(question.toString(), operandCount); + result = ensureBalancedParentheses(result); + + // 检查平方后是否有运算符 + if (!hasProperOperatorSpacing(result)) { + continue; + } + + if (isQuestionUnique(result) && isValidParentheses(result) && + (hasOperator(result) || hasSpecialOperator)) { + addToGeneratedQuestions(result); + String regex = "(?= parts.length) pos = parts.length - 1; + if (random.nextBoolean()) { + parts[pos] = parts[pos] + "²"; + } else { + parts[pos] = "√" + parts[pos]; + } + question = new StringBuilder(String.join(" ", parts)); + hasSpecialOperator = true; + } + h = hasSpecialOperator; + q = question; + } + + private boolean hasProperOperatorSpacing(String expression) { + String[] parts = expression.split(" "); + for (int i = 0; i < parts.length - 1; i++) { + // 如果当前部分是平方或开方,下一部分必须是运算符 + if ((parts[i].endsWith("²") || parts[i].startsWith("√")) && + i + 1 < parts.length && !isOperator(parts[i + 1])) { + return false; + } + // 如果当前部分是数字,下一部分不是运算符,也不合理 + if (parts[i].matches("\\d+") && i + 1 < parts.length && !isOperator(parts[i + 1])) { + return false; + } + } + return true; + } + + private boolean isOperator(String str) { + return str.equals("+") || str.equals("-") || str.equals("×") || str.equals("÷"); + } + + public String addReasonableParentheses(String expression, int operandCount) { + if (operandCount <= 2 || random.nextDouble() < 0.4) { + return expression; + } + + String[] parts = expression.split(" "); + if (parts.length < 5) return expression; + + StringBuilder newExpr = new StringBuilder(); + int start = random.nextInt(Math.max(1, parts.length / 2 - 1)); + int end = start + 1 + random.nextInt(Math.max(1, parts.length / 2 - start - 1)); + + for (int i = 0; i < parts.length; i++) { + if (i == start * 2 && start * 2 < parts.length - 3) { + newExpr.append("( "); + } + newExpr.append(parts[i]); + if (i == end * 2 && i < parts.length - 2 && end * 2 > start * 2 + 2) { + newExpr.append(" )"); + } + if (i < parts.length - 1) { + newExpr.append(" "); + } + } + + return newExpr.toString().trim(); + + } + +} diff --git a/src/Login.java b/src/Login.java new file mode 100644 index 0000000..0936322 --- /dev/null +++ b/src/Login.java @@ -0,0 +1,158 @@ +import java.io.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Scanner; + +public class Login { + private static final String USER_FILE = "users.txt"; + private static List users = new ArrayList<>(); + public void Main() { + initializeUserFile(); + load(); + Scanner scanner = new Scanner(System.in); + while (true) { + System.out.println("\n---------登录系统---------"); + System.out.println("请输入用户名和密码(用空格隔开): "); + String input = scanner.nextLine().trim(); + if (input.equalsIgnoreCase("q")) { + System.out.println("\n已退出!"); + break; + } + String[] NandP = input.split(" "); + if (NandP.length != 2) { + System.out.println("请输入正确的用户名和密码!"); + continue; + } + String username = NandP[0]; + String password = NandP[1]; + User user = Prove(username, password); + if (user != null) { + Success(user, scanner); + } else { + System.out.println("请输入正确的用户名和密码!"); + } + } + scanner.close(); + } + + + private static void initializeUserFile() { + File file = new File(USER_FILE); + if (!file.exists()) { + try (PrintWriter writer = new PrintWriter(new FileWriter(file))) { + + writer.println("张三1 123 primary\r\n" + + "张三2 123 primary\r\n" + + "张三3 123 primary\r\n" + + "李四1 123 junior\r\n" + + "李四2 123 junior\r\n" + + "李四3 123 junior\r\n" + + "王五1 123 senior\r\n" + + "王五2 123 senior\r\n" + + "王五3 123 senior"); + writer.close(); + System.out.println("已创建users.txt"); + } catch (IOException e) { + System.out.println("创建用户文件失败: " + e.getMessage()); + } + } + } + + + private static void load() { + users.clear(); + try (BufferedReader reader = new BufferedReader(new FileReader(USER_FILE))) { + String line; + while ((line = reader.readLine()) != null) { + line = line.trim(); + if (!line.isEmpty()) { + String[] parts = line.split(" "); + if (parts.length == 3) { + users.add(new User(parts[0], parts[1], parts[2])); + } + } + } + reader.close(); + System.out.println("Loading..."); + } catch (IOException e) { + System.out.println("出错!" + e.getMessage()); + } + } + + private static User Prove(String username, String password) { + for (User user : users) { + if (user.getUsername().equals(username) && user.getPassword().equals(password)) { + return user; + } + } + return null; + } + + private static void Success(User user, Scanner scanner) { + String role = getRole(user.getRole()); + System.out.println("\n登录成功!\n" + user.getUsername() + " [" + role + "]"); + QuestionManager questionManager = new QuestionManager(user.getUsername(), user.getRole()); + while (true) { + System.out.println("\n输入 -1 退出登录,输入 q 退出程序,输入\"切换为XX\"切换难度(XX为小学、初中、高中)"); + System.out.println("准备生成[" + questionManager.getCurrentRoleChinese() + "]数学题目,请输入生成题目数量(10~30):"); + String input = scanner.nextLine().trim(); + if (input.equals("-1")) { + System.out.println("返回登录界面..."); + break; + } else if (input.equalsIgnoreCase("q")) { + System.out.println("\n已退出!"); + System.exit(0); + } else if (input.startsWith("切换为")) { + Switch(questionManager, input); + } else { + try { + int count = Integer.parseInt(input); + if (count >= 10 && count <= 30) { + questionManager.generateQuestions(count); + } else if (count == -1) { + System.out.println("返回登录界面..."); + break; + } else { + System.out.println("题目数量应在10~30之间!"); + } + } catch (NumberFormatException e) { + System.out.println("请输入有效的数字(10~30)或指定命令!"); + } + } + } + } + + private static void Switch(QuestionManager questionManager, String input) { + String newRole = input.substring(3).trim(); + switch (newRole) { + case "小学": + questionManager.setRole("primary"); + System.out.println("已切换为小学难度"); + break; + case "初中": + questionManager.setRole("junior"); + System.out.println("已切换为初中难度"); + break; + case "高中": + questionManager.setRole("senior"); + System.out.println("已切换为高中难度"); + break; + default: + System.out.println("请输入小学、初中和高中三个选项中的一个"); + } + } + + private static String getRole(String role) { + switch (role) { + case "primary": + return "小学"; + case "junior": + return "初中"; + case "senior": + return "高中"; + default: + return "未知"; + } + } + +} diff --git a/src/PrimaryQuestionGenerator.java b/src/PrimaryQuestionGenerator.java new file mode 100644 index 0000000..c177f06 --- /dev/null +++ b/src/PrimaryQuestionGenerator.java @@ -0,0 +1,64 @@ +public class PrimaryQuestionGenerator extends AbstractQuestionGenerator { + private static final String[] OPERATORS = {"+", "-", "×", "÷"}; + + @Override + public String generateQuestion() { + int attempts = 0; + while (attempts < 100) { + attempts++; + int operandCount = random.nextInt(4) + 2; // 2~5个操作数 + StringBuilder question = new StringBuilder(); + + // 生成操作数和运算符 + for (int i = 0; i < operandCount; i++) { + question.append(generateNumber()); + if (i < operandCount - 1) { + question.append(" ").append(generateOperator(OPERATORS)).append(" "); + } + } + // 随机添加括号 + String result = addReasonableParentheses(question.toString(), operandCount); + result = ensureBalancedParentheses(result); // 确保括号平衡 + + if (isQuestionUnique(result) && isValidParentheses(result) && hasOperator(result)) { + addToGeneratedQuestions(result); + String regex = "(?= start * 2 + 2) { + newExpr.append(" )"); + } + if (i < parts.length - 1) { + newExpr.append(" "); + } + } + + return newExpr.toString().trim(); + } + +} diff --git a/src/QuestionGenerator.java b/src/QuestionGenerator.java new file mode 100644 index 0000000..3e89dad --- /dev/null +++ b/src/QuestionGenerator.java @@ -0,0 +1,6 @@ +public interface QuestionGenerator { + String generateQuestion(); + String normalizeQuestion(String question); + String generateOperator(String[] operators); + boolean isValidParentheses(String expression); +} diff --git a/src/QuestionManager.java b/src/QuestionManager.java new file mode 100644 index 0000000..c7490dc --- /dev/null +++ b/src/QuestionManager.java @@ -0,0 +1,94 @@ +import java.io.*; +import java.text.SimpleDateFormat; +import java.util.Date; + +public class QuestionManager { + private QuestionGenerator generator; + private String currentRole; + private String username; + private static final String QUESTIONS_DIR = "questions"; + + public QuestionManager(String username, String role) { + this.username = username; + setRole(role); + createQuestionsDirectory(); + } + + public void setRole(String role) { + this.currentRole = role; + switch (role) { + case "primary": + generator = new PrimaryQuestionGenerator(); + break; + case "junior": + generator = new JuniorQuestionGenerator(); + break; + case "senior": + generator = new SeniorQuestionGenerator(); + break; + } + } + + // 创建questions目录 + private void createQuestionsDirectory() { + File questionsDir = new File(QUESTIONS_DIR); + if (!questionsDir.exists()) { + questionsDir.mkdir(); + } + + // 创建用户子目录 + File userDir = new File(questionsDir, username); + if (!userDir.exists()) { + userDir.mkdir(); + } + } + + public void generateQuestions(int count) { + if (count < 10 || count > 30) { + System.out.println("题目数量应在10~30之间"); + return; + } + + // 使用questions目录下的用户文件夹 + File userDir = new File(QUESTIONS_DIR, username); + if (!userDir.exists()) { + userDir.mkdir(); + } + + // 生成文件名 + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss"); + String fileName = sdf.format(new Date()) + ".txt"; + File outputFile = new File(userDir, fileName); + + try (PrintWriter writer = new PrintWriter(new FileWriter(outputFile))) { + for (int i = 1; i <= count; i++) { + String question = generator.generateQuestion(); + writer.println(i + ". " + question); + if (i < count) { + writer.println(); // 题目之间空一行 + } + } + System.out.println("题目已生成到: " + outputFile.getPath()); + } catch (IOException e) { + System.out.println("生成题目时出错: " + e.getMessage()); + } + } + + public String getCurrentRoleChinese() { + switch (currentRole) { + case "primary": return "小学"; + case "junior": return "初中"; + case "senior": return "高中"; + default: return "未知"; + } + } + + // 获取指定用户的所有题目文件(用于查重功能) + public static File[] getUserQuestionFiles(String username) { + File userDir = new File(QUESTIONS_DIR, username); + if (userDir.exists() && userDir.isDirectory()) { + return userDir.listFiles((dir, name) -> name.endsWith(".txt")); + } + return new File[0]; + } +} diff --git a/src/SeniorQuestionGenerator.java b/src/SeniorQuestionGenerator.java new file mode 100644 index 0000000..7489673 --- /dev/null +++ b/src/SeniorQuestionGenerator.java @@ -0,0 +1,163 @@ +public class SeniorQuestionGenerator extends AbstractQuestionGenerator{ + private static final String[] OPERATORS = {"+", "-", "×", "÷"}; + private static boolean h = false; + private static StringBuilder q; + + @Override + public String generateQuestion() { + int attempts = 0; + while (attempts < 100) { + attempts++; + + int operandCount = random.nextInt(5) + 1; // 1~5个操作数 + StringBuilder question = new StringBuilder(); + boolean hasTrigOperator = false; + + AddTrigOperator(operandCount, hasTrigOperator, question); + hasTrigOperator = h; + question = q; + ForceAddTrigOperator(hasTrigOperator, question); + hasTrigOperator = h; + question = q; + + String result = addReasonableParentheses(question.toString(), operandCount); + result = ensureBalancedParentheses(result); + result = Revise(result); + + + if (isQuestionUnique(result) && isValidParentheses(result) && + (hasOperator(result) || hasTrigOperator)) { + addToGeneratedQuestions(result); + String regex = "(? start * 2 + 2) { + newExpr.append(" )"); + } + if (i < parts.length - 1) { + newExpr.append(" "); + } + } + + return newExpr.toString().trim(); + } + + private String Revise(String expression) { + + if(!expression.contains("(")) { + return expression; + } + + String[] parts = expression.split(" "); + int count = 0; + while(count < 2) { + count++; + for (int i = 1; i < parts.length - 1; i++) { + if (parts[i].equals("(") && (parts[i+1].equals("+") || parts[i+1].equals("-") || parts[i+1].equals("×") || parts[i+1].equals("÷"))) { + String t = parts[i]; + parts[i] = parts[i+1]; + parts[i+1] = t; + } + if (parts[i].equals(")") && (parts[i-1].equals("+") || parts[i-1].equals("-") || parts[i-1].equals("×") || parts[i-1].equals("÷") + || parts[i-1].equals("cos") || parts[i-1].equals("sin") || parts[i-1].equals("tan") || parts[i-1].equals("sincos") || parts[i-1].equals("sintan") + || parts[i-1].equals("cossin") || parts[i-1].equals("costan") || parts[i-1].equals("tansin") || parts[i-1].equals("tancos"))) { + String t = parts[i]; + parts[i] = parts[i-1]; + parts[i-1] = t; + } + + } + } + StringBuilder result = new StringBuilder(); + for (int i = 0; i < parts.length; i++) { + if (!parts[i].isEmpty()) { + result.append(parts[i]).append(" "); + } + } + return result.toString(); + + } + + + private void AddTrigOperator(int operandCount, boolean hasTrigOperator, StringBuilder question) { + for (int i = 0; i < operandCount; i++) { + // 决定是否添加三角函数 + if (!hasTrigOperator && random.nextDouble() < 0.4) { + String trigOp = generateOperator(new String[]{"sin", "cos", "tan"}); + int angle = random.nextInt(101); + + // 随机决定是否嵌套三角函数(30%概率) + if (random.nextDouble() < 0.3) { + String nestedTrig = generateOperator(new String[]{"sin", "cos", "tan"}); + while (nestedTrig.equals(trigOp)) { + nestedTrig = generateOperator(new String[]{"sin", "cos", "tan"}); + } + question.append(trigOp).append(nestedTrig).append(" ").append(angle).append("°"); + } else { + question.append(trigOp).append(" ").append(angle).append("°"); + } + hasTrigOperator = true; + } else { + question.append(generateNumber()); + } + + if (i < operandCount - 1) { + String operator = generateOperator(OPERATORS); + question.append(" ").append(operator).append(" "); + } + } + h = hasTrigOperator; + q = question; + } + + private void ForceAddTrigOperator(boolean hasTrigOperator, StringBuilder question) { + // 如果还没有三角函数,强制添加一个 + if (!hasTrigOperator) { + String[] parts = question.toString().split(" "); + int pos = random.nextInt(parts.length / 2 + 1) * 2; + if (pos >= parts.length) pos = parts.length - 1; + + String trigOp = generateOperator(new String[]{"sin", "cos", "tan"}); + int angle = random.nextInt(101); + + // 随机决定是否嵌套 + if (random.nextDouble() < 0.3) { + String nestedTrig = generateOperator(new String[]{"sin", "cos", "tan"}); + while (nestedTrig.equals(trigOp)) { + nestedTrig = generateOperator(new String[]{"sin", "cos", "tan"}); + } + parts[pos] = trigOp + nestedTrig + " " + angle + "°"; + } else { + parts[pos] = trigOp + " " + angle + "°"; + } + question = new StringBuilder(String.join(" ", parts)); + hasTrigOperator = true; + } + h = hasTrigOperator; + q = question; + } + +} diff --git a/src/Start.java b/src/Start.java new file mode 100644 index 0000000..6af142e --- /dev/null +++ b/src/Start.java @@ -0,0 +1,7 @@ +public class Start { + + public static void main(String[] args) { + Login login = new Login(); + login.Main(); + } +} diff --git a/src/User.java b/src/User.java new file mode 100644 index 0000000..9ea6bad --- /dev/null +++ b/src/User.java @@ -0,0 +1,28 @@ +public class User { + private String username; + private String password; + private String role; + + public User(String username, String password, String role) { + this.username = username; + this.password = password; + this.role = role; + } + + public String getUsername() { + return username; + } + + public String getPassword() { + return password; + } + + public String getRole() { + return role; + } + + @Override + public String toString() { + return username + " " + password + " " + role; + } +} diff --git a/src/main.jar b/src/main.jar new file mode 100644 index 0000000..09d8582 Binary files /dev/null and b/src/main.jar differ