个人项目互评(中小学数学卷子自动生成程序)

发布时间 2023-09-20 19:45:45作者: 就乐意敲点代码

一、项目需求:

用户:

小学、初中和高中数学老师。

功能:

1、命令行输入用户名和密码,两者之间用空格隔开(程序预设小学、初中和高中各三个账号,具体见附表),如果用户名和密码都正确,将根据账户类型显示“当前选择为XX出题”,XX为小学、初中和高中三个选项中的一个。否则提示“请输入正确的用户名、密码”,重新输入用户名、密码;

2、登录后,系统提示“准备生成XX数学题目,请输入生成题目数量(输入-1将退出当前用户,重新登录):”,XX为小学、初中和高中三个选项中的一个,用户输入所需出的卷子的题目数量,系统默认将根据账号类型进行出题。每道题目的操作数在1-5个之间,操作数取值范围为1-100;

3、题目数量的有效输入范围是“10-30”(含10,30,或-1退出登录),程序根据输入的题目数量生成符合小学、初中和高中难度的题目的卷子(具体要求见附表)。同一个老师的卷子中的题目不能与以前的已生成的卷子中的题目重复(以指定文件夹下存在的文件为准,见5);

4、在登录状态下,如果用户需要切换类型选项,命令行输入“切换为XX”,XX为小学、初中和高中三个选项中的一个,输入项不符合要求时,程序控制台提示“请输入小学、初中和高中三个选项中的一个”;输入正确后,显示“”系统提示“准备生成XX数学题目,请输入生成题目数量”,用户输入所需出的卷子的题目数量,系统新设置的类型进行出题;

5、生成的题目将以“年-月-日-时-分-秒.txt”的形式保存,每个账号一个文件夹。每道题目有题号,每题之间空一行;

6、个人项目9月17日晚上10点以前提交至创新课程管理系统。提交方式:工程文件打包,压缩包名为“几班+姓名.rar”。迟交2天及以内者扣分,每天扣20%。迟交2天及以上者0分。

附表-1:账户、密码

账户类型

账户

密码

备注

小学

张三1

123

 

张三2

123

 

张三3

123

 

初中

李四1

123

 

李四2

123

 

李四3

123

 

高中

王五1

123

 

王五2

123

 

王五3

123

 

附表-2:小学、初中、高中题目难度要求

 

小学

初中

高中

 

难度要求

+,-,*./

平方,开根号

sin,cos,tan

 

备注

只能有+,-,*./和()

题目中至少有一个平方或开根号的运算符

题目中至少有一个sin,cos或tan的运算符

 

 

 

 二、程序运行测试:

运行程序进入登陆界面:

输入账号密码并生成题目:

成功生成,题目也符合要求。

切换难度并生成题目:

 也成功生成。

 

 

三、队友代码分析:

结构:

使用了User类,Test类,PaperMaker类,Login类以及一个MakeNewProblem接口来完成该项目。

Test类:

1 public class Test {
2   public static void main(String[] args) {
3     Login.userInitiail(); //登录系统
4   }
5 }
View Code

运行程序的主类。

User类:

 1 public class User {
 2   private String name; //名称
 3   private String password; //密码
 4   private String type; //类型
 5 
 6   public User(String name, String password, String type) {
 7     this.name = name;
 8     this.password = password;
 9     this.type = type;
10   }
11 
12   public String getType() {
13     return type;
14   }
15 
16   public void setType(String type) {
17     this.type = type;
18   }
19 
20   public String getName() {
21     return name;
22   }
23 
24   public void setName(String name) {
25     this.name = name;
26   }
27 
28   public String getPassword() {
29     return password;
30   }
31 
32   public void setPassword(String password) {
33     this.password = password;
34   }
35 
36 }
View Code

User十分简洁,包含三个属性:账号名称,账号密码,账号类别。方法包括构造方法和获取这三个类别的方法。

