@ -0,0 +1,3 @@
|
||||
Manifest-Version: 1.0
|
||||
Main-Class: src.Main
|
||||
Class-Path: .
|
||||
@ -0,0 +1,19 @@
|
||||
@echo off
|
||||
REM Math Question Generator System - Windows Batch File
|
||||
REM Author: 赵俊杰
|
||||
REM Created: 2025
|
||||
|
||||
@echo off
|
||||
|
||||
REM Set console encoding to GBK to match scanner input
|
||||
REM GBK code page is 936, which supports Chinese characters
|
||||
chcp 936 >nul
|
||||
|
||||
echo Starting Math Question Generator System...
|
||||
echo.
|
||||
|
||||
REM Execute Java program
|
||||
java -jar MathQuestionGenerator.jar
|
||||
|
||||
REM Pause after program execution to prevent window from closing immediately
|
||||
pause
|
||||
Binary file not shown.
Binary file not shown.
@ -0,0 +1,77 @@
|
||||
package src;
|
||||
|
||||
public class JuniorTea extends Teacher{
|
||||
final static String[] binaryOps = {"+", "-", "*", "/"}; // 操作符
|
||||
final static String[] unaryOps = {"^2", "√"};
|
||||
int operandCount;
|
||||
String[] questionParts; // 操作数
|
||||
boolean[] specialOpFlags; // 特殊操作符索引序列
|
||||
int parenStart;
|
||||
int parenEnd;
|
||||
|
||||
public JuniorTea(String name, String password, String path) {
|
||||
super(name, password, path);
|
||||
}
|
||||
|
||||
// 数据预处理
|
||||
public void getRandom(){
|
||||
this.operandCount = random.nextInt(4) + 2;
|
||||
this.questionParts = new String[this.operandCount];
|
||||
// 随机决定特殊操作符的数量和位置
|
||||
int specialNum = Math.min(this.operandCount, random.nextInt(this.operandCount) + 1);
|
||||
this.specialOpFlags = new boolean[this.operandCount];
|
||||
for (int i = 0; i < specialNum; i++) {
|
||||
int pos;
|
||||
do {
|
||||
pos = random.nextInt(this.operandCount);
|
||||
} while (this.specialOpFlags[pos]);
|
||||
this.specialOpFlags[pos] = true;
|
||||
}
|
||||
for (int i = 0; i < this.operandCount; i++) {
|
||||
int operand = random.nextInt(100) + 1;
|
||||
if (this.specialOpFlags[i]) {
|
||||
String op = unaryOps[random.nextInt(unaryOps.length)];
|
||||
if (op.equals("√")) {
|
||||
this.questionParts[i] = op + operand;
|
||||
} else {
|
||||
this.questionParts[i] = operand + op;
|
||||
}
|
||||
} else {
|
||||
this.questionParts[i] = String.valueOf(operand);
|
||||
}
|
||||
}
|
||||
// 生成有效括号
|
||||
boolean useParen = this.operandCount > 2 && random.nextBoolean();
|
||||
this.parenStart = 0;
|
||||
this.parenEnd = this.operandCount - 1;
|
||||
while (this.parenStart == 0 && this.parenEnd == this.operandCount - 1) {
|
||||
this.parenStart = useParen ? random.nextInt(this.operandCount - 1) : -2;
|
||||
this.parenEnd = useParen ? random.nextInt(this.operandCount - 1 - this.parenStart) + this.parenStart + 1 : -2;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String generateSingleQuestion(){
|
||||
getRandom();
|
||||
StringBuilder question = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < operandCount; i++) {
|
||||
if (i == parenStart) {
|
||||
question.append("(");
|
||||
}
|
||||
question.append(questionParts[i]);
|
||||
if (i == parenEnd) {
|
||||
question.append(")");
|
||||
}
|
||||
if (i < operandCount - 1) {
|
||||
question.append(" ").append(binaryOps[random.nextInt(binaryOps.length)]).append(" ");
|
||||
}
|
||||
}
|
||||
return question.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType(){
|
||||
return "初中";
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@ -0,0 +1,34 @@
|
||||
package src;
|
||||
|
||||
import java.util.Scanner;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class Main {
|
||||
public static void main(String[] args) {
|
||||
// 用户预加载
|
||||
SysFunc.init();
|
||||
Scanner scanner = new Scanner(System.in, "GBK");
|
||||
while(true){
|
||||
// 登录界面
|
||||
SysFunc.login(scanner);
|
||||
// 出题界面
|
||||
SysFunc.Operate(scanner);
|
||||
// 退出选项
|
||||
System.out.println("是否返回登陆(y/n)?");
|
||||
String choice = scanner.nextLine();
|
||||
if (choice.charAt(0) == 'y') {
|
||||
continue;
|
||||
} else if (choice.charAt(0) == 'n') {
|
||||
System.out.println("感谢您的使用");
|
||||
break;
|
||||
} else {
|
||||
System.out.println("无效输入, 正在返回登陆界面");
|
||||
try {
|
||||
TimeUnit.SECONDS.sleep(1);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@ -0,0 +1,61 @@
|
||||
package src;
|
||||
|
||||
public class PrimaryTea extends Teacher{
|
||||
final static char[] operators = {'+', '-', '*', '/'}; // 操作符
|
||||
int operandCount; // 操作数个数
|
||||
int[] operands; // 操作数列表
|
||||
int parenStart; // 左括号索引
|
||||
int parenEnd; // 右括号
|
||||
|
||||
public PrimaryTea(String name, String password, String path) {
|
||||
super(name, password, path);
|
||||
}
|
||||
|
||||
// 数据预处理
|
||||
public void getRandom(){
|
||||
// 随机决定操作数个数
|
||||
this.operandCount = random.nextInt(4) + 2;
|
||||
this.operands = new int[operandCount];
|
||||
for (int j = 0; j < operandCount; j++) {
|
||||
operands[j] = random.nextInt(100) + 1;
|
||||
}
|
||||
// 产生有效括号
|
||||
boolean useParen = this.operandCount > 2 && random.nextBoolean();
|
||||
this.parenStart = 0;
|
||||
this.parenEnd = this.operandCount - 1;
|
||||
while (this.parenStart == 0 && this.parenEnd == this.operandCount - 1) {
|
||||
this.parenStart = useParen ? random.nextInt(this.operandCount - 1) : -2;
|
||||
this.parenEnd = useParen ? random.nextInt(this.operandCount - 1 - this.parenStart) + this.parenStart + 1 : -2;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String generateSingleQuestion() {
|
||||
getRandom();
|
||||
StringBuilder question = new StringBuilder();
|
||||
|
||||
for (int j = 0; j < this.operandCount; j++) {
|
||||
if (j == this.parenStart) {
|
||||
question.append("(");
|
||||
}
|
||||
question.append(operands[j]);
|
||||
if (j == this.parenEnd) {
|
||||
question.append(")");
|
||||
}
|
||||
|
||||
if (j < this.operandCount - 1) {
|
||||
char op = operators[random.nextInt(operators.length)];
|
||||
if (op == '/') {
|
||||
this.operands[j+1] = this.operands[j+1] == 0 ? 1 : this.operands[j+1];
|
||||
}
|
||||
question.append(" ").append(op).append(" ");
|
||||
}
|
||||
}
|
||||
return question.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType(){
|
||||
return "小学";
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@ -0,0 +1,75 @@
|
||||
package src;
|
||||
|
||||
public class SeniorTea extends Teacher{
|
||||
final static String[] binaryOps = {"+", "-", "*", "/"}; // 操作符
|
||||
final static String[] trigOps = {"sin", "cos", "tan"};
|
||||
int operandCount;
|
||||
String[] questionParts; // 操作数
|
||||
boolean[] specialOpFlags; // 特殊操作符索引序列
|
||||
int parenStart;
|
||||
int parenEnd;
|
||||
|
||||
public SeniorTea(String name, String password, String path) {
|
||||
super(name, password, path);
|
||||
}
|
||||
|
||||
// 数据预处理
|
||||
public void getRandom(){
|
||||
this.operandCount = random.nextInt(4) + 2;
|
||||
this.questionParts = new String[this.operandCount];
|
||||
// 随机决定特殊操作符的数量和位置
|
||||
int specialNum = Math.min(this.operandCount, random.nextInt(this.operandCount) + 1);
|
||||
this.specialOpFlags = new boolean[this.operandCount];
|
||||
for (int i = 0; i < specialNum; i++) {
|
||||
int pos;
|
||||
do {
|
||||
pos = random.nextInt(this.operandCount);
|
||||
} while (this.specialOpFlags[pos]);
|
||||
this.specialOpFlags[pos] = true;
|
||||
}
|
||||
for (int i = 0; i < operandCount; i++) {
|
||||
int operand = random.nextInt(100) + 1;
|
||||
if (specialOpFlags[i]) {
|
||||
String op = trigOps[random.nextInt(trigOps.length)];
|
||||
questionParts[i] = op + "(" + operand + ")";
|
||||
} else {
|
||||
questionParts[i] = String.valueOf(operand);
|
||||
}
|
||||
}
|
||||
// 生成有效括号
|
||||
boolean useParen = this.operandCount > 2 && random.nextBoolean();
|
||||
this.parenStart = 0;
|
||||
this.parenEnd = this.operandCount - 1;
|
||||
while (this.parenStart == 0 && this.parenEnd == this.operandCount - 1) {
|
||||
this.parenStart = useParen ? random.nextInt(this.operandCount - 1) : -2;
|
||||
this.parenEnd = useParen ? random.nextInt(this.operandCount - 1 - this.parenStart) + this.parenStart + 1 : -2;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String generateSingleQuestion(){
|
||||
getRandom();
|
||||
StringBuilder question = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < operandCount; i++) {
|
||||
if (i == parenStart) {
|
||||
question.append("(");
|
||||
}
|
||||
question.append(questionParts[i]);
|
||||
if (i == parenEnd) {
|
||||
question.append(")");
|
||||
}
|
||||
|
||||
if (i < operandCount - 1) {
|
||||
String op = binaryOps[random.nextInt(binaryOps.length)];
|
||||
question.append(" ").append(op).append(" ");
|
||||
}
|
||||
}
|
||||
return question.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType(){
|
||||
return "高中";
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@ -0,0 +1,155 @@
|
||||
package src;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Scanner;
|
||||
|
||||
public class SysFunc {
|
||||
// 题目数量
|
||||
static final int LEAST_NUM = 10;
|
||||
static final int MAX_NUM = 30;
|
||||
// 用户列表
|
||||
static ArrayList<Teacher> teachers;
|
||||
// 当前用户
|
||||
static Teacher teacher;
|
||||
|
||||
static HashMap<String, Integer> typeMap;
|
||||
|
||||
// ANSI颜色代码
|
||||
static final String RESET = "\u001B[0m";
|
||||
static final String RED = "\u001B[31m";
|
||||
static final String GREEN = "\u001B[32m";
|
||||
static final String YELLOW = "\u001B[33m";
|
||||
static final String BLUE = "\u001B[34m";
|
||||
static final String PURPLE = "\u001B[35m";
|
||||
static final String CYAN = "\u001B[36m";
|
||||
static final String BOLD = "\u001B[1m";
|
||||
|
||||
public static void init(){
|
||||
// 用户预加载
|
||||
teachers = new ArrayList<>();
|
||||
teachers.add(new PrimaryTea("张三1", "123", null));
|
||||
teachers.add(new PrimaryTea("张三2", "123", null));
|
||||
teachers.add(new PrimaryTea("张三3", "123", null));
|
||||
teachers.add(new JuniorTea("李四1", "123", null));
|
||||
teachers.add(new JuniorTea("李四2", "123", null));
|
||||
teachers.add(new JuniorTea("李四3", "123", null));
|
||||
teachers.add(new SeniorTea("王五1", "123", null));
|
||||
teachers.add(new SeniorTea("王五2", "123", null));
|
||||
teachers.add(new SeniorTea("王五3", "123", null));
|
||||
typeMap = new HashMap<>();
|
||||
typeMap.put("小学", 1);
|
||||
typeMap.put("初中", 2);
|
||||
typeMap.put("高中", 3);
|
||||
}
|
||||
|
||||
// 登陆界面
|
||||
public static Teacher login(Scanner scanner) {
|
||||
boolean flag = false;
|
||||
System.out.println(BOLD + CYAN + "=== 数学题目生成系统 ===" + RESET);
|
||||
System.out.println(BOLD + CYAN + "请登录您的账户" + RESET);
|
||||
while (!flag) {
|
||||
System.out.println(BOLD + YELLOW + "请输入: 用户名 密码" + RESET);
|
||||
System.out.print(BOLD + BLUE + "> " + RESET);
|
||||
|
||||
String cur = scanner.nextLine();
|
||||
if (cur.indexOf(" ") == -1) {
|
||||
System.out.println(RED + "请输入用户名和密码,中间用空格隔开");
|
||||
continue;
|
||||
}
|
||||
String cur_name = cur.substring(0, cur.indexOf(" "));
|
||||
String cur_password = cur.substring(cur.indexOf(" ") + 1);
|
||||
|
||||
// 匹配已有帐户
|
||||
for (Teacher t : teachers) {
|
||||
if (t.name.equals(cur_name) && t.password.equals(cur_password)) {
|
||||
teacher = t;
|
||||
flag = true;
|
||||
System.out.println(GREEN + "当前选择为" + teacher.getType() + "出题");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!flag) {
|
||||
System.out.println(RED + "请输入正确的用户名、密码");
|
||||
}
|
||||
}
|
||||
return teacher;
|
||||
}
|
||||
|
||||
// 切换类型界面
|
||||
public static void ShiftType(Scanner scanner) {
|
||||
int type = SysFunc.typeMap.get(SysFunc.teacher.getType());
|
||||
System.out.println(BOLD + PURPLE + "=== 是否切换出题类型(y/n) ===" + RESET);
|
||||
System.out.print(BOLD + BLUE + "> " + RESET);
|
||||
|
||||
String choice = scanner.nextLine();
|
||||
if (choice.equals("y")) {
|
||||
System.out.println(BOLD + YELLOW + "请输入指令: 切换** (支持小学,初中,高中难度): " + RESET);
|
||||
while (true) {
|
||||
System.out.print(BOLD + BLUE + "> " + RESET);
|
||||
String choice_type = scanner.nextLine();
|
||||
if (choice_type.substring(0, 2).equals("切换") && typeMap.containsKey(choice_type.substring(2))) {
|
||||
type = typeMap.get(choice_type.substring(2));
|
||||
if (type == 1) {
|
||||
teacher = new PrimaryTea(teacher.name, teacher.password, teacher.path);
|
||||
} else if (type == 2) {
|
||||
teacher = new JuniorTea(teacher.name, teacher.password, teacher.path);
|
||||
} else {
|
||||
teacher = new SeniorTea(teacher.name, teacher.password, teacher.path);
|
||||
}
|
||||
System.out.println(GREEN + "准备生成" + teacher.getType() + "数学题目,请输入生成题目数量(输入-1将退出当前用户,重新登录):");
|
||||
break;
|
||||
} else {
|
||||
System.out.println(RED + RESET + "请输入小学、初中和高中三个选项中的一个");
|
||||
}
|
||||
}
|
||||
} else if (choice.equals("n")) {
|
||||
System.out.println(GREEN + "请继续输入题目数量:");
|
||||
} else {
|
||||
System.out.println(RED + RESET + "无效输入,已为您设置默认类型:" + teacher.getType());
|
||||
System.out.println(GREEN + "请输入题目数量:");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 出题界面
|
||||
public static void Operate(Scanner scanner){
|
||||
boolean logout = false;
|
||||
while (!logout) {
|
||||
SysFunc.ShiftType(scanner);
|
||||
int num = 0;
|
||||
while (true) {
|
||||
try {
|
||||
System.out.print(BOLD + BLUE + "> " + RESET);
|
||||
String input = scanner.nextLine();
|
||||
num = Integer.parseInt(input);
|
||||
break;
|
||||
} catch (NumberFormatException e) {
|
||||
System.out.println(RED + RESET + "请输入有效的数字(10-30之间的整数,或-1退出登录):");
|
||||
}
|
||||
}
|
||||
while (true) {
|
||||
if (num == -1) {
|
||||
System.out.println(BOLD + YELLOW + "已退出登录" + RESET);
|
||||
logout = true;
|
||||
break;
|
||||
}
|
||||
if (num >= LEAST_NUM && num <= MAX_NUM) {
|
||||
System.out.println(BOLD + GREEN + "正在生成题目..." + RESET);
|
||||
String filepath = teacher.generateEX(num);
|
||||
System.out.println(GREEN + RESET + "题目生成成功,已保存至" + filepath);
|
||||
System.out.println(BOLD + CYAN + "=== 操作完成 ===" + RESET);
|
||||
break;
|
||||
} else {
|
||||
System.out.println(RED + RESET + "题目数量应在10-30之间,请重新输入");
|
||||
try {
|
||||
System.out.print(BOLD + BLUE + "> " + RESET);
|
||||
num = Integer.parseInt(scanner.nextLine());
|
||||
} catch (NumberFormatException e) {
|
||||
System.out.println(RED + RESET + "请输入有效的数字:");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@ -0,0 +1,113 @@
|
||||
package src;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Random;
|
||||
|
||||
public abstract class Teacher {
|
||||
protected String name;
|
||||
protected String password;
|
||||
protected String path = null; // 教师文件夹路径
|
||||
public Random random = new Random(); // 共用Random
|
||||
|
||||
public Teacher(String name, String password, String path) {
|
||||
this.name = name;
|
||||
this.password = password;
|
||||
if (path != null) {
|
||||
this.path = path;
|
||||
return;
|
||||
}
|
||||
// 生成文件夹
|
||||
File folder = new File(name);
|
||||
try {
|
||||
if (!folder.exists()) {
|
||||
folder.mkdirs();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
this.path = folder.getAbsolutePath();
|
||||
}
|
||||
|
||||
// 查重
|
||||
public boolean checkDuplicate(String question){
|
||||
File folder = new File(this.path);
|
||||
File[] files = folder.listFiles();
|
||||
if (files == null) {
|
||||
return false;
|
||||
}
|
||||
for (File file : files) {
|
||||
if (!file.getName().endsWith(".txt")) {
|
||||
continue;
|
||||
}
|
||||
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
if (line.contains(")")) {
|
||||
try {
|
||||
String fileQuestion = line.substring(line.indexOf(")") + 2).trim();
|
||||
if (fileQuestion.equals(question)) {
|
||||
return true;
|
||||
}
|
||||
} catch (StringIndexOutOfBoundsException e) {
|
||||
// 继续处理下一行
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
System.err.println("读取文件时出错: " + file.getName());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 生成存储文档
|
||||
public String generatePath(){
|
||||
Date date = new Date();
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
|
||||
File file = new File(this.path, sdf.format(date) + ".txt");
|
||||
try {
|
||||
if (!file.exists()) {
|
||||
file.createNewFile();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return file.getAbsolutePath();
|
||||
}
|
||||
|
||||
// 生成并存储题目
|
||||
public String generateEX(int num) {
|
||||
Path filePath = Paths.get(generatePath());
|
||||
for (int i = 0; i < num; i++) {
|
||||
String question = generateSingleQuestion();
|
||||
if (checkDuplicate(question)) {
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
String qstr = "(" + (i + 1) + ") " + question + " =\n";
|
||||
try {
|
||||
Files.writeString(filePath, qstr + '\n', StandardOpenOption.APPEND);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return filePath.toString();
|
||||
}
|
||||
|
||||
// 生成单个题目
|
||||
protected abstract String generateSingleQuestion();
|
||||
|
||||
// 返回教师类型
|
||||
public abstract String getType();
|
||||
}
|
||||
Loading…
Reference in new issue