個人項目實戰-四則混合運算

代碼倉庫地址:https://dev.tencent.com/u/qingYinGuo/p/software_homework/git

測試效果見result.txt文件

一、 需求分析與功能設計

任務1

    使用JAVA編程語言,獨立完成一個35個運算符的四則運算練習的軟件。

軟件基本功能要求如下:

  • 程序可接收一個輸入參數n,然後隨機產生n道加減乘除(分別使用符號+-*÷來表示)練習題,每個數字在 0 和 100 之間,運算符在3個到5個之間。
  • 每個練習題至少要包含2種運算符。同時,由於小學生沒有分數與負數的概念,你所出的練習題在運算過程中不得出現負數與非整數,比如不能出 3÷5+2=2.6,2-5+10=7等算式。
  • 練習題生成好後,將你的學號與生成的n道練習題及其對應的正確答案輸出到文件“result.txt”中,不要輸出額外信息,文件目錄與程序目錄一致。
  • 當程序接收的參數爲4時,以下爲一個輸出文件示例。

2018010203

13+17-1=29

11*15-5=160

3+10+4-16=1

15÷5+3-2=4

軟件附加功能要求如下:(請有餘力的同學完成)

  • 支持有括號的運算式,包括出題與求解正確答案。注意,算式中存在的括號數必須大於2對,且不得超過運算符的個數。
  • 擴展程序功能支持真分數的出題與運算(只需要涵蓋加減法即可),例如:1/6 + 1/8 + 2/3= 23/24。注意在實現本功能時,需支持運算時分數的自動化簡,比如 1/2+1/6=2/3,而非4/6,且計算過程中與結果都須爲真分數

二、 設計實現

項目的目錄結構

 

 

  • Main類:主類,負責接收命令行的參數並啓動程序。
  • GenerateFile類:創建文件類,負責每次出題類型併產生result.text文件,將學號與練習題寫入文件。
  • GenerateFormula類:式子類,負責根據調用產生各類型的式子,簡單四則運算、帶括號的四則運算、真分數加減運算。
  • Calculator類:計算類,負責各種計算,含有結果運算、有條件產生減數、有條件產生除數、有條件產生分子、有條件產生分母、判斷數的大小、求取最大公因數、求取最小公倍數、分數相加、分數相減等方法。

二、收穫點

1.利用js的eval函數對生成的四則運算進行計算,簡化了很多的代碼

static ScriptEngine scriptEngine=
			new ScriptEngineManager().getEngineByName("JavaScript");
	public static Object calulate(String str){
		//爲什麼定義時一定要帶上=0?
		Object result=0;
		try {
			 result=scriptEngine.eval(str);
		} catch (ScriptException e) {
			e.printStackTrace();
		}
		return result;
	}

2.最小公倍數簡單算法的實現

	//最小公倍數
	
	public static int lcm(int num1,int num2){
		int lcm=num1;
		while(lcm%num1!=0||lcm%num2!=0){
			lcm++;
		}
		return lcm;
		
	}

 3.對小數的判斷

//  對於小數的判斷
	public static boolean decimals(String result){
		boolean hasDecimals=false;
		if (result.contains(".")){
			hasDecimals=true;
			
		}
		return hasDecimals;
	}

4.最大公因數

//  對於小數的判斷
	public static boolean decimals(String result){
		boolean hasDecimals=false;
		if (result.contains(".")){
			hasDecimals=true;
			
		}
		return hasDecimals;
	}

三、整個項目最麻煩也最關鍵的生成計算式的類

public class GenerateFormula {
	
	//形成運算式子
	
	public static String simpleArithmetic(){
		//標準形式
		char[] stanSympol = new char[] { '*', '+', '/', '-' };
		//輸出形式
		char[] outSympol = new char[] { '*', '+', '÷', '-' };
		String str1="";
		String str2="";
		//生成符號的個數
		int symbolCount= (int) (Math.random()*3+3);
		//生成數字數組
		int num[]=new int[symbolCount+1];
		for(int i=0;i<=symbolCount;i++){
			num[i]= (int) (Math.random()*100+1);
		}
		//生成符號數組
		//符號的個數比數字少一
		int symbol[]=new int[symbolCount];
		for (int i=0;i<symbolCount;i++){
			if (i>0&&symbol[i-1]==3){
				
				//減號之後必須是加號
				
				symbol[i]=1;
			}
			else if(i>0&&symbol[i-1]==2){
				//除號之後必須是乘法或加法
				symbol[i]= (int) (Math.random()*2);
			}
			else {
				symbol[i]= (int) (Math.random()*4);
			}
			str1+=String.valueOf(num[i])+String.valueOf(stanSympol[symbol[i]]);
			str2+=String.valueOf(num[i])+String.valueOf(outSympol[symbol[i]]);
			
			if (symbol[i]==2){
				num[i+1]=Calculator.divisor(num[i],num[i+1]);
			}
			else if(symbol[i]==3){
				num[i+1]=Calculator.subtractor(num[i],num[i+1]);
			}
		}
		int j=0;
		while (j<(symbolCount-1)&&symbol[j]==symbol[j+1]){
			j++;
		}
		if(j==(symbolCount-1)){
			return simpleArithmetic();
		}
		else {
			str1+=String.valueOf(num[symbolCount]);
			str2+=String.valueOf(num[symbolCount]);
			return str2+"="+Calculator.calulate(str1);
		}
		
		
	}
	
