1.软工作业3_结对编程:四则运算
软件工程 | 21计科34班 |
---|---|
作业要求 | 结对项目 |
作业目标 | 结对设计实现一个生成四则运算题目的命令行程序 |
作业GitHub地址 | 第三次作业GitHub地址) |
结对同学 | 赵俊宇3121005190 裴传传(找了外校同学组队) |
2.PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 50 | 100 |
· Estimate | · 估计这个任务需要多少时间 | 70 | 100 |
Development | 开发 | 500 | 555 |
· Analysis | · 需求分析 (包括学习新技术) | 340 | 400 |
· Design Spec | · 生成设计文档 | 70 | 20 |
· Design Review | · 设计复审 | 20 | 20 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 20 | 20 |
· Design | · 具体设计 | 50 | 50 |
· Coding | · 具体编码 | 120 | 100 |
· Code Review | · 代码复审 | 10 | 10 |
· Test | · 测试(自我测试,修改代码,提交修改) | 100 | 35 |
Reporting | 报告 | 80 | 80 |
· Test Report | · 测试报告 | 20 | 40 |
· Size Measurement | · 计算工作量 | 40 | 20 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 50 | 30 |
· 合计 | 770 | 775 |
3.效能分析
覆盖率:
性能分析图:
字符数组char[ ]和String类占用最多的内存,这主要与运算符号、题目文本及答案文本等的生成和文件写入时,调用了一系列List类方法、String类方法有关
cpu负载:
4.设计实现过程
主要分成了Run、Fraction、Creat、Calc、Checkanswer、Expression这几个类:
- Run类:包含了程序的入口点,即
main
方法。它负责启动整个程序,接受用户输入,调用其他类的方法来生成题目、计算答案和检查答案的正确性。它还负责输出结果到控制台或文件。 - Fraction类:表示分数,包含分子和分母的属性,以及一些用于操作分数的方法,如分数的加法、减法、乘法、除法等。
- Create类:生成题目。包含一些方法,用于生成随机的数学表达式,包括运算符、操作数和括号。生成的表达式可以以字符串的形式返回,供其他类使用。
- Calc类:计算数学表达式的结果。包含一些方法,用于将数学表达式转换为后缀表达式,并执行后缀表达式的计算。这个类可以处理各种运算符和括号。
- CheckAnswer类:检查用户提供的答案是否正确。包含一些方法,用于比较用户答案和正确答案,然后返回检查结果(正确或错误)。
- Expression类:表示数学表达式。包含一些属性,如操作数、运算符和括号的列表,以及一些方法,用于操作和转换表达式,如将中缀表达式转换为后缀表达式。
5.代码说明
Create类:生成题目。
public class Create {
Expression expression=new Expression();
Calc cal=new Calc();
HashMap<String,String> map = new HashMap<String,String>();
public void cr(int n,int r) throws IOException {
BufferedWriter btex=new BufferedWriter(new FileWriter("Exercises.txt"));
BufferedWriter btan=new BufferedWriter(new FileWriter("Answers.txt"));
for(int i=1;i<n+1;i++){
String exps=expression.getexp(r);
List<String> cnkiexp1=cal.getcnki(exps);
String cnki1=cal.list2String(cnkiexp1);
boolean contains2 =false;
if(cnkiexp1.get(0).equals("+")||cnkiexp1.get(0).equals("×")) {
List<String> cnkiexp2=cnkiexp1;
String t1=cnkiexp2.get(1);
String t2=cnkiexp2.get(2);
cnkiexp2.set(1, t2);
cnkiexp2.set(2, t1);
String cnki2=cal.list2String(cnkiexp2);
contains2 = map.containsKey(cnki2);
}
if(i==1) {map.put(cnki1,"");}
boolean contains = map.containsKey(cnki1);
if(contains==true||contains2==true) {
exps=expression.getexp(r);
cnkiexp1=cal.getcnki(exps);
cnki1=cal.list2String(cnkiexp1);
contains2 =false;
if(cnkiexp1.get(0).equals("+")||cnkiexp1.get(0).equals("×")) {
List<String> cnkiexp2=cnkiexp1;
String t1=cnkiexp2.get(1);
String t2=cnkiexp2.get(2);
cnkiexp2.set(1, t2);
cnkiexp2.set(2, t1);
String cnki2=cal.list2String(cnkiexp2);
contains2 = map.containsKey(cnki2);
}
}
map.put(cnki1,"");
Fraction answer=cal.calculate(exps);
String answers=answer.toString();
btex.write(i+". "+exps+"\r\n");
btan.write(i+". "+answers+"\r\n");
}
btex.flush();
btan.flush();
btex.close();
btan.close();
}
}
Calc类:计算数学表达式的结果。
public class Calc {
char[] oper6 = {'+', '-', '×', '÷', '(', ')'};
String[] oper4 = {"+", "-", "×", "÷"};
private static int ADDITION = 1;
private static int SUBTRACTION = 1;
private static int MULTIPLICATION = 2;
private static int DIVISION = 2;
public static int getValue(String op) {
int value;
switch (op) {
case "+":
value = ADDITION;
break;
case "-":
value = SUBTRACTION;
break;
case "×":
value = MULTIPLICATION;
break;
case "÷":
value = DIVISION;
break;
default:
value = 0;
}
return value;
}
//判断是否是操作符
public boolean isoper(char c) {
for (char op : oper6) {
if (op == c) return true;
}
return false;
}
public boolean isoper(String s) {
for (String op1 : oper4) {
if (s.equals(op1)) return true;
}
return false;
}
//判断是否是数字
public boolean isfra(char c) {
if (c >= '0' && c <= '9') {
return true;
}
return false;
}
public boolean isfraop(char c) {
if (c == '\'' || c == '/') {
return true;
}
return false;
}
//将String类型表达式转换成List<String>类型
public List<String> Stringtolist(String str) {
List<String> infix = new ArrayList<String>();
str = str.replace(" ", "");
char op;
String temp = "";
for (int i = 0; i < str.length(); i++) {
op = str.charAt(i);
if (isfra(op) || isfraop(op)) {
temp += op;
} else if (isoper(op)) {
if (!temp.isEmpty()) {
infix.add(temp);
temp = "";
}
infix.add(op + "");
}
}
if (!temp.isEmpty()) {
infix.add(temp);
temp = "";
}
return infix;
}
//将中缀表达式转换为后缀表达式
public List<String> infixtopostfix(List<String> infix) {
List<String> postfix = new ArrayList<String>();
Stack<String> s1 = new Stack<String>();
for (String str : infix) {
if (str.equals("(")) {
s1.push(str);
} else if (str.equals(")")) {
while (!s1.peek().equals("(")) {
postfix.add(s1.pop());
}
s1.pop();
} else if (str.equals("+") || str.equals("-") || str.equals("×") || str.equals("÷")) {
while (s1.size() != 0 && getValue(s1.peek()) >= getValue(str)) {
postfix.add(s1.pop());
}
s1.push(str);
} else {
postfix.add(str);
}
}
while (s1.size() != 0) {
postfix.add(s1.pop());
}
return postfix;
}
//对后缀表达式进行计算
public Fraction calculate(String str) {
List<String> linfix = Stringtolist(str);
List<String> lpostfix = infixtopostfix(linfix);
Stack<Fraction> s2 = new Stack<Fraction>();
Fraction f1;
Fraction f2;
Fraction answer;
for (String cal : lpostfix) {
if (!isoper(cal)) {
Fraction f = Fraction.tofraction(cal);
s2.push(f);
} else {
switch (cal) {
case "+":
f1 = s2.pop();
f2 = s2.pop();
answer = f2.add(f1);
s2.push(answer);
break;
case "-":
f1 = s2.pop();
f2 = s2.pop();
answer = f2.sub(f1);
s2.push(answer);
break;
case "×":
f1 = s2.pop();
f2 = s2.pop();
answer = f2.mult(f1);
s2.push(answer);
break;
case "÷":
f1 = s2.pop();
f2 = s2.pop();
answer = f2.div(f1);
s2.push(answer);
break;
}
}
}
return s2.pop();
}
public String list2String(List<String> list) {
String str1 = "";
for (String s : list) {
str1 = str1 + s + " ";
}
return str1;
}
}
CheckAnswer类:检查用户提供的答案是否正确。
public class Checkanswer {
public void check(String expath,String anpath) throws IOException{
BufferedReader brex=new BufferedReader(new FileReader(expath));
BufferedReader bran=new BufferedReader(new FileReader(anpath));
BufferedWriter bwgrade=new BufferedWriter(new FileWriter(".\\Grade.txt"));
List<String> Correct=new ArrayList<String>();
List<String> Wrong=new ArrayList<String>();
String an=null;
String ex=null;
while((an=bran.readLine())!=null) {
ex=brex.readLine();
int point=an.indexOf(".");
String stran=an.substring(point+1);
stran=stran.trim();
String strex=ex.substring(point+1);
strex=strex.trim();
if(stran.equals(strex)) {
String cno=an.substring(0, point);
Correct.add(cno);
}else {
String wno=an.substring(0, point);
Wrong.add(wno);
}
}
String corr=String.join(",",Correct);
String wr=String.join(",",Wrong);
bwgrade.write("Correct: "+Correct.size()+" ("+corr+")"+"\r\n");
bwgrade.write("Wrong: "+Wrong.size()+" ("+wr+")");
bwgrade.flush();
bwgrade.close();
}
}
6.测试说明
一万条:
7.小结
在本次结对编程项目中,我们共同合作完成了一个四则运算题目生成和批改的Java应用程序。通过这次合作,我们获得了许多宝贵的经验和教训,以下是我们的项目小结:
项目概述: 本项目旨在开发一个四则运算题目生成器和答案批改器,可以生成一系列四则运算题目,并根据给定的答案文件来批改用户的答案。
项目分工: 我们在项目中交替担任主驱动者和导航者的角色,确保了代码的质量和可读性。这种协作方式帮助我们更好地理解和修复代码中的问题。
项目亮点:
- 功能完整:我们成功实现了题目生成和答案批改的核心功能。题目生成器可以生成多种类型的题目,答案批改器可以准确判断答案的正确性。
- 代码质量:通过结对编程,我们共同审查和改进了代码,确保其质量和可维护性。我们遵循了Java的最佳实践,使用了合适的命名和注释。
经验教训:
- 沟通至关重要:项目中充分的沟通非常重要。通过不断讨论和解释代码,我们能够更好地理解对方的思维和意图。
- 版本控制:及时提交和同步代码到版本控制系统(如Git)非常重要。这有助于避免代码冲突和数据丢失。
- 任务分解:我们应该更好地将任务分解为更小的子任务,以便更容易管理和实施。这有助于提高工作效率。