結對項目-最長單詞鏈

  1. Github地址html

  2. 見文末git

  3. 看教科書和其它資料中關於Information Hiding, Interface Design, Loose Coupling的章節,說明大家在結對編程中是如何利用這些方法對接口進行設計的github

    在本次做業中,是須要將gui與計算模塊耦合在一塊兒。爲了下降耦合,咱們實現了標準接口,gui直接將信息傳給計算模塊的函數,而後獲取結果。爲了與更好的與gui庫耦合,咱們在接口上儘量使用基本類型。計算模塊部分,將信息處理與邏輯處理分開設計,將信息處理與邏輯處理自身的信息隱藏起來,只須要互相調用接口就能夠實現完整的邏輯。算法

    extern "C" CoreAPI int build_map(char* words[], char* text); \\對單詞進行拆分
    extern "C" CoreAPI int gen_chain_word(char* words[], int len, char* result[], char head, char tail, bool enable_loop);\\計算最長單詞單詞鏈
    extern "C" CoreAPI int gen_chain_char(char* words[], int len, char* result[], char head, char tail, bool enable_loop);\\計算最長字母單詞鏈
  4. 計算模塊接口的設計與實現過程。 設計包括代碼如何組織,好比會有幾個類,幾個函數,他們之間關係如何,關鍵函數是否須要畫出流程圖?說明你的算法的關鍵(沒必要列出源代碼),以及獨到之處編程

    有3個類:CoreFindChainInit。18個函數。Init處理原始數據,命令行參數處理、單詞切分等任務。FindChainInit的數據進行深加工,抽象出邊和圖,進行相關的計算。Core將兩個類結合在一塊兒,進行必要的調度。判斷是否有環是經過是否存在拓撲序進行判斷的,無環的最長路是用一個簡單的spfa,在處理有環的最長路是,爲了提升效率使用鄰接鏈表,並使用了一個剪枝:若是當前最長路已經將一個點的全部出邊都覆蓋到,那麼這個點的最長路必定不會更優。函數

  5. 閱讀有關UML的內容:https://en.wikipedia.org/wiki/Unified_Modeling_Language。畫出UML圖顯示計算模塊部分各個實體之間的關係(畫一個圖便可)。工具

  1. 算模塊接口部分的性能改進。 記錄在改進計算模塊性能上所花費的時間,描述你改進的思路,並展現一張性能分析圖(由VS 2015/2017的性能分析工具自動生成),並展現你程序中消耗最大的函數

在計算部分進行性能改進時,咱們基本上就在對有環的狀況進行優化,咱們爲了提升效率使用鄰接鏈表,使用了一個剪枝:若是當前最長路已經將一個點的全部出邊都覆蓋到,那麼這個點的最長路必定不會更優。oop

咱們性能分析後發現主要性能仍是消耗在dfs的遞歸上,所以主要優化目標仍是對dfs進行剪枝。性能

  1. 看Design by Contract, Code Contract的內容:
    http://en.wikipedia.org/wiki/Design_by_contract
    http://msdn.microsoft.com/en-us/devlabs/dd491992.aspx
    描述這些作法的優缺點, 說明你是如何把它們融入結對做業中的單元測試

    這些作法會增長代碼編寫的工做量可是卻能夠保證代碼的正確性,在代碼的開發階段加入assert可以提前發現bug,測試階段須要assert來進行正確性的測試

  2. 計算模塊部分單元測試展現。 展現出項目部分單元測試代碼,並說明測試的函數,構造測試數據的思路。並將單元測試獲得的測試覆蓋率截圖,發表在博客中。要求整體覆蓋率到90%以上,不然單元測試部分視做無效。

  • 該部分代碼測試的是GetWordChain_NoRing函數,即沒環的狀況。
TEST_METHOD(TestMethod8)
{
    char* words[10] = { "abb","bc", "cd", "de", "drrrrr","rrrrr" };
    char* result[105];
    FindChain findchain;
    findchain.BuildMap(words, 6, 1, 0, 0);
    int len = findchain.GetWordChain_NoRing(result);
    Assert::AreEqual(len, 5);
    for (int i = 0; i < 3; i++)
    {
        int slen = strlen(result[i]);
        Assert::IsTrue(result[i][slen - 1] == result[i + 1][0]);
    }
}

以上爲當自環在這個鏈的最後時的測試,用來檢查自環是否被計算上。

TEST_METHOD(TestMethod7)
{
    char* words[10] = { "aa","cc","bb", "dd", "ee", "rr" };
    char* result[105];
    FindChain findchain;
    findchain.BuildMap(words, 6, 1, 'c', 0);
    int len = findchain.GetWordChain_NoRing(result);
    Assert::AreEqual(len, 1);
}

以上爲對每一個字母都是自環的狀況進行考慮,雖然沒有造成鏈可是一個單詞也要輸出鏈。

  • 該部分代碼測試的是GetWordChain_Ring函數,即有環的狀況。
