一、 Github项目地址
https://github.com/mykang0318/hello-world
二、 PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 120 | 120 |
Estimate | 估计这个任务需要多少时间 | 120 | 120 |
Development | 开发 | 1380 | 1970 |
Analysis | 需求分析 (包括学习新技术) | 600 | 1200 |
Design Spec | 生成设计文档 | 60 | 30 |
Design Review | 设计复审 | 60 | 20 |
Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 60 | 10 |
Design | 具体设计 | 120 | 30 |
Coding | 具体编码 | 300 | 500 |
Code Review | 代码复审 | 120 | 60 |
Test | 测试(自我测试,修改代码,提交修改) | 60 | 120 |
Reporting | 报告 | 90 | 70 |
Test Repor | 测试报告 | 30 | 20 |
Size Measurement | 计算工作量 | 30 | 20 |
Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 60 | 120 |
Total | 合计 | 1620 | 2250 |
三、 解题思路描述
刚刚拿到题目首先想到的是直接使用枚举法,一个一个的填,一个数一个数的试。但是要用到命令行程序,我一开始是没搞明白什么是命令行程序的。后面百度查资料才了解到什么是命令行程序,Java中命令行输入的参数都保存到main()函数的args[]数组里面,只需要取出这些参数拿来用就行。其次是需要读取文件,和写入文件。所以看到这题目我先将指定的文件内容读取出来存到ArrayList数组里面。然后一行一行的保存到一个数组里面,每m行是一个数独盘,进行填数,得到能填的数就填上去,如果这一步没有能够填的数就返回到上一次要填数的地方,将这个数重新填下一个数,如果没有能填的就报错程序结束。如果有就再往下走。每完成一个数独盘就写入到指定文件中。目前还只是完成三宫格,后面还会继续完成四宫格、五宫格...九宫格。
四、 设计实现过程
1. 类与函数
总共1个类,但是含有5个方法,分别是:input()方法,save()方法,number()方法,output()方法,check()方法。
其中,input()方法是将文件里面的内容(数独盘题目)读取输出到程序里面的数组中,然后调用save()方法进行填数,check()方法进行判断最后有没有填对,和output()方法进行将填好的数独盘进行写入到指定的文件。number()方法是在save方法里面被调用,用于填正确的数字。
2. 单元测试设计
对这5个方法分别进行测试,和输入一些特殊的或不符合规则的数字进行测试。发现自己的代码是先进入input()方法才调用后面的所有方法。所以测试都是直接想好情况输入不同的数据进行测试。
五、 改进思路
准备将每一个需要填的数的地方可以填哪些数保存到一个ArrayList数组里面,然后根据每一个地方可以填的数字的多少个来优先填哪个数。按照优先级排列,先从能选择的数最少的开始填,,再用蛮力法依次遍历要填的数,不合格就换下一个数。(这只是一个想法也不知道能不能行,还没有实现)当然还可以用更好的算法去实现。如:回溯算法等。(我在算法这一块的知识量还是太浅!)
六、 代码说明
1. 关键代码
public static void input(int a[][], int m) {
boolean flag = false;
int num = 0;
ArrayList<String> list = new ArrayList();
File file = new File(path + "\" + i_name);
try {
FileReader fileReader = new FileReader(file);
BufferedReader bufferedReader = new BufferedReader(fileReader);
String str = null;
while ((str = bufferedReader.readLine()) != null) {
if (!"".equals(str)) {
list.add(str);
}
}
String str2 = null;
int k = 0;
for (int i = 0; i < list.size(); i++) {
if (i > 0 && i % m == 0) {
k = 0;
a = save(a, m);
flag = check(a, m);
if (flag) {
output(a, m);
}
System.out.println();
}
str2 = list.get(i);
int l = 0;
for (int j = 0; j < str2.length(); j++) {
if (str2.charAt(j) != ' ') {
num = Integer.parseInt(String.valueOf(str2.charAt(j)));
if (num >= 0 && num <= m) { //添加一个判断读取出的数独盘的数是否符合规则
a[k][l] = num;
l++;
} else {
System.out.println("数独盘内容错误!题目错误!");
System.exit(0);
}
}
}
k++;
}
a = save(a, m);
flag = check(a, m);
if (flag) {
output(a, m);
}
fileReader.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static int[][] save(int a[][], int m) {
ArrayList<int[]> list = new ArrayList();
int[] b = new int[3];
int p = 1;
for (int i = 0; i < m; i++) {
for (int j = 0; j < m; j++) {
if (a[i][j] == 0) {
a[i][j] = number(i, j, a, p, m);
if (a[i][j] == 0) { //用于判断这一步是否没有数可填,如果为0,就放回到上一步判断的地方,再次进行判断
b = list.get(list.size() - 1);
i = b[0];
j = b[1];
if (b[2] + 1 > 3) {
System.out.println("该数据题目错误!");
System.exit(0);
} else {
a[i][j] = number(i, j, a, b[2] + 1, m);
continue;
}
} else {
b[0] = i;
b[1] = j;
b[2] = a[i][j];
list.add(b);
}
}
}
}
return a;
}
public static int number(int i, int j, int a[][], int p, int m) { //判断该填的数字 p为上次填的数,如果是第一次p还是从1开始
int num = 0;
for (int k = p; k <= m; k++) {
if (a[i][0] != k && a[i][1] != k && a[i][2] != k) {
if (a[0][j] != k && a[1][j] != k && a[2][j] != k) {
num = k;
break;
}
}
}
return num;
}
2. 思路说明
第一个关键代码是进行文件读取保存到数组,第二个关键代码是在数组中把每一个为0的数,也就是需要填的数填好数。第三个关键代码是进行判断可以填的数,传给save()方法进行填数。
七、 心路历程与收获
刚刚拿到《构建之法》这本书时,我“一口气”看完了第一章内容,让我明白了软件工程的重要性。以前只知道:程序=数据结构+算法。而现在知道:软件=程序+软件工程。而软件是需要开发、运营和维护的。软件工程就是用一些方法应用到软件的开发、运营和维护中的过程。书中用了一个例子来表达了从一个简单的小程序到工程的复杂过程和需要哪些步骤。而需要软件工程是为了创造“足够好”的软件。既能提高程序质量,又能便于维护,让用户满意。知道了写好一个软件,并不是写写程序就完事了的事。
第二章讲到了个人技术和流程。尤其是单元测试和PSP表格。以前我写一个程序是重来没有写过单元测试的。完全是写点程序运行下,看看有没有错误。有错误再去改代码,运行结果正确就完事了。对于一些特殊情况也许也有考虑不到的。在这次作业的写程序中,虽然我用到了单元测试,不过我还是不知道到底该怎么去测试。我能想到的就是输入几个例子然后依次看看结果正不正确。从书中还知道了做好单元测试需要覆盖所有的代码路径。所以我在这次作业中想到的是把需要运行的方法都测试一边。总的来说,我虽然知道需要单元测试,但是还是不太了解到底该测试什么,总感觉自己测试的内容还是没有覆盖所有代码路径。还是对自己写的程序认为有没有考虑到的地方。后面的PSP表格让我知道了首先计划好的好处。以前写一个程序从来都是直接敲代码。先写代码再说,代码里面有几个类,需要什么方法,都没有想好。都是想到哪里就写到哪里,然后写到后面认为不行的代码再改,甚至还会把很多代码都写在main()方法里面。使代码看起来很乱。而且写出这个PSP表格后也能更清晰的发现自己有哪些地方不足。比如说在这次作业中,我的需求分析所用的时间是最多的,大部分的时间都是在学习怎么去使用git和github,怎么去写单元测试。然后花了点时间先想好需要哪些方法,再去写代码。在写代码的过程也是让5我认识到了自己写程序的量还是少了。这次仅仅只写了三宫格的数独,就用了大约500分钟。其中很多的时间是用来了解什么是命令行程序和main()方法中的args[]数组里面存的是命令参数。还有再次复习了对文件的输入输出。说明了自己的基础还不牢固。
第三章讲了软件工程师的职业技能规划之类的。让我印象深刻的是最后讲的那个“到底精不精通魔方”的例子。像我自己,现在认为自己还是在经常解决一些低层次的问题。书中将一个技能的学习过程分为三个层次:低层次问题、中间层次的问题和高层次的问题。而我从这次作业中认识到自己还是在经常解决低层次问题,在写程序时,还是因为一些函数不太了解啊(有印象,或者以前学过又忘了,现在又得重新学),觉得需要用到这个函数,但是又不记得该怎么用了。然后我就只能自己乖乖的网上找和查看帮助文档。在这里面花费了很多的时间。比较刚刚拿到这次作业——九宫格。时还是认为比较简单的,结果在写程序时,各种问题就出现了,尤其是自己直接用笔去填九宫格和怎么去让程序去填正确的数区别还是很大的。像那个关于“魔方”的例子。与我自己会哪些专业技能做比较。想一想自己会C语言吗?会点写个小程序,但是连指针都忘记差不多了还算是会吗?再比如自己会的Java语言。从这次作业中体现了我自己还算是会Java吗?感觉自己还是学的太浅了,第一次作业在写简历时,把自己学过的都写了上去,但是真正的能够不用上网找,不用查资料的几乎没有,像我学过的前端的Vue。虽然看过几集视频。但是要说自己会吗?感觉还是不会的,甚至在真正写代码的过程中根本不会用到这些方法。而且还有很多我对Vue没有深入了解过的使用方法、功能。
总的来说,在这次作业中,认识到了自己哪些地方有不足的,还需要在这些地方多多加油!“精通”尚未成功,“本人”还需更加努力!