Login类:

  1 package mathpaper;
  2 
  3 import java.util.HashMap;
  4 import java.util.Scanner;
  5 
  6 /**
  7  * This class is used for user login
  8  *
  9  * @author jason-st
 10  * @date 2023/9/13
 11  * @project Work_Of_Junior
 12  */
 13 public class Login {
 14   static HashMap<String, User> hmap = new HashMap<>();
 15 
 16   /*
 17    * Initialization of Hash Table
 18    * */
 19   public static void hmapInitial() {
 20     hmap.put("张三1", new User("张三1", "123", "小学"));
 21     hmap.put("张三2", new User("张三2", "123", "小学"));
 22     hmap.put("张三3", new User("张三3", "123", "小学"));
 23     hmap.put("李四1", new User("李四1", "123", "初中"));
 24     hmap.put("李四2", new User("李四2", "123", "初中"));
 25     hmap.put("李四3", new User("李四3", "123", "初中"));
 26     hmap.put("王五1", new User("王五1", "123", "高中"));
 27     hmap.put("王五2", new User("王五2", "123", "高中"));
 28     hmap.put("王五3", new User("王五3", "123", "高中"));
 29   }
 30 
 31   /*
 32    * Implement of user login
 33    * */
 34   public static void userInitiail() {
 35     hmapInitial();
 36     Scanner sc = new Scanner(System.in);
 37     while (true) {
 38       System.out.println("请输入用户名和密码(两者之间用空格隔开)");
 39       String tempname = sc.next();
 40       String temppassword = sc.next();
 41       User tempuser = hmap.get(tempname); //名字对不上则tempuser为null,名字对密码不对则要重新登录
 42       if (tempuser != null && tempuser.getPassword().equals(temppassword)) {
 43         while (true) {
 44           System.out.println("准备生成" + tempuser.getType() + "数学题目");
 45           System.out.println("请输入生成题目数量(输入-1将退出当前用户,重新登录)");
 46           int num = sc.nextInt();
 47           if (num >= 10 && num <= 30) {
 48             PaperMaker.makePaper(tempuser, num, tempuser.getType()); //生成试卷
 49             System.out.println("已为您生成完毕,是否继续出题,出题请输入1,切换难度请输入2,退出请输入3");
 50             int picknum = sc.nextInt();
 51             dealPickNum(picknum, tempuser);
 52           } else if (num == -1) {
 53             return; //退出了当前用户,重新登录意味着整个系统要重新开始,直接return;
 54           } else {
 55             System.out.println("请输入10-30之间的自然数");
 56           }
 57         }
 58       } else {
 59         System.out.println("请输入正确的用户名和密码");
 60       }
 61     }
 62   }
 63 
 64   /*
 65    * Change the type of user to create a question
 66    *
 67    * @param tempuser the given user
 68    * */
 69   public static void changeTpye(User tempuser) {
 70     Scanner sc = new Scanner(System.in);
 71     while (true) {
 72       System.out.println("请输入:切换为xx");
 73       System.out.println("xx为小学或初中或高中");
 74       String s = sc.next();
 75       if (s.substring(3, 5).equals("小学")) {
 76         dealSpecificType("小学", tempuser);
 77         break;
 78       } else if (s.substring(3, 5).equals("初中")) {
 79         dealSpecificType("初中", tempuser);
 80         break;
 81       } else if (s.substring(3, 5).equals("高中")) {
 82         dealSpecificType("高中", tempuser);
 83         break;
 84       } else {
 85         System.out.println("请输入小学、初中和高中三个选项中的一个");
 86       }
 87     }
 88   }
 89 
 90   /*
 91    * deal with a particular type
 92    *
 93    * @param type the given string
 94    * @param tempuser the given user
 95    * */
 96   public static void dealSpecificType(String type, User tempuser) {
 97     Scanner sc = new Scanner(System.in);
 98     System.out.println("准备生成" + type + "数学题目,请输入生成题目数量");
 99     int num = sc.nextInt();
100     PaperMaker.makePaper(tempuser, num, type);
101     System.out.println("已为您生成完毕,谢谢您的使用");
102   }
103 
104   /*
105    * deal with a particular pick number
106    *
107    * @param picknum the given picked number
108    * @param tempuser the given user
109    * */
110   public static void dealPickNum(int picknum, User tempuser) {
111     switch (picknum) {
112       case 1:
113         break;
114       case 2:
115         changeTpye(tempuser);
116         break;
117       case 3:
118         System.exit(0);
119       default:
120         break;
121     }
122   }
123 }
View Code

