軟件工程我的做業01

題目:     

像二柱子那樣,花二十分鐘寫一個能自動生成三十道小學四則運算題目的 「軟件」,要求:除了整數之外,還要支持真分數的四則運算(須要驗證結果的正確性)、題目避免重複、可定製出題的數量。(有能力者改編成網頁版)java

設計思想: 

  • 項目名稱:CTXT
  • 包名稱:cn.simo
  • 文件名稱:
    1. Arithmetic.java
    2. ChangeToFenshuDemo.java
    3. CT.java
  • main方法在文件3中,文件1中的GetQueston_int()和GetQuestion_div()方法分別用來生成整數表達式和分數表達式;
  • 文件1中定義了arithmetic()方法來求解表達式字符串的結果(返回值double型),支持分數表達式;
  • 文件2中定義了toFenshu()方法來將小數轉化成分數,在GetQuestion_div()中使用它能夠生成小於1的隨機分數;
  • 當已作題數到達5的倍數時就出一道分數題,不然出整數題;
  • 定義一個大小30的字符串數組盛放已作題目,生成題目時須要判斷是否已經作過;
  • 在文件1中計算除法時,運算數是BigDecimal型的,使用divide方法運算時若是沒有告訴計算機小數位精確到哪位的話,將結果分爲小數部分和整數部分,小數部分可能由於超過int數值範圍而報錯,因此須要在81行位置指定精度2。

源代碼:

Github源碼:git@github.com:54Simo/Java-Tutorial.gitgit

Arithmetic.javagithub

package cn.simo;

import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/** 
 * 四則運算表達式計算 
 * @see 功能:能夠用arithmetic返回一個double類型的結果,在calculate方法中由「劉立偉」設置了精度解決某些BUG。
 * @author penli 
 */  
public class Arithmetic {  
    public static double arithmetic(String exp){  
        String result = parseExp(exp).replaceAll("[\\[\\]]", "");  
        return Double.parseDouble(result);  
    }  
    /** 
     * 解析計算四則運算表達式,例:2+((3+4)*2-22)/2*3 
     * @param expression 
     * @return String
     */  
    public static String parseExp(String expression){  
        //String numberReg="^((?!0)\\d+(\\.\\d+(?<!0))?)|(0\\.\\d+(?<!0))$";  
        expression=expression.replaceAll("\\s+", "").replaceAll("^\\((.+)\\)$", "$1");  
        String checkExp="\\d";  
        String minExp="^((\\d+(\\.\\d+)?)|(\\[\\-\\d+(\\.\\d+)?\\]))[\\+\\-\\*\\/]((\\d+(\\.\\d+)?)|(\\[\\-\\d+(\\.\\d+)?\\]))$";  
        //最小表達式計算  
        if(expression.matches(minExp)){  
            String result=calculate(expression);  
              
            return Double.parseDouble(result)>=0?result:"["+result+"]";  
        }  
        //計算不帶括號的四則運算  
        String noParentheses="^[^\\(\\)]+$";  
        String priorOperatorExp="(((\\d+(\\.\\d+)?)|(\\[\\-\\d+(\\.\\d+)?\\]))[\\*\\/]((\\d+(\\.\\d+)?)|(\\[\\-\\d+(\\.\\d+)?\\])))";  
        String operatorExp="(((\\d+(\\.\\d+)?)|(\\[\\-\\d+(\\.\\d+)?\\]))[\\+\\-]((\\d+(\\.\\d+)?)|(\\[\\-\\d+(\\.\\d+)?\\])))";  
        if(expression.matches(noParentheses)){  
            Pattern patt=Pattern.compile(priorOperatorExp);  
            Matcher mat=patt.matcher(expression);  
            if(mat.find()){  
                String tempMinExp=mat.group();  
                expression=expression.replaceFirst(priorOperatorExp, parseExp(tempMinExp));  
            }else{  
                patt=Pattern.compile(operatorExp);  
                mat=patt.matcher(expression);  
                  
                if(mat.find()){  
                    String tempMinExp=mat.group();  
                    expression=expression.replaceFirst(operatorExp, parseExp(tempMinExp));  
                }  
            }  
            return parseExp(expression);  
        }  
        //計算帶括號的四則運算  
        String minParentheses="\\([^\\(\\)]+\\)";  
        Pattern patt=Pattern.compile(minParentheses);  
        Matcher mat=patt.matcher(expression);  
        if(mat.find()){  
            String tempMinExp=mat.group();  
            expression=expression.replaceFirst(minParentheses, parseExp(tempMinExp));  
        }  
        return parseExp(expression);  
    }  
    /** 
     * 計算最小單位四則運算表達式(兩個數字) 
     * @param exp 
     * @return String
     */  
    public static String calculate(String exp){  
        exp=exp.replaceAll("[\\[\\]]", "");  
        String number[]=exp.replaceFirst("(\\d)[\\+\\-\\*\\/]", "$1,").split(",");  
        BigDecimal number1=new BigDecimal(number[0]);  
        BigDecimal number2=new BigDecimal(number[1]);  
        BigDecimal result=null;  
        /*
         * 設置精度,不然報錯(計算機並不知道要保留幾位,因此很乾脆的報錯)
         * By 劉立偉
         */
        MathContext mc = new MathContext(2, RoundingMode.HALF_DOWN);
        //精度爲2,舍入模式爲大於0.5進1,不然捨棄。 
        
        String operator=exp.replaceFirst("^.*\\d([\\+\\-\\*\\/]).+$", "$1");  
        if("+".equals(operator)){  
            result=number1.add(number2);  
        }else if("-".equals(operator)){  
            result=number1.subtract(number2);  
        }else if("*".equals(operator)){  
            result=number1.multiply(number2);  
        }else if("/".equals(operator)){  
            result=number1.divide(number2,mc);  
        }  
          
        return result!=null?result.toString():null;  
    }  
}  