	//生成分數
	public static String fraction(){
		char[] symbol={'+','-'};
		String str="";
		int symCount= (int) (Math.random()*3+3);
		//分子
		int x[]=new int[symCount+1];
		//分母
		int y[]=new int[symCount+1];
		//符號集
		int z[]=new int[symCount];
		//中間運算結果
		int mid[]=new int[2];
		//生成分數數字集
		for (int i=0;i<=symCount;i++){
			x[i]= (int) (Math.random()*35+1);
			y[i]=Calculator.stfraction(x[i]);
		}
		mid[0]=x[0];
		mid[1]=y[1];
		//生成符號集
		for (int i=0;i<symCount;i++){
			z[i]= (int) (Math.random()*2);
			if (z[i]==0){
				int a1[]=new int[2];
				a1=Calculator.addFraction(mid[0],mid[1],x[i+1],y[i+1]);
				//中間的運算結果也要爲真分數
				if (a1[0]>=a1[1]){
					z[i]=1;
				}
				else {
					mid=a1;
				}
			}
			if (z[1]==1){
				int a1[]=new int[2];
				a1=Calculator.subFraction(mid[0],mid[1],x[i+1],y[i+1]);
				if (a1[0]<0){
					x[i+1]=Calculator.stfraction2(mid[0],mid[1]);
					y[i+1]=mid[1];
					a1=Calculator.subFraction(mid[0],mid[1],x[i+1],y[i+1]);
				}
				mid=a1;
			}
			str+=String.valueOf(x[i])+"/"+String.valueOf(y[i])+String.valueOf(symbol[z[i]]);
		}
		int j=0;
		while (j<(symCount-1)&&z[j]==z[j+1]){
			j++;
		}
		if (j==(symCount-1)) {
			return fraction();
		}
		else {
			str+=String.valueOf(x[symCount])+"/"+String.valueOf(y[symCount]);
			return str+"="+mid[0]+"/"+mid[1];
		}
		
	}
	//隨機產生括號的四則運算
	
	public static String addBracket() {
		//標準形式
		char[] stanSympol = new char[]{'*', '+', '/', '-'};
		//輸出形式
		char[] outSympol = new char[]{'*', '+', '÷', '-'};
		String str1 = "";
		String str2 = "";
		//生成括號的個數
		int bracket = 0;
		//未匹配的左括號的個數
		int bracket_left = 0;
		//符號個數
		int symCount = (int) (Math.random() * 3 + 3);
		//存儲符號的數組
		int[] symbol = new int[symCount];
		//存儲數字的數組
		int[] num = new int[symCount + 1];
		//隨機產生數字
		for (int i = 0; i <= symCount; i++) {
			num[i] = (int) (Math.random() * 100 + 1);
		}
		//隨機生成符號
		for (int j = 0; j <= (symCount - 1); j++) {
			symbol[j] = (int) (Math.random() * 4);
		}
		//形成運算式
		for (int i = 1; i <= (symCount - 1); i++) {
			//減數時防止產生負數
			if (symbol[i] == 3) {
				num[i] = Calculator.subtractor(num[i - 1], num[i]);
			} else if (symbol[i] == 2) {
				num[i] = (int) (Math.random() * 100 + 1);
			}
			str1 += num[i];
			str2 += num[i];
			int bracket_left1 = bracket_left;
			for (int j = 0; j < bracket_left1; j++) {
				if ((int) (Math.random() * 3) > 1) {
					bracket_left--;
					str1 += ")";
					str2 += ")";
				}
			}
			str1 += stanSympol[symbol[i]];
			str2 += outSympol[symbol[i]];
			
			if (((bracket * 2) <= symCount) && (((int) (Math.random() * 9)) > 1)) {
				str1 += "(";
				str2 += "(";
				bracket++;
				bracket_left++;
				str1 += num[++i];
				str2 += num[i];
				str1 += stanSympol[symbol[i - 1]];
				str2 += outSympol[symbol[i - 1]];
				
				
			}
		}
		int k = 0;
		while (k != symCount) {
			if (symbol[k] == 3) {
				num[k + 1] = Calculator.subtractor(num[k], num[k + 1]);
			} else if (symbol[k] == 2) {
				num[k + 1] = (int) (Math.random() * 100 + 1);
			}
			str1 += num[k];
			str2 += num[k];
			str1 += stanSympol[symbol[k]];
			str2 += outSympol[symbol[k]];
			k++;
		}
		if (symbol[symCount - 1] == 3) {
			num[symCount] = Calculator.subtractor(num[symCount - 1], num[symCount]);
		}
		str1 += num[symCount];
		str2 += num[symCount];
		while (bracket_left != 0) {
			str1 += ")";
			str2 += ")";
			bracket_left--;
		}
		str2 += "=";
		String result = String.valueOf(Calculator.calulate(str1));
		if (Calculator.decimals(result) || result.contains("Infinity")) {
			return addBracket();
		} else if (bracket >= 2) {
			int result1 = Integer.parseInt(result);
			if (result1 < 0) {
				return addBracket();
			} else {
				return str2 + result;
			}
		}
		else {
			return addBracket();
		}
		
	}
}

5.本地命令行運行報錯

a.中文亂碼

b.編譯問題

四、總結

這個項目我開始想的時候式很簡單的,但是真正寫起來才發現並不如我所想的那樣簡單。開始寫簡單四則運算的時候,我就開始要寫代碼的數量發愁,偶然發現了eval()方法,心底真的式發出了感嘆,居然會有如此神奇的算法,編程世界的前輩們真的是太優秀啦!

有了這種方法的幫助,四則運算也很快的就完成了。對於附加功能的實現,我是借鑑了學長學姐的方法,當然。我相信只要給我時間,擁有耐心,我相信,我也是可以成功實現的。前輩們的方法好則好矣,卻是使我減少了思考過程的探險,少了許多項目完成時的欣喜。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章