日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java数独流程图_软件工程个人项目总结-数独

發布時間:2023/12/10 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java数独流程图_软件工程个人项目总结-数独 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Github項目地址

包含博客

這篇博客將之前的每周所發整合成了一篇

PSP表格

PSP2.1

Personal Software Process Stages

預估耗時(分鐘)

實際耗時(分鐘)

Planning

計劃

60

60

· Estimate

· 估計這個任務需要多少時間

60

60

Development

開發

870

1710

· Analysis

· 需求分析 (包括學習新技術)

120

120

· Design Spec

· 生成設計文檔

120

160

· Design Review

· 設計復審 (和同事審核設計文檔)

60

30

· Coding Standard

· 代碼規范 (為目前的開發制定合適的規范)

120

60

· Design

· 具體設計

60

120

· Coding

· 具體編碼

240

500

· Code Review

· 代碼復審

30

120

· Test

· 測試(自我測試,修改代碼,提交修改)

120

600

Reporting

報告

150

240

· Test Report

· 測試報告

60

120

· Size Measurement

· 計算工作量

30

30

· Postmortem & Process Improvement Plan

· 事后總結, 并提出過程改進計劃

60

90

合計

1080

2010

需求分析

需求

運行一個命令行程序,程序能:

1. 生成不重復的數獨終局至文件。

2. 讀取文件內的數獨問題,求解并將結果輸出到文件。

數據建模

將數獨分成9個宮進行求解,ER表示如下,因為數獨左上角第一塊確定,所以將其看作數獨的屬性。

功能建模

數據源:用戶

數據終點:文件

主要數據流:生成指令、求解指令、數獨(待求解),以及終局

主要支持文件:待求解數獨文件

主要處理過程:生成終局、求解數獨

0層圖

對系統進行求精,劃分系統的子系統。

行為建模

解題思路

在最開始拿到題目的時候,想起上學期算法課程學過的回溯算法,決定用會回溯算法進行實現,所以翻看了算法設計的課本和ppt,對回溯算法重新進行了學習。在生成n個不同局面和求解給定數獨的思路大致一致,但有在細節處的處理有些不同。首先是生成n個不同的局面,按行進行循環,有一個二維數組保存每個位置的可能數字,從可能數字中隨機選一個放在該位置,若該位置找不到可能的位置,則回到上一個,修改上一個位置的解。不斷進行回溯,直到所有的位置都合法。若是對給定局面進行求解,則將空白位置用數組記錄下來,只對空白位置進行回溯即可。

但在該回溯算法中,搜索時盲目的,效率較低,最差的實現對每個空方格試探所有可能的數字,有大量的時間浪費。并且如果需要生成多個終局時,每一個終局都是通過回溯實現,且生成不同的終局由Random()進行數字選擇實現,但實際上Random生成偽隨機數,在一定時間會生成相同隨機數,無法保證在生成終局數目足夠大時,不會產生兩個相同的終局。

因為算法效率有很大的改進空間,以及無法保證在n足夠大時,所有終局都相異,所以在對代碼重構的過程中,引入了排列組合的算法,對原有進行優化。將數獨分成9個3X3的小方塊,每個小方塊是一個宮。

參考維基百科提供的一個生成終局思路,由第一宮生成其余八個宮。對第一宮中的塊進行排列組合即可,因為生成終局時,要求左上角的第一個數為:(學號后兩位相加)%9+1,(1+3)%9+1=5,所以左上角為5,且不允許改變。即在第一宮內只有八個塊可以移動,有8!=40320種情況,并且在每一宮內(除了第一宮)進行列列變換有3!×3!×3!×3!=1296,第二宮和第三宮可以交換,第四宮和第七宮可以交換有2!×2!=4,總共可以生成209,018,880個終局(大于1,000,000),此方案可行。

對于各種全排列,使用遞歸的方式實現。

設計實現過程

???編譯器:Intellij IDEA 2019.2

???語言:java

???運行環境:JDK 1.8

活動圖

