1. 程式人生 > >#2018BIT軟件工程基礎#結對項目:四則運算題目生成

#2018BIT軟件工程基礎#結對項目:四則運算題目生成

重新 不為 寫代碼 tro borde 位數 後綴表達式 嘗試 stand

小隊成員:

1120161945 雷雲霖

1120161949 劉鎵煜


一、開發時間

PSP2.1 Personal Software Process Stages 預估耗時(分鐘) 實際耗時(分鐘)
Planning 計劃
· Estimate · 估計這個任務需要多少時間 5 6
Development 開發
· Analysis · 需求分析 (包括學習新技術) 120 120
· Design Spec · 生成設計文檔 120 180
· Design Review · 設計復審 (和同事審核設計文檔) 10 20
· Coding Standard · 代碼規範 (為目前的開發制定合適的規範) 10 10
· Design · 具體設計 20 30
· Coding · 具體編碼 120 360
· Code Review · 代碼復審 30 30
· Test · 測試(自我測試,修改代碼,提交修改) 60 120
Reporting 報告
· Test Report · 測試報告 20 20
· Size Measurement · 計算工作量 20 20
· Postmortem & Process Improvement Plan · 事後總結, 並提出過程改進計劃 20 20
合計 555 936


二、思路分析與設計編碼

重點在於兩個方面,第一是生成不重復的隨機題目,第二是如何計算這個題目。

對於題目生成的不重復性,有了個人項目數獨的實戰經驗,便不是什麽大的問題。當然在這個方面小組的成員還是有一定分歧的,小雷同學決定采用重復概率為百萬分之一的隨機數方法,小劉同學決定采用排列組合排出必然不相同的一千種。最後取了一個二者折中的方法,如果真發生了重復的情況,一來是對題目的復習,二來也可以告知用戶他今日運氣特別的好中了億萬分之一的概率,充分體現了我們軟件的人性化設計——不僅僅限於做題。關鍵代碼展示如下(C++):

技術分享圖片
string takeTest()
{
    srand((unsigned)time(NULL));
    int num1, num2;
    string signal;
    string ans = "";

    signal = getSignal(6);
    num1 = random(0, 100);
    num2 = random(1, 100);

    if (signal == "‘")
    {
        if (num1<num2)
        {
            swap(num1, num2);
        }
    }

    if (signal == "**"||signal=="^")
    {
        num2 /= 35;
    }

    if (signal == "/")
    {
        if (num2 == 0)
        {
            swap(num1, num2);
        }
    }

    ans = ans + to_string(num1) + signal + to_string(num2);
    signal = getSignal(4);
    ans = ans + signal;

    signal = getSignal(6);
    num1 = random(0, 100);
    num2 = random(1, 100);

    if (signal == "‘")
    {
        if (num1<num2)
        {
            swap(num1, num2);
        }
    }

    if (signal == "**" || signal == "^")
    {
        num2 /= 35;
    }

    if (signal == "/")
    {
        if (num2 == 0)
        {
            swap(num1, num2);
        }
    }

    ans = ans + to_string(num1) + signal + to_string(num2);

    return ans;
}
技術分享圖片

如何計算題目,對於我們來說也不是難事,用堆棧的方法實現中綴表達式轉後綴表達式即可。能力不強的小劉同學此時發問了:那**這表示乘方的符號有兩個字符串怎麽辦?小雷同學回答他:對算式做預處理,把**改為^。

對於分數的計算,則采取把所有操作數先通分,在分子上進行四則運算,最後約分化簡的的操作。

關鍵代碼展示如下(C++):

技術分享圖片
string MidToBack(string s)       //轉後綴表達式,利用棧
{
    string ret;
    stack<int> stk;
    int pos; 
    while ((pos = s.find("**"))!=s.npos)  //將**轉換成^
    {
        s.replace(pos, 2, "^");
    }
    for (string::size_type i = 0; i< s.size(); i++)
    {
        if (isdigit(s[i]))
        {
            ret += s[i];
            if ((i < s.size() - 1 && !isdigit(s[i + 1])) || i == (s.size() - 1))
                ret += ‘ ‘;//這裏是用空格將數跟符號隔開。目的是在後綴計算中提取數的時候,有些數可能不止一位,如果沒有空格符,一個多位的數會被誤認為是多個個位數。
        }
        else
        {
            switch (s[i])
            {
            case ‘(‘:
                stk.push(s[i]);
                break;
            case ‘)‘:
                while (!stk.empty() && stk.top() != ‘(‘)
                {
                    ret += stk.top();
                    stk.pop();
                }
                stk.pop();
                break;
            case ‘+‘:
            case ‘-‘:
                while (!stk.empty() && stk.top() != ‘(‘)
                {
                    ret += stk.top();
                    stk.pop();
                }
                stk.push(s[i]);
                break;
            case ‘*‘:
            case ‘/‘:
                while (!stk.empty() && (stk.top() == ‘*‘ || stk.top() == ‘/‘ || stk.top() == ‘^‘))
                {
                    ret += stk.top();
                    stk.pop();
                }
                stk.push(s[i]);
                break;
            case ‘^‘: stk.push(s[i]); break;
            }

        }
    }
    while (!stk.empty())
    {
        ret += stk.top();
        stk.pop();
    }
    return ret;
}
技術分享圖片

三、測試與優化

測試共花費2小時時間。

測試用例的設計與運行結果

1)參數的測試用例

I. -a abcd 不合法格式的參數,成功輸出了錯誤信息

II. -a 0或-a -1 越界參數,成功輸出了錯誤信息

III. -c 100 命令參數錯誤,成功輸出了錯誤信息

2)性能優化的測試用例

-a 1000

題目生成的速度十分迅速,性能分析圖不像個人項目一樣波濤洶湧,反而平靜如水,其中耗時最大的便是等待用戶輸入答案的程序段,可優化的空間不大。

技術分享圖片

技術分享圖片

經過2個人2小時的排查改進,還是發現了問題,采用隨機數時產生了分母為0的錯誤情況,於是加了一個分母不為0的限制,解決了問題。


四、擴展需求

能力有限的小劉只能照著小雷同學的C++模板,嘗試了用從未學過的JAVA語言重新編寫四則運算程序。正好軟件工程基礎結課後開設了JAVA課程,也算對新課的一次提前了解吧。經過自學和課程的學習,小劉同學不但完成了用JAVA重新編寫程序的目標,還自己嘗試用JAVA基本實現了做GUI圖形界面的需求。

實現算法同C++實現。

估計完成所需時間:24小時(平攤到3個星期之中),實際完成時間:24+小時

程序思路圖如下:

技術分享圖片

效果如下:

技術分享圖片


五、心得體會

  結對項目和個人項目體驗完全不一樣,個人項目只要一個人默默寫就好了,而結對項目更多的是需要交流。我個人感覺受益是很大的,因為結對編程能夠讓一部分功能的實現趨近於最優的方式,兩個人一起討論問題怎麽解決,如何做更好。舉個例子來說吧,我對項目的細節經常犯錯誤,比如求用戶正確率這樣的小需求經常忘記實現了,這個時候partner都很細心的幫我指出這些,這是一個人默默寫代碼所無法體驗到的。當然這也應該是結對項目的目的之一吧,培養大家之間的信任。

  在這次合作中的確是1+1>2的體驗,收獲良多。

#2018BIT軟件工程基礎#結對項目:四則運算題目生成