包含一个属性,一个存有所有账户信息的hashmap数据结构。

四个方法:

UserInitial()方法:

初始化登陆界面,账号和密码的输入和判断,并且进入下一级页面。

changeType()方法:

显示切换难度的界面,新的难度的输入以及通过调用dealSpecialType()方法来实现切换难度。

dealSpecialType()方法:

切换难度的具体实现。

dealPickNum()方法:

生产完题目后的下一步操作的选择和处理。

PaperMaker类:

  1 package mathpaper;
  2 
  3 import java.io.BufferedReader;
  4 import java.io.File;
  5 import java.io.FileReader;
  6 import java.io.FileWriter;
  7 import java.text.SimpleDateFormat;
  8 import java.util.Date;
  9 import java.util.Random;
 10 
 11 /**
 12   * This class is used for generating and storing test papers
 13   *
 14   * @author jason-st
 15   * @date 2023/9/13
 16   * @project Work_Of_Junior
 17   */
 18 public class PaperMaker implements MakeNewProblem {
 19   /*
 20    * Generate some problem due to type
 21    *
 22    * @param type The type of the question
 23    * @return the string of problem
 24    * */
 25   public String makeProblem(String type) {
 26     String s = "";
 27     if (type.equals("小学")) {
 28       s = makePrimarySchoolProblem();
 29     } else if (type.equals("初中")) {
 30       s = makeMiddleSchoolProblem();
 31     } else if (type.equals("高中")) {
 32       s = makeHighSchoolProblem();
 33     }
 34     return s;
 35   }
 36 
 37   /*
 38    * Implementation of interfaces
 39    *
 40    * @param u a particular User
 41    * @param n the num of the question
 42    * @param type the type of the school
 43    * @return a particular method due to the type.
 44    * */
 45   public static void makePaper(User u, int n, String type) {
 46     if (type.equals("小学")) {
 47       primarySchool(u, n);
 48     } else if (type.equals("初中")) {
 49       middleSchool(u, n);
 50     } else if (type.equals("高中")) {
 51       highSchool(u, n);
 52     }
 53   }
 54 
 55   /*
 56    * get a randomnumber of a particular interval
 57    *
 58    * @param min the min number
 59    * @param max the max number
 60    * @return a random number between the min and the max
 61    * */
 62   public static int getRandomNumber(int min, int max) {
 63     Random r = new Random();
 64     return r.nextInt(max - min + 1) + min;
 65   }
 66 
 67   /*
 68    * judge if the newformula is repetitive
 69    *
 70    * @param u the particular User
 71    * @param newformula the new problem
 72    * @return whether the formula is repetitive
 73    * */
 74   public static boolean judge(User u, String newformula) {
 75     //查重,需要对应的用户和新的公式
 76     boolean flag = true; //默认不重复
 77     String fatherpath = ".\\autopaper\\" + u.getName();
 78 
 79     File fp = new File(fatherpath);
 80     //每个父亲目录下子目录名字的集合
 81     String[] sonfiles = fp.list();
 82     //逐个目录进行查找
 83     for (int i = 0; i < sonfiles.length; i++) {
 84       try (FileReader fw1 = new FileReader(fatherpath + "\\" + sonfiles[i]);
 85            BufferedReader bf = new BufferedReader(fw1);) {
 86         String oldformula;
 87         while ((oldformula = bf.readLine()) != null) {   //旧的公式一定会包含公式后面的空格,所以用contains来进行判断比较合适
 88           if (oldformula.contains(newformula)) {
 89             return false;
 90           }
 91         }
 92 
 93       } catch (Exception e) {
 94         e.printStackTrace();
 95       }
 96     }
 97 
 98     return true;
 99   }
100 
101   /*
102    * input a problem into the given path
103    *
104    * @param path the saved path
105    * @param newformula the new problem
106    * */
107   public static void input(String path, String newformula) {
108     //写入,需要对应路径,和新的公式
109     // 注意是追加写入,保证写的内容不会覆盖
110     try (FileWriter fw = new FileWriter(path, true);) {
111       fw.write(newformula);
112       fw.write("\r\n"); //第一次换行
113       fw.write("\r\n"); //空行
114     } catch (Exception e) {
115       e.printStackTrace();
116     }
117   }
118 
119   /*
120    * Write n questions into the corresponding user path
121    *
122    * @param u the particular user
123    * @param n the number of problems
124    * */
125   public static void primarySchool(User u, int n) {
126     String path = "./autopaper\\" + u.getName();
127     File f = new File(path);
128     //如果不存在对应的文件夹,先进行创建
129     if (!f.exists()) {
130       f.mkdir();
131     }
132     //存在对应文件夹,则进行创建文件的操作
133     String rightnowtime = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date());
134     path = path + "\\" + rightnowtime + ".txt"; //在该路径下去创建txt文件
135     try (FileWriter fw = new FileWriter(path);) {
136       //成功创建对应文件后。1.进行出题 2.进行查重判断3.将题目写入
137       for (int index = 1; index <= n; index++) {
138         String newformula = new PaperMaker().makeProblem("小学");
139         //创建的不带序号,这样后面才好判断
140         if (judge(u, newformula)) {
141           //进行写入操作
142           newformula = index + ". " + newformula;
143           input(path, newformula);
144         } else {
145           index--; //之前写过就就重新写入
146         }
147       }
148     } catch (Exception e) {
149       e.printStackTrace();
150     }
151 
152   }
153 
154   /*
155    * Write n questions into the corresponding user path
156    *
157    * @param u the particular user
158    * @param n the number of problems
159    * */
160   public static void middleSchool(User u, int n) {
161     String path = "./autopaper\\" + u.getName();
162     File f = new File(path);
163     //如果不存在对应的文件夹,先进行创建
164     if (!f.exists()) {
165       f.mkdir();
166     }
167     //存在对应文件夹,则进行创建文件的操作
168     String rightnowtime = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date());
169     path = path + "\\" + rightnowtime + ".txt"; //在该路径下去创建txt文件
170     try (FileWriter fw = new FileWriter(path);) {
171       //成功创建对应文件后。1.进行出题 2.进行查重判断3.将题目写入
172       for (int index = 1; index <= n; index++) {
173         String newformula = new PaperMaker().makeProblem("初中");
174         //创建的不带序号,这样后面才好判断
175         if (judge(u, newformula)) {
176           //进行写入操作
177           newformula = index + ". " + newformula;
178           input(path, newformula);
179         } else {
180           index--;
181         }
182       }
183     } catch (Exception e) {
184       e.printStackTrace();
185     }
186   }
187 
188   /*
189    * Write n questions into the corresponding user path
190    *
191    * @param u the particular user
192    * @param n the number of problems
193    * */
194   public static void highSchool(User u, int n) {
195     String path = "./autopaper\\" + u.getName();
196     File f = new File(path);
197     //如果不存在对应的文件夹,先进行创建
198     if (!f.exists()) {
199       f.mkdir();
200     }
201     //存在对应文件夹,则进行创建文件的操作
202     String rightnowtime = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date());
203     path = path + "\\" + rightnowtime + ".txt"; //在该路径下去创建txt文件
204     try (FileWriter fw = new FileWriter(path);) {
205       //成功创建对应文件后。1.进行出题 2.进行查重判断3.将题目写入
206       for (int index = 1; index <= n; index++) {
207         String newformula = new PaperMaker().makeProblem("高中");
208         //创建的不带序号,这样后面才好判断
209         if (judge(u, newformula)) {
210           //进行写入操作
211           newformula = index + ". " + newformula;
212           input(path, newformula);
213         } else {
214           index--;
215         }
216       }
217     } catch (Exception e) {
218       e.printStackTrace();
219     }
220   }
221 
222   /*
223    * Generate a primary school question
224    *
225    * @return a primary school question
226    * */
227   public static String makePrimarySchoolProblem() {   //完美的方法!
228     Random r = new Random();
229     String[] symbol = {"+", "-", "*", "/"};
230     int op_num = getRandomNumber(2, 5);
231     String[] ops = new String[op_num];
232     for (int i = 0; i < op_num; i++) {
233       ops[i] = String.valueOf(getRandomNumber(1, 100));
234     }
235     if (op_num >= 3 && r.nextBoolean()) {  //如何加括号
236       int l = getRandomNumber(1, op_num - 2);
237       int left = getRandomNumber(0, op_num - l - 1);
238       int right = left + l;
239       ops[left] = "(" + ops[left];
240       ops[right] = ops[right] + ")";
241     }
242     String result = "";
243     for (int i = 0; i < op_num - 1; i++) {
244       result += ops[i] + symbol[getRandomNumber(0, 3)];
245     }
246     result += ops[op_num - 1] + "=";
247     return result;
248   }
249 
250   /*
251    * Generate a middle school question
252    *
253    * @return a middle school question
254    * */
255 
256   public static String makeMiddleSchoolProblem() {
257     Random r = new Random();
258     String[] symbol = {"+", "-", "*", "/", "^2", "√"};
259     int op_num = getRandomNumber(2, 5);
260     String[] ops = new String[op_num];
261     for (int i = 0; i < op_num; i++) {
262       ops[i] = String.valueOf(getRandomNumber(1, 100));
263     }
264     //特殊处理的数字个数
265     int magicnum = getRandomNumber(1, op_num);
266     boolean[] modify_or_not = new boolean[op_num];
267     //添加平方或者根号项
268     for (int i = 0; i < magicnum; i++) {
269       int modify_index = getRandomNumber(0, op_num - 1);
270       if (modify_or_not[modify_index] == false) {
271         if (r.nextBoolean()) {
272           ops[modify_index] += symbol[4];
273           modify_or_not[modify_index] = true;
274         } else {
275           ops[modify_index] = symbol[5] + ops[modify_index];
276           modify_or_not[modify_index] = true;
277         }
278       }
279     }
280     if (op_num >= 3 && r.nextBoolean()) {  //太巧妙了,真的牛
281       int l = getRandomNumber(1, op_num - 2);
282       int left = getRandomNumber(0, op_num - l - 1);
283       int right = left + l;
284       ops[left] = "(" + ops[left];
285       ops[right] = ops[right] + ")";
286     }
287     String result = "";
288     for (int i = 0; i < op_num - 1; i++) {
289       result += ops[i] + symbol[getRandomNumber(0, 3)];
290     }
291     result += ops[op_num - 1] + "=";
292     return result;
293   }
294 
295   /*
296    * Generate a high school question
297    *
298    * @return a high school question
299    * */
300 
301   public static String makeHighSchoolProblem() {
302     Random r = new Random();
303     String[] symbol = {"+", "-", "*", "/", "^2", "√", "sin", "cos", "tan"};
304     int op_num = getRandomNumber(2, 5);
305     String[] ops = new String[op_num];
306     for (int i = 0; i < op_num; i++) {
307       ops[i] = String.valueOf(getRandomNumber(1, 100));
308     }
309     int magicnum = getRandomNumber(1, op_num); //特殊处理的数字个数
310     boolean[] modify_or_not = new boolean[op_num]; //添加平方,根号项,sin,cos,tan
311     for (int i = 0; i < magicnum; i++) {
312       int modify_index = getRandomNumber(0, op_num - 1);
313       if (i == 0) {
314         ops[modify_index] = symbol[getRandomNumber(6, 8)] + ops[modify_index];
315         modify_or_not[modify_index] = true;
316       } else {
317         if (modify_or_not[modify_index] == false) {
318           int picknum = getRandomNumber(4, 8);
319           dealPickNum(picknum, ops, symbol, modify_index);
320           modify_or_not[modify_index] = true;
321         }
322       }
323     }
324     if (op_num >= 3 && r.nextBoolean()) {  //太巧妙了,真的牛
325       int l = getRandomNumber(1, op_num - 2);
326       int left = getRandomNumber(0, op_num - l - 1);
327       int right = left + l;
328       ops[left] = "(" + ops[left];
329       ops[right] = ops[right] + ")";
330     }
331     String result = "";
332     for (int i = 0; i < op_num - 1; i++) {
333       result += ops[i] + symbol[getRandomNumber(0, 3)];
334     }
335     result += ops[op_num - 1] + "=";
336     return result;
337   }
338 
339   /*
340    * deal with the picknum
341    *
342    * @param picknum the num you input
343    * @param ops  the Operand array
344    * @param symbol the symbol array
345    * @param modify_index the index of the modified number
346    * */
347   public static void dealPickNum(int picknum, String[] ops, String[] symbol, int modify_index) {
348     switch (picknum) {
349       case 4:
350         ops[modify_index] += symbol[4];
351         break;
352       case 5:
353         ops[modify_index] = symbol[5] + ops[modify_index];
354         break;
355       case 6:
356         ops[modify_index] = symbol[6] + ops[modify_index];
357         break;
358       case 7:
359         ops[modify_index] = symbol[7] + ops[modify_index];
360         break;
361       case 8:
362         ops[modify_index] = symbol[8] + ops[modify_index];
363         break;
364       default:
365         break;
366     }
367   }
368 
369 }
View Code