順序圖

下面是生成終局的順序圖

下面是求解數獨的順序圖

類圖

???共有三個類,Main用于判斷輸入是否合法、將終局寫入文件、判斷輸入命令是否合法,Generate類用于生成終局,Solve類用于求解數獨。

具體代碼說明

Generate中主要函數:

?generateSudoku 外部調用的接口,傳入一個n(n<=1,000,000),即可以生成n個終局。

createSeed 將第一宮作為種子,進行交換操作,得到不同的種子。

createMap 通過種子的變換,得到該種子生成的第一個終局。

changeIndex 對于第一個終局進行行列變換,生成不同的終局。

writeToOutput 將生成的int[ ] [ ]的終局,按照輸出格式要求,存放在一個char[]中 。

changeIndex流程圖如下

具體實現代碼如下所示,在goalNum=1時,不用進行變換,在>1開始,先交換index[16]和index[17],即先在第三大列內進行列變換,可以有6中不同的終局,接著在第二大列內進行交換,依次類推,到行進行交換,可以快速產生大量不相同的終局。

/**

* @Title: changeIndex

* @Description: 對宮內的行列進行全排列

* @param a

* @param start

* @param end

* @return void

* @throws

*/

public void changeIndex( int start, int end) {

int i;

//分段進行全排列

if (start == end) {

if (end == 5) {

changeIndex( 6, 8);

}else if(end==8){

changeIndex( 12, 14);

}else if(end==14){

changeIndex( 15, 17);

}

else {

writeToOutput();

}

}

else {

for (i = start; i <= end; i++) {

swap(index, start, i);

changeIndex( start + 1, end);

if (nowNum == goalNum) break;

swap(index, start, i);

}

}

}

Solve中主要函數

findSolution外部調用的接口,傳入一個txt的絕對路徑,即可對該txt中的數獨進行求解。

dealFile將txt中的所有數獨,存在一個int[]中,并得到要求解的數獨數目。

initCriterion將Criterion(表示行列宮沒有用過的數)初始化,并將數獨中出現過的數在Criterion進行標記。

chooseCriterion遞歸對數獨進行求解。

chooseCriterion流程圖

chooseCriteron和dealWithCriterion是求解數獨的主要兩個函數。chooseCriterion中state表示當前是否能找到可行解,找到返回true,沒找返回false。先循環1-9九個數,找到一個所在行、列、宮都沒有使用過的數放入,然后調用dealWithCriterion函數,若后面的位置沒有待求解位置,則返回true,此時state為true,結束求解。若后面仍有待求解位置(a,b),則dealWithCriterion函數返回chooseCriterion(a, b)進行求解,若可以找到可行解,則前面所求解保留,若找不到,則修改前面找到的可行解。本質是利用回溯算法進行求解。

起初兩個函數寫在一起,但在代碼質量檢查時,該函數復雜度太高,所以拆分成兩個函數

/**

* @Title: chooseCriterion

* @Description: 回溯選擇合適的數

* @param row

* @param col

* @return boolean

* @throws

*/

private boolean chooseCriterion(int row, int col) {

int value;

boolean state = false;

for (int k = 0; k < 9; k++) {

if(!state) {

value = k + 1;

if (!fill(row, col, value)) {

continue;

}

map[row][col] = value;

usedNum(row, col, value);

state = dealWithCriterion(row, col);

if (!state) {

releaseNum(row, col, value);

map[row][col] = 0;

}

}

}

return state;

}

/**

* @Title: dealWithCriterion

* @Description: 查找是否有空位要求解

* @param row

* @param col

* @return boolean

* @throws

*/

public boolean dealWithCriterion( int row, int col) {

//沒有空位

boolean state = false;

for (; row < 9; row++) {

for (; col < 9; col++) {

if (map[row][col] == 0) {

state = true;

break;

}

}

if (state)

break;

col = 0;

}

//沒有空位

if (!state) {

return true;

}

return chooseCriterion(row, col);

}

Main中主要函數