ChangeToFenshuDemo.java算法

package cn.simo;  

/**
 * 小數轉分數
 * @author Happy_Girl2012
 */
public class ChangeToFenshuDemo {  
	/**
	 * 取得公約數
	 * @param a
	 * @param b
	 * @return int
	 */
    public static int getGongYueShu(int a, int b) {//求兩個數的最大公約數  
        int t = 0;  
        if(a < b){  
        t = a;  
        a = b;  
        b = t;  
        }  
        int c = a % b;  
        if(c == 0){  
            return b;  
        }else{  
            return getGongYueShu(b, c);  
        }  
    }  
    /**
     * 轉化成分數
     * @param xiaoshu
     * @return String
     */
    public static String toFenshu(String xiaoshu) {   
  
        String[] array = new String[2];  
        array = xiaoshu.split("\\.");  
        int a = Integer.parseInt(array[0]);//獲取整數部分  
        int b = Integer.parseInt(array[1]);//獲取小數部分  
        int length = array[1].length();  
        int FenZi = (int) (a * Math.pow(10, length) + b);  
        int FenMu = (int) Math.pow(10, length);  
        int MaxYueShu = getGongYueShu(FenZi, FenMu);  
        return new String(FenZi / MaxYueShu + "/" + FenMu / MaxYueShu);  
    }  
  
}  

CT.javaexpress

package cn.simo;

import java.util.Scanner;
/**
 * 小學生出題系統(30道四則運算題)
 * @author www.cnsimo.cn
 * @since 2017-03-07 21:53:14
 */
public class CT {

	public static String str = "";//保存題目的字符串
    public static int num = 5;//每題中數的個數
    public static int num_i = 0;//題目中已有數的個數    
    public static int numberRange = 100;//運算中數的最大取值    
    public static double sum = 0;//記錄結果
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		System.out.println("注意:結果保留1位小數!");
		System.out.println("共30道題目:");
		Scanner in = new Scanner(System.in);
		double answer = 0;
		double result = 0;
		String[] question = new String[30];
		int questionNumber = 0;
		int answerTrue = 0;
		boolean flag;
		for(;;) {
			answer = 0; result = 0; flag = true; str="";
			if((questionNumber + 1)%5 != 0) {
				GetQuestion_int();
			} else {
				GetQuestion_div();
			}
			for(int j = questionNumber-1; j >= 0; j --) {
				if(question[j].equals(str)) {
					flag = false; break;
				}
			}
			if(!flag) continue;
			else {question[questionNumber] = new String(str); questionNumber++;}
			System.out.print("" + questionNumber + ". " + str+" = ");
			answer = in.nextDouble();
			if(!str.isEmpty()) {
				result = Arithmetic.arithmetic(str);
			}
			if(answer == result) {
				System.out.println("   ✔️");
				answerTrue++;
			} else {
				System.out.println("   ❌ " + "  正確答案:" + result);
			}
			
			if(questionNumber == 30) break;         // 滿30個跳出
		}
		