TEST_METHOD(TestMethod1)
{
    char* words[10] = { "ab","bc","ca", "cd", "de", "dee" };
    char* result[105];
    FindChain findchain;
    findchain.BuildMap(words, 6, 1, 0, 0);
    int len = findchain.GetWordChain_Ring(result);
    Assert::AreEqual(len, 5);
    for (int i = 0; i < 4; i++)
    {
        int slen = strlen(result[i]);
        Assert::IsTrue(result[i][slen - 1] == result[i + 1][0]);
    }
}

  1. 計算模塊部分異常處理說明。 在博客中詳細介紹每種異常的設計目標。每種異常都要選擇一個單元測試樣例發佈在博客中,並指明錯誤對應的場景。

    • 不能識別的參數
    TEST_METHOD(InitError5)
    {
       Core core;
       char* argv[10] = { "program", "w" };
       try
       {
           Init* init = core.init_word(2, argv);
           Assert::Fail();
       }
       catch (const char* msg)
       {
           Assert::AreEqual("Incorrect command line parameters!", msg);
       }
    }

    對應可能忘記加上-等等場景。測試時保證必定會拋出異常,不然會fail,而且異常信息正確。

    • 同時輸入了-w-c指令
    TEST_METHOD(InitError2)
    {
       Core core;
       char* argv[10] = { "program", "-w","a.txt","-c","a.txt" };
       try
       {
           Init* init = core.init_word(5, argv);
           Assert::Fail();
       }
       catch (const char* msg)
       {
           Assert::AreEqual("Command line arguments include both -w and -c", msg);
       }
    }

    測試時同時輸入w和c參數,保證必定會拋出異常,且異常信息正確。

    • 沒有輸入-w-c指令
    TEST_METHOD(InitError3)
    {
       Core core;
       char* argv[10] = { "program" };
       try
       {
           Init* init = core.init_word(1, argv);
           Assert::Fail();
       }
       catch (const char* msg)
       {
           Assert::AreEqual("Command line parameters do not contain - w or -c", msg);
       }
    }

    測試時沒有輸入w和c參數,保證必定會拋出異常,且異常信息正確。

    • -h-t指令後參數格式錯誤
    TEST_METHOD(InitError4)
    {
       Core core;
       char* argv[10] = { "program", "-w", "a.txt", "-h", "0" };
       try
       {
           Init* init = core.init_word(5, argv);
           Assert::Fail();
       }
       catch (const char* msg)
       {
           Assert::AreEqual("The parameter should be a letter", msg);
       }
    }

    測試時-h後面的格式錯誤,保證必定會拋出異常,且異常信息正確。

    • 存在環路且沒有-r指令
    TEST_METHOD(LoopError1)
    {
       HINSTANCE CoreDLL = LoadLibrary("Core.dll");
       p_gen_chain_word gen_chain_word = (p_gen_chain_word)GetProcAddress(CoreDLL, "gen_chain_word");
       Core core;
       char* words[10] = { "ab","bc","cd", "da", "abb", "bcc" };
       char* result[105];
       try
       {
           int len = gen_chain_word(words, 6, result, 0, 0, 0);
           Assert::Fail();
       }
       catch (const char* msg)
       {
           Assert::AreEqual("There is a ring in the word list", msg);
       }
    }

    測試時不輸入-r,且單詞中存在環路,保證必定會拋出異常,且異常信息正確。

    • 缺失參數
    TEST_METHOD(InitError1)
    {
       Core core;
       char* argv[10] = { "program", "-w" };
       try
       {
           Init* init = core.init_word(2, argv);
           Assert::Fail();
       }
       catch (const char* msg)
       {
           Assert::AreEqual("Missing parameters", msg);
       }
    }

    測試時-w後未接文件路徑,致使缺失參數,保證必定會拋出異常,且異常信息正確。

    • 找不到文件
    TEST_METHOD(BuildError1)
    {
       Core core;
       char text[1000];
       char* argv[10] = { "program","-w","../WordlistProject/zzy.txt" };
       Init* init = core.init_word(3, argv);
       try
       {
           core.read_file(init, text);
           Assert::Fail();
       }
       catch (const char* msg)
       {
           Assert::AreEqual("File not found", msg);
       }
    }

    構造一個不存在的文件,保證必定會拋出異常,且異常信息正確。

  2. 界面模塊(若是沒有實現GUI,則能夠描述命令行模塊)的詳細設計過程。 在博客中詳細介紹界面模塊是如何設計的,並寫一些必要的代碼說明解釋實現過程。

    界面模塊的第一步是選擇一個溫馨的gui庫,咱們去github上選擇star數最高的imgui。簡單的練習後能夠上手了,可是發現缺乏文件操做的函數,因而去issues找到了須要的函數。

    ShowMainMenuBar(core, init);
    OpenButtonMonitor(core, init, inputText);
    SaveButtonMonitor(core, init, outputText);
               
    ImGui::Columns(3, "mixed");
    ImGui::Text("Input");
    ImGuiInputTextFlags inputFlags = ImGuiInputTextFlags_AllowTabInput;
    ImGui::InputTextMultiline("##Input", inputText, IM_ARRAYSIZE(inputText), ImVec2(-1.0f, ImGui::GetTextLineHeight() * 32), inputFlags);
    //ImGui::Separator();
    ImGui::NextColumn();
    ImGui::Text("Output");
    ImGuiInputTextFlags outputFlags = ImGuiInputTextFlags_AllowTabInput | ImGuiInputTextFlags_ReadOnly;
    ImGui::InputTextMultiline("##output", outputText, IM_ARRAYSIZE(outputText), ImVec2(-1.0f, ImGui::GetTextLineHeight() * 32), outputFlags);
               
    ImGui::NextColumn();
    FlagCheckBox(core, init, inputText, outputText);

    主界面將劃分爲3列,分別爲輸入、輸出和相關功能的按鈕

    static ImGuiFs::Dialog openDlg;
    const char* myPath = openDlg.chooseFileDialog(OpenButtonPressed);
    OpenButtonPressed = false;
    
    if (strlen(openDlg.getChosenPath()) > 0)
    {
       ImGui::Text("Open file: \"%s\"", openDlg.getChosenPath());
    }
    else
    {
       ImGui::Text("Open file: \"%s\"", "");
    }
    if (strlen(myPath) > 0)
    {
       FILE* fp = fopen(myPath, "r");
       int i = 0;
       while ((text[i] = fgetc(fp)) != EOF && i < MAX_BYTES - 1) i++;
       text[i] = '\0';
       fclose(fp);
    }

    在菜單按鈕上實現文件打開與導出,根據打開的文件路徑,將文件內容讀入到輸入框中。導出功能相似,將輸出框中的內容處處到所選的文件。

  3. 界面模塊(GUI或命令行模塊)與計算模塊的對接。 詳細地描述UI模塊的設計與兩個模塊的對接,並在博客中截圖實現的功能。