stringToFile傳入一個char[],將其寫入可執行文件同級文件夾中的layout.txt(沒有會創建)。

isNumeric,whetherSolve,whetherGenerate都是判斷輸入是否合法。

測試

?使用Junit5對三個類分別進行單元測試,單元測試的編寫思路是黑盒測試,運用了路徑覆蓋和邊界覆蓋。對接口功能、邊界條件等進行測試,并使測試覆蓋率盡可能,測試用例盡可能全面。

?MainTest用于測試輸入是否合法,以及是否可以順利寫入文件,

?GenerateTest測試其中的函數是否正常,并進行了重復性檢測,檢測器生成的1000個終局中是否有相同的情況。

?SolveTest對Solve中部分主要函數進行了檢測,并對求解結果進行了有效性檢測,判斷是否是否求出了正確的數獨解。

?單元測試覆蓋率

Main部分測試設計(期待狀態=實際狀態,即為成功)

編號

內容

狀態

1

args[0]=11,args[1]=null

成功

2

args[0]="-c", args[1]="0"

成功

3

args[0]="-c", args[1]="1_000_001"

成功

4

args[0]="-c", args[1]="1_000_000"

成功

5

args[0]="-c", args[1]="D:/1.txt"

成功

6

args[0]="-s", args[1]="D:/1.txt"

成功

7

args[0]="-s", args[1]="D:/app/"

成功

Generate部分測試用例

函數

內容

狀態

createSeed

seed={1,2,...9},goalNum=1

成功

createSeed

seed={1,2,...9},goalNum=100

成功

createMap

