热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

简易四则运算生成程序——第一次改进

变更后的需求1.程序运行在终端或控制台上2.程序可以扩展出优秀界面,即核心部分可重用并可拓展3.题目可包含括号4.限定题目数量,精美打印输出5.支持分数出题和运算6.约分和带分数分析和设计1.原

变更后的需求

1.程序运行在终端或控制台上

2.程序可以扩展出优秀界面,即核心部分可重用并可拓展

3.题目可包含括号

4.限定题目数量,"精美"打印输出

5.支持分数出题和运算

6.约分和带分数

 

分析和设计

1.原出题程序为网页版,现在新建了一个加载出题核心的类用于在终端中提供用户使用,并带有提示和运行逻辑。

2.核心出题类提供多种需求参数列表,并作出相应处理,为不同难度和需求生成相应题目。

3.括号和题目计算部分可以使用"逆波兰","后缀表达式"或"堆栈",本程序计算部分选择使用栈维护运算数和运算符,用ArrayList维护随机生成的括号位置列表,然后使用TreeMap计算并保存应该生成括号的位置,最后在题目生成的时候进行拼接。

4.题目数量可以由用户自行输入,输入题目难度和数量以后可选择答题模式或者打印模式,答题模式可以边答题边判题,错误的给出正确答案,最后生成答题结果,即答题正确数量和错误数量。打印模式则直接生成相应数量题目并给出结果。

5.分数运算则新建Fraction类,并添加加减乘除的相应函数,注意java不支持运算符重载,Fraction类包含随机生成函数,可以生成随机的分数,并保证不为0或者分母为零,以免发生除零错误。

6.类中还包含一个约分函数,方便运算和减少溢出情况的发生。带分数可以使用%运算符来求出,通过重新toSting函数来输出带分数。

 

程序的使用设计

程序启动时用户选择题目难度或者查看题目难度说明,然后选择出题数量,接着选择运行模式,即直接查看答案的打印模式还是边出题边答题的答题模式。

简易运行流程图:

部分代码实现

Fraction类定义(分数类),截取部分

  1 package cn.edu.nenu.cw2016.zjs.paperUtil;
2
3 public class Fraction {
4 public int up;
5 public int down;
6
7 public Fraction(int up, int down) {
8 if (down == 0 | up == 0) {
9 System.out.println("divided by zero error");
10 return;
11 }
12 int smaller = up > down ? up : down;
13 int maxCommOnFactor= 1;
14 for (int i = 1; i <= smaller; i++) {
15 if (up % i == 0 && down % i == 0) {
16 maxCommOnFactor= i;
17 }
18 }
19
20 this.up = up / maxCommonFactor;
21 this.down = down / maxCommonFactor;
22 }
23
24 public Fraction(Fraction f) {
25 if (f.down == 0 | up == 0) {
26 System.out.println("divided by zero error");
27 return;
28 }
29
30 f = f.gcd(f);
31 this.up = f.up;
32 this.down = f.down;
33 }
34
35 public Fraction gcd(Fraction f) {
36 int smaller = f.up > f.down ? f.up : f.down;
37 int maxCommOnFactor= 1;
38 for (int i = 1; i <= smaller; i++) {
39 if (f.up % i == 0 && f.down % i == 0) {
40 maxCommOnFactor= i;
41 }
42 }
43 f.up = f.up / maxCommonFactor;
44 f.down = f.down / maxCommonFactor;
45
46 return f;
47 }
48
49 public String toString() {
50 if (down == 1)
51 return "" + up;
52 if(Math.abs(up)/down>0){
53 return up>0?up/down+" "+up%down+"/"+down:"-"+Math.abs(up)/down+" "+Math.abs(up)%down+"/"+down;
54 }
55 return up + "/" + down;
56 }
57
58 public Fraction add(Fraction f) {
59 Fraction a = new Fraction(up, down);
60 a.up = f.up * a.down + a.up * f.down;
61 a.down = a.down * f.down;
62
63 return a.gcd(a);
64 }
65
66 public Fraction minus(Fraction f) {
67 Fraction a = new Fraction(up, down);
68 a.up = a.up * f.down - f.up * a.down;
69 a.down = a.down * f.down;
70
71 return a.gcd(a);
72 }
73
74 public Fraction multiply(Fraction f) {
75 Fraction a = new Fraction(up, down);
76 a.up = a.up * f.up;
77 a.down = a.down * f.down;
78 return a.gcd(a);
79 }
80
81 public Fraction divide(Fraction f) {
82 Fraction a = new Fraction(up, down);
83 a.up = a.up * f.down;
84 a.down = a.down * f.up;
85 return a.gcd(a);
86 }
87
88 public Fraction changeSign(){
89 up = -up;
90 return this;
91 }
92
93 public static Fraction getRandiom(int Max) {
94 return new Fraction((int) (Math.random() * Max / 2) + 1, (int) (Math.random() * Max / 2) + 1);
95 }
96
97 public static Fraction getRandiom(int Max, boolean isInt) {
98 return new Fraction((int) (Math.random() * Max / 2) + 1, isInt ? 1 : (int) (Math.random() * Max / 2) + 1);
99 }
100 }

