结对编程——paperOne基于java的四则运算 功能改进
项目成员:张金生 张政
由于新的需求,原本使用JSP的实现方式目前改为Java实现,即去除了B/S端。
需求分析:
1.四则运算要满足整数运算、分数运算两种;
2.运算题目随机,并且可以打印题目和答案;
3.可以由用户输入答案,并进行对错判断;
4.支持括号。
5.出现的分数要约分,并且以“m p/n”方式输出。
程序概要:
1.原本用JSP实现,为满足需求现改用Java实现;
2.用户可选择题目数量、题目难度(比如简单难度为两位数加减乘除,中等难度为四位数的加减乘除并包含括号,高难度为四位分数加减乘除等);
3.用户可以选择进入答题还是打印问题与答案;
4.答题时输入答案并回车会立即反馈结果;
5.整数运算中不仅运算数是整数,结果也一定是整数;
6.分数运算结果是约分后的,因此填写的答案也需要约分,否则会判为错。
程序运行流程图:
实现过程:
分数类
分数类构造函数
在构造时直接进行约分操作,其中的maxCommonFactor是分子与分母的最大公约数。
1 public Fraction(int up, int down) { 2 if (down == 0 | up == 0) { 3 System.out.println("divided by zero error"); 4 return; 5 } 6 int smaller = up > down ? up : down; 7 int maxCommonFactor = 1; 8 for (int i = 1; i <= smaller; i++) { 9 if (up % i == 0 && down % i == 0) { 10 maxCommonFactor = i; 11 } 12 } 13 14 this.up = up / maxCommonFactor; 15 this.down = down / maxCommonFactor; 16 }
约分函数
与构造函数中的月份操作有所不同,主要用来对进行四则运算后的结果数进行约分操作。
1 public Fraction gcd(Fraction f) { 2 int smaller = f.up > f.down ? f.up : f.down; 3 int maxCommonFactor = 1; 4 for (int i = 1; i <= smaller; i++) { 5 if (f.up % i == 0 && f.down % i == 0) { 6 maxCommonFactor = i; 7 } 8 } 9 f.up = f.up / maxCommonFactor; 10 f.down = f.down / maxCommonFactor; 11 12 return f; 13 }
转化函数
用于最后打印时使分数符合规范。
1 public String toString() { 2 if (down == 1) 3 return "" + up; 4 if(Math.abs(up)/down>0){ 5 return up>0?up/down+" "+up%down+"/"+down:"-"+Math.abs(up)/down+" "+Math.abs(up)%down+"/"+down; 6 } 7 return up + "/" + down; 8 }
四则运算函数
因为数据结构用到了栈,所以减法有些特殊,详情后面会给出解释说明,这里的changesign函数就是用来做减法运算的一个中间函数。
1 public Fraction add(Fraction f) { 2 Fraction a = new Fraction(up, down); 3 a.up = f.up * a.down + a.up * f.down; 4 a.down = a.down * f.down; 5 6 return a.gcd(a); 7 } 8 9 public Fraction minus(Fraction f) { 10 Fraction a = new Fraction(up, down); 11 a.up = a.up * f.down - f.up * a.down; 12 a.down = a.down * f.down; 13 14 return a.gcd(a); 15 } 16 17 public Fraction multiply(Fraction f) { 18 Fraction a = new Fraction(up, down); 19 a.up = a.up * f.up; 20 a.down = a.down * f.down; 21 return a.gcd(a); 22 } 23 24 public Fraction divide(Fraction f) { 25 Fraction a = new Fraction(up, down); 26 a.up = a.up * f.down; 27 a.down = a.down * f.up; 28 return a.gcd(a); 29 } 30 31 public Fraction changeSign(){ 32 up = -up; 33 return this; 34 }
随机数函数
用来随机生成分数。
1 public static Fraction getRandiom(int Max) { 2 return new Fraction((int) (Math.random() * Max / 2) + 1, (int) (Math.random() * Max / 2) + 1); 3 } 4 5 public static Fraction getRandiom(int Max, boolean isInt) { 6 return new Fraction((int) (Math.random() * Max / 2) + 1, isInt ? 1 : (int) (Math.random() * Max / 2) + 1); 7 }
题目生成
这里包含了括号的随机插入:用ArrayList维护随机生成的括号位置列表,然后使用TreeMap计算并保存应该生成括号的位置,最后在题目生成的时候进行拼接。
1 public String generateQuestion(int numOfOperand, int rangeMin, int rangMax, SupportedOperation[] operation, 2 boolean isFractional, boolean hasbracket) { 3 String question = ""; 4 int[] ioperands = null; 5 ArrayList<Fraction> af = new ArrayList<Fraction>(); 6 SupportedOperation[] so = null; 7 if (numOfOperand < 2) { 8 System.out.println("操作数数量至少为2"); 9 return ""; 10 } 11 if (rangMax > 500) { 12 System.out.println("操作数数最大值不能超过500"); 13 return ""; 14 } 15 getBcPrint(numOfOperand); 16 if (!isFractional) { 17 ScriptEngine se = new ScriptEngineManager().getEngineByName("JavaScript"); 18 ioperands = new int[numOfOperand]; 19 for (int i = 0; i < numOfOperand; i++) { 20 ioperands[i] = (int) (Math.random() * rangMax / 2 + 1); 21 22 } 23 so = new SupportedOperation[numOfOperand - 1]; 24 for (int i = 0; i < operation.length; i++) { 25 if (operation[i] == SupportedOperation.ALL) { 26 operation = new SupportedOperation[4]; 27 operation[0] = SupportedOperation.ADD; 28 operation[1] = SupportedOperation.MINUS; 29 operation[2] = SupportedOperation.MULTIPLY; 30 operation[3] = SupportedOperation.DIVIDE; 31 32 } 33 } 34 // 除法運算,保证整除 35 int value = 0; 36 for (int j = numOfOperand - 1; j > 0; j--) { 37 so[numOfOperand - 1 - j] = operation[(int) (Math.random() * operation.length)]; 38 } 39 for (int j = numOfOperand - 2; j >= 0; j--) { 40 if (so[j] == SupportedOperation.DIVIDE) { 41 if (value < 1) { 42 ioperands[j] = ioperands[j] * ioperands[j + 1]; 43 value++; 44 45 } else { 46 so[j] = operation[(int) (Math.random() * (operation.length - 2))]; 47 } 48 } 49 } 50 // 输出括号 51 for (int i = 0; i < numOfOperand - 1; i++) { 52 if (frequency.containsKey(i)) { 53 if (direction.get(i) == 0) { 54 for (int k = 0; k < frequency.get(i); k++) { 55 question += "("; 56 } 57 } 58 } 59 question += ioperands[i]; 60 if (frequency.containsKey(i)) { 61 if (direction.get(i) == 1) { 62 for (int k = 0; k < frequency.get(i); k++) { 63 question += ")"; 64 } 65 } 66 } 67 question += so[i]; 68 } 69 if (frequency.containsKey(numOfOperand - 1)) { 70 if (direction.get(numOfOperand - 1) == 0) { 71 for (int k = 0; k < frequency.get(numOfOperand - 1); k++) { 72 question += "("; 73 } 74 } 75 } 76 question += ioperands[numOfOperand - 1]; 77 if (frequency.containsKey(numOfOperand - 1)) { 78 if (direction.get(numOfOperand - 1) == 1) { 79 for (int k = 0; k < frequency.get(numOfOperand - 1); k++) { 80 question += ")"; 81 } 82 } 83 } 84 85 try { 86 Integer d = (Integer) se.eval(question); 87 answer = "" + d; 88 } catch (Exception e) { 89 generateQuestion(numOfOperand, rangeMin, rangMax, operation, isFractional, hasbracket); 90 } 91 92 } else { 93 for (int i = 0; i < numOfOperand; i++) { 94 af.add(Fraction.getRandiom(rangMax)); 95 } 96 97 so = new SupportedOperation[numOfOperand - 1]; 98 for (int i = 0; i < operation.length; i++) { 99 if (operation[i] == SupportedOperation.ALL) { 100 operation = new SupportedOperation[4]; 101 operation[0] = SupportedOperation.ADD; 102 operation[1] = SupportedOperation.MINUS; 103 operation[2] = SupportedOperation.MULTIPLY; 104 operation[3] = SupportedOperation.DIVIDE; 105 106 } 107 } 108 question += af.get(0); 109 for (int j = 0; j < numOfOperand - 1; j++) { 110 so[j] = operation[(int) (Math.random() * operation.length)]; 111 question += (so[j] == SupportedOperation.DIVIDE ? "÷" : so[j].toString()) + af.get(j + 1); 112 113 } 114 answer = getanswer(af, so).toString(); 115 try { 116 } catch (Exception e) { 117 e.printStackTrace(); 118 } 119 } 120 121 return question; 122 123 } 124 }
括号维护
1 public String answer; 2 3 Stack<SupportedOperation> oplist = new Stack<SupportedOperation>(); 4 Stack<Fraction> numlist = new Stack<Fraction>(); 5 ArrayList<Integer[]> bclist; 6 TreeMap<Integer, Integer> frequency; 7 TreeMap<Integer, Integer> direction; 8 9 private void getBcPrint(int numOfOperand) { 10 bclist = new ArrayList<Integer[]>(); 11 if (numOfOperand > 2) { 12 int bcnum = (int) (Math.random() * (numOfOperand - 2)); 13 for (int n = 0; n < bcnum; n++) { 14 Integer[] bracket = new Integer[2]; 15 bracket[0] = (int) (Math.random() * (numOfOperand - 2)); 16 bracket[1] = (int) (Math.random() * (numOfOperand - 2 - bracket[0]) + bracket[0]); 17 if (bracket[0] == bracket[1]) { 18 bracket[1]++; 19 } 20 boolean canput = true; 21 for (int i = 0; i < bclist.size(); i++) { 22 Integer[] tmp = bclist.get(i); 23 if (bracket[0] < tmp[0] & bracket[1] >= tmp[0] & bracket[1] < tmp[1]) { 24 canput = false; 25 break; 26 } else if (bracket[1] > tmp[1] & bracket[0] > tmp[0] & bracket[0] <= tmp[1]) { 27 canput = false; 28 break; 29 } else if (bracket[0] == tmp[0] & bracket[1] == tmp[1]) { 30 31 } 32 } 33 if (canput) { 34 bclist.add(bracket); 35 } 36 } 37 38 } 39 frequency = new TreeMap<Integer, Integer>(); 40 direction = new TreeMap<Integer, Integer>(); 41 for (int i = 0; i < bclist.size(); i++) { 42 Integer[] tmp = bclist.get(i); 43 if (frequency.containsKey(tmp[0])) { 44 frequency.put(tmp[0], frequency.get(tmp[0]) + 1); 45 } else { 46 frequency.put(tmp[0], 1); 47 direction.put(tmp[0], 0); 48 } 49 if (frequency.containsKey(tmp[1])) { 50 frequency.put(tmp[1], frequency.get(tmp[1]) + 1); 51 } else { 52 frequency.put(tmp[1], 1); 53 direction.put(tmp[1], 1); 54 } 55 } 56 }
计算结果
1 public Fraction getanswer(ArrayList<Fraction> frlist, SupportedOperation[] so) { 2 3 numlist.push(frlist.get(0)); 4 for (int n = 0; n < so.length; n++) { 5 switch (so[n]) { 6 case ADD: 7 oplist.push(so[n]); 8 numlist.push(frlist.get(n + 1)); 9 break; 10 case MINUS: 11 oplist.push(SupportedOperation.ADD); 12 numlist.push(frlist.get(n + 1).changeSign()); 13 break; 14 case MULTIPLY: { 15 Fraction r = numlist.pop().multiply(frlist.get(n + 1)); 16 numlist.push(r); 17 } 18 break; 19 case DIVIDE: { 20 Fraction r = numlist.pop().divide(frlist.get(n + 1)); 21 numlist.push(r); 22 } 23 break; 24 default: 25 System.out.println("不支持的运算"); 26 break; 27 } 28 } 29 30 while (!oplist.isEmpty()) { 31 Fraction answer = numlist.pop(); 32 switch (oplist.pop()) { 33 case ADD: { 34 answer = answer.add(numlist.pop()); 35 numlist.push(answer); 36 } 37 break; 38 case MINUS: { 39 answer = answer.minus(numlist.pop()); 40 numlist.push(answer); 41 } 42 break; 43 default: 44 System.out.println("不支持的运算"); 45 break; 46 } 47 48 } 49 50 return numlist.pop(); 51 }
程序运行结果:
简单难度答题:
普通难度出题打印:
复杂题目出题打印:
程序退出:
结对编程体会
两个人在一台电脑上进行编码,其实感觉效率未必会提高,编码速度取决于正在编程的人的打字速度。而且有时候反而会因为在同一问题上看法不同、解决方式不同而产生分歧。不过因为结对编程可以了解到他人的编程思路,也是一种学习的过程。所以本次体会觉得效率提高是其次,互相学习才是最大的收获!
争论点:
1.整除问题:输出结果在尽量调节为整数的情况下可能因括号的出现导致结果为小数或者分数,对于这样的情况选择直接重出题目(仅限简单和普通难度的问题);
2.分数减法入栈出栈顺序:计算结果采用栈来解决,出栈时仅剩加减法需要运算,当出现减法,甚至连减时选择将减法换为加法运算,然后改变操作数符号,即Fraction.changSign();
3.括号列表维护:括号生成是根据操作数数量决定的,生成括号位置列表时排除无效和冗余括号,最后将括号列表转化位置和括号方向、数量的Map,用于打印括号,即先有操作数后有括号的设计,而不是括号匹配的方式;
4.连除问题:用计数器检测除法的出现,防止连除,但是不会妨碍一个题目出现两个或更多的除法运算(仅限简单和普通难度)。因为在整数运算中,为保证可以整除,需要改变被除数,这样做太多次连除会导致最顶层操作数过大,不利于题目平衡性。
花费时间较长的问题:括号位置列表生成及维护。
工程地址:https://coding.net/u/jx8zjs/p/paperOne/git
SSH: ssh://git@git.coding.net:jx8zjs/paperOne.git
转载于:https://www.cnblogs.com/regretless/p/5871378.html
结对编程——paperOne基于java的四则运算 功能改进相关推荐
- java周志第二周_20165325 2017-2018-2 《Java程序设计》结对编程_第二周:四则运算
20165325 2017-2018-2 <Java程序设计>结对编程_第二周:四则运算 一.码云链接 1.Git提交日志已经实现一个功能/一个bug修复的注释说明,如图所示: 2.测试代 ...
- 结对编程1-基于GUI的四则运算生成器
https://git.coding.net/kjc976118457/work2.git 201421123017 康建灿 201421123016 郑怀勇 一.需求分析 记录用户的对错总数. 程序 ...
- 结对编程-俞神JAVA代码赏析
结队编程的队友俞神采用了JAVA进行个人项目的编程,项目由五部分组成: 1.main:主程序入口 2.menu:进行了命令行与用户的交互处理 3.Teacher:存储了可以登陆的老师的用户信息 4.Q ...
- spark 中的RDD编程:基于Java api
1.RDD介绍: RDD,弹性分布式数据集,即分布式的元素集合.在spark中,对所有数据的操作不外乎是创建RDD.转化已有的RDD以及调用RDD操作进行求值.在这一切的背后,Spark会自动将RDD ...
- java机票编程_基于java的网上飞机票预订系统
[实例简介] 使用java和sql server 设计的网上飞机票预订系统的详细代码设计.. [实例截图] [核心代码] kys └── kys ├── src │ ├── action │ ...
- java的网络功能与编程_Java的网络功能与编程(转载)
Java的 网络 功能与编程 徐迎晓 (上海大学计算中心25#) 摘 要:Java语言是Internet上最热门的编程语言,本文针对 Java的 网络 功能,对Java从 网络 上获取图象.声音. ...
- 敏捷开发“松结对编程”实践之二:计划与设计篇(大型研发团队,学习型团队,139团队,师徒制度,设计评审,预想陈述,共同估算,扑克牌估算)...
本文是"松结对编程"系列的第二篇.(之一,之二,之三,之四,之五,之六,之七,之八) 新人其实很少偷懒,因为一方面正处于入门学习的高峰期,另一方面工作时间不长需要得到企业和团队的认 ...
- java网上书店管理系统_基于JAVA的网上书店管理系统的开发.doc
基于JAVA的网上书店管理系统的开发 基于 JAVA 的网上书店系统的设计与开发 摘 要 电子商务是一种在互联网上进行商务活动的形式,近年来随着互联网技术的 发展得以迅速普及.如何利用最新互联网编程技 ...
- java web聊天室论文_基于Java网页版聊天室的设计与实现毕业论文含开报告及文献综述.doc...
基于Java网页版聊天室的设计与实现毕业论文含开报告及文献综述 本科生毕业论文(设计) 题 目: 基于Java网页版聊天室的设计与实现 姓 名:学 院: 理学院 专 业: 信息与计算科学 班 级: 信 ...
最新文章
- 死宅福音:乐高不怕多,智能分拣机帮你归类
- 自动驾驶中的车道线跟踪技术
- 用于模拟短信群发情况的随机数产生
- GCC跟NASM联合编译
- 23种设计模式C++源码与UML实现--命令模式
- 动手学无人驾驶(6):基于IMU和GPS数据融合的自车定位
- python中lower()函数的用法
- python 指定版本号
- python写透视挂_python – OpenCV透视变换给出了意想不到的结果
- paip.提升性能---协程“微线程”的使用.
- android首字母检索音乐,ATX 系列 - 如何测试网易云音乐 (Android 篇)
- 架构系列---发号器(全局唯一ID生成器)系统设计方案和思路
- codeforces题解
- 关于OSS如何获得直接访问文件的路径,哪位朋友指点一二??感激不尽
- 近观香港,远看上海,反思深圳
- android7.1 科大讯飞语音引擎设置为首选引擎
- Bibexcel 与 Pajek 基本分析
- [前端积累]--响应式布局(二)
- 轻量级网络--ShuffleNet论文解读
- jQuery事件,对象以及插件
热门文章
- 读书_w3c架构师01通用设计与方法论
- django进阶05中间件
- [转]Serverless,后端小程序的未来
- 企业应该如何运用商业智能
- AIR访问操作系统剪贴板粘贴操作延迟呈现解决办法
- 数据分析学习笔记—python面向对象与模块
- git add 撤销_Git系列——Git添加提交(add)和查看状态(status)
- python图片保存需要在图片展示后_用python处理图片之打开\显示\保存图像的方法...
- 软件工程导论 05章总体设计
- 内网渗透扫描神器 Perun