一、背景介绍
张陈东芳 201521123001 博客链接
戴建钊 201521123023 博客链接
二、需求分析
题目要求
1、自动随机生成真分数和整数;
2、随机生成一则简单的四则运算题目;
3、能够计算题目,并判断用户输入的答案正确与否,若错误则输出正确答案;
4、能够计算用户答题的正确率;
5、计时器功能,点击开始计时时,能显示用户开始答题后的消耗时间;
6、界面支持中文简体/中文繁体/英语,用户可以选择一种。
改进版
对用户输入题数的内容设置了容错功能,只可以输入1~10之间的数字,输入字母或者不在范围内的数字将无法点击确定按钮;
能持续记录用户的对错总数,程序退出再启动的时候,能把以前的对错数量保存并在此基础上增量计算;
实现了错题复习功能,可以将用户使用以来做错的题目保存在文档中,点击“复习”按钮,生成的题目将全部是之前用户做错的题目,达到用户复习的目的;
重写了四则运算,能实现乘方、立方、四次方、n次方功能。
三、程序设计
四、代码展示
后缀表达式
package arithmetic;
import java.util.Stack;
public class Expression {
private String operator[] = { "+", "-", "*", "/" };
public DefineQueue<String> expressionCreate() {
// 创建后缀表达式
DefineQueue<String> queue = new DefineQueue<String>();
int num = 4, count = 0;
boolean opera = false;
while (num != 0 || count != 1) {
Integer choice = (int) (Math.random() * 20000);
if (choice > 0 && choice < 10000)
choice = 1;
else
choice = 2;
if (num == 0)
choice = 2;
switch (choice) {
case 1:
if (num > 0) {
count++;
num--;
Integer num0 = (int) (Math.random() * 30 + 1);
queue.add(num0.toString());
// int 一个随机数入队列
break;
}
break;
case 2:
if (count >= 2) {
opera = true;
Integer opNum = (int) (Math.random() * 4000);
if (opNum > 0 && opNum < 1000)
opNum = 0;
else if (opNum >= 1000 && opNum < 2000)
opNum = 1;
else if (opNum >= 2000 && opNum < 3000)
opNum = 2;
else
opNum = 3;
queue.add(operator[opNum]);
break;
}
break;
}
if (opera == true) {
count--;
opera = false;
}
}
return queue;
}
public Double expressionCalculate(DefineQueue<String> queue) throws CloneNotSupportedException {
String str = "";
DefineQueue<String> que = queue.clone();
Stack<Double> stack = new Stack<Double>();
while (!que.isEmpty()) {
str = que.poll();// 出队一个
if (str.equals("+") || str.equals("-") || str.equals("*") || str.equals("/")) {
Double num2 = stack.pop();// 等于出栈数字
Double num1 = stack.pop();// 等于出栈数字
// +-*/
Double sum = 0d;// 入栈
if (str.equals("+"))
sum = num1 + num2;
if (str.equals("-"))
sum = num1 - num2;
if (str.equals("*"))
sum = num1 * num2;
if (str.equals("/"))
sum = num1 / num2;
stack.push(sum);
} else {
stack.push(Double.parseDouble(str));
// 入栈
}
}
Double dd = stack.pop();
// System.out.println(stack.peek());
return dd;
}
public String expressionTransform(DefineQueue<String> queue) throws CloneNotSupportedException {
String str = "";
// String strLast="";
Stack<String> stack = new Stack<String>();
DefineQueue<String> que = queue.clone();
while (!que.isEmpty()) {
// strLast=str;
str = que.poll();
String expresOfMath = "";
if ((str.equals("+") || str.equals("-")) && !que.isEmpty()) {
String expres1 = stack.pop();// 等于出栈数字
String expres2 = stack.pop();
expresOfMath = "(" + expres2 + str + expres1 + ")";
stack.push(expresOfMath);
} else if ((str.equals("+") || str.equals("-")) && que.isEmpty()) {
String expres1 = stack.pop();// 等于出栈数字
String expres2 = stack.pop();
expresOfMath = expres2 + str + expres1;
stack.push(expresOfMath);
} else if (str.equals("*") || str.equals("/")) {
String expres1 = stack.pop();// 等于出栈数字
String expres2 = stack.pop();
expresOfMath = expres2 + str + expres1;
stack.push(expresOfMath);
} else
stack.push(str);
}
String str1 = stack.pop();
// System.out.println(stack.peek());
return str1;
}
}
重载clone
package arithmetic;
import java.util.LinkedList;
public class DefineQueue<E> implements Cloneable{
LinkedList<E> queue=new LinkedList<E>();
public DefineQueue() {
}
public void add(E e) {
queue.addLast(e);
}
/*private E peek() {
if(!queue.isEmpty()) {
return queue.getFirst();
}
return null;
}*/
public E poll() {
if(!queue.isEmpty()) {
E getE=queue.getFirst();
queue.removeFirst();
return getE;
}
return null;
}
public boolean isEmpty() {
return queue.isEmpty();
}
@SuppressWarnings("unchecked")
@Override
public DefineQueue<E> clone() throws CloneNotSupportedException {
// TODO Auto-generated method stub
DefineQueue<E> DQ=(DefineQueue<E>) super.clone();
DQ.queue=(LinkedList<E>) queue.clone();
return DQ;
}
@Override
public String toString() {
return queue+"";
}
public void setQueue(LinkedList<E> queue) {
this.queue = queue;
}
}
创建错题集
public void Histroy_create() {
String path = "f:\Myapp";
File f = new File(path);
if (!f.exists()) {
f.mkdirs();
String fileName = "histroy.txt";
File file = new File(f, fileName);
if (!file.exists()) {
Writer writer = null;
try {
writer = new OutputStreamWriter(new FileOutputStream(file), "UTF-8");
} catch (UnsupportedEncodingException | FileNotFoundException e) {
e.printStackTrace();
}
try {
if (writer != null) {
writer.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
f.mkdirs();
String fileName2 = "histroy_num.txt";
File file2 = new File(f, fileName2);
if (!file2.exists()) {
Writer writer = null;
try {
writer = new OutputStreamWriter(new FileOutputStream(file2), "UTF-8");
} catch (UnsupportedEncodingException | FileNotFoundException e) {
e.printStackTrace();
}
try {
if (writer != null) {
writer.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
Histroy_saveNum();
}
}
public void Histroy_save() {
FileWriter writer;
String fileName = ("f:\Myapp\histroy.txt");
try {
writer = new FileWriter(fileName, true);
writer.write(str);
writer.write("
");
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public void Histroy_saveNum() {
FileWriter writer2;
String fileName2 = ("f:\Myapp\histroy_num.txt");
try {
writer2 = new FileWriter(fileName2, true);
writer2.write(str2);
writer2.write("
");
writer2.close();
} catch (IOException e) {
e.printStackTrace();
}
}
五、程序运行
系统主界面
开始做题并计时
输出正确答案和正确率,计时停止
六、小结感受
首先,我们体会到编程中的注释有多么重要,因为在看上一届学姐学长的代码时,一大段的代码让人头晕目眩,盯着研究了好久才知道这段代码在做什么,这对再编程产生了很大的影响,降低了工作效率,如果有注释的话,即使几个字也减轻了工作量,就能很快摸清整篇代码的脉络,进而改进原有程序。
其次,对于结队编程,其实我们在以前的课设中就是几个人共同完成一个程序,对于团队合作并不陌生。我们从一开始就体会到共同创建类的重要性,包括对象名和主函数,只要先把框架拟定好,再在里面写函数就很简单了,如果一开始没有定好框架,整合的时间可能会比写代码的时间多得多。所以我们一开始干的事情就是分析原有代码的构造,把它的逻辑先搞清楚,再来想要怎么把它改进好。
然后,对于结对编程是否能够带来1+1>2的效果,我觉得利大于弊:
一个人的编程工作量比较大,有些函数其实每个人都写的出来,但是一个人的话就要写很多,比较繁琐;一个人写代码还很无聊,要有恒心有毅力才能坚持下去;一个人很容易被外界干扰,比如舍友说要点外卖了,那吃外卖的时候就可能看个剧,剧看完可能就比较晚了,为了保持健康就得早点睡觉,一个晚上就过去了。
两个人的话就不一样啦,互相监督去图书馆写代码或者qq上交流沟通,有收获能及时地分享出去,比起一个人要有趣得多,更主要是对自己不理解的地方能得到最贴近自己想要的答复,而不是百度上泛泛的答案,对我们的交流和理解能力也有帮助。
比较不好的一点就是一个人的编程比较有大局观,因为一个人做就清楚自己做的是什么,结队编程把一个项目变成两部分,我们会对自己的那部分比较熟悉,对对方的那部分比较不熟悉,当然,这次的结队编程还有一个审核的工作,我们觉得这个确实是有必要的,因为一个人做的时候有些错误自己是不容易看出来的,一直出错也找不到错在哪里,但另一个人看就很容易看出来错误,可能是因为当一个人集中思考一件事情的时候往往忽视其他逻辑的错误吧>_<这对我们完整地理解工作任务也有很大帮助。
最后,虽然老师发布任务是两周的时间,但我们有机会凑在一起讨论和交流的时间还是比较少的,大多数时间是在qq上交流,这让信息的传递大打折扣。总体来说,这次的结队编程还是很愉快的。
七、结对的过程,提供非摆拍的两人在讨论、细化和编程时的结对照片。
面对面交流
远程交流
QQ交流
实现乘方的代码分析