結對項目-數獨程序擴展(要求細化更新)

DeadLine:2017.10.15 3:00pmhtml

咱們在第一個做業中,用各類語言實現了一個命令行的生成數獨終局和求解數獨的小程序。咱們看看若是要把咱們的小程序升級爲能穩定運行,給用戶提供服務的軟件,應該怎麼作。git

1.結對項目

第一階段目標:把生成數獨終局與求解數獨的功能封裝爲獨立模塊,並設計單元測試。

你們的代碼都各有特點,你們寫的「軟件」也有必定的用處。若是如今咱們要把這個功能放到不一樣的環境中去(例如,命令行,Windows圖形界面程序,網頁程序,手機App),就會碰到困難:許多同窗的代碼都散落在各個函數中,很難把剝離出來做爲一個獨立的模塊運行以知足不一樣的需求。算法

咱們看到,不一樣的代碼解決不一樣層面的問題:編程

  • 有些是計算數據的(例如生成數獨)
  • 有些是控制輸入的(例如scanf,cin,圖形界面的輸入字段)
  • 有些是數據可視化的(例如printf,cout,println,DrawText)
    有些則更爲特殊,是架構相關的(例如main函數,並非全部的程序都須要某個特定格式的main)

這些代碼的種類不一樣,混雜在一塊兒對於後期的維護擴展很不友好,因此它們的組織結構就須要精心的整理和優化。小程序

咱們但願把生成數獨終局/求解數獨的功能能獨立出來,成爲一個獨立的模塊(class library, DLL, 或其它),這樣的話,命令行和GUI的程序都能使用同一份代碼。爲了方便起見,咱們稱之爲計算核心"Core模塊",這個模塊至少能夠在幾個地方使用:api

  • 命令行測試程序使用
  • 在單元測試框架下使用
  • 與數據可視化部分結合使用

把計算核心在單元測試框架中作過完備的測試後,咱們就能夠在算法層級保證了這個模塊的正確性。數組

但咱們知道軟件並不是只有計算核心,實際的軟件是交付給最終用戶的軟件,除了計算核心外,還須要有必定的界面和必要的輔助功能。那麼這個Core模塊和使用它的其餘模塊之間是什麼關係呢?它們要經過必定的API(Application Programming Interface)來和其餘模塊交流。這個API接口應該怎麼設計呢?爲了簡單,咱們能夠從下面的最簡單的接口開始:架構

void generate(int number, int[][] result)

這個函數接受一個整數number和一個大小爲number x 81的二維數組做爲輸入,其中number表示要求生成的數獨的個數,result用來存儲生成的number個數獨終局。框架

注意:本次做業再也不限定左上角的數字。函數

假設咱們用類Core封裝了這個接口,咱們的測試程序能夠是很是簡單的:

//調用Core中封裝好的函數
int result[100][81];
Core.generate(100, result);
bool valid = true;
for (int i = 0; i < 100 ; i += 1)
    //對於第i個棋盤,左上角要求固定爲1
    valid &= (result[i][0]==1);
//咱們斷言valid爲true,即全部生成的數獨左上角都符合固定某個數字的要求
Assert(valid==true);

固然,咱們這裏的判斷並不充分,沒有驗證數獨終局自己的特性:每行每列每宮都只能由1-9不重複的數字組成,但同窗們在測試時不能這樣「偷懶」。

在本次做業中,咱們但願你們在我的項目的基礎上完成一個數獨遊戲軟件,這個軟件會爲用戶提供以下特點功能:

  1. 難度區分,每盤遊戲用戶均可以選擇 容易/中等/難 三個等級。
  2. 提示功能,用戶不會的時候能夠點擊‘提示’,程序就會提示當前空格應該填什麼。
  3. 計時功能,可以保持用戶的最佳記錄。

爲了實現上述軟件,咱們首先要在我的項目基礎上增量改進,實現一個Core模塊,並基於Core模塊實如今命令行測試程序中支持下述命令行參數(原有命令行參數不變)

-m 參數設定難度

命令行中使用-n和-m參數分別控制生成數獨遊戲初始盤的數量與難度等級,

sudoku.exe -n [number] -m [mode]

-n和-m參數的限制範圍不一樣,具體約定以下:

  • [number]的範圍限定爲1 - 10000。
  • [mode]的範圍限定爲1 - 3,不一樣的數字表明瞭數獨遊戲的難度級別,以下表所示:
編號 級別
1 簡單
2 入門
3 困難

請在博客中說明你對於不一樣難度級別的嚴格定義,並說明這樣定義的理由。

