H^+cp6olXUzDe3}t3#tz|J~4Y=76_E|*Cfwy<({REmjVWNL03D> zs1?nYEf+?W8w^|IkE!zxxTDkMd)IWC9e{REs3adGLESPNBkd8!BgLkuiM(ACu9lIq zq|l0ai`UAT<<+!Gx4lnE2(v0HS9n>A9#>LRT9h7CMNSpbcFk}vsNIyGrkPK~P89RW zC?ofoHAjoyi>Ocf2GyI^&(ZDbRV|v0+?7i;1#sfnilbc-+#W#yEwkMe$Uw=1Y<)N5 z=8TV(-c6r@1vzeTpEb+@(|4MpYPPHv-~~YJ(hE^-gbfhcyOWS9NC#GVgtB^HedrwD z(HK5YYp_)tU}yj(&-s$_*U0i~2=i|d!;;pknqss8J%-kdRL}4joPMRsUzhSvqI(A{ zF*=3YSqO`ExqH#zcNY-+e#pF&cVUc@x5qXiqW77hy&;KAM`-2HHH98yqmwb2B#rNy zJIsNLPuc1mG<^t^L1hNI1MvB#Su`EbZnB2eVcaFfOG$4wwrC%c`VIWGH#-s^XLUfP zu>D8Vcf&1aY#ZhW$+DK1Th60C3AWqT_0{UEha(;ChOGzM${6G&R&qe-@2fb)RtVtXp?D zILVri0(hp+>HgFP5)_JPsaKpnkILk&DbfGhr%>lMXSg(DKm=Wv)N_6nDG`m)2$5HB z*8c{qZf-1_rh?a_9m-IQII3hR1nNgwK#CS#eEvC4g2=&yOe`*5zZl$x4Id0YV0cxL z%@q-aD?4W(0*m9Y&`^ 5hK~1> zCLi ho;E1d?8_A+LQa)hJ+-BRC@rqS9TvVYNFS6XJ@NBKsoi0 z>yrUOKC?+c!Q*j=iuP7(6cPAbd3}xqd6oQlf{>d7T&3wSgIh#F>}mND3x^T2K#Hiv z6%kNUTY3JhP=zB}^qO$Mf>IqR3%k_NANmlQ`eYI4HU7qhaZG$Zy(7ou*YU2i2tNvb zV0${ua%8a+=D-zHNgj{LSy4!1nz+!E4h%Kq_w1L?=uMz=CE3ORl9-exvY5E|7aPYq zofH<1X+$IWjW6QmXd$qxmP2Gs-p%z$nLWPW$l}sB92uGOvRDu^BuNY3&3;0oxRJL$ zINvUOtDPQI;Ofl0^-d+in&_5xUh(7r6LpXt=1s7{7=OT>*<%pj nATDd z-o1j#T5_Sxh}7H`{*Oz@yGJ0n&YrZzj*I1UdT4#J7mB7~!i(lKk)OG*G*~=2ZpFup z6lsZ5v(5gyQF1f&!>A*}nGb?|Zl^4eo6>C? HPf-{sZk-L!PbK8}M tjbW~le8w)=0Y=oBkw zgUAOz^f9Kz&P#S{SrXi+-e7M<@EL%a#59hin0`@rrpahIzQQ(WNRIiq&6B?Kr#hw{ z`B};9n9qWJ`IeQJ{74+$Hk5!@|3b&e$$68Ovi^4Wa76kIOjR5Y==- FFx4J(GC@q^(;`*jg{^@`$>`ILdU zHmv0bA VoC#eynqvr5=5leEO6I(vxxNg1cEp3pd z>v`6w6_2j<9L?m;KZEy v{K166KI D7yN$ouk#E3tS|p{e!*|b{dxQEPJf}je|@0; zDg7@Ne^xsGDn$QH*gwbmZx+AH(*H^9U+#n7H2-rZeiujoUG6`tIe!7u-}LfFufGKU zTe0+i%KvBC<1bDBO~yav`AdMmSp7%o;y;b%=d1aHf`7&*|E!z*J)U3b@qZ@H|4LQ+ zP1S$v_m6dye~#=I(?2ug$bNJDc{hgiH(~xU1OGp{{uzz^yQp8V|K$3QId=avZ@&V$ zzX_k@Z(-g4zUKd~H=;kg{VUA--+TND^!_IEfA{zu_Wk{eeg%I2^nm>e{Qjo+|LFNU z4E#^S{QF`rp#Qzc{5j*ld}n`tpZx-aziI4`UjNIJ_9vTPiuxzw{JYNh{5<{SuMO_6 zh5ong?LS%lxo`emqI-_tto|2Z{ZBT38pXe>o;%NPHveVIm6ZVf^lK)5SyJJjU$6VT HzkdBch9Mg6 literal 0 HcmV?d00001 diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..d8248f9 --- /dev/null +++ b/pom.xml @@ -0,0 +1,118 @@ + + + \ No newline at end of file diff --git a/src/main/java/Main.java b/src/main/java/Main.java new file mode 100644 index 0000000..fe7aa2b --- /dev/null +++ b/src/main/java/Main.java @@ -0,0 +1,15 @@ +//TIP 要运行代码,请按4.0.0 + + +com.math +math-test-generator +1.0.0 + + ++ + + +8 +8 +UTF-8 + +Main ++ + + + ++ +junit +junit +4.13.2 +test ++ ++ + ++ + + +org.apache.maven.plugins +maven-compiler-plugin +3.8.1 ++ +8 +8 +UTF-8 ++ + + +org.apache.maven.plugins +maven-jar-plugin +3.2.2 ++ ++ ++ + +${main.class} + +true +lib/ ++ + + +org.apache.maven.plugins +maven-dependency-plugin +3.3.0 ++ ++ +copy-dependencies +package ++ +copy-dependencies ++ +${project.build.directory}/lib +false +false +true ++ +org.apache.maven.plugins +maven-assembly-plugin +3.4.2 ++ ++ ++ +${main.class} ++ + +jar-with-dependencies +math-test-generator +false ++ ++ +make-assembly +package ++ +single +或 +// 点击装订区域中的 图标。 +public class Main { + public static void main(String[] args) { + //TIP 当文本光标位于高亮显示的文本处时按 + // 查看 IntelliJ IDEA 建议如何修正。 + System.out.printf("Hello and welcome!"); + + for (int i = 1; i <= 5; i++) { + //TIP 按 开始调试代码。我们已经设置了一个 断点 + // 但您始终可以通过按 添加更多断点。 + System.out.println("i = " + i); + } + } +} \ No newline at end of file diff --git a/src/main/java/entity/Question.java b/src/main/java/entity/Question.java new file mode 100644 index 0000000..9239c2c --- /dev/null +++ b/src/main/java/entity/Question.java @@ -0,0 +1,58 @@ +<<<<<<< HEAD +package entity; + +/** + 题目实体类 + 封装题目的基本属性:题号和题目内容 + 提供格式化的字符串输出方法 + */ +public class Question { + private final int number; // 题号 + private final String content; // 题目内容(数学表达式) + + /** + 构造函数 + @param number 题号(从1开始) + @param content 题目内容 + */ +======= +package main.java.entity; + +//题目类定义 +public class Question { + private int number; + private String content; + +>>>>>>> 93d8b771666e4fb2ee7477c19dcf6f4fb1eec045 + public Question(int number, String content) { + this.number = number; + this.content = content; + } + +<<<<<<< HEAD + // Getter方法 + public int getNumber() { return number; } + public String getContent() { return content; } + + /** + 重写toString方法,格式化输出题目 + 格式:题号. 题目内容 + @return 格式化后的题目字符串 + */ + @Override + public String toString() { + return number + ". " + content; + } +} +======= + //获取题目信息 + public int getNumber() {return number;} + public String getContent() {return content;} + + @Override + //重写toString方法返回number与content + public String toString() { + return number + " " + content; + } +} +>>>>>>> 93d8b771666e4fb2ee7477c19dcf6f4fb1eec045 diff --git a/src/main/java/entity/User.java b/src/main/java/entity/User.java new file mode 100644 index 0000000..1d51d7a --- /dev/null +++ b/src/main/java/entity/User.java @@ -0,0 +1,49 @@ +<<<<<<< HEAD +package entity; + +/** + 用户实体类 + 用于存储用户的基本信息:用户名、密码和用户类型(小学/初中/高中) + 这是一个不可变类,所有字段都是final的,确保对象创建后状态不会被修改 + */ +public class User { + private final String username; // 用户名 + private final String password; // 密码 + private final String type; // 用户类型:小学、初中、高中 + + /** + 构造函数 + @param username 用户名 + @param password 密码 + @param type 用户类型 + */ +======= +package main.java.entity; + +//用户类定义 +public class User { + private String username; + private String password; + private String type; + +>>>>>>> 93d8b771666e4fb2ee7477c19dcf6f4fb1eec045 + public User(String username, String password, String type) { + this.username = username; + this.password = password; + this.type = type; + } + +<<<<<<< HEAD + // Getter方法 + public String getUsername() { return username; } + public String getPassword() { return password; } + public String getType() { return type; } +} +======= + //获得用户信息 + public String getUsername() {return username;} + public String getPassword() {return password;} + public String getType() {return type;} +} + +>>>>>>> 93d8b771666e4fb2ee7477c19dcf6f4fb1eec045 diff --git a/src/main/java/factory/QuestionFactory.java b/src/main/java/factory/QuestionFactory.java new file mode 100644 index 0000000..c01b113 --- /dev/null +++ b/src/main/java/factory/QuestionFactory.java @@ -0,0 +1,34 @@ +<<<<<<< HEAD +package factory; + +/** + 题目生成器工厂类 + 使用工厂模式创建不同难度的题目生成器 + 封装了对象创建的细节,客户端无需知道具体实现类 + */ +public class QuestionFactory { + /** + 根据类型创建对应的题目生成器 + @param type 题目类型:小学、初中、高中 + @return 对应的题目生成器实例 + @throws IllegalArgumentException 如果类型不支持 + */ + public static QuestionGenerator createGenerator(String type) { + switch (type) { + case "小学": + return new generator.PrimaryQuestionGenerator(); + case "初中": + return new generator.JuniorQuestionGenerator(); + case "高中": + return new generator.SeniorQuestionGenerator(); + default: + throw new IllegalArgumentException("不支持的题目类型: " + type); + } + } +======= +package main.java.factory; + +public class QuestionFactory { + +>>>>>>> 93d8b771666e4fb2ee7477c19dcf6f4fb1eec045 +} diff --git a/src/main/java/factory/QuestionGenerator.java b/src/main/java/factory/QuestionGenerator.java new file mode 100644 index 0000000..dad820b --- /dev/null +++ b/src/main/java/factory/QuestionGenerator.java @@ -0,0 +1,37 @@ +<<<<<<< HEAD +package factory; + +import entity.Question; +import java.util.List; + +/** + 题目生成器接口 + 定义所有题目生成器必须实现的方法 + 采用策略模式,支持不同难度题目的生成 + */ +public interface QuestionGenerator { + /** + 生成指定数量的题目列表 + @param count 要生成的题目数量 + @return 题目列表,包含指定数量的题目 + */ + List generateQuestions(int count); + + /** + 生成单个题目 + @return 单个题目对象 + */ + Question generateQuestion(); + + /** + 获取题目生成器的类型 + @return 类型字符串(小学/初中/高中) + */ + String getType(); +} +======= +package main.java.factory; + +public class QuestionGenerator { +} +>>>>>>> 93d8b771666e4fb2ee7477c19dcf6f4fb1eec045 diff --git a/src/main/java/generator/JuniorQuestionGenerator.java b/src/main/java/generator/JuniorQuestionGenerator.java new file mode 100644 index 0000000..5f3f710 --- /dev/null +++ b/src/main/java/generator/JuniorQuestionGenerator.java @@ -0,0 +1,244 @@ +<<<<<<< HEAD +package generator; + +import entity.Question; +import factory.QuestionGenerator; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +/** + 初中题目生成器 + 生成初中难度的数学题目,包含平方(²)和开根号(√)运算符 + 确保每个题目至少有一个平方或开根号运算符,并且这些运算符处理的操作数 + 需要通过四则运算符与其他操作数连接 + */ +public class JuniorQuestionGenerator implements QuestionGenerator { + private static final String[] BINARY_OPERATORS = {"+", "-", "*", "/"}; + private static final String[] UNARY_OPERATORS = {"²", "√"}; + private static final int MIN_OPERAND_COUNT = 3; + private static final int MAX_OPERAND_COUNT = 5; + private static final int MIN_OPERAND_VALUE = 1; + private static final int MAX_OPERAND_VALUE = 100; + private static final double UNARY_OPERATOR_PROBABILITY = 0.6; + + private final Random random; + + /** + 构造函数 + */ + public JuniorQuestionGenerator() { + this.random = new Random(); + } + + /** + 生成指定数量的初中题目 + @param count 要生成的题目数量 + @return 题目列表,包含指定数量的初中难度题目 + */ + @Override + public List
generateQuestions(int count) { + List questions = new ArrayList<>(); + for (int i = 0; i < count; i++) { + questions.add(generateQuestion()); + } + return questions; + } + + /** + 生成单个初中题目 + 确保题目中至少有一个平方或开根号的运算符,并且这些运算符处理的操作数 + 需要通过四则运算符与其他操作数连接 + @return 单个题目对象 + */ + @Override + public Question generateQuestion() { + String expression; + boolean hasAdvancedOperator; + boolean hasBinaryConnection; + + // 循环生成直到满足条件 + do { + expression = generateValidExpression(); + hasAdvancedOperator = containsAdvancedOperator(expression); + hasBinaryConnection = hasBinaryOperatorConnection(expression); + } while (!hasAdvancedOperator || !hasBinaryConnection); + + return new Question(0, expression); + } + + /** + * 获取题目生成器的类型 + * + * @return 类型字符串"初中" + */ + @Override + public String getType() { + return "初中"; + } + + /** + * 生成有效的表达式 + * + *
生成包含操作数和运算符的表达式,确保有足够的操作数来支持四则运算连接 + * + * @return 有效的表达式字符串 + */ + private String generateValidExpression() { + int operandCount = random.nextInt(MAX_OPERAND_COUNT - MIN_OPERAND_COUNT + 1) + MIN_OPERAND_COUNT; + StringBuilder expression = new StringBuilder(); + + // 添加第一个操作数,可能应用一元运算符 + expression.append(generateOperandWithPossibleUnaryOperator()); + + // 添加后续操作数和运算符 + for (int i = 1; i < operandCount; i++) { + expression.append(" ").append(generateBinaryOperator()).append(" "); + expression.append(generateOperandWithPossibleUnaryOperator()); + } + + return expression.toString(); + } + + /** + * 生成可能带有一元运算符的操作数 + * + * @return 可能应用了一元运算符的操作数字符串 + */ + private String generateOperandWithPossibleUnaryOperator() { + String operand = generateOperand(); + + // 根据概率决定是否应用一元运算符 + if (random.nextDouble() < UNARY_OPERATOR_PROBABILITY) { + String operator = UNARY_OPERATORS[random.nextInt(UNARY_OPERATORS.length)]; + return applyUnaryOperator(operand, operator); + } + + return operand; + } + + /** + * 应用一元运算符到操作数 + * + * @param operand 操作数 + * @param operator 一元运算符 + * @return 应用运算符后的表达式 + */ + private String applyUnaryOperator(String operand, String operator) { + switch (operator) { + case "²": + return "(" + operand + ")²"; + case "√": + return "√(" + operand + ")"; + default: + return operand; + } + } + + /** + * 生成操作数(1-100) + * + * @return 操作数字符串 + */ + private String generateOperand() { + return String.valueOf(random.nextInt(MAX_OPERAND_VALUE) + MIN_OPERAND_VALUE); + } + + /** + * 生成二元运算符 + * + * @return 二元运算符字符串 + */ + private String generateBinaryOperator() { + return BINARY_OPERATORS[random.nextInt(BINARY_OPERATORS.length)]; + } + + /** + * 检查表达式是否包含高级运算符(平方或开根号) + * + * @param expression 数学表达式 + * @return 如果包含高级运算符返回true,否则返回false + */ + private boolean containsAdvancedOperator(String expression) { + return expression.contains("²") || expression.contains("√"); + } + + /** + * 检查高级运算符处理的操作数是否有四则运算符连接其他操作数 + * + *
确保平方或根号处理的操作数不是孤立存在的,而是通过四则运算与其他操作数连接 + * + * @param expression 数学表达式 + * @return 如果满足连接条件返回true,否则返回false + */ + private boolean hasBinaryOperatorConnection(String expression) { + // 如果表达式包含高级运算符,检查是否有足够的二元运算符连接 + if (containsAdvancedOperator(expression)) { + int binaryOperatorCount = countBinaryOperators(expression); + // 至少需要1个二元运算符来连接操作数 + return binaryOperatorCount >= 1; + } + return false; + } + + /** + * 计算表达式中二元运算符的数量 + * + * @param expression 数学表达式 + * @return 二元运算符的数量 + */ + private int countBinaryOperators(String expression) { + int count = 0; + for (String operator : BINARY_OPERATORS) { + // 简单的计数方法,实际可能需要更复杂的解析 + int index = expression.indexOf(operator); + while (index >= 0) { + count++; + index = expression.indexOf(operator, index + 1); + } + } + return count; + } + + /** + * 生成一个确保满足条件的表达式(备用方法) + * + *
这个方法确保生成的表达式一定包含高级运算符并且有二元运算符连接 + * + * @return 满足条件的表达式 + */ + private String generateGuaranteedValidExpression() { + StringBuilder expression = new StringBuilder(); + + // 至少生成3个操作数以确保有连接 + int operandCount = random.nextInt(MAX_OPERAND_COUNT - MIN_OPERAND_COUNT + 1) + MIN_OPERAND_COUNT; + + // 第一个操作数:普通操作数 + expression.append(generateOperand()); + expression.append(" ").append(generateBinaryOperator()).append(" "); + + // 第二个操作数:应用高级运算符 + String advancedOperand = generateOperand(); + String unaryOperator = UNARY_OPERATORS[random.nextInt(UNARY_OPERATORS.length)]; + expression.append(applyUnaryOperator(advancedOperand, unaryOperator)); + + // 如果有更多操作数,继续添加 + for (int i = 2; i < operandCount; i++) { + expression.append(" ").append(generateBinaryOperator()).append(" "); + // 随机决定是否应用一元运算符 + if (random.nextBoolean()) { + expression.append(generateOperandWithPossibleUnaryOperator()); + } else { + expression.append(generateOperand()); + } + } + + return expression.toString(); + } +} +======= +package main.java.generator; + +public class JuniorQuestionGenerator { +} +>>>>>>> 93d8b771666e4fb2ee7477c19dcf6f4fb1eec045 diff --git a/src/main/java/generator/PrimaryQuestionGenerator.java b/src/main/java/generator/PrimaryQuestionGenerator.java new file mode 100644 index 0000000..3986c7b --- /dev/null +++ b/src/main/java/generator/PrimaryQuestionGenerator.java @@ -0,0 +1,208 @@ +<<<<<<< HEAD +package generator; + +import entity.Question; +import factory.QuestionGenerator; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +/** + 小学题目生成器 +
生成小学难度的数学题目,只包含加减乘除和括号 + 确保每个题目至少有两个操作数,操作数范围1-100 + */ +public class PrimaryQuestionGenerator implements QuestionGenerator { + private static final String[] OPERATORS = {"+", "-", "*", "/"}; + private static final int MIN_OPERAND_COUNT = 2; + private static final int MAX_OPERAND_COUNT = 5; + private static final int MIN_OPERAND_VALUE = 1; + private static final int MAX_OPERAND_VALUE = 100; + private static final double PARENTHESIS_PROBABILITY = 0.3; + + private final Random random; + + /** + 构造函数 + */ + public PrimaryQuestionGenerator() { + this.random = new Random(); + } + + /** + 生成指定数量的小学题目 + @param count 要生成的题目数量 + @return 题目列表,包含指定数量的小学难度题目 + */ + @Override + public List
generateQuestions(int count) { + List questions = new ArrayList<>(); + for (int i = 0; i < count; i++) { + questions.add(generateQuestion()); + } + return questions; + } + + /** + 生成单个小学题目 + 题目包含2-5个操作数,操作数范围1-100 + 只包含加减乘除运算符,可能包含括号 + @return 单个题目对象 + */ + @Override + public Question generateQuestion() { + // 生成基础表达式(不带括号) + String baseExpression = generateBaseExpression(); + + // 随机决定是否添加括号 + String finalExpression = maybeAddParentheses(baseExpression); + + return new Question(0, finalExpression); + } + + /** + 获取题目生成器的类型 + @return 类型字符串"小学" + */ + @Override + public String getType() { + return "小学"; + } + + /** + 生成基础表达式(不带括号) + @return 基础表达式字符串 + */ + private String generateBaseExpression() { + int operandCount = random.nextInt(MAX_OPERAND_COUNT - MIN_OPERAND_COUNT + 1) + MIN_OPERAND_COUNT; + StringBuilder expression = new StringBuilder(); + + // 添加第一个操作数 + expression.append(generateOperand()); + + // 添加后续操作数和运算符 + for (int i = 1; i < operandCount; i++) { + expression.append(" ").append(generateOperator()).append(" "); + expression.append(generateOperand()); + } + + return expression.toString(); + } + + /** + 随机决定是否为表达式添加括号 + @param expression 原始表达式 + @return 可能添加括号后的表达式 + */ + private String maybeAddParentheses(String expression) { + // 只有当操作数大于2时才考虑添加括号 + if (countOperands(expression) > 2 && random.nextDouble() < PARENTHESIS_PROBABILITY) { + return addParentheses(expression); + } + return expression; + } + + /** + 为表达式添加括号 +
在表达式中随机选择一个子表达式添加括号 + @param expression 原始表达式 + @return 添加括号后的表达式 + */ + private String addParentheses(String expression) { + String[] parts = expression.split(" "); + + // 如果表达式太短,直接为整个表达式添加括号 + if (parts.length <= 3) { + return "(" + expression + ")"; + } + + // 随机选择括号的起始位置(操作数的位置) + int startPos = random.nextInt(parts.length / 2) * 2; // 确保在操作数位置 + + // 随机选择括号的长度(包含的操作数数量,至少2个) + int maxLength = (parts.length - startPos) / 2 + 1; + int length = random.nextInt(maxLength - 1) + 2; // 至少2个操作数 + + // 计算结束位置 + int endPos = startPos + (length * 2 - 1); + if (endPos >= parts.length) { + endPos = parts.length - 1; + } + + // 构建带括号的表达式 + StringBuilder result = new StringBuilder(); + for (int i = 0; i < parts.length; i++) { + if (i == startPos) { + result.append("("); + } + + result.append(parts[i]); + + if (i == endPos) { + result.append(")"); + } + + if (i < parts.length - 1) { + result.append(" "); + } + } + + return result.toString(); + } + + /** + 计算表达式中的操作数数量 + @param expression 数学表达式 + @return 操作数的数量 + */ + private int countOperands(String expression) { + // 简单估算:操作数数量 ≈ (分割后的数组长度 + 1) / 2 + String[] parts = expression.split(" "); + return (parts.length + 1) / 2; + } + + /** + 生成操作数(1-100) + @return 操作数字符串 + */ + private String generateOperand() { + return String.valueOf(random.nextInt(MAX_OPERAND_VALUE) + MIN_OPERAND_VALUE); + } + + /** + 生成运算符 + @return 运算符字符串 + */ + private String generateOperator() { + return OPERATORS[random.nextInt(OPERATORS.length)]; + } + + /** + 生成一个确保有两个操作数的表达式(备用方法) +
这个方法确保生成的表达式至少有两个操作数 + @return 至少有两个操作数的表达式 + */ + private String generateGuaranteedTwoOperandExpression() { + StringBuilder expression = new StringBuilder(); + + // 确保至少有两个操作数 + int operandCount = random.nextInt(MAX_OPERAND_COUNT - MIN_OPERAND_COUNT + 1) + MIN_OPERAND_COUNT; + + // 添加第一个操作数 + expression.append(generateOperand()); + + // 添加后续操作数和运算符 + for (int i = 1; i < operandCount; i++) { + expression.append(" ").append(generateOperator()).append(" "); + expression.append(generateOperand()); + } + + return expression.toString(); + } +} +======= +package main.java.generator; + +public class PrimaryQuestionGenerator { +} +>>>>>>> 93d8b771666e4fb2ee7477c19dcf6f4fb1eec045 diff --git a/src/main/java/generator/SeniorQuestionGenerator.java b/src/main/java/generator/SeniorQuestionGenerator.java new file mode 100644 index 0000000..9963ecb --- /dev/null +++ b/src/main/java/generator/SeniorQuestionGenerator.java @@ -0,0 +1,234 @@ +<<<<<<< HEAD +package generator; + +import entity.Question; +import factory.QuestionGenerator; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +/** + 高中题目生成器(包含三角函数) + 生成高中难度的数学题目,确保每个题目至少包含一个三角函数 + 操作数范围:1-100 + 操作数数量:1-5个 + */ +public class SeniorQuestionGenerator implements QuestionGenerator { + private static final String[] BINARY_OPERATORS = {"+", "-", "*", "/"}; + private static final String[] TRIGONOMETRIC_FUNCTIONS = {"sin", "cos", "tan"}; + private final Random random = new Random(); + + /** + 生成指定数量的高中题目 + @param count 题目数量 + @return 题目列表 + */ + @Override + public List
generateQuestions(int count) { + List questions = new ArrayList<>(); + for (int i = 1; i <= count; i++) { + questions.add(generateQuestion()); + } + return questions; + } + + /** + 生成单个高中题目 + 确保题目中至少包含一个三角函数 + 操作数数量在1-5之间 + 操作数范围在1-100之间 + @return 单个题目 + */ + @Override + public Question generateQuestion() { + // 生成1-5个操作数 + int operandCount = random.nextInt(5) + 1; + + // 确保至少有一个三角函数 + int trigFunctionCount = random.nextInt(operandCount) + 1; + + // 构建表达式 + StringBuilder expression = new StringBuilder(); + + // 生成第一个操作数或三角函数 + if (random.nextBoolean() && trigFunctionCount > 0) { + expression.append(generateTrigonometricFunction()); + trigFunctionCount--; + } else { + expression.append(generateOperand()); + } + + // 生成后续操作数和运算符 + for (int i = 1; i < operandCount; i++) { + // 添加运算符 + expression.append(" ").append(generateBinaryOperator()).append(" "); + + // 决定下一个是普通操作数还是三角函数 + if (random.nextBoolean() && trigFunctionCount > 0) { + expression.append(generateTrigonometricFunction()); + trigFunctionCount--; + } else { + expression.append(generateOperand()); + } + } + + // 如果还没有包含三角函数,强制添加一个 + if (!expression.toString().contains("sin") && + !expression.toString().contains("cos") && + !expression.toString().contains("tan")) { + // 在表达式的随机位置插入一个三角函数 + expression = insertTrigonometricFunction(expression.toString()); + } + + // 随机添加括号以增加复杂度 + if (operandCount > 2 && random.nextBoolean()) { + expression = addParentheses(expression.toString()); + } + + return new Question(0, expression.toString()); + } + + /** + 获取生成器类型 + @return "高中" + */ + @Override + public String getType() { + return "高中"; + } + + /** + 生成操作数(1-100) + @return 随机操作数 + */ + private int generateOperand() { + return random.nextInt(100) + 1; + } + + /** + 生成二元运算符 + @return 运算符字符串 + */ + private String generateBinaryOperator() { + return BINARY_OPERATORS[random.nextInt(BINARY_OPERATORS.length)]; + } + + /** + 生成三角函数表达式 + @return 三角函数表达式字符串 + */ + private String generateTrigonometricFunction() { + String function = TRIGONOMETRIC_FUNCTIONS[random.nextInt(TRIGONOMETRIC_FUNCTIONS.length)]; + int angle = generateAngle(); // 生成合适的角度值 + + // 随机决定是否使用度数符号 + if (random.nextBoolean()) { + return function + "(" + angle + "°)"; + } else { + return function + "(" + angle + ")"; + } + } + + /** + 生成适合三角函数的角度值 + 返回常见角度值,使三角函数值更合理 + @return 角度值 + */ + private int generateAngle() { + // 常见角度值,使三角函数值更合理 + int[] commonAngles = {0, 30, 45, 60, 90, 120, 135, 150, 180, 210, 225, 240, 270, 300, 315, 330, 360}; + + // 80%的概率使用常见角度,20%的概率使用随机角度 + if (random.nextDouble() < 0.8) { + return commonAngles[random.nextInt(commonAngles.length)]; + } else { + return random.nextInt(360) + 1; // 1-360度 + } + } + + /** + 在表达式中插入三角函数 + 确保表达式至少包含一个三角函数 + @param expression 原始表达式 + @return 包含三角函数的表达式 + */ + private StringBuilder insertTrigonometricFunction(String expression) { + String[] parts = expression.split(" "); + StringBuilder newExpression = new StringBuilder(); + + // 随机选择一个位置插入三角函数 + int insertPosition = random.nextInt(parts.length); + + for (int i = 0; i < parts.length; i++) { + if (i == insertPosition) { + // 在选定位置插入三角函数 + if (i % 2 == 0) { // 偶数位置是操作数 + // 替换操作数为三角函数 + newExpression.append(generateTrigonometricFunction()); + } else { // 奇数位置是运算符 + // 在运算符后添加三角函数 + newExpression.append(parts[i]).append(" ").append(generateTrigonometricFunction()); + // 跳过下一个操作数 + if (i + 1 < parts.length) { + i++; + } + } + } else { + newExpression.append(parts[i]); + } + + if (i < parts.length - 1) { + newExpression.append(" "); + } + } + + return newExpression; + } + + /** + 为表达式添加括号 + @param expression 原始表达式 + @return 添加括号后的表达式 + */ + private StringBuilder addParentheses(String expression) { + // 简化的括号添加逻辑:为部分表达式添加括号 + String[] parts = expression.split(" "); + + if (parts.length <= 2) { + return new StringBuilder(expression); + } + + // 随机选择括号的起始和结束位置 + int start = random.nextInt(parts.length / 2) * 2; // 确保从操作数开始 + int end = start + 2 + random.nextInt((parts.length - start) / 2) * 2; // 确保以操作数结束 + + if (end - start < 2 || end > parts.length) { + return new StringBuilder(expression); + } + + StringBuilder result = new StringBuilder(); + for (int i = 0; i < parts.length; i++) { + if (i == start) { + result.append("("); + } + + result.append(parts[i]); + + if (i == end - 1) { + result.append(")"); + } + + if (i < parts.length - 1) { + result.append(" "); + } + } + + return result; + } +} +======= +package main.java.generator; + +public class SeniorQuestionGenerator { +} +>>>>>>> 93d8b771666e4fb2ee7477c19dcf6f4fb1eec045 diff --git a/src/main/java/org/example/Main.java b/src/main/java/org/example/Main.java new file mode 100644 index 0000000..74ba0f2 --- /dev/null +++ b/src/main/java/org/example/Main.java @@ -0,0 +1,184 @@ +package org.example; + +import entity.User; +import entity.Question; +import service.UserService; +import service.QuestionService; +import service.FileService; +import service.ValidationService; +import java.util.List; +import java.util.Scanner; + +/** + * 主程序类 - 应用程序的入口点 + * 负责协调各个组件,处理用户交互 + * 实现主要的业务流程控制 + */ +public class Main { + // 依赖注入的服务组件 + private final UserService userService; + private final QuestionService questionService; + private final FileService fileService; + private final ValidationService validationService; + private final Scanner scanner; + + // 当前会话状态 + private User currentUser; // 当前登录用户 + private String currentType; // 当前题目类型 + + /** + * 构造函数 - 初始化所有服务组件 + */ + public Main() { + this.userService = new UserService(); + this.validationService = new ValidationService(); + this.questionService = new QuestionService(validationService); + this.fileService = new FileService(); + this.scanner = new Scanner(System.in); + } + + /** + * 应用程序主入口 + * @param args 命令行参数 + */ + public static void main(String[] args) { + Main app = new Main(); + app.run(); + } + + /** + * 主运行循环 + * 控制整个应用程序的生命周期 + */ + public void run() { + System.out.println("=== 中小学数学卷子自动生成程序 ==="); + + while (true) { + // 登录阶段 + if (!login()) { + continue; // 登录失败,重新尝试 + } + + // 题目生成阶段 + generateQuestionsLoop(); + } + } + + /** + * 用户登录处理 + * @return 登录成功返回true,失败返回false + */ + private boolean login() { + System.out.print("请输入用户名和密码(用空格隔开): "); + String input = scanner.nextLine().trim(); + + // 输入验证 + if (input.isEmpty()) { + System.out.println("请输入正确的用户名、密码"); + return false; + } + + String[] credentials = input.split(" "); + if (credentials.length != 2) { + System.out.println("请输入正确的用户名、密码"); + return false; + } + + String username = credentials[0]; + String password = credentials[1]; + + // 用户认证 + User user = userService.authenticate(username, password); + if (user == null) { + System.out.println("请输入正确的用户名、密码"); + return false; + } + + // 登录成功,设置当前状态 + currentUser = user; + currentType = user.getType(); + System.out.println("当前选择为" + currentType + "出题"); + return true; + } + + /** + * 题目生成循环 + * 处理登录后的各种用户操作 + */ + private void generateQuestionsLoop() { + while (currentUser != null) { + System.out.print("准备生成" + currentType + "数学题目,请输入生成题目数量(输入-1将退出当前用户,重新登录): "); + String input = scanner.nextLine().trim(); + + // 检查是否是切换命令 + if (validationService.isValidSwitchCommand(input)) { + handleSwitchCommand(input); + continue; + } + + // 处理数字输入 + try { + int count = Integer.parseInt(input); + + if (count == -1) { + // 退出当前用户 + currentUser = null; + System.out.println("退出当前用户,重新登录..."); + break; + } + + // 验证题目数量 + if (!questionService.validateQuestionCount(count)) { + System.out.println("题目数量应在10-30之间"); + continue; + } + + // 生成并保存题目 + generateAndSaveQuestions(count); + + } catch (NumberFormatException e) { + System.out.println("请输入小学、初中和高中三个选项中的一个或有效的数字"); + } + } + } + + /** + * 处理类型切换命令 + * @param command 切换命令字符串 + */ + private void handleSwitchCommand(String command) { + String newType = validationService.extractTypeFromCommand(command); + if (newType.equals("小学") || newType.equals("初中") || newType.equals("高中")) { + currentType = newType; + System.out.println("准备生成" + currentType + "数学题目,请输入生成题目数量"); + } else { + System.out.println("请输入小学、初中和高中三个选项中的一个"); + } + } + + /** + * 生成并保存题目 + * @param count 题目数量 + */ + private void generateAndSaveQuestions(int count) { + try { + // 生成题目 + List questions = questionService.generateQuestions(currentType, count); + + // 查重检查 + if (fileService.checkDuplicate(currentUser.getUsername(), questions)) { + System.out.println("检测到重复题目,重新生成中..."); + generateAndSaveQuestions(count); // 递归重新生成 + return; + } + + // 保存到文件 + String filePath = fileService.saveQuestions(currentUser.getUsername(), questions); + System.out.println("题目已生成并保存到: " + filePath); + + } catch (Exception e) { + System.out.println("生成题目时出现错误: " + e.getMessage()); + e.printStackTrace(); // 调试用,实际应该记录日志 + } + } +} \ No newline at end of file diff --git a/src/main/java/service/FileService.java b/src/main/java/service/FileService.java new file mode 100644 index 0000000..ca71eee --- /dev/null +++ b/src/main/java/service/FileService.java @@ -0,0 +1,74 @@ +<<<<<<< HEAD +package service; + +import entity.Question; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; + +/** + 文件服务类 + 负责题目的文件存储和查重功能 + 每个用户有独立的文件夹存储生成的题目文件 + */ +public class FileService { + private static final String BASE_DIR = "doc"; // 基础存储目录 + + /** + 保存题目到文件 + @param username 用户名(用于创建用户文件夹) + @param questions 题目列表 + @return 保存的文件路径 + @throws IOException 文件操作异常 + */ + public String saveQuestions(String username, List questions) throws IOException { + // 创建用户专属文件夹 + File userDir = new File(BASE_DIR, username); + if (!userDir.exists()) { + userDir.mkdirs(); // 递归创建目录 + } + + // 生成基于时间戳的文件名 + String filename = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date()) + ".txt"; + File file = new File(userDir, filename); + + // 使用try-with-resources确保文件正确关闭 + try (FileWriter writer = new FileWriter(file)) { + for (Question question : questions) { + writer.write(question.toString()); // 写入题目 + writer.write("\n\n"); // 题目之间空一行 + } + } + + return file.getAbsolutePath(); + } + + /** + 检查题目是否重复(简化版实现) + 实际应该读取用户所有历史文件进行比较 + @param username 用户名 + @param newQuestions 新生成的题目 + @return 是否发现重复题目 + */ + public boolean checkDuplicate(String username, List newQuestions) { + File userDir = new File(BASE_DIR, username); + if (!userDir.exists()) { + return false; // 用户没有历史文件,肯定不重复 + } + + // 简化的查重实现 + // 实际应该:1.读取用户所有历史文件 2.解析历史题目 3.比较新题目与历史题目 + // 这里为了简化直接返回false,表示没有重复 + + // TODO: 实现完整的查重逻辑 + return false; + } +======= +package main.java.service; + +public class FileService { +>>>>>>> 93d8b771666e4fb2ee7477c19dcf6f4fb1eec045 +} diff --git a/src/main/java/service/QuestionService.java b/src/main/java/service/QuestionService.java new file mode 100644 index 0000000..ea1a74f --- /dev/null +++ b/src/main/java/service/QuestionService.java @@ -0,0 +1,59 @@ +<<<<<<< HEAD +package service; + +import entity.Question; +import factory.QuestionGenerator; +import factory.QuestionFactory; +import java.util.List; + +/** + 题目服务类 + 负责题目的生成和管理 + 协调题目生成器和验证服务的工作 + */ +public class QuestionService { + private final ValidationService validationService; + + /** + 构造函数 + @param validationService 验证服务实例 + */ + public QuestionService(ValidationService validationService) { + this.validationService = validationService; + } + + /** + 生成指定类型和数量的题目 + @param type 题目类型(小学/初中/高中) + @param count 题目数量 + @return 题目列表,包含正确题号的题目 + */ + public List generateQuestions(String type, int count) { + // 使用工厂创建对应的题目生成器 + QuestionGenerator generator = QuestionFactory.createGenerator(type); + // 生成题目 + List questions = generator.generateQuestions(count); + + // 为每个题目设置正确的题号 + for (int i = 0; i < questions.size(); i++) { + Question question = questions.get(i); + questions.set(i, new Question(i + 1, question.getContent())); + } + + return questions; + } + + /** + 验证题目数量是否有效 + @param count 题目数量 + @return 是否有效(10-30或-1) + */ + public boolean validateQuestionCount(int count) { + return validationService.isValidQuestionCount(count); + } +======= +package main.java.service; + +public class QuestionService { +>>>>>>> 93d8b771666e4fb2ee7477c19dcf6f4fb1eec045 +} diff --git a/src/main/java/service/UserService.java b/src/main/java/service/UserService.java new file mode 100644 index 0000000..8a600f6 --- /dev/null +++ b/src/main/java/service/UserService.java @@ -0,0 +1,64 @@ +<<<<<<< HEAD +package service; + +import entity.User; +import java.util.HashMap; +import java.util.Map; + +/** + 用户服务类 + 负责用户认证和用户数据管理 + 使用内存存储用户信息(实际项目中应该使用数据库) + */ +public class UserService { + private final Map users = new HashMap<>(); // 用户名到用户的映射 + + /** + 构造函数,初始化预定义的用户数据 + */ + public UserService() { + initializeUsers(); + } + + /** + 初始化预定义的用户账户 + 包括小学、初中、高中各三个账户 + */ + private void initializeUsers() { + // 小学账户 + users.put("张三1", new User("张三1", "123", "小学")); + users.put("张三2", new User("张三2", "123", "小学")); + users.put("张三3", new User("张三3", "123", "小学")); + + // 初中账户 + users.put("李四1", new User("李四1", "123", "初中")); + users.put("李四2", new User("李四2", "123", "初中")); + users.put("李四3", new User("李四3", "123", "初中")); + + // 高中账户 + users.put("王五1", new User("王五1", "123", "高中")); + users.put("王五2", new User("王五2", "123", "高中")); + users.put("王五3", new User("王五3", "123", "高中")); + } + + /** + 用户认证方法 + @param username 用户名 + @param password 密码 + @return 认证成功的用户对象,失败返回null + */ + public User authenticate(String username, String password) { + User user = users.get(username); + // 检查用户是否存在且密码匹配 + if (user != null && user.getPassword().equals(password)) { + return user; + } + return null; + } +} +======= +package main.java.service; + +public class UserService { +} +>>>>>>> 93d8b771666e4fb2ee7477c19dcf6f4fb1eec045 diff --git a/src/main/java/service/ValidationService.java b/src/main/java/service/ValidationService.java new file mode 100644 index 0000000..a7c0a81 --- /dev/null +++ b/src/main/java/service/ValidationService.java @@ -0,0 +1,42 @@ +<<<<<<< HEAD +package service; + +/** + 验证服务类 + 集中处理各种输入验证逻辑 + 保持验证规则的统一性 + */ +public class ValidationService { + + /** + 验证题目数量是否有效 + @param count 题目数量 + @return 有效返回true(10-30或-1) + */ + public boolean isValidQuestionCount(int count) { + return count == -1 || (count >= 10 && count <= 30); + } + + /** + 验证切换命令格式是否正确 + @param command 用户输入的命令 + @return 格式正确返回true + */ + public boolean isValidSwitchCommand(String command) { + return command.matches("切换为(小学|初中|高中)"); + } + + /** + 从切换命令中提取类型 + @param command 切换命令 + @return 提取的类型(小学/初中/高中) + */ + public String extractTypeFromCommand(String command) { + return command.replace("切换为", ""); + } +======= +package main.java.service; + +public class ValidationService { +>>>>>>> 93d8b771666e4fb2ee7477c19dcf6f4fb1eec045 +} diff --git a/src/main/resources/META-INF/MANIFEST.MF b/src/main/resources/META-INF/MANIFEST.MF new file mode 100644 index 0000000..53851ab --- /dev/null +++ b/src/main/resources/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Main-Class: org.example.Main + -- 2.34.1 From 2bb6e9a0a93b596f4cb66d510f45f947489d7392 Mon Sep 17 00:00:00 2001 From: ymst <2605946526@qq.com> Date: Mon, 29 Sep 2025 00:02:39 +0800 Subject: [PATCH 7/8] =?UTF-8?q?=E5=88=A0=E9=99=A4=E5=A4=9A=E4=BD=99?= =?UTF-8?q?=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/Main.java | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 src/main/java/Main.java diff --git a/src/main/java/Main.java b/src/main/java/Main.java deleted file mode 100644 index fe7aa2b..0000000 --- a/src/main/java/Main.java +++ /dev/null @@ -1,15 +0,0 @@ -//TIP 要运行代码,请按 或 -// 点击装订区域中的 图标。 -public class Main { - public static void main(String[] args) { - //TIP 当文本光标位于高亮显示的文本处时按 - // 查看 IntelliJ IDEA 建议如何修正。 - System.out.printf("Hello and welcome!"); - - for (int i = 1; i <= 5; i++) { - //TIP 按 开始调试代码。我们已经设置了一个 断点 - // 但您始终可以通过按 添加更多断点。 - System.out.println("i = " + i); - } - } -} \ No newline at end of file -- 2.34.1 From 553c9d00d3019a75673e67c0e6cb7ee53257be03 Mon Sep 17 00:00:00 2001 From: ymst <2605946526@qq.com> Date: Mon, 29 Sep 2025 00:09:24 +0800 Subject: [PATCH 8/8] =?UTF-8?q?Markdown=E6=96=87=E4=BB=B6=E6=8F=90?= =?UTF-8?q?=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 298 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 298 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..8f275d0 --- /dev/null +++ b/README.md @@ -0,0 +1,298 @@ +中小学数学卷子自动生成程序 + +项目概述 + +中小学数学卷子自动生成程序是一个基于 Java 开发的命令行应用程序,旨在帮助小学、初中和高中数学老师快速生成符合教学要求的数学题目。程序支持不同难度级别的题目生成、用户认证、题目查重和文件保存等功能。 + + + +核心功能 + +🔐 用户认证系统 + +预设账户:系统内置小学、初中、高中各三个教师账户 + + + +登录验证:通过用户名和密码进行身份验证 + + + +权限分级:根据账户类型自动确定题目难度级别 + + + +📚 题目生成引擎 + +小学题目 + +运算符:加(+)、减(-)、乘(\*)、除(/) + + + +特殊要求:可能包含括号 + + + +操作数:2-5个操作数,取值范围1-100 + + + +初中题目 + +运算符:包含平方(²)、开根号(√)等高级运算符 + + + +特殊要求:至少包含一个平方或开根号运算符,且必须通过四则运算连接其他操作数 + + + +操作数:3-5个操作数,取值范围1-100 + + + +高中题目 + +运算符:包含三角函数(sin、cos、tan) + + + +特殊要求:至少包含一个三角函数和一个平方/开根号运算符 + + + +操作数:2-5个操作数,取值范围1-100 + + + +🔄 交互功能 + +难度切换:登录后可通过命令切换题目难度 + + + +题目数量控制:支持生成10-30道题目 + + + +重复检测:避免生成与历史题目重复的内容 + + + +灵活退出:支持退出当前用户重新登录 + + + +💾 文件管理 + +按用户分文件夹:每个用户的题目单独存放 + + + +时间戳命名:文件格式为"年-月-日-时-分-秒.txt" + + + +规范格式:每道题目有序号,题目间空一行 + + + +技术架构 + +项目结构 + +text + +MathGenerator/ + +└── src/ + + └── test/ + + └── java/ + + ├── main/ + + │ └── Main.java # 主程序入口 + + ├── entity/ + + │ ├── User.java # 用户实体类 + + │ └── Question.java # 题目实体类 + + ├── service/ + + │ ├── UserService.java # 用户认证服务 + + │ ├── QuestionService.java # 题目生成服务 + + │ ├── FileService.java # 文件操作服务 + + │ └── ValidationService.java # 输入验证服务 + + ├── factory/ + + │ ├── QuestionFactory.java # 题目生成器工厂 + + │ └── QuestionGenerator.java # 题目生成器接口 + + └── generator/ + + ├── PrimaryQuestionGenerator.java # 小学题目生成器 + + ├── JuniorQuestionGenerator.java # 初中题目生成器 + + └── SeniorQuestionGenerator.java # 高中题目生成器 + +设计模式 + +工厂模式:通过 QuestionFactory 创建不同难度的题目生成器 + + + +策略模式:QuestionGenerator 接口支持多难度题目生成策略 + + + +分层架构:清晰的 entity-service-factory 分层结构 + + + +使用指南 + +启动程序 + +bash + +mvn clean package + +java -jar target/math-test-generator.jar + +操作流程 + +登录系统 + + + +text + +请输入用户名和密码(用空格隔开): 张三1 123 + +当前选择为小学出题 + +生成题目 + + + +text + +准备生成小学数学题目,请输入生成题目数量(输入-1将退出当前用户,重新登录): 15 + +题目已生成并保存到: exams/张三1/2025-01-20-14-30-25.txt + +切换难度 + + + +text + +切换为初中 + +准备生成初中数学题目,请输入生成题目数量 + +退出登录 + + + +text + +输入-1将退出当前用户,重新登录 + +预设账户 + +类型 用户名 密码 + +小学 张三1, 张三2, 张三3 123 + +初中 李四1, 李四2, 李四3 123 + +高中 王五1, 王五2, 王五3 123 + +代码规范 + +项目严格遵循 Google Java 编码规范: + + + +使用 2 空格缩进 + + + +完整的 Javadoc 注释 + + + +清晰的包和类结构 + + + +方法长度控制在 40 行以内 + + + +有意义的命名约定 + + + +输出示例 + +生成的题目文件格式: + + + +text + +1\. 25 + 47 - 13 + + + +2\. (18 \* 3) / 6 + 29 + + + +3\. 45 - 17 + 32 \* 2 + + + +... + +扩展性 + +程序具有良好的扩展性,可以轻松: + + + +添加新的题目难度级别 + + + +支持更多的数学运算符 + + + +集成数据库存储 + + + +添加图形用户界面 + + + +支持自定义题目模板 + + + +该项目专为中小学数学教育设计,帮助教师提高出题效率,确保题目质量一致性。 + -- 2.34.1