功能1:根据输入的题目个数和用户类别生成相对应的题目.方法:makeHighSchoolProblem()、makeMiddleSchoolProblem()、makePrimarySchoolProblem()。

功能2:将生成的题目存入txt文件中并保存。方法:primarySchool()、middleSchool()、highSchool()。

功能3:将新生成的题目和该用户之前的题目对比,重复则不使用该题目。方法:jungle()。

 其他一些方法主要是调用刚才这些方法。

 

 

四、优缺点分析:

优点:

1.代码编写符合规范,各种关键字的命名方式也很正确,每个方法和类都写了注释,通过检查没有问题。

2.合理得将代码分成多个类,让每个类专注于特定的功能,整个代码清晰易读。

3.代码可复用性高,同一个方法可以被重复利用来实现想要的功能,而且使用了接口,减少代码冗余。

4.在程序运行界面交互逻辑清晰,提供了数字选项供用户选择自己的功能。

5.在保存文件时使用相对路径,代码有较高的可移植性和灵活性。

缺点:

1.在第一次登陆成功后不能直接切换难度,要先出一次该账号类型的题目才可以切换难度。

2.在切换难度后只能出一次题,要再切换难度必须先出一次该账户类型的题目才行。

3.切换难度时不能识别其他的错误输入。

 

 

五、总结:

总的来说,整个项目还是基本完成了该完成的功能,作为我们在这门课的第一个项目已经很好了。在项目的代码编写过程中,我们也学到了很多东西,认识到了自己的不足,希望在之后的项目中我们能做的更好。