week2的作业弄到现在week3才开始着手做,所幸截止日期还有几天。

Coding.net源码仓库地址:https://git.coding.net/Agustin_Leonard_DPS/Calculation.git

计划

明确需求及相关因素,指明时间成本和依赖关系

首先,我们这个作业给出了他的需求如下:

  • 程序可接收一个输入参数n,然后随机产生n道加减乘除(分别使用符号+-*÷来表示)练习题,每个数字在 0 和 100 之间,运算符在3个到5个之间。
  • 为了让小学生得到充分锻炼,每个练习题至少要包含2种运算符。同时,由于小学生没有分数与负数的概念,你所出的练习题在运算过程中不得出现负数与非整数,比如不能出 3÷5+2=2.6,2-5+10=7等算式。
  • 练习题生成好后,将你的学号与生成的n道练习题及其对应的正确答案输出到文件“result.txt”中,不要输出额外信息,文件目录与程序目录一致。
  • 当程序接收的参数为4时,以下为一个输出文件示例。

其中,这个作业要求用java语言编写,由于java语言有一段时间没有用(平时多用C),所以找来了以前java的课本复习一下……

开发

分析需求

在生成的n道题中,要求有:

①运算数字:在0~100范围;

②运算符:要有3~5个,且至少要有两种不同的运算符;

③结果&过程:不得出现负数和非整数;

④格式:输出文件为txt形式,即“result.txt”。

生成设计文档(暂无)

设计复审(暂无)

代码规范

与《构建之法》P70所的代码风格规范略有不同,如缩进为Tab,这是个人习惯,在以后的设计过程中会慢慢改正。

具体设计

这个项目开发并不复杂,其中Main和Lib构架设计如下: 

      

Lib:

其中,生成题目的方法有多种,我参考了许征航同学的博客,他是在生成题目的过程中多加限制,确保生成的题目绝对符合规范。此外,我还想到了两种方法:

①在生成题目的过程中,每添加一个运算符和运算数就进行一次判定,判断每个步骤的结果和最终结果是否都符合规范,如果不符合,返回上一步,重新随机生成运算符和运算数;

②先生成若干道题目,编写算法对每个题目都进行一次判定,完全符合规范的题目则通过并添加到“result.txt”文件中,若不符合规范则不添加,重新生成。

我想使用①方法与许征航同学的方法相结合,在少量限定生成的符号与运算数时,每个步骤进行一次判定。

                                                          

                                                                         编辑于

 

2018-03-21)

具体编码

实践永远高于理论,设计时的方案总要通过实践来测试是否可行。其中我修改了许多方案,其中包括多加多层嵌套(if-else)判定,并且多加一个方法用以判断该运算是否符合要求。

最后式子运算的方法总是出错,借用了同学的方法,最后大致成功了,但是或多或少还是有一点bug,出于自己羸弱的代码能力和deadline,这些个问题以后请教同学后慢慢解决。

lib文件:

package src;
import java.io.*;
public class Lib {
private static char[] sign = new char[] {'+', '-', '*', '÷'};

public static int Random(int min, int max){
return (int) (Math.random()*(max - min) + min + 0.5);
}
public static void CreateQues(String Ques[] ,int QuesNum ) {/*创建问题,QuseNum是问题数,OpNum是每个问题的运算符数 */
char Sign[] = new char[20];/*运算符*/
int Num[] = new int [20];/*运算数*/

for(int i = 0;i<QuesNum;i++) {
Num[0] = Random(1,100);
int OpNum = Random(3,5);

int result[] = new int [10];/*储存算式中每个不走的运算结果*/
for(int j = 0;j<OpNum;j++) {
int flag = 1;
addSignNum(Sign,Num,j);
if(j==0) 
{
result[j] = calQues(Num,Sign[j],j);
flag = isCorrect(Num,Sign[j],j);
if(flag == -1) {
result[0]= Num[0];j--;continue;
}
}
else if (j>0)
{    
if (Sign[j]=='*'||Sign[j]=='÷')
{
if(j == 1)
result[0] = Num[0];
else
result[j-1] = result[j-2];
result[j] = calQues(Num,Sign[j],j);
flag = isCorrect(Num,Sign[j],j);
if(flag == -1) {
result[j] = result[j-1];j--;continue;
}
result[j] = calQues(result,Sign[j-1],j-1);
flag = isCorrect(result,Sign[j-1],j-1);
if(flag == -1) {
result[j] = result[j-1];j--;continue;
}
}
if(Sign[j]=='-'||Sign[j]=='+')
{    
if(result[j-1]<0) {
j=j-2;continue;

}
result[j] = Num[j+1];
result[j] = calQues(result,Sign[j],j-1);
flag = isCorrectPlus(result[j]);
if(flag == -1) {
result[j] = result[j-1];j--;continue;
}
}
}


}
/*for(int k=0;k<result.length;k++)
System.out.println(result[k]);-*/
String question = "" + Num[0];
for(int k = 0;k<OpNum;k++) 
question = question + Sign[k] + Num[k+1];
question = question + "=" +calQuestion(question);
System.out.println(question);
Ques[i] = question;
}
}
public static void addSignNum(char a[] , int b[],int c) {
if(c!=0 &&(a[c-1]== '*'||a[c-1]== '÷')) a[c] = sign[Random(0,1)];
else a[c] = sign[Random(0,3)];
if(a[c] == '÷') b[c+1] = Random(2,10);
else b[c+1] = Random(0,100); /*这里考虑到除号后面不能为0,进行一步限制*/
}
public static int calQues(int a[],char b,int c) {
if(b == '+') return a[c]+a[c+1];
else if(b == '-') return a[c]-a[c+1];
else if(b == '*') return a[c]*a[c+1];
else if(b == '÷') return a[c]/a[c+1];
return -1;
}
public static int isCorrect(int a[],char b,int c) {
int flag = 1;
if(b == '-'&& a[c] - a[c+1]<0) flag = -1;
if(b == '÷'&& a[c] % a[c+1]!=0) flag = -1;
return flag;
}
public static int isCorrectPlus(int a) {
if(a<0) return -1;
else return 1;
}
static public void filePrint(String[] Ques, int QuesNum, String path) throws IOException{
FileOutputStream fs = new FileOutputStream(new File(path));
PrintStream p = new PrintStream(fs);
p.println("2016012033");
for(int i=0; i<QuesNum; i++)
p.println(Ques[i]);
p.close();
}
static private int calQuestion(String question){
char[] ch = new char[50];
char[] oc = new char[15]; 
int[] num = new int[15];
int temp = 0, pn = -1, pc = -1;
ch = question.toCharArray();

for(int i=0; i<ch.length; i++){
if(Character.isDigit(ch[i])) {
temp = temp*10 + ch[i]-'0'; 
if(i == ch.length-1)
num[++pn] = temp; 
}
else {
num[++pn] = temp; 
temp = 0;

while(pc!=-1 && getw(oc[pc]) >= getw(ch[i]) ) {
int num1 = num[pn--];
int num2 = num[pn--];
char ch1 = oc[pc--];
num[++pn] = calc(num2, num1, ch1);
}

//if(pc == -1) oc[++pc] = ch[i];
oc[++pc] = ch[i];
}
}

while(pc != -1) {
int num1 = num[pn--];
int num2 = num[pn--];
char ch1 = oc[pc--];
num[++pn] = calc(num2, num1, ch1);
}

return num[0];
}
static private int getw(char c){
if(c=='*' || c=='÷') return 2;
else if(c=='+' || c=='-') return 1;
else return -1;
}

static private int calc(int a, int b, char c) {

//System.out.println("" + a +c + b);

if(c == '+') return a + b;
else if(c == '-') return a - b;
else if(c == '*') return a * b;
else if(c == '÷') return a / b;
else return -1;
}
}

 

 

main文件:

package src;

import java.io.IOException;

import java.util.*;

public class Main {

    public static void main(String[] args) {

        Scanner input = new Scanner(System.in);

        String path = "result.txt";

        String[] Ques = new String[100];

        int QuesNum;

        

        System.out.println("现在!让我们决定要多少道(0~100)四则运算题,然后我们把它们rua出来!");

        QuesNum = input.nextInt();

        Lib.CreateQues(Ques, QuesNum);

        try {

            Lib.filePrint(Ques, QuesNum, path);

        }

        catch(IOException ioe) {

            ioe.printStackTrace();

        }

        input.close();

    }

}

总结