题目生成

  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 af = new ArrayList();
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 ) {
20 ioperands[i] = (int) (Math.random() * rangMax / 2 + 1);
21
22 }
23 so = new SupportedOperation[numOfOperand - 1];
24 for (int i = 0; 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 ) {
52 if (frequency.containsKey(i)) {
53 if (direction.get(i) == 0) {
54 for (int k = 0; 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 ) {
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 ) {
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 ) {
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 ) {
94 af.add(Fraction.getRandiom(rangMax));
95 }
96
97 so = new SupportedOperation[numOfOperand - 1];
98 for (int i = 0; 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 ) {
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 oplist = new Stack();
4 Stack numlist = new Stack();
5 ArrayList bclist;
6 TreeMap frequency;
7 TreeMap direction;
8
9 private void getBcPrint(int numOfOperand) {
10 bclist = new ArrayList();
11 if (numOfOperand > 2) {
12 int bcnum = (int) (Math.random() * (numOfOperand - 2));
13 for (int n = 0; 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 ) {
22 Integer[] tmp = bclist.get(i);
23 if (bracket[0] = tmp[0] & bracket[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();
40 direction = new TreeMap();
41 for (int i = 0; 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 }
57
58 public Fraction getanswer(ArrayList frlist, SupportedOperation[] so) {
59
60 numlist.push(frlist.get(0));
61 for (int n = 0; n ) {
62 switch (so[n]) {
63 case ADD:
64 oplist.push(so[n]);
65 numlist.push(frlist.get(n + 1));
66 break;
67 case MINUS:
68 oplist.push(SupportedOperation.ADD);
69 numlist.push(frlist.get(n + 1).changeSign());
70 break;
71 case MULTIPLY: {
72 Fraction r = numlist.pop().multiply(frlist.get(n + 1));
73 numlist.push(r);
74 }
75 break;
76 case DIVIDE: {
77 Fraction r = numlist.pop().divide(frlist.get(n + 1));
78 numlist.push(r);
79 }
80 break;
81 default:
82 System.out.println("不支持的运算");
83 break;
84 }
85 }
86
87 while (!oplist.isEmpty()) {
88 Fraction answer = numlist.pop();
89 switch (oplist.pop()) {
90 case ADD: {
91 answer = answer.add(numlist.pop());
92 numlist.push(answer);
93 }
94 break;
95 case MINUS: {
96 answer = answer.minus(numlist.pop());
97 numlist.push(answer);
98 }
99 break;
100 default:
101 System.out.println("不支持的运算");
102 break;
103 }
104
105 }
106
107 return numlist.pop();
108 }

 

程序运行结果:

简单难度答题:

普通难度出题打印:

复杂题目出题打印:

程序退出:

结对编程体会

结对编程可以了解队友的编程习惯和解决问题的思路,学习对方的解决问题方式,而且当一个人遇到瓶颈的时候,另一个人可能会提前想出思路,多种解决方式的时候可以择优选择。这种工作模式有点像cpu的双核处理器,两个线程同时工作,一定程度上可以快速的开发项目,并减少代码合并带来的麻烦。这个工作模式以前也是尝试过的,尤其是主要作为指导在旁边跟进时效率不一定会很高,思维的协调不一定比直接看结果来的快,不过对于学习阶段很是受用。

争论点:

1.整除问题:输出结果在尽量调节为整数的情况下可能因括号的出现导致结果为小数或者分数,对于这样的情况选择直接重出题目(仅限简单和普通难度的问题)

2.分数减法入栈出栈顺序:计算结果采用栈来解决,出栈时仅剩加减法需要运算,当出现减法,甚至连减时选择将减法换为加法运算,然后改变操作数符号,即Fraction.changSign();

3.括号列表维护:括号生成是根据操作数数量决定的,生成括号位置列表时排除无效和冗余括号,最后将括号列表转化位置和括号方向、数量的Map,用于打印括号,即先有操作数后有括号的设计,而不是括号匹配的方式

4.连除问题:用计数器检测除法的出现,防止连除,但是不会妨碍一个题目出现两个或更多的除法运算(仅限简单和普通难度)。因为在整数运算中,为保证可以整除,需要改变被除数,这样做太多次连除会导致最顶层操作数过大,不利于题目平衡性

花费时间较长的问题:括号列表维护

 

结对编程照片: 

 

工程地址:https://coding.net/u/jx8zjs/p/paperOne/git

ssh://git@git.coding.net:jx8zjs/paperOne.git


推荐阅读
  • WPF之Binding初探
      初学wpf,经常被Binding搞晕,以下记录写Binding的基础。首先,盗用张图。这图形象的说明了Binding的机理。对于Binding,意思是数据绑定,基本用法是:1、 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 前景:当UI一个查询条件为多项选择,或录入多个条件的时候,比如查询所有名称里面包含以下动态条件,需要模糊查询里面每一项时比如是这样一个数组条件:newstring[]{兴业银行, ... [详细]
  • IjustinheritedsomewebpageswhichusesMooTools.IneverusedMooTools.NowIneedtoaddsomef ... [详细]
  • EPPlus绘制刻度线的方法及示例代码
    本文介绍了使用EPPlus绘制刻度线的方法,并提供了示例代码。通过ExcelPackage类和List对象,可以实现在Excel中绘制刻度线的功能。具体的方法和示例代码在文章中进行了详细的介绍和演示。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 推荐系统遇上深度学习(十七)详解推荐系统中的常用评测指标
    原创:石晓文小小挖掘机2018-06-18笔者是一个痴迷于挖掘数据中的价值的学习人,希望在平日的工作学习中,挖掘数据的价值, ... [详细]
  • 本文介绍了Java高并发程序设计中线程安全的概念与synchronized关键字的使用。通过一个计数器的例子,演示了多线程同时对变量进行累加操作时可能出现的问题。最终值会小于预期的原因是因为两个线程同时对变量进行写入时,其中一个线程的结果会覆盖另一个线程的结果。为了解决这个问题,可以使用synchronized关键字来保证线程安全。 ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • 这是一个愚蠢的问题,但我只是对此感到好奇.假设我在Pythonshell,我有一些我查询的数据库对象.我做:db.query(的queryString)该查询在0xffdf842c ... [详细]
author-avatar
捕鱼达人2602884285
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有