例以下述命令將生成20個簡單級別的數獨遊戲初始棋盤至文件sudoku.txt中,挖空的地方用0表示:

sudoku.exe -n 20 -m 1

9 0 8 0 6 0 1 2 0
2 0 7 4 0 1 9 0 8
1 4 6 0 2 0 3 5 0
0 1 2 0 7 0 5 0 3
0 7 3 0 1 0 4 8 2
4 8 0 0 0 5 6 0 1
7 0 4 5 9 0 8 1 6
0 0 0 7 4 6 2 0 0
3 0 5 0 8 0 7 0 9
 
9 0 0 8 0 0 4 0 0
……

-r 參數設定挖空數量

命令行中使用-n參數控制生成數獨遊戲初始盤的數量,-r參數控制生成數獨遊戲初始盤中挖空的數量範圍,使用-u參數控制生成數獨遊戲初始盤的解必須惟一,

sudoku.exe -n [number] -r [lower]~[upper] -u

-r參數的範圍限制以下:

  • [lower] 的值最小爲20,
  • [upper] 的值最大爲55,
  • [upper] >= [lower]。

若是命令行中有-u參數,則生成的數獨遊戲初始盤的解必須惟一;不然,則對解的數量不作限制。

注意: -m參數不與-r和-u參數同時出現,若是同時出現則提示參數的正確用法。

例以下述命令將生成20個挖空數在20到55之間的數獨遊戲初始盤至文件sudoku.txt中,

sudoku.exe -n 20 -r 20~55

下述命令將生成20個挖空數在20到55之間而且解惟一的數獨遊戲初始盤至文件sudoku.txt中,

sudoku.exe -n 20 -r 20~55 -u

如今,請同窗們在我的項目的基礎上進行增量修改,根據以上修改本身的數獨項目。

完成上述接口後,咱們要把以前程序中實現的其餘功能也封裝成獨立的模塊並一一進行測試,好比讀取數獨題目文件、輸出打印等。建議你們在每一步只增量修改一個模塊並作測試。這裏的測試包括新模塊的單元測試原功能的迴歸測試。每實現一個新的功能,要保證之前運行正確的例子繼續是正確的。經過這樣的迴歸測試,能夠保證本身實現的系統始終是知足預約狀態約束的。(請看書中關於單元測試,迴歸測試的內容)在確認修改的功能正確以後再簽入代碼。

項目要求:

  • 在我的項目上增量修改,實現void generate(int number, int mode, int[][] result)接口,對於輸入的數獨遊戲的需求數量和難度等級,經過result返回生成的數獨遊戲的集合。
  • 對這一generate接口進行測試,把單元測試代碼Push到Github上(注意避免把單元測試的結果Push到Github上)。
  • 實現void generate(int number, int lower, int upper, bool unique, int[][] result)接口,生成number個空白數下界爲lower,上界爲upper的數獨遊戲,而且若是unique爲真,則生成的數獨遊戲的解必須惟一,計算的結果存儲在result中。
  • 對這一generate接口進行測試,把單元測試代碼Push到Github上(注意避免把單元測試的結果Push到Github上)。
  • 實現bool solve(int[] puzzle, int[] solution)接口,對於輸入的數獨題目puzzle(數獨矩陣按行展開爲一維數組),返回一個bool值表示是否有解。若是有解,則將一個可行解存儲在solution中(一樣表示爲數獨矩陣的一維數組展開)。
  • solve接口進行測試,把單元測試代碼Push到Github上(注意避免把單元測試的結果Push到Github上)。
  • 設計其餘部分的接口,按照設計好的接口在我的項目基礎上增量修改,一樣把單元測試代碼Push到Github上。
  • 在完成這一階段的任務以後,使用git tag step1標記第一階段已經完成,並在Push到Github上時使用--tags參數把tag也推送到Github,例如git push origin --tags

博客要求:

  • 詳細介紹你對於上述Core接口的實現,以及你爲Core模塊設計的其餘接口,並說明UI模塊該如何使用這些接口。
  • 選擇部分單元測試代碼發佈在博客中,並說明測試的函數,構造測試數據的思路。
  • 將單元測試獲得的測試覆蓋率截圖,發表在博客中。要求整體覆蓋率到90%以上,不然單元測試部分視做無效。

第二階段目標:經過測試程序和API接口測試對於異常處理的支持

在上面咱們只討論了正確的輸入下,咱們對於程序輸出的期待。但若是程序的輸入出現了錯誤,好比命令行參數是「-10000」,或者是「1000000000000c」,你又該怎麼辦呢?要怎樣才能告訴函數的調用者「你錯了」?又該如何方便地告訴函數的調用者「哪裏錯了」?在這種時候,咱們通常會定義各類異常(Exception),讓Core在碰到各類異常狀況的時候,能給調用者充分的錯誤信息。固然,咱們一樣要進行增量修改:

項目要求:

  • 設計好異常的種類與錯誤提示,例如讓程序支持「生成數獨數量」異常。
  • Core模塊中實現拋出異常的功能,並撰寫測試用例:傳進去一個錯誤的數獨遊戲,指望能捕獲這個異常。若是沒有,測試就報錯。
  • 迴歸測試全部之前的功能,保證之前的功能還能繼續工做。
  • 在完成這一階段的任務以後,使用git tag step2標記第二階段已經完成,並在Push到Github上時使用--tags參數把tag也推送到Github。

博客要求:

  • 在博客中詳細介紹對哪些異常進行了處理以及每種異常的設計目標。
  • 每種異常都要選擇一個單元測試樣例發佈在博客中,並指明錯誤對應的場景。

第三階段目標:從計算模塊到可用軟件

在我的項目階段已經有同窗作了一些不錯的GUI,但大部分同窗只是增長了一個界面而已,並不能稱得上是開發了一個軟件。一個軟件不只須要有負責數據計算的Core模塊,用戶體驗友好的UI模塊,還要有足夠的健壯性、詳細的運行說明等。

首先要開發一個用戶體驗友好的UI模塊,並把計算核心與用戶界面完美地對接起來。

項目要求:

  • 新建一個工程,把Core核心模塊做爲一個DLL(動態連接庫)引用在新工程中。
  • 開發一個UI模塊,實現以下需求:
    1. 隨機生成數獨遊戲的功能,將會從用戶體驗角度對隨機性進行測試。
    2. 每盤遊戲用戶均可以選擇 容易/中等/難 三個等級,將會從用戶體驗角度對不一樣難度的遊戲進行測試。
    3. 用戶不會的時候能夠在某個空格上點擊‘提示’,程序會提示該空格處須要填什麼數字。
    4. 計時功能,可以記錄用戶解數獨棋盤的耗時,並保持用戶的最佳記錄。
  • 將UI模塊與Core模塊對接。
  • 在完成這一階段的任務以後,使用git tag step3標記第三階段已經完成,並在Push到Github上時使用--tags參數把tag也推送到Github。

博客要求:詳細地描述UI模塊的設計與兩個模塊的對接,並在博客中截圖實現的功能。

第四階段目標:界面模塊,測試模塊和核心模塊的鬆耦合【附加題】

既然各組同窗都寫了高質量的各個模塊,並且模塊之間的關係是明肯定義的,一致的,那麼,小組A的測試模塊就能夠測試小組B的核心模塊;小組C的用戶界面模塊就能夠和小組B的核心模塊結合起來,正常運行。對吧?

那麼如今,請你(假設爲A)尋找另一個小組(假設爲B),與他們交換核心模塊與界面模塊,並測試一下下面的狀況:

  • A的核心模塊,加上B的測試模塊和用戶界面模塊
  • B的核心模塊,加上A的測試模塊和用戶界面模塊

項目要求:
根據與合做小組對接過程當中出現的問題,尋找並改進模塊中的bug。這部分修改須要另開一個新的分支dev-combine,並Push到Github上。

博客要求:
在博客中指明合做小組兩位同窗的學號,分析兩組不一樣的模塊合併以後出現的問題,爲什麼會出現這樣的問題,以及是如何根據反饋改進本身模塊的。

第五階段目標:經過增量修改的方式,改進程序,發佈一個真正的軟件【附加題】

在完成第四階段的目標後,能夠經過大家小組的界面模塊和合做小組的計算模塊組合成一個帶界面的數獨遊戲。但它還不是一個完整的軟件,你要爲數獨遊戲增長必要的說明與引導步驟,好比怎麼玩,若是卡住了怎麼辦。

項目要求:
把相關代碼簽入Github一個新的分支dev-product

博客要求:
把這個軟件發佈出來,在博客中發佈下載地址。收集至少10位用戶的反饋,並說明你在收到反饋後是怎樣改進本身的產品的。

2.評分規則

博文部分得分點

博客共五十分