整出一个四则运算题出题系统其实不难(我之前一篇博客:http://www.cnblogs.com/longaotian/p/8526473.html),不过当时的要求少,而且不限语言,我自然用的是我熟练的C语言,但是在加了这么多条件和限制后,这两个问题的难度就不是一个等级的了。同时受限于自身的代码能力(被自己菜哭了)……其中仍然会有一些bug如偶尔还是会出现结果为负数的情况,这些我会在以后的课余时间里请教同学并且修复这些问题。在这里要感谢许征航同学的帮助,他帮我找出了我的代码里许多导致bug的地方并提出一些修改建议,在这个过程中我也学到了许多,如控制变量并且进行简单的单元测试等,获益良多。

PSP展示

  花费时间(单位:h) 花费时间百分比(%)
计划 0.5     1  
明确需求 0.5   1
开发 24.6 90
需求分析 0.5 1
代码规范 0.1 0.2
具体设计 3 11
具体编码 18 66
代码复审&测试 3 11
报告 2 4
测试报告 1   2
计算工作量 0.5 1
事后总结 0.5 1

dpackage src;import java.io.*;public class Lib {private static char[] sign = new char[] {'+', '-', '*', '÷'};public static  int Random(int min, int max){        return (int) (Math.random()*(max - min) + min + 0.5);    }public static void CreateQues(String Ques[] ,int QuesNum ) {/*创建问题,QuseNum是问题数,OpNum是每个问题的运算符数 */char Sign[] = new char[20];/*运算符*/int  Num[] = new int [20];/*运算数*/for(int i = 0;i<QuesNum;i++) {Num[0] = Random(1,100);int OpNum = Random(3,5);
int result[] = new int [10];/*储存算式中每个不走的运算结果*/for(int j = 0;j<OpNum;j++) {int flag = 1;addSignNum(Sign,Num,j);if(j==0) {result[j] = calQues(Num,Sign[j],j);flag = isCorrect(Num,Sign[j],j);if(flag == -1) {result[0]= Num[0];j--;continue;}}else if (j>0){if (Sign[j]=='*'||Sign[j]=='÷'){if(j == 1)result[0] = Num[0];elseresult[j-1] = result[j-2];result[j] = calQues(Num,Sign[j],j);flag = isCorrect(Num,Sign[j],j);if(flag == -1) {result[j] = result[j-1];j--;continue;}result[j] = calQues(result,Sign[j-1],j-1);flag = isCorrect(result,Sign[j-1],j-1);if(flag == -1) {result[j] = result[j-1];j--;continue;}}if(Sign[j]=='-'||Sign[j]=='+'){if(result[j-1]<0) {j=j-2;continue;}result[j] = Num[j+1];result[j] = calQues(result,Sign[j],j-1);flag =  isCorrectPlus(result[j]);if(flag == -1) {result[j] = result[j-1];j--;continue;}}}}/*for(int k=0;k<result.length;k++)System.out.println(result[k]);-*/String question = "" + Num[0];for(int k = 0;k<OpNum;k++) question = question + Sign[k] + Num[k+1];question = question + "=" +calQuestion(question);System.out.println(question);Ques[i] = question;}}public static void addSignNum(char a[] , int b[],int c) {if(c!=0 &&(a[c-1]== '*'||a[c-1]== '÷')) a[c] = sign[Random(0,1)];else a[c] = sign[Random(0,3)];if(a[c] == '÷') b[c+1] = Random(2,10);else b[c+1] = Random(0,100);    /*这里考虑到除号后面不能为0,进行一步限制*/}public static int calQues(int a[],char b,int c) {if(b == '+') return a[c]+a[c+1];else if(b == '-') return a[c]-a[c+1];else if(b == '*') return a[c]*a[c+1];else if(b == '÷') return a[c]/a[c+1];return -1;}public static int isCorrect(int a[],char b,int c) {int flag = 1;if(b == '-'&& a[c] - a[c+1]<0) flag = -1;if(b == '÷'&& a[c] % a[c+1]!=0) flag = -1;return flag;}public static int isCorrectPlus(int a) {if(a<0) return -1;else return 1;}static public void filePrint(String[] Ques, int QuesNum, String path) throws IOException{        FileOutputStream fs = new FileOutputStream(new File(path));        PrintStream p = new PrintStream(fs);        p.println("2016012033");        for(int i=0; i<QuesNum; i++)            p.println(Ques[i]);        p.close();    }    static private int calQuestion(String question){        char[] ch = new char[50];        char[] oc = new char[15];         int[] num = new int[15];        int temp = 0, pn = -1, pc = -1;  //temp用于存放中间数值,pn用于在num数组中模拟栈顶, pc用于在ch数组中模拟栈顶                ch = question.toCharArray();                for(int i=0; i<ch.length; i++){            if(Character.isDigit(ch[i])) {                temp = temp*10 + ch[i]-'0';                 if(i == ch.length-1)                    num[++pn] = temp;   //最后一个数入栈            }            else {                num[++pn] = temp;       //temp入栈                temp = 0;                                while(pc!=-1 && getw(oc[pc]) >= getw(ch[i]) ) {                    int num1 = num[pn--];                    int num2 = num[pn--];                    char ch1 = oc[pc--];                    num[++pn] = calc(num2, num1, ch1);                }                                //if(pc == -1) oc[++pc] = ch[i];                oc[++pc] = ch[i];            }        }                while(pc != -1) {            int num1 = num[pn--];            int num2 = num[pn--];            char ch1 = oc[pc--];            num[++pn] = calc(num2, num1, ch1);        }                return num[0];    }    static private int getw(char c){        if(c=='*' || c=='÷') return 2;        else if(c=='+' || c=='-') return 1;        else return -1;    }        static private int calc(int a, int b, char c) {                //System.out.println("" + a +c + b);                if(c == '+') return a + b;        else if(c == '-') return a - b;        else if(c == '*') return a * b;        else if(c == '÷') return a / b;        else return -1;    }}