这个作业属于哪个课程 | https://edu.cnblogs.com/campus/zswxy/software-engineering-2017-1 |
---|---|
这个作业要求在哪里 | https://edu.cnblogs.com/campus/zswxy/software-engineering-2017-1/homework/10494 |
这个作业的目标 | 编写数独小程序,并对其进行性能优化,单元测试 |
作业正文 | 下文 |
其他参考文献 | 百度 |
Github地址:https://github.com/Dagenjun-kami/Sudoku
PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 60 | 60 |
Estimate | 估计这个任务需要多少时间 | 1350 | 1190 |
Development | 开发 | 1200 | 1070 |
Analysis | 需求分析 (包括学习新技术) | 240 | 180 |
Design Spec | 生成设计文档 | 70 | 60 |
Design Review | 设计复审 | 70 | 50 |
Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 50 | 50 |
Design | 具体设计 | 50 | 120 |
Coding | 具体编码 | 400 | 300 |
Code Review | 代码复审 | 60 | 60 |
Test | 测试(自我测试,修改代码,提交修改) | 120 | 300 |
Reporting | 报告 | 150 | 120 |
Test Repor | 测试报告 | 60 | 60 |
Size Measurement | 计算工作量 | 45 | 0 |
Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 45 | 60 |
合计 | 1410 | 1250 |
思路描述
数独是我日常喜欢玩的一款游戏,但是玩的时候基本上是凭经验和感觉的,要我解释我是如何解数独,以我的表达能力也说不出什么。电脑解数独的话,我认为就是一格一格1-9不断尝试,无法填入就返回上一格,直到盘面全部填满为止,通过百度,我了解到这应该是叫做回溯法。
大致思路是有了,但是编程不仅仅是有了思路即可的,技术不达标,一切都是空话。
要实现数独程序,需要解决以下问题:
1.如何使用命令行传入参数?
2.如何实现txt文件读入并存入数组及txt文件的写出?
3.如何实现解数独?
通过我的不懈努力(百度),找出了各种各样的解决方法,接下来就剩领悟这些代码了,看了大佬们的博客之后越来越觉得自己就是个废物
好在最后终于!还是把代码给逼了出来!
在此感谢那些网络上的大佬们!要不然咱这样的渣渣哪能够按时完成作业呢
功能模块设计
-
读取指令模块
主函数的String args[]可以传入命令行的参数,用load()函数对args[]进行处理
public static void load(String args[])
{
m = Integer.valueOf(args[1]);
n = Integer.valueOf(args[3]);
inputFileName = args[5];
outputFileName = args[7];
}
-
文件IO模块
这部分对我来说是最困难的。
事实证明有关IO的知识,我是完全没有学好,哎,没法,只能慢慢仔细研究网上大佬的代码了,研究了老半天,总算有了点头绪
用split()将txt文件分割保存为字符串数组,再通过Integer.parseInt()保存为m*m整型二维数组
static void fileIO() { try { BufferedReader br = new BufferedReader(new FileReader(inputFileName)); PrintStream ps = new PrintStream(new FileOutputStream(outputFileName,true)); System.setOut(ps); for(int p=0 ; p<n ; p++) { int i=0;String s; boolean first = true; int emptyRow = 0,emptyCol = 0; //读入文件写入数组循环 for(int k=0 ; k < m ; k++) { if ((s = br.readLine()) != null); { String[] temp = s.split(" "); for (int j = 0; j < m; j++) { sudoku[i][j] = Integer.parseInt(temp[j]); if (sudoku[i][j] == 0) { if (first) { emptyRow = i; emptyCol = j; first = false; } emptyNum++; } } i++; } } backTrace(emptyRow,emptyCol); if(p<n-1) { System.out.println(); } br.readLine(); } br.close(); ps.close(); } catch (FileNotFoundException e1) { e1.printStackTrace(); System.exit(-1); } catch (IOException e2) { e2.printStackTrace(); System.exit(-1); } }
-
判断行列宫有无重复模块
先判断行列,重复则返回false,再判断宫,3,5,7没有宫就直接返回true,4,6,8,9有宫的先定义宫的大小,计算每个宫第一格坐标,再用两个For循环判断
public static Boolean judge(int a[][],int row, int col, int num,int m) {
for (int i = 0; i < m; i++) {
if (i != row && a[i][col] == num) {
return false;
}
if (i != col && a[row][i] == num) {
return false;
}
}
int x, y, px = 0 , py = 0;
//宫的大小
if (m == 3 || m == 5 || m == 7) {
return true;
}
if (m == 4) {
px = 2;
py = 2;
} else if (m == 6) {
px = 2;
py = 3;
} else if (m == 8) {
px = 4;
py = 2;
} else if (m == 9) {
px = 3;
py = 3;
}
//(x,y)是(row,col)所属小宫格第一格的坐标
x = row / px * px;
y = col / py * py;
for (int i = x; i < x + px; i++) {
for (int j = y; j < y + py; j++) {
if (i != row && j != col && a[i][j] == num) {
return false;
}
}
}
return true;
}
-
回溯法解数独模块
画了一个简单的流程图
static void backTrace(int row , int col) { for(int i = 1 ; i <= m ;i++) { //填上行列宫不重复数字 if(judge(sudoku,row,col,i,m)) { sudoku[row][col] = i ; emptyNum--; //填完所有空缺 if(emptyNum==0) { print(); break; } int tempArray[] ; tempArray = nextEmpty(row,col); backTrace(tempArray[0] ,tempArray[1]); //回溯 sudoku[row][col] = 0; emptyNum++; } } }
-
待填空缺定位模块
用两个for循环嵌套,找出为零的坐标
测试过程
在测试过程中出现这样的情况,开始以为代码有错,检查了老半天,结果发现是输入数独第一个和第三个无解!
不过,这也告诉我程序缺少报错功能!
用flag判断结果是否输出即可解决此问题
测试结果
编写有且只有一个结果的数独太麻烦了,所以就挑选几条有代表性的进行测试
就酱吧!
性能优化
嗯......完全看不懂!还全是英文,百度了也百思不得其解
慢慢研究吧
总结
这次作业让我明白了自己的不足,也促使我去学习新知识,关于单元测试和性能分析优化啥的,真是一窍不通,完成作业的过程是很痛苦的,交作业的紧迫感使得我这名养生的中年少女开始熬夜,每天醒来只想搞学习,结果……还算愉快?编写出程序还是有些成就感的,希望我可以进步吧!交作业截止时间迫在眉睫,先这样吧,没有完成的部分,希望我能够在后续完成。
编程技术得到提高的话,熬的夜应该会少点了……吧?