對接時gui只須要將輸入框數據傳給計算模塊建圖而且進行最長路的計算。並將計算的內容導出到輸出框中。

  • 計算功能
  • 文件功能
與王冰小組耦合

咱們與王冰小組進行了gui的耦合。

  • 咱們的gui和他們的計算模塊耦合,沒什麼須要修改的地方,只須要調用他們計算模塊的兩個計算鏈的函數。
  • 咱們的計算模塊和他們gui耦合,也沒什麼問題,直接調用接口就能計算。
  • 這是與他們gui耦合的截圖
  • 王冰學號:16061155 謝靜芬學號:16061093

  1. 描述結對的過程,提供非擺拍的兩人在討論的結對照片。

    咱們坐到一個電腦前,坐在一個凳子上擠在一塊兒,一個看一個寫。

  2. 看教科書和其它參考書,網站中關於結對編程的章節,例如:
    http://www.cnblogs.com/xinz/archive/2011/08/07/2130332.html
    說明結對編程的優勢和缺點。
    結對的每個人的優勢和缺點在哪裏 (要列出至少三個優勢和一個缺點)。

    在作題的時候就習慣先討論後編碼。結對編程能夠更好地將討論過程融入到編碼中。並且能夠提早發現對方的bug,減小測試的壓力。缺點:結對編程會同時佔用兩我的的時間,可是隻有一臺電腦,當一我的編碼時,另外一我的會很着急。並且在宿舍中結對編程很是擁擠,致使結對編程的環境不夠溫馨。

    優勢 缺點
    餘宸狄 (1)思惟嚴謹,謀定後動(2)熟悉多種算法,更好地提出思路(3)喜歡使用基本類型,迴歸c本質 不夠細心,是個瞎子
    張朝陽 (1)對搜索算法提出了不少改進,思惟活躍。(2)代碼能力強。(3) 熟悉STL庫 喜歡摸魚
  3. 在你實現完程序以後,在附錄提供的PSP表格記錄下你在程序的各個模塊上實際花費的時間。

PSP2.1 Personal Software Process Stages 預估耗時(分鐘) 實際耗時(分鐘)
Planning 計劃 20
· Estimate · 估計這個任務須要多少時間 0 5
Development 開發 1500
· Analysis · 需求分析 (包括學習新技術) 120 300
· Design Spec · 生成設計文檔 60 0
· Design Review · 設計複審 (和同事審覈設計文檔) 30 0
· Coding Standard · 代碼規範 (爲目前的開發制定合適的規範) 120 30
· Design · 具體設計 120 180
· Coding · 具體編碼 120 600
· Code Review · 代碼複審 90 40
· Test · 測試(自我測試,修改代碼,提交修改) 60 450
Reporting 報告 180
· Test Report · 測試報告 60 30
· Size Measurement · 計算工做量 20 10
· Postmortem & Process Improvement Plan · 過後總結, 並提出過程改進計劃 20 140
合計 820 1700
相關文章
相關標籤/搜索