int[][] temp={{5,1,2,7,8....},goal=1

成功

createMap

int[][] temp={{5,1,2,7,8....},goal=1

成功

swap

交換兩個數

成功

generateSudoku

count=1000(檢測生成的1000個終局是否重復)

成功

generateSudoku

count=1,000,000(檢測生成的1,000,000個終局是否重復)

成功

Solve部分測試用例

函數

內容

狀態

findSolution

PATH=txt路徑,里面有1000個數獨,檢查找到的解是否正確

成功

findSolution

PATH=txt路徑,里面有100個高難數獨,檢查找到的解是否正確

成功

fill

Criterion[0]=510,Criterion[9]=510,Criterion[18]=510,row=0,col=0,value=5;

成功

releaseNum

PATH=txt路徑,row=0,col=0,value=4;

成功

getBlock

row=0,col=0

成功

getBlock

row=3,col=4

成功

通過命令行執行程序,對得到結果進程測試

編號

命令行參數

結果

1

-c 0

能生成的終局在1-1,000,000之間

2

-c -1

能生成的終局在1-1,000,000之間

3

-c 1000

運行成功

4

-c 1000000

運行成功

5

-c 1000001

能生成的終局在1-1,000,000之間

6

-c

生成終局命令為:java sudoku -c 阿拉伯數字

7

-a

您的輸入不正確

生成終局命令為:java sudoku -c 阿拉伯數字

求解數獨命令為:java sudoku -s puzzle.txt的絕對路徑

8

-s D:\app\

路徑需指向一個txt文件

9

-s D:\app\unexisted.txt

系統找不到指定的文件

10

-s puzzle.txt

運行成功

代碼質量分析

?用SonarLint插件對每個java文件進行代碼質量優化

?分析過后,除了Main類中因為需要打印命令錯誤提示,仍存在一些warning,其余文件中的warning全部消除。

性能改進

用Intellij中插件JProfiler進行程序性能分析

最初的程序每生成一個終局,直接寫入文件,且進行回溯時,多次進行值的交換。為了保證隨機性,每一次將所有可能值先放入鏈表,然后將隨機選取一個放入該空位。在求解數獨時,先讀取一個數獨,求解后寫入文件,再繼續讀取下一個數據。這種算法會頻繁創建很多對象,且讀寫會花費大量的時間。

改進后,時間上有了非常大的提升,且在回溯,用一個27位數組Criterion,前九位表示每一行可能解,中間九位表示每一列可能解,最后九位表示每一個宮的可能解,且每一個數可以表示成一個九位的二進制,從右到左依次表示1-9,若Criterion[0]=000_000_001,則表示第一行只有1沒有用過,該位置的可行解只有1。選擇一個數時只需將該數與對應的下標的Criterion進行與運算,即可將該數標記為使用,這樣減少了反復復制的時間。且改進后不再隨機選取可行解,按順序進行選擇。

并且改進后每生成一個終局,先放在一個char數組中,生成所有的終局,統一寫入文件;在求解數獨時,一次讀取出所有的待求解數獨,每個分別求解,再統一寫入。

下圖為Jprofiler中提供的CallTree,通過樹形圖體現了方法間的層次調用關系,并按照執行總時間從小到大排列。

改進之前,用FileWriter寫入文件,生成1000個終局需要12s左右。每生成一個終局馬上寫入文件。下圖看到關閉流花費了大量的時間。

改進后,用BufferedWrite寫入文件,由于含有緩沖區,所以效率要比FileWriter高,但內部仍用FileWrite進行讀寫。在生成1000個終局時,總耗時為0.034s。由下表寫入文件所消耗的時間遠大于生成終局。

以后討論情況均為改進以后

在生成1,000,000個終局時,總耗時0.805。stringToFile,即將終局寫入文件所占比例最大,即耗時最長,但生成終局的方法generateSudoku執行耗時雖然不是最長,但仍占有較大的比例。

綜合生成1000和1,000,000個終局可得,在生成終局的情況下,stringToFile時消耗最多的函數。

在求解數獨時,首先讀取1000個數獨,進行求解,總耗時0.325s。此時findSolution函數耗時最多,但在這個函數中會調用其他函數,其中dealFile即讀取文件耗時最多。

求解10,000個數獨時,findSolution耗時最多,在該函數調用的函數中,SolveSudoku求解數獨的函數耗時超過了讀取文件的耗時。在求解數目較小,讀取文件的時間相對較長,在求解數獨變大以后,求解數獨的時間要更長。

GUI界面開發

開發運行環境

運行環境:JDK1.8

運行命令:java -jar sudokuGUI.jar

語言:java

開發環境:Intellij IDEA 2019.2,JavaFX Scene Builder 8.3.0

項目結構和說明

為了利用之前的源代碼,UI界面采用javafx進行開發,使用MVC框架來設計整個應用,使用了數據綁定,通過構建容器組件,添加menu、監聽器等實現圖形化界面功能。

軟件功能說明

主要頁面如下所示,一打開應用自動進行計時。

點擊菜單中的開始,可以開始新游戲、提交當前頁面,查看答案,退出游戲。

點擊提交時,計時器停止,若有空位置沒有填,會提示填滿再提交,若有錯誤會彈窗會提示,完全正確時會彈窗恭喜用戶。

面向對象分析設計

用例圖

類圖

總共有五個類

Main用于顯示UI界面,界面用xml編寫,在sample.xml中。

Controller監聽圖形頁面、鼠標、鍵盤等。

Solve驗證用戶提交的數獨是否正確。

Generate用于生成終局,對終局隨機挖空,形成數獨,顯示在UI中。

AlterInfo用于彈窗提示。

SudokuCell表示數獨中的每一個小塊,控制是否可以輸入,顯示數字等。

狀態圖

設計思路

GUI中的主體代碼和命令行部分幾乎一致,最開始選擇生成數獨的回溯算法。最初實現UI界面,用了優化以后利用排列組合快速生成終局的算法,但因為終局是由變換第一宮形成的,所以存在規律性,降低數獨的可玩性。所以采用了最初生成終局的回溯算法。

實現思路是先通過回溯算法生成一個終局,因為要求最少挖30個空,最多挖60個空,每個宮中最少有兩個。當每個最少挖4個,4×9=36符合要求,每個宮最多挖6個,6×9=54個符合要求。所以循環九個宮,每個宮產生一個隨機數n(4<=n<=6),然后在1-9中生成n個不同的隨機數,在該宮中將n個隨機數所在的位置挖掉,便生成了一個數獨。

在編寫代碼的過程中,卡殼了很久一直在思考如何保證數獨解的唯一性,但因為自己對這部分算法的理解并不是很深入,所以放棄了保證了數獨解的唯一性。用戶提交數獨時,不與最初生成的終局比較,而是利用循環檢查用戶提交的答案中是否有錯誤,沒有錯誤即為正確答案。若用戶選擇查看答案,則提供最初的終局。

自定義了一個數據類型SudokuCell,來存放數獨中的每一個小塊,其中設置一個屬性write保證可以多次修改答案,若數獨中該位置需要填寫,則將write設置為true,若不需要則設置為false,并且可以對每一個SudokuCelle用css進行美化,使數獨的外觀更加美觀。

具體代碼實現

對用戶提交數獨進行檢查,正確時返回true,錯誤時返回false,這個方法在命令行中用于測試,檢查對txt數獨中求解時,是否有錯誤。

/**

* @Title: checkSolution

* @Description: 檢查結果

* @param data

* @return boolean

* @throws

*/

boolean checkSolution(int[] data)

{

int index=0;

int[] criterion=new int[27];

Solve s=new Solve();

for (int j = 0; j < 27; j++) {

criterion[j] = 511;

}

s.setCriterion(criterion);

if(!checkSudoku(data,index,s))

return false;

return true;

}

/**

* @Title: checkSudoku

* @Description: 檢查數獨答案是否正確

* @param data

* @param index

* @param s

* @return boolean

* @throws

*/

private boolean checkSudoku(int[] data,int index,Solve s) {

for (int j = 0; j < 9; j++) {

for (int k = 0; k < 9; k++) {

while (data[index]>9 || data[index]<1)

{

index++;

}

int temp = data[index++];

if (!s.fill(j, k, temp)) {

Logger logger=Logger.getLogger("SolveTest");

logger.setLevel(Level.SEVERE);

String msg="row:"+(j+1)+"clo:"+(k+1)+"value:"+temp;

logger.severe(msg);

return false;

}else{

s.usedNum(j,k,temp);

}

}

}

return true;

}

測試

因為GUI項目中,除了UI部分代碼,都是在命令行中經過測試的代碼,所以只進行簡單的系統測試,檢測頁面的響應、監聽等是否正常。

編號

操作

預期結果

實際結果

狀態

1

頁面有空位,點擊提交

未完成彈窗

未完成彈窗

通過

2

頁面沒有空位,存在錯誤,點擊提交

錯誤彈窗

錯誤彈窗

通過

3

正確完成數獨,點擊提交

正確彈窗

計時停止

正確彈窗

計時停止

通過

4

點擊查看答案

顯示答案

計時停止

顯示答案

計時停止

通過

5

點擊退出

退出程序

退出程序

通過

6

點擊新游戲

開始新游戲

開始新游戲

通過

7

在空位輸入非數字字符

輸不進去

輸不進去

通過

8

在空位輸入數字字符

空位顯示該數字

空位顯示該數字

通過

9

點擊查看答案以后,點擊提交

正確彈窗

正確彈窗

通過

10

點擊關于

信息彈窗

信息彈窗

通過

11

點擊幫助

幫助彈窗

幫助彈窗

通過

簡要開發過程

時間

內容

2019年12月19日 - 2019年12月20日

需求分析、概要設計

2019年12月26日 - 2020年1月1日

基本完成命令行功能

2019年12月26日 - 2020年1月1日

開始單元測試

2020年1月2日 - 2020年1月3日

修改算法、對代碼結構進行優化,完成測試

2020年1月4日 - 2020年1月16日

代碼質量檢測、UI編寫

2020年1月17日 - 2020年1月18日

博客優化

總結

以上是生活随笔為你收集整理的java数独流程图_软件工程个人项目总结-数独的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。