大二软件构造第一次实验
本人本次实验操作系统:macOS high Sierra 10.13.3
任务一:MagicSquare
对于本任务,主要需要实现两个方法,一个是isLegalMagicSquare方法,一个是generateMagicSquare方法。
首先,是要实现isLegalMagicSquare方法,该方法是根据一个String fileName判断路径所指的文件内容重的数据能否构成一个幻方。若能,则返回true,否则返回false。
当然,这个方法要能够正确处理几种异常情况。包括所读入的数据根本不足以构成一个方阵、传入数据不是整数、数据之间不是用' '字符来分割的等等。对于这些异常情况,要简单输出错误信息,继而方法返回false。
对于这个任务,我的想法比较简单:首先读入一行数据,根据这行数据就可以确定这个Square的列数(col)和一行数的和(sum)。对于一个幻方来说,这两个数字是唯一确定的,也就是或只要根据第一行数据确定了这两个数值,就能据此判断接下来输入的内容能否保证这组数据构成一个幻方。
于是在每次读入一行数据之后,都可以对这一行的sum值(这里记为temp)进行判断。若temp等于sum,则继续读入下一行,并把本行数据存入二维数组中;若temp不等于sum,则直接输出错误信息:这不是一个方阵,进而方法返回false即可。此方法同样适用于判断这一行的col值和已计算的col值是否相等。同样地,当一行数据用其余分隔符来分割时,由于预设的每一行数据是根据' '来进行分割的,故这样的读入的数据行会使得数据的个数不相等,从而也会输出错误信息并返回false。若读入的数据不是一个整数,则在程序中会抛出一个异常,通过捕获这个异常来实现输出错误信息并将方法返回false即可。
其次,是要实现generateMagicSquare方法,本方法也是一个返回值为boolean的函数。在实验手册上,已经给出了这个方法的主要代码,要添加的功能就是判断输入的参数n是否合法。
首先,说明一下这个方法的功能:构造一个n阶幻方矩阵(n为传入参数),其中n一定是一个奇数,同时一定要是一个大于零的整数。故根据其功能,要先对传入的参数进行判断,若传入的n是非正数或是一个偶数,则输出错误信息,并且使方法返回false。其次,要把生成的幻方矩阵数据写入到一个指定文件中。
对于这个任务,我遇到的问题在于文件读写上。因为之前并没有太多地接触到Java程序从文件中读写数据,正好利用这次实验来学习一下。
通过Bing一些网上论坛、翻看一些Java编程资料。基本掌握了Java程序读写文件的方法。对于Java这种典型的OOP编程语言,一切内容都是围绕着类与对象展开的。所以有了OOP的编程思想,学习文件读写的这些内容也不是很难。
任务二:Turtle绘图
Turtle是MIT最初开发的一种图形化编程工具,用来解决太空航天方面的一些问题。本任务就是实现一些简单的Turtle绘图基本方法。
获取实验包文件之后,观察比较这几个Java文件,基本对整个任务有了一定的认识。实验已经提供了TurtleGUI文件、Turtle工具类等文件,要实现的也只是几个方法。而且其中最重要的forward和turn方法已经实现了。根据要求,要完成一些类似于绘制正方形、正多边形等方法。
根据中学知识,很容易完成其中的根据正多边形的边数来求其内角度数、根据多边形内角度数求出其边数(分别是angle = (sides - 2) * 180° / sides 和 sides = 360° / (180° - angle) )。
然后是完成一个方法,使其计算出当前顶点到指定顶点,Turtle应偏转的角度。这个方法利用到了中学学过的向量部分的知识,通过将向量知识与三角函数结合起来,即可计算出应当偏转的角度。
这个任务中需要注意的内容就是如何用库函数求解偏转角度以及计算结果的精度舍入问题。在Java的Math库中,提供了这样的一个方法:atan2方法。该方法通过传入一个向量,即可计算出其对应的角的大小。这个方法的返回值,实际上是直角坐标系y轴正方向和向量所成角的大小,而且返回值为对应角的弧度值。因而要对这个角有一个正确的认识,并将其单位进行一个简单的转换。在这个任务中,我曾因为不会导入JUnit进行测试而被困住,最后在同学帮助下成功解决了这个问题。
最终,所有方法均完成了预期功能要求,并且一些特定的方法也通过了JUnit的测试。
、
任务三:Social Network
根据实验手册可知,这个任务用到了简单的图论方面的知识。相对而言,这个任务就显得十分简单了。
对于这个任务,主要实现构建一个图(存储于一个邻接矩阵中)并计算出图中顶点之间的最短路径。下面说一下每个方法的设计与实现。
addVertex(Person)方法:实现向图中添加顶点的功能。在这个方法中,将Graph的内部Person类总数更新,从而实现确定遍历的二维数组的大小。
addEdge(Person, Person)方法:功能:为传入的两个顶点(Person类对象)之间构建一条单向边。我设计的方法中,默认传入的两个Person类对象已经通过addVertex(Person)方法加入到图中。其结果就是让顶点之间的邻接矩阵值置为1。
addVertex(Person, Person)方法:功能:为传入的连个顶点(Person类对象)之间构架一条单向边。这个方法是从实验手册中读到的,根据我的理解, 所重载的addVertex方法实现了与前两者不同的功能。本方法首先会判断传入的Person类对象是否已经存在于图中,若存在,则直接在传入的顶点之间搭建一条边,若不存在,则先在图中创建出这个顶点,再在传入的顶点之间构建一条单向边。
就三者功能而言,可以这样理解:addVertex(Person, Person) == addVertex(Person) + addEdge(Person, Person)。
此外,我还设计了一个generate的方法,该方法的功能是将邻接矩阵转换为最短路径矩阵。通过实验手册的代码,我理解为每次搭建了一条边之后,都会将这个邻接矩阵更新为最短路径矩阵,因而会在每次调用addEdge方法(addVertex(Person, Person)方法)时调用generate方法。从而实现了运行中程序结果的更新。
-------------------分割线开始-------------------Date:2018.3.8
/* 经过一番讨论,发现...上述的addVertex(Person, Person)方法,不存在。
* 也就是说,实验手册中,这个功能其实指的就是addEdge方法,于是也就不存在不经过addVertex方法直接调用addEdge方法的情况。
* 也就是说,上述对于addVertex(Person, Person)的讨论,是无意义的... (不妨作为实验外的一个小玩意儿)
*/
所以为了回归到实验,在此说一下新想法:
手册中提到:不能使用静态变量或方法(除了定义的final常量或main方法)。因而在Person类的构造器中来判断是否重名就变得有些棘手,因为不能在Person类中定义一个静态nameList来存储已经构造的对象的名字,而且此处定义静态nameList的话对于后面重新创建FriendshipGraph来讲,还会有一些问题。故...舍... -.-||
于是乎,对于判断是否重名的过程,就放在了Graph的addVertex方法里,这样想来,也是一样简单明了,实现起来,也不会很难,只需在FriendshipGraph类里定义个List存一下就ok。
这样就能很好地满足实验要求,实现起来也变得更加简洁。
反思一下犯错误的原因:没能很好地理解手册中提到的“一旦该条件被违反,提示出错并结束程序运行”。
-------------------分割线结束-------------------Date:2018.3.8
实验总结:
第一次实验,总体来说还是比较简单的。主要使得自己对Java编程更加熟悉,对Eclipse中工程项目的构建更加熟悉。此外,收获最大的就是对git的学习和使用。
之前对于git使用得并不多,但通过本次试验,对git进行更深的学习,才发现git原来是管理代码与协作的一个“法宝”。并且对git的简便与功能之强大深深折服。
在一次提交实验目录到GitHub时,出现了ssh无法连接的状况(我的git本地仓和GitHub之间采用的是ssh协议)。在网上查了一下相关的解决文档,大都是建议更改ssh配置文件sshd_profile。当我准备尝试把这个配置文件的权限改一下的时候,发现又可以正常连接了。期间我只是尝试了一下 $ git push -u origin master (当做第一次push,甚至未曾进行远程仓库重新绑定)。这个问题就这样迷一般地解决了,若以后再次遇到,等我解决后,也会分享一下解决经验。
最后,感谢Google翻译对本次实验的大力支持...
附(本次实验中用到的相关文档或资料网站):
《Java编程思想(第四版)》
实验手册:https://cms.hit.edu.cn
获取实验包的GitHub地址:https://github.com/rainywang/Spring2018_HITCS_SC_Lab1
MIT关于Turtle绘图的实验要求说明:http://web.mit.edu/6.031/www/sp17/psets/ps0/
个人本次实验GitHub仓库地址(私人仓库,供本人在此页查看跳转使用):https://github.com/ComputerScienceHIT/Lab1-1160300320