		System.out.println("你的正確機率:" + answerTrue + "/30");
		in.close();
	}
	
    private static void GetQuestion_int() {
        //獲得問題函數,在這裏調用遞歸函數quesGrow()。
        str = "";
        sum = 0;
        num_i = num;//用前都清零
        quesGrow_int();
    }
    
    private static void GetQuestion_div() {
    	str = "";
        sum = 0;
        num_i = num;//用前都清零
        quesGrow_div();
    }

    private static void quesGrow_int() {
        //
        if( num_i > 1 ) {
            int j = num_i;//記錄這是第幾層調用。
            num_i--;
            quesGrow_int();//遞歸
            
            int w=1+(int)(Math.random()*numberRange);//隨機生成一個數
            int t=1+(int)(Math.random()*100);//向左生成,仍是向右生成,相似於樹。
            int f=1+(int)(Math.random()*100);//運算符控制
            
            if(t>50)//新數往右加
            {
                if(f>50) {
                    sum = sum + w;
                    str = str + "+" + String.valueOf( w );
                }
                else {
                    sum = sum - w;
                    str = str + "-" + String.valueOf( w );        
                }
            }
            else//不然 新數往左加
            {
                if(f>50) {
                    sum = w + sum;
                    str = String.valueOf( w ) + "+" + str;    
                }
                else {
                    if( j < 3 ) {//3——摸索出的數,不用給本身套上括號。實際上就是j=2
                        sum = w - sum;
                        str = String.valueOf( w ) + "-" + str;
                    }
                    else {
                        sum = w - sum;
                        str = String.valueOf( w ) + "-" + "(" +str+ ")";
                        //向左添減法的時候加括號,打破順序計算模式。
                    }
                }
            }
        }
        else if( num_i == 1 ) {
            //最後一層,也是輸出的第一層
            int w=1+(int)(Math.random()*numberRange);
            sum = sum + w;
            str = str + String.valueOf( w );
        }
    }
    
    private static void quesGrow_div() {
    	if( num_i > 1 ) {
            int j = num_i;//記錄這是第幾層調用。
            num_i--;
            quesGrow_div();//遞歸
            
            double w=Math.random();//隨機生成一個數
            int t=1+(int)(Math.random()*100);//向左生成,仍是向右生成,相似於樹。
            int f=1+(int)(Math.random()*100);//運算符控制
            
            if(t>50)//新數往右加
            {
                if(f>50) {
                    sum = sum + w;
                    str = str + "+" + ChangeToFenshuDemo.toFenshu((""+(w+0.01)).substring(0, 4));
                }
                else {
                    sum = sum - w;
                    str = str + "-" + ChangeToFenshuDemo.toFenshu((""+(w+0.01)).substring(0, 4));        
                }
            }
            else//不然 新數往左加
            {
                if(f>50) {
                    sum = w + sum;
                    str = ChangeToFenshuDemo.toFenshu((""+(w+0.01)).substring(0, 4)) + "+" + str;    
                }
                else {
                    if( j < 3 ) {//3——摸索出的數,不用給本身套上括號。實際上就是j=2
                        sum = w - sum;
                        str = ChangeToFenshuDemo.toFenshu((""+(w+0.01)).substring(0, 4)) + "-" + str;
                    }
                    else {
                        sum = w - sum;
                        str = ChangeToFenshuDemo.toFenshu((""+(w+0.01)).substring(0, 4)) + "-" + "(" +str+ ")";
                        //向左添減法的時候加括號,打破順序計算模式。
                    }
                }
            }
        }
        else if( num_i == 1 ) {
            //最後一層,也是輸出的第一層
            double w=Math.random();
            sum = sum + w;
            str = str + ChangeToFenshuDemo.toFenshu((""+(w+0.01)).substring(0, 4));
        }
	}
}

運行結果: 

總結: 

平時要善於積累經常使用的算法,以及本身寫的以爲有用的代碼;數組

寫代碼時,千萬不要全部的東西都疊在一個方法裏面,根據功能寫相應的方法,之後用的時候能夠直接調用;app

相關文章
相關標籤/搜索