结对编程之个人项目代码互评
作者:互联网
结对编程之个人项目代码互评
简介
这篇文章是我的结对编程搭档刘正豪——豪神的个人项目代码的总结评价。
豪神使用Java语言实现中小学数学卷子自动生成程序的预期功能,代码结构清晰,其中的某些函数不乏亮点。
项目需求
- 针对小学、初中和高中数学老师为主体用户的程序
- 要完成的功能有:
- 命令行输入用户名和密码进行登录,两者用空格隔开。
- 登录成功显示用户可生成的题目类型,可以输入所需的题目数量(限制在10-30之间),若输入-1可以退出当前登录并重新登录。
- 生成的题目保存到目标用户名文件中并以"年-月-日-时-分-秒.txt"的形式保存,每个用户名一个文件夹,每道题目以(+题号+)开头并且每题之间要空一行,同一账号生成的题目不允许和已生成的题目重复。
- 用户可以在任何时刻输入“切换为”+类型切换到指定教师类型,同时具备该类型老师的出题资格。
- 备注:
- 预制账户:
账户类型 用户名 密码 小学 张三1 123 小学 张三2 123 小学 张三3 123 初中 李四1 123 初中 李四2 123 初中 李四3 123 高中 王五1 123 高中 王五2 123 高中 王五3 123 - 题目要求:
小学 初中 高中 难度要求 +,-,*./ 平方、开方 sin,cos,tan 备注 只能有+,-,*./和() 题目中至少有一个平方或开根号的运算符 题目中至少有一个sin,cos或tan的运算符
- 预制账户:
代码结构
USer
由于代码全部复制过来太多,只说几个关键的。
public class User {
private String id;
private String psw;
private String type;
private boolean convert;
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
User user = (User) o;
return id.equals(user.id) && psw.equals(user.psw);
}
@Override
public int hashCode() {
return Objects.hash(id, psw);
}
}
成员属性有4个,convert用于判断后续的是否重新登录的判断。
equals()函数用于登录时的判断
hashCode()函数用于后续查重
Login
剩余的代码都写在了Login里面,由于代码量较大,只展示其中几个关键的函数:
private void paper(int cnt,User u) throws IOException {
Random r = new Random();
String[] specialSigns = {"?","√","sin","cos","tan"};
HashSet<String> hisQ = historyPaper(u);
String path = "F:\\4\\Auto_Math\\out\\production\\Mathpaper\\" + u.getId() + "/";
Calendar date = Calendar.getInstance();
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
String time = formatter.format(date.getTime());
path = path + time + ".txt";
//生成题目
FileWriter fw = new FileWriter(path,true);
for(int i = 0;i < cnt;i++){
String question;
//生成单个题目
question = singleQuestion(u, r, specialSigns);
//查询是否与历史题目重复
if(hisQ.contains(question)){
i--;
continue;
}
question = "第" + (i + 1) + "题: " + question + "=";
fw.write(question+"\r\n");
}
fw.close();
}
本次的关键是生成题目,先生成路径后生成题目,生成单个题目之后进行查重,最后输出到文件里,思路清晰,代码简洁。
private String singleQuestion(User u, Random r, String[] specialSigns) {
String[] signs = {"+","-","×","÷"};
String question = null;
String[] opQ = null;
String type= u.getType();
switch (type){
case "小学" -> {
int opNum = r.nextInt(4) + 2;
opQ = new String[opNum];
for(int i = 0;i < opNum;i++){
opQ[i] = String.valueOf(r.nextInt(100) + 1);
}
//括号
addBracket(r, opQ, opNum);
}
case "初中" -> {
int opNum = r.nextInt(5) + 1;
opQ = new String[opNum];
for(int i = 0;i < opNum;i++){
opQ[i] = String.valueOf(r.nextInt(100) + 1);
}
//特殊符号数
int sopNum = r.nextInt(opNum) + 1;
while((sopNum--) != 0){
int rPos = r.nextInt(opNum);
if(!opQ[rPos].contains("?") && !opQ[rPos].contains("√")){
opQ[rPos]= r.nextBoolean()? opQ[rPos]+"?": "√"+opQ[rPos];
}
}
addBracket(r, opQ, opNum);
}
case "高中" -> {
int opNum = r.nextInt(5) + 1;
opQ = new String[opNum];
for(int i = 0;i < opNum;i++){
opQ[i] = String.valueOf(r.nextInt(100) + 1);
}
//特殊符号数
int sopNum = r.nextInt(opNum) + 1;
boolean[] speOpFlag = new boolean[opNum];
//确保至少有一个三角函数
int tri = 0;
while((sopNum--) != 0){
int rPos = r.nextInt(opNum);
if(tri == 0 && !opQ[rPos].contains("sin") && !opQ[rPos].contains("cos") && !opQ[rPos].contains("tan")){
opQ[rPos] = specialSigns[r.nextInt(3)+2] + opQ[rPos];
tri++;
speOpFlag[rPos] = true;
}
if(!speOpFlag[rPos]){
int rOp = r.nextInt(5);
opQ[rPos] = rOp < 1 ? opQ[rPos] + specialSigns[rOp] : specialSigns[rOp] + opQ[rPos];
speOpFlag[rPos] = true;
}
}
addBracket(r, opQ, opNum);
}
default -> System.out.println("error");
}
assert opQ != null;
for(int i = 0;i < opQ.length ;i++){
int opType = r.nextInt(4);
question = (question == null?"":question) + (i!=0?signs[opType]:"") + opQ[i];
}
return question;
}
这是生成单个题目的函数,分为三类来进行。逻辑基本是差不多的,先通过随机数生成几个操作数,之后再利用循环判断添加操作符。
private void addBracket(Random r, String[] opQ, int opNum) {
boolean bracket = r.nextBoolean() && opNum > 2;
if(bracket){
int range = r.nextInt(opNum - 2) + 1;
int left = r.nextInt(opNum - range);
opQ[left] = "(" + opQ[left];
opQ[left+range] = opQ[left+range] + ")";
}
}
括号是在算式最后添加的,通过随机数来确定位置。
private HashSet<String> historyPaper(User u) throws IOException {
HashSet<String> hisQuestions = new HashSet<>();
String path = "F:\\4\\Auto_Math\\out\\production\\Mathpaper" + "\\" + u.getId();
File folder = new File(path);
if(!folder.exists()){
folder.mkdir();
}
File[] fList = folder.listFiles();
assert fList != null;
for(File f : fList){
if (f.isFile() && f.getName().endsWith(".txt")){
BufferedReader br = new BufferedReader(new FileReader(f));
String s;
while((s = br.readLine()) != null){
hisQuestions.add(s);
}
br.close();
}
}
return hisQuestions;
}
对于题目查重,豪神采用了哈希表,将同一用户名文件夹下的题目导入哈希表中,挨个查询,这样做大大节省了查询的复杂度,好评!
优缺点分析
优点
- 因为我使用的C++,在我看来Java的代码更加的简洁,功能强大,同时不会出现编码上的问题,看的出来豪神的编程能力十分强力。
- 生成题目的方式和我相比非常的易于理解,同时不会出现看起来特别怪异的题目,思路比较清晰。
- 在查重时使用哈希表,非常的妙啊。
缺点
- 有些地方命名不是很规范,过于简单,同时有些地方欠缺一点注释,希望下次可以多一点。
- 初高中题目不够随机,可以有一些复杂符号的多重组合,折磨一下考生(bushi
- 比较主观的见解:可以分更多的类出来,而不是几乎全部写在其中一个类里面,让代码的复用性更好。
心得
Java还是非常好用的,要今后多学习Java的使用,很多都封装好了可以直接拿来用,不需要我再写了。多看看其他人的代码一方面可以让我学到更多的编程思路,学习其他人的切入点,另一方面通过检查他人代码的缺陷,我也能反省自身,不再犯类似的错误。
标签:rPos,结对,opQ,int,编程,互评,nextInt,opNum,String 来源: https://www.cnblogs.com/klutzz/p/16691361.html