1)在文章開頭給出Github項目地址。(1')
2)在開始實現程序以前,在下述PSP表格記錄下你估計將在程序的各個模塊的開發上耗費的時間。(0.5')
3)看教科書和其它資料中關於Information Hiding, Interface Design, Loose Coupling的章節,說明大家在結對編程中是如何利用這些方法對接口進行設計的。(5')
4)計算模塊接口的設計與實現過程。設計包括代碼如何組織,好比會有幾個類,幾個函數,他們之間關係如何,關鍵函數是否須要畫出流程圖?說明你的算法的關鍵(沒必要列出源代碼),以及獨到之處。(7')
5)閱讀有關UML的內容:https://en.wikipedia.org/wiki/Unified_Modeling_Language。畫出UML圖顯示計算模塊部分各個實體之間的關係(畫一個圖便可)。(2’)
6)計算模塊接口部分的性能改進。記錄在改進計算模塊性能上所花費的時間,描述你改進的思路,並展現一張性能分析圖(由VS 2015/2017的性能分析工具自動生成),並展現你程序中消耗最大的函數。(3')
7)看Design by Contract, Code Contract的內容:
http://en.wikipedia.org/wiki/Design_by_contract
http://msdn.microsoft.com/en-us/devlabs/dd491992.aspx
描述這些作法的優缺點, 說明你是如何把它們融入結對做業中的。(5')
8)計算模塊部分單元測試展現。展現出項目部分單元測試代碼,並說明測試的函數,構造測試數據的思路。並將單元測試獲得的測試覆蓋率截圖,發表在博客中。要求整體覆蓋率到90%以上,不然單元測試部分視做無效。(6')
9)計算模塊部分異常處理說明。在博客中詳細介紹每種異常的設計目標。每種異常都要選擇一個單元測試樣例發佈在博客中,並指明錯誤對應的場景。(5')
10)界面模塊的詳細設計過程。在博客中詳細介紹界面模塊是如何設計的,並寫一些必要的代碼說明解釋實現過程。(5')
11)界面模塊與計算模塊的對接。詳細地描述UI模塊的設計與兩個模塊的對接,並在博客中截圖實現的功能。(4')
12)描述結對的過程,提供非擺拍的兩人在討論的結對照片。(1')
13)看教科書和其它參考書,網站中關於結對編程的章節,例如:
http://www.cnblogs.com/xinz/archive/2011/08/07/2130332.html
說明結對編程的優勢和缺點。
結對的每個人的優勢和缺點在哪裏 (要列出至少三個優勢和一個缺點)。(5')
14)在你實現完程序以後,在附錄提供的PSP表格記錄下你在程序的各個模塊上實際花費的時間。(0.5')

注:結對小組中兩我的發佈獨立博客,其中2)、3)、5)、7)、13)、14)部分請獨立完成,不容許雷同。項目的測試分數兩人共享,博客的分數各自獨立。附加題的相關要求請按附加題的要求補充在博客中。

程序部分得分點

程序共七十分

