GitHub develop分支
GitHub master
隊員:
蓋嘉軒031602211
許郁楊031602240
我和我的隊友計劃先寫一篇1.0,描述一下程式本身包括程式的代碼、編碼規範、送出記錄等等,由于要說的東西很多,例如合作過程和合作體會會在下一篇團隊總結中講述
- 隊員分工
- 日程規劃
- 程式設計規範
- 實作設計思路和遇到的困難
- 代碼
- 運作測試
- 送出記錄
- 合作證據
一開始我們決定要使用多源檔案編寫程式,由于我C++不是很熟練,而且這道題我一開始用C語言嘗試寫了一下,遇到了許多問題,是以我決定采取我隊友的方案,一開始是這樣分類的:
檔案名 | 功能 |
---|---|
head.h | 頭檔案 |
main.cpp | 使用者界面 |
calculate.cpp | 生成題目、檢驗結果 |
fraction.cpp | 生成、計算真分數 |
stack.cpp | 計算表達式結果 |
這個版本我負責head、main、calculate;因為根本不會用棧去處理四則運算,也不會寫分數的部分,是以隻能請隊友去寫fraction、stack,但由于和隊友的程式不相容,是以我在隊友的指導下又寫了一個1.0 的版本
1.0的檔案分類
初始界面 | |
generate.cpp | 生成題目 |
生成、計算分數 | |
計算表達式 | |
verify.cpp | 檢驗答案并輸出 |
與最開始相比,就是将calculate分成generate、verify,以及對fraction、和stack做了一些改進。盡可能的将功能子產品化。
由于發作業時剛過完年,我和隊友各自都有事,而且我也需要一些時間去百度本次作業需要的知識,是以一直到8号才開始正式寫代碼。
由于13号隊友在測試程式時發現了一個大坑,隊友一夜未眠進行debug,才解決。。。。
一開始我們就決定要用描述性變量名,經過修改後:
變量名 | 作用 |
---|---|
i,j | 循環變量 |
flag | 判斷變量 |
tmp | 臨時變量 |
frac | 分數 |
low、high | 數字範圍 |
answer | 結果 |
sign | 符号 |
para | 參數 |
infix | 中綴表達式 |
postfix | 字尾表達式 |
point | 棧頂指針 |
函數的命名也采用的是描述性命名
函數 | |
---|---|
getRand | 擷取随機數 |
getAndCalculate | 擷取表達式 |
transEquation | 中綴轉為字尾 |
countEquation | 計算字尾的值 |
ifOnly | 判斷是否重複 |
checkAndOutput | 檢查答案并輸出正确答案 |
finalOut | 輸出正誤個數 |
gcd | 最大公約數 |
fixUp | 保持分母為正 |
getFrac | 生成分數 |
transFrac | 整數化為分數 |
simplify | 分數化簡 |
transString | 分數轉為字元串(不判斷整數) |
transToString | 分數轉為字元串(判斷整數) |
operator | 分數四則運算 |
我負責程式的界面(中英文界面切換),生成題目,檢驗結果。生成界面還是比較容易,看完我的代碼基本都能明白我的思路,主要是這次首次使用了static靜态變量,是以我主要講生成題目和檢驗結果。
- 首先分析完這道題後有以下幾個難點:
- 随機數的生成(想要學習的話可以看我隊友的部落格。如何在C++中産生随機數)
- 四則運算符号的随機生成
- 括号的生成
一開始說實話我根本沒有頭緒,我試着用C語言寫了一下,根本寫不出來!後來還是我的搭檔告訴我這道題需要用到的知識,給我推薦了一些部落格,經過學習,我才知道要運用srand()函數和rand()函數生成随機數,而srand()函數需要一個“種子”去初始化,我用的是srand((unsigned int)(time(NULL))的方法,利用系統時鐘,産生不同的随機數種子。
單純的rand()會傳回一個0至RAND_MAX之間的随機數值,而RAND_MAX的值與int位數有關,最小是32767。不過rand()是一次性的,因為系統預設的随機數種子為1,隻要随機數種子不變,其生成的随機數序列就不會改變。
其實,對于rand()的範圍,我們是可以進行人為設定的,隻需要在宏定義中定義一個random(int x)函數,就可以生成範圍為0至x的随機數值。當然,也可以定義為random(a,b),使其生成範圍為a至b的随機數值。
至于運算符号,我利用随機數的生成,采用switch結構,随機選擇+、-、x、/、可以在之後的代碼中看到。
最後是括号,首先分成兩種情況,有括号出現的算式,沒有括号出現的算式,而且還要讓算式中不能出現過多重複的數字,是以分成四種情況,一次生成一個A+B ,通過循環讓這種類型的式子進行随機組合。
- 檢驗結果
我寫程式時最頭疼的就是這個問題,因為根本沒有思路。後來在隊友的提示下在生成題目時就将題目存儲到不同的變量中ans和result,最後進行比較。
/*************************************************************
檔案名:head.h
作者:蓋嘉軒 日期:2016/02/16
描述: 頭檔案
*************************************************************/
#pragma once
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<sstream>
#include<cmath>
#include<ctime>
#include<stack>
#include<cassert>
#define Min(x,y) (((x)<(y))?(x):(y))
#define Max(x,y) (((x)>(y))?(x):(y))
#define random(a,b) (rand()%(b-a+1)+a)
#define MAX 1000
using namespace std;
/*generate.cpp*/
int getRand(int down,int up);
void getAndCalculate(int opt,int num,int low,int high,char flag1,char flag2,char flag3);
/*Stack.cpp*/
void transEquation(string infix,char postfix[]);
string countEquation(string infix);
/*verify.cpp*/
int ifOnly(string str,string se[],int k);
void checkAndOutput(string equ,int n,int opt);
void finalOut(int opt);
/*fraction.cpp*/
class Fraction
{
private:
int numerator,denominator;
string numerators,denominators;
int greatestCommonDivisor(int x,int y);
void fixUp(Fraction frac);
public:
Fraction();
Fraction(int numerator,int denominator);
Fraction getFrac(int l,int h);
Fraction transFrac(int up,int down);
Fraction simplify(Fraction frac);
string transString(Fraction frac);
string transToString(Fraction frac);
friend const Fraction operator +(Fraction frac1,Fraction frac2);
friend const Fraction operator -(Fraction frac1,Fraction frac2);
friend const Fraction operator *(Fraction frac1,Fraction frac2);
friend const Fraction operator /(Fraction frac1,Fraction frac2);
};
/*************************************************************
檔案名:main.cpp
作者:蓋嘉軒 日期:2016/02/16
描述: 初始界面
主要功能包括:語言切換、功能選擇
*************************************************************/
#include"head.h"
int main()
{
int i,j,k,num,low,high,opt;
char flag1,flag2,flag3,tmp;
cout<<"請問要選擇哪種語言/Which language you would like to choose?\n";
cout<<"輸入 1 切換中文 ;輸入 2 切換英文./input 1 for Chinese ; input 2 for English: ";
cin>>opt;
if(opt==1)
{
cout<<"請輸入題目數(1~1000):";
cin>>num;
cout<<"請輸入算式中的數字大小的絕對值範圍(如:1 100):";
cin>>low>>high;
cout<<"是否允許乘除(y/n):";
cin>>flag1;
cout<<"是否允許分數(y/n)(結果請以假分數的形式輸出,例如13\\5):";
cin>>flag2;
cout<<"是否允許括号(y/n):";
cin>>flag3;
cout<<"********************************************************************"<<endl;
cout<<" "<<endl;
}
if(opt==2)
{
cout<<"Please enter a number as the amount of the calculation questions: ";
cin>>num;
cout<<"Please enter the size range of the numbers'absolute value in the equation.(e.g 1 100): ";
cin>>low>>high;
cout<<"Would you permit the multiplication and division as a part of the equation?(y/n): ";
cin>>flag1;
cout<<"Would you permit the fraction as a part of the equation?(y/n): ";
cin>>flag2;
cout<<"Would you permit the parenthesis--() as a part of the equation?(y/n): ";
cin>>flag3;
cout<<"********************************************************************"<<endl;
cout<<" "<<endl;
}
getAndCalculate(opt,num,low,high,flag1,flag2,flag3);
return 0;
}
/*************************************************************
檔案名:generate.cpp
作者:蓋嘉軒 日期:2016/02/16
描述: 生成表達式
主要功能包括:生成随機數、生成表達式
*************************************************************/
#include"head.h"
int flag=1,k=0;
int getRand(int down,int up)//生成随機數
{
if (flag==1)
{
flag=0;
srand((unsigned)time(NULL));//種子
}
return random(down,up);
}
string equation[MAX];
void getAndCalculate(int opt,int num,int low,int high,char flag1,char flag2,char flag3)
{
int i=1,tmp;
char sign;
while (i<=num)
{
int flag4=1,number=getRand(2,7);
string paras1,paras2,equ;
for (int j=0;j<number;j++)
{
if (flag1=='y') //允許乘除
{
tmp=getRand(1,4);
switch (tmp)
{
case 1:sign='+';
break;
case 2:sign='-';
break;
case 3:sign='*';
break;
case 4:sign='/';
break;
}
}
else
{
tmp=getRand(1,2);
switch (tmp)
{
case 1:sign='+';
break;
case 2:sign='-';
break;
}
}
if (flag2=='y') //允許分數
{
tmp=getRand(1,3);
switch (tmp)
{
case 1: //整數和整數
{
stringstream tmps1,tmps2;
tmps1<<getRand(low,high);
tmps1>>paras1;
tmps2<<getRand(low,high);
tmps2>>paras2;
break;
}
case 2: //整數和真分數
{
stringstream tmps;
tmps<<getRand(low,high);
tmps>>paras1;
Fraction frac2=frac2.simplify(frac2.getFrac(low,high));
paras2=frac2.transString(frac2);
break;
}
case 3: //分數和分數
{
Fraction frac1=frac1.simplify(frac1.getFrac(low,high));
Fraction frac2=frac2.simplify(frac2.getFrac(low,high));
paras1=frac1.transString(frac1);
paras2=frac2.transString(frac2);
break;
}
}
}
else
{
stringstream tmps3,tmps4;
tmps3<<getRand(low,high);
tmps3>>paras1;
tmps4<<getRand(low,high);
tmps4>>paras2;
}
if (flag3=='y') //允許括号
{
tmp=getRand(1,4);
switch (tmp)
{
case 1: //無括号
{
if (flag4==1)
{
equ=paras1+sign+paras2;
flag4=0;
}
else equ=equ+sign+paras1;
break;
}
case 2:
{
if (flag4==1)
{
equ=paras2+sign+paras1;
flag4=0;
}
else equ=paras1+sign+equ;
break;
}
case 3: //有括号
{
if (flag4==1)
{
equ="["+paras1+sign+paras2+"]";
flag4=0;
}
else equ="["+equ+sign+paras1+"]";
break;
}
case 4:
{
if (flag4==1)
{
equ="["+paras2+sign+paras1+"]";
flag4=0;
}
else equ="["+equ+sign+paras1+"]";
break;
}
}
}
else
{
tmp=getRand(1,2);
switch (tmp)
{
case 1:
{
if (flag4==1)
{
equ=paras1+sign+paras2;
flag4=0;
}
else equ=equ+sign+paras1;
break;
}
case 2:
{
if (flag4==1)
{
equ=paras2+sign+paras1;
flag4=0;
}
else equ=paras1+sign+equ;
}
}
}
}
if (ifOnly(equ,equation,k)==1) //判斷表達式是否重複
{
k++;
equation[k]=equ;
checkAndOutput(equ,i,opt);
i++;
}
}
finalOut(opt);
}
/*************************************************************
檔案名:verify.cpp
作者:蓋嘉軒 日期:2016/02/16
描述: 檢驗和輸出結果
主要功能包括:判重、檢驗答案、輸出答案
*************************************************************/
#include"head.h"
int correct=0,wrong=0;
int ifOnly(string str,string se[],int k) //判斷表達式是否重複
{
int count=0;
for (int i=0;i<k;i++)
{
if (str!=se[i]) count++;
else break;
}
if (count==k) return 1;
else return 0;
}
void checkAndOutput(string equ,int n,int opt) //檢驗答案并輸出正确答案
{
string result=countEquation(equ),ans;
cout<<"("<<n<<") "<<equ<<"=";
cin>>ans;
if (ans==result)
{
if(opt==2)cout<<"Correct Answer!"<<endl;
else cout<<"正确"<<endl;
correct++;
}
else
{
if(opt==2)cout<<"Wrong Answer! The correct answer is "<<result<<endl;
else cout<<"錯誤,正确答案為:"<<result<<endl;
wrong++;
}
}
void finalOut(int opt) //輸出正誤個數
{
cout<<"********************************************************************"<<endl;
cout<<" "<<endl;
if(opt==2) cout<<" "<<correct<<" answers are correct, "<<wrong<<" answers are wrong.";
else cout<<"做對了"<<correct<<"道題,做錯了"<<wrong<<"道題";
}
由于我們使用生成随機數的方法生成運算符号,并且将各種功能子產品化設計,是以我們的程式可以自行選擇計算的難度,是否出現乘除,括号分數;而且不隻有四個數字,可能出現很多數字在同一個算式中,不僅國小生可以用,國中生,高中生也可以使用!.

由于我主要是将代碼先發給隊友,在與他的代碼相容後才能在github上釋出,是以送出記錄不是很多
這是我在最開始寫好的三個檔案,用QQ給隊友發了過去