源代碼管理評分(5'):
該評分主要經過源代碼管理中的commit註釋信息,增量修改的內容,是否有運行說明,每一個階段是否打上了標籤等內容給分。(5')

第一階段(20'):

該評分將進行這-c -s -n -m -u -r六個參數的正確性測試

第二階段(20'):

將針對上述六個參數進行魯棒性測試,可能測試的內容包括且不限於:
錯誤的命令、錯誤的參數、大小寫、錯誤的參數組合、錯誤的文件格式等。
要求必須正常結束,崩潰不得分。
錯誤無任何提示,不得分。
錯誤種類較多,提示合理,得正分。

第三階段(25'):

1)隨機生成數獨遊戲的功能,將會從用戶體驗角度對隨機性進行測試。(6')
2)每盤遊戲用戶均可以選擇 容易/中等/難 三個等級,將會從用戶體驗角度對不一樣難度的遊戲進行測試。 (7')
3)用戶不會的時候能夠在某個空格上點擊‘提示’,程序會提示該空格處須要填什麼數字。(6')
4)計時功能,可以記錄用戶解數獨棋盤的耗時,並保持用戶的最佳記錄。(6')

附加題得分點

附加題1(10'):
在結對項目博客中按照階段四的博客要求添加相應內容(5')
最終的對接效果(5')

附加題2(10'):
在結對項目博客中按照階段五的博客要求添加相應內容(5')
可玩性(5')

3.測試須知

組織目錄

與我的項目相似,在結對項目中咱們也會對你們的計算核心進行正確性的自行測試,須要你們遵循必定的規範。全部提交到Github上的項目均須要創建一個名字爲BIN的文件夾,裏面必須含有計算核心生成的可執行文件與相關的依賴庫,請注意如下三點:

  • 確保VS產生的臨時文件和編譯生成臨時文件不被加入到Git代碼倉庫中(使用.gitignore文件管理哪些文件能夠被忽略)。
  • 確保命令行測試程序的名字爲sudoku.exe,確保核心模塊的DLL名字爲Core.dll。
  • 確保生成的棋盤文件sudoku.txt與可執行文件在同一目錄下,生成文件時請使用相對路徑!

一個示例組織目錄以下所示:

/ SudokuProject(工程名字自行指定便可)
/ main.cpp
    / generator.cpp
/ BIN
    / Core.dll(Core模塊)
    / Lib.dll(運行須要的[其餘]動態連接庫文件)
    / sudoku.exe
    / sudoku.txt (運行exe後生成)

參數約定

助教在測試時,將以命令行運行可執行文件的方式進行批量測試,參數及其約定以下:

參數名字 參數意義 範圍限制 用法示例
-c 須要的數獨終盤數量 1-1000000 示例:sudoku.exe -c 20 [表示生成20個數獨終盤]
-s 須要解的數獨棋盤文件路徑 絕對或相對路徑 示例: sudoku.exe -s game.txt [表示從game.txt讀取若干個數獨遊戲,並給出其解答,生成到sudoku.txt中]
-n 須要的遊戲數量 1-10000 示例:sudoku.exe -n 1000 [表示生成1000個數獨遊戲]
-m 生成遊戲的難度 1-3 示例:sudoku.exe -n 1000 -m 1 [表示生成1000個簡單數獨遊戲,只有m和n一塊兒使用才認爲參數無誤,不然請報錯]
-r 生成遊戲中挖空的數量範圍 20-55 示例:sudoku.exe -n 20 -r 20~55 [表示生成20個挖空數在20到55之間的數獨遊戲,只有r和n一塊兒使用才認爲參數無誤,不然請報錯]
-u 生成遊戲的解惟一 示例:sudoku.exe -n 20 -u [表示生成20個解惟一的數獨遊戲,只有u和n一塊兒使用才認爲參數無誤,不然請報錯]

[新]等價數獨

須要注意的是,在我的項目的測試中,咱們把等價但不相同的數獨也算做了不重複的數獨。但由於本次結對項目咱們更加註重數獨遊戲的可玩性,因此在本次項目中,咱們會屏蔽經過數字交換獲得的等價數獨,這部分重複的數獨不計入最終結果。何爲「經過數字交換獲得的數獨」呢,請看下面的例子:

9 5 8 3 6 7 1 2 4
2 3 7 4 5 1 9 6 8
1 4 6 9 2 8 3 5 7
6 1 2 8 7 4 5 9 3
5 7 3 6 1 9 4 8 2
4 8 9 2 3 5 6 7 1
7 2 4 5 9 3 8 1 6
8 9 1 7 4 6 2 3 5
3 6 5 1 8 2 7 4 9

19的位置調換,能夠獲得一個新的「有效數獨」。

1 5 8 3 6 7 9 2 4
2 3 7 4 5 9 1 6 8
9 4 6 1 2 8 3 5 7
6 9 2 8 7 4 5 1 3
5 7 3 6 9 1 4 8 2
4 8 1 2 3 5 6 7 9
7 2 4 5 1 3 8 9 6
8 1 9 7 4 6 2 3 5
3 6 5 9 8 2 7 4 1

那麼每一個測試點的最終得分計算公式爲:

測試點正確性測試得分 × 不等價數獨組數 ÷ 實際需求個數個數

因爲只有數獨終盤才存在「等價數獨」的狀況,因此咱們將利用開發者提供的「求解數獨」命令行接口求解開發者生成的數獨遊戲,將求解後的終盤做爲判斷不重複數據比例的依據。好比某個測試點sudoku.exe -n 100 -r 30~40基準分爲10分,經過開發者提供的「求解數獨」命令行求解該命令生成的數獨遊戲後,發現求解出的數獨終盤一共有40組(等價的數獨都會歸類到同一組中),那麼最終開發者在該測試點的得分爲 40/100 * 10 = 4 分。

請注意,因爲開發者的求解數獨接口直接關係到數獨遊戲的評分,請確保sudoku.exe -s puzzle_file_path的接口依舊有效!

[新]錯誤處理

咱們都知道健壯性對於軟件來講是很是必要的,因此本次自動測試咱們也會加入各類各樣出錯狀況的測試。助教測試時將會選擇不一樣種類的出錯場景,要求開發者程序不會崩潰的狀況下,可以儘量精確報錯(就像編譯器同樣)。你能夠有「容錯性」的出錯設計,但必須輸出必要的提示或說明。

4. FAQ

有任何疑問請直接在本博客下留言,咱們會盡快回復。

5. 附錄

附:PSP 2.1表格

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