2020年春季学期计算机学院《软件构造》课程 Lab 1实验报告
目录
1 实验目标概述 1
2 实验环境配置 1
3 实验过程 2
3.1 Magic Squares 2
3.1.1 isLegalMagicSquare() 2
3.1.2 generateMagicSquare() 3
3.2 Turtle Graphics 6
3.2.1 Problem 1: Clone and import 6
3.2.2 Problem 3: Turtle graphics and drawSquare 6
3.2.3 Problem 5: Drawing polygons 7
3.2.4 Problem 6: Calculating Bearings 8
3.2.5 Problem 7: Convex Hulls 9
3.2.6 Problem 8: Personal art 9
3.2.7 Submitting 10
3.3 Social Network 11
3.3.1 设计/实现FriendshipGraph类 11
3.3.2 设计/实现Person类 12
3.3.3 设计/实现客户端代码main() 12
3.3.4 设计/实现测试用例 13
4 实验进度记录 14
5 实验过程中遇到的困难与解决途径 14
6 实验过程中收获的经验、教训、感想 15
6.1 实验过程中收获的经验和教训 15
6.2 针对以下方面的感受 15
1 实验目标概述
本次实验通过求解三个问题,训练基本 Java 编程技能,能够利用 Java OO 开 发基本的功能模块,能够阅读理解已有代码框架并根据功能需求补全代码,能够 为所开发的代码编写基本的测试程序并完成测试,初步保证所开发代码的正确性。 另一方面,利用 Git 作为代码配置管理的工具,学会 Git 的基本使用方法。 基本的 Java OO 编程,基于 Eclipse IDE 进行 Java 编程,基于 JUnit4 的测试 ,基于 Git 的代码配置管理。
2 实验环境配置
1.配置环境的过程:参考了实验手册
(1) 阅读 http://web.mit.edu/6.031/www/fa18/getting-started/,在本地机器安装了相应的开发环境(JDK、Eclipse、Git)
(2) 阅读https://github.com/junit-team/junit4/wiki/Download-and-Install,并在自 己的 Eclipse IDE 中安装配置 JUnit4。
(3) 阅读 https://github.com/junit-team/junit4/wiki/Getting-started,了解如何使 用 JUnit4 为 Java 程序编写测试代码并执行测试
2.遇到的问题和困难,以及解决方式:
配置JDK时候出现下列问题:
解决方法:重新安装后解决
3.在这里给出你的GitHub Lab1仓库的URL地址
3 实验过程
3.1 Magic Squares这个任务分为两个问题:第一,设计算法来识别输入的矩阵是否是幻方,要保持正确性和健壮性;第二,分析所给代码,画流程图,找出偶数负数报错的原因,并且把输入的矩阵保存为6.txt,再用第一个问题中所设计的矩阵进行测试。
3.1.1 isLegalMagicSquare()
设计和实现思路:
(1)读取文件,如果找不到文件,提示错误信息,返回false
(2)判断文件中的元素是否用\t分开,如果不是,提示错误信息,返回false
(3)判断元素是否全是正整数,如果不是,提示错误信息,返回false
(4)判断矩阵行列数是否相等,如果不相等,提示错误信息,返回false
(5)判断矩阵是否完整,如果缺项,提示错误信息,返回false
(6)累加各个行、列、对角线的所有元素和,比较是否相等:如果其中两个不相等,提示错误信息,返回false;如果全相等,提示是幻方,返回true
过程:
(1)读取时采用FileReader和BufferedReader这两个类,再利用try catch语句,检查IOException异常
(2)利用.indexOf(" "),若返回值不是-1,说明存在空格,则不是用\t分开
(3)利用Character.isDigit(line_string[i].charAt(j),可以判断字符串数组line_string中第i个字符串中的第j个字符是否是0~9,如果该方法返回false,则说明不全是正整数;此外,该方法返回true时,还要判断该字符串中是否每一个字符都是0,如果全是0,也说明不全是正整数
(4)比较行数和列数即可
(5)初始化一个二维数组全为0,存放中的所有元素,如果这个二维数组中还有0,说明原矩阵缺项不完整
(6)循环累加后,再循环判断判断即可
结果:(如下图所示)
3.1.2 generateMagicSquare()
设计和实现思路:
(1)绘制流程图
(2)解释该函数如何生成n×n的幻方
(3)给出注释
(4)分析为何输入负数或者偶数时,会提示错误
(5)在输入负数或者偶数时,提示错误信息,并返回false
(6)将生成的矩阵保存为6.txt,并用3.1.1设计的函数中测试它
过程:
(1)流程图如下:
(2)解释该函数如何生成n×n的幻方先从第0行的中间位置开始赋值,直到赋值了n×n次。赋值从1开始,每次加一,直到赋值了n×n次。在赋值过程中,如果当前赋值是n的倍数,则下一次赋值下一行同一列的位置;否则,如果当前赋值的元素在第0行,下一次赋值第n-1行;如果当前赋值的元素在第n-1列,下一次赋值第0列。除了上述情况以外,下一次就赋值上一行右一列的位置(3)注释如下图
(4)分析输入负数或者偶数时,提示错误的原因输入负数时(提示如下图) 这是说明数组的大小不能为负数
输入偶数时(提示如下图) 说明数组越界比如n=2,初始化时,第一个赋值的元素位置为(0,1),赋值为i(=1)由于在第0行,下次赋值在第n-1(=1)行由于在第n-1(=1)列,下次赋值在第0列第二个赋值的元素位置为(1,0),赋值为i(=2)由于i(=2)是n(=2)的倍数,下一次赋值同一列下一行(2,0),越界
(5)在输入负数或者偶数时,提示错误信息,并返回false用两个if判断n即可
(6)将生成的矩阵保存为6.txt,并用3.1.1设计的函数中测试它写入文件时采用FileWriter和BufferedWriter这两个类,再利用try catch语句,检查IOException异常,再用3.1.1设计的函数测试生成的6.txt是否是幻方
结果:
(1)测试非法输入
输出:
(2)用3.1.1设计的函数测试生成的6.txt是否是幻方
输出:
3.2 Turtle Graphics
该任务分为几个部分:首先要求学会从github上下载代码,然后要求利用已有的方法来绘画,包括画正方形,画正多边形,已知当前角度、起点、终点判断需要转过的角度,凸包问题,画出自己想画的图形。最后要求提交代码到github上
3.2.1 Problem 1: Clone and import
(1)从GitHub获取该任务的代码:通过实验指导手册找到该任务的网站https://github.com/rainywang/Spring2020_HITCS_SC_Lab1/tree/master/P2,
然后点击后,再点击,然后选择下载到目标位置即可
(2)在本地创建git仓库、使用git管理本地开发
(超详细见https://blog.csdn.net/qq_28849009/article/details/104486824)
①到要上传的文件夹里面cd /c/Users/10025/Desktop/xxx
②初始化本地git仓库git init
③选择需要存入的文件git add .
④添加修改日志git commit -m “xxx”
3.2.2 Problem 3: Turtle graphics and drawSquare
题意是:利用Turtle类中给的forward(units) 和turn(degrees) 方法,来完成drawSquare(Turtle turtle, int sideLength)方法,最后的输出要是一个正方形。实现方法很容易,先走sideLength,顺时针转向90,再走sideLength,顺时针转向90,然后走sideLength,顺时针转向90,最后走sideLength即可,结果如下:
3.2.3 Problem 5: Drawing polygons
(1)实现calculateRegularPolygonAngle方法题意是:已知边个数,求出任意多边形的内角根据数学定理:任意的多边形边与角个数相同。那么对于正多边形,各个内角相等,则各个外角也相等,等于360°/角个数,也等于360°/边个数,即外角为360°/边个数再根据数学定理:任意多边形内外角和为180°,且所有的外角和为360°那么正多边形的每一个内角为180°-外角,即180°- (360.0 / 边个数)测试通过如下:
(2)实现drawRegularPolygon方法为了画出一个正多边形,画笔的转角应该是该正多边形的外角。边是参数,调用上述的calculateRegularPolygonAngle方法,来得到正多边形的内角,再用180°-内角,就可以得到正多边形的外角。结果如下:(画一个边长为40的正五边形)
3.2.4 Problem 6: Calculating Bearings
(1)实现calculateBearingToPoint方法题意是:给定当前的转角(与y轴正向夹角,顺时针为正),当前位置,目标位置,求出到目标位置所需要的转角。
①先求当前转角与x正半轴的夹角:90- currentBearing
②再求从当前位置到目标位置的方向,与x正半轴的夹角Math.toDegrees(Math.atan2(targetY - currentY,targetX - currentX ))注意:atan2的返回值是弧度,要用Math类中的toDegrees方法转换为角度然后前者减后者,若为正,即为所求;若为负,加上360°,即为所求测试通过如下:
(2)实现calculateBearings方法 题意是:给定一个x坐标的列表,y坐标的列表,组合为一些坐标位置,求出从上一个坐标位置到下一个坐标位置所需要的转角。
①先从x、y列表中求出第i个坐标和第i个坐标,当前转角为0,初始i=0
②再利用上述calculateBearingToPoint方法可以算出第i个所需转角,存入结果列表
③更新当前转角:刚刚“所需转角” + 之前的“当前转角”(若大于等于360°,则减去360°)
④i++,重复①②③,直到有n-1个
结果测试通过如下:
3.2.5 Problem 7: Convex Hulls
题意是:给定一些点的集合,求出这些点的凸包。通俗来讲,就是求出包围所有点的最小点集合。Spec中提到了 gift-wrapping 算法。gift-wrapping 算法有许多不同的形式,我选择了“顺时针包围”的形式
①如果所给集合中点的个数≤3,则该集合就是所求凸包,返回即可
②否则,首先找到最左边最下面的点,作为now_Point
③now_Point与其余的点进行比较,找到偏转角最小的点(若有两个点的偏转角相同,选较远的那个),加入结果集合
④把上述找到点作为now_Point,然后再执行③,直到找到的点是最左边最下面的点(说明形成了一个圈,即为所求的凸包)测试通过如下:
3.2.6 Problem 8: Personal art
题目要求是:画一个自己想要的图形,不能单单使用forward和turn命令
我的画是画一个彩色的圆,再在其中画一个红色的五角星。由于不能直接画圆,我的圆采用每次画很短的直线,然后转过微小的角,在每次画直线时,循环改变颜色,就可以得到彩色的直线,总体就是彩色的圆;对于五角星,先把画笔恢复水平,然后改变颜色为红色,然后每画一条边就转144°即可。(还要注意一开始画笔的起始转角,保证五角星在圆的内部)最终结果如下: 3.2.7 Submitting
通过Git提交当前版本到GitHub上的Lab1仓库
(超详细见https://blog.csdn.net/qq_28849009/article/details/104486824)
①到要上传的文件夹里面cd /c/Users/10025/Desktop/xxx
②初始化本地git仓库git init
③选择上传的文件git add .
④添加修改日志git commit -m “xxx”
⑤添加仓库urlgit remote add origin https://github.com/xxx
⑥本地同步git pull origin master
⑦认证git config --global user.name “xxx”
git config --global user.email “[email protected]”
⑧上传git push -u origin master
3.3 Social Network
建立一个图,来搭建社交网络,能实现添加点、边、求最短路径等操作。设计并实现java程序,包括FriendshipGraph类,Person类,main()以及测试用例
3.3.1 设计/实现FriendshipGraph类
实现思路:我设计的FriendshipGraph类中包括四个方法
(1)添加点的public Boolean addVertex(Person person) 方法
(2)添加边的public Boolean addEdge(Person person1, Person person2) 方法
(3)判断两个点的最小路径的public int getDistance(Person person1, Person person2) 方法(4)客户端的public static void main(String[] args)方法
(5)回答实验手册的的思考题
过程:
(1)加入点之前要先判断图中是否有同名的点,如果有,则添加失败,提示错误信息,抛出异常后直接结束程序(实验手册要求并且老师强调);如果没有就加入图中,返回true,表示添加成功
(2)首先判断输入的参数是否在图中,如果不在,提示错误信息,返回false,表示添加失败;再判断输入的边是否包含相同起点与相同终点(字符串比较是用.equals(),而不要用 ==),如果是,提示错误信息,返回false,表示添加失败;然后判断要添加的边是否已经添加过了,如果是,提示错误信息,返回false,表示添加失败;否则,就添加到图里,返回true,表示添加成功
(3)利用BFS进行找出最短路径即可,注意需要保存在最短路径上,某个结点的上一个结点,用于回溯求长度
(4)按照实验指导手册上的要求添加即可,此外,还添加了部分注释,按照注释替换代码,可以实现不同需求
(5)去掉第五行注释以后,从rachel出发,到不了任何点(如左图所示),因此输出应该变为-1,-1,0,-1,与运行结果相符(如右图所示)
结果:
符合实验指导手册上的17行要求以及JUnit测试的要求
3.3.2 设计/实现Person类
实现思路:我设计的Person类中只有private的姓名,还有构造函数以及获取获取这个人姓名的方法
过程:仿照了P2中的Point.java,修改了其变量名、方法名
结果:符合实验指导手册上的17行要求以及JUnit测试的要求
3.3.3 设计/实现客户端代码main()
实现思路:在实验指导手册上寻找需求过程:通过实验指导手册找到P3的需求,直接采用了该pdf下的17行代码(添加了部分注释,按照注释替换代码,可以实现不同需求)
结果:
输出与要求一致,如下图:
3.3.4 设计/实现测试用例实现思路:
(1)对不同人但同名的异常进行测试
(2)对同人同名的异常进行测试
(3)对添加点的方法的测试
(4)对添加边的方法的测试
(5)对判断两个点的最小路径的方法的测试(测试图如下)
过程:
首先要先定义规则,否则测试用例不会通过(因为抛出异常而终止)@Rulepublic ExpectedException thrown = ExpectedException.none();
(1)testSameNameDifferentPerson() throws IllegalArgumentException
①添加a后,添加一次aa(a与aa的名字都是“A”)
②判断抛出异常的内容是否相同
(2)testSameNameSametPerson() throws IllegalArgumentException
①添加a后再添加一次a
②判断抛出异常的内容是否相同
(3)testAddVertex()
①正确输入未重复的人名
②输入重复的人名,分为同一个人重名和不同人重名(4)testAddEdge()①正确输入未重复的边②输入重复的边
③输入的边 包含相同起点,相同终点
④输入的边上的点不在图中,分为起始点不在图中,终点不在图中,两个点都不在图中
(5)public void testGetDistance()
①输入相同的两个点。
②输入可达的两个点,分为距离为1(相邻),距离大于1 (不相邻)
③输入不可达的两个点,分为两个点都在图中但不可达,其中有点不在图中导致的不可达
④可达的路径有两条,结果要能选择最短的那条。
结果:
覆盖了所有的代码,所有测试用例都通过了,结果如下图:
4 实验进度记录
20-02-2720:08-23:49学会使用gitbash上传/删除/下载文件按计划完成
2020-03-0120:52-21:23尝试完成P1遇到困难,未完成
2020-03-0420:02-00:28完成P1.1按计划完成
2020-03-0519:34-21:53完成P1.2按计划完成
2020-03-0718.54-22:38完成P1的报告按计划完成
2020-03-0722:42-23:28完成P2的问题1、3以及对应的报告按计划完成
2020-03-0723:33-0:56完成P2的问题5以及对应的报告按计划完成
2020-03-0814:51-17:02完成P2的问题6、8以及对应的报告按计划完成
2020-03-0818:15-21:15完成P2的问题7以及对应的报告按计划完成
2020-03-0821:39-23:48完成P3的基本类,方法的定义按计划完成
2020-03-0918:52-23:17完成P3的问题以及对应的报告按计划完成
2020-03-1012:56-14:27优化了P3中的数据类型,取消了数组按计划完成
2020-03-1018:30-0:11修改了部分错误,添加了一些需求按计划完成
5 实验过程中遇到的困难与解决途径
不会使用java进行读写文件:上网查了关于java的相关知识
不会用java计算反三角函数:上网查了关于java的相关知识
在做P2时,部分英文看不懂:使用百度翻译,翻译了不会的英文单词,便于理解题意
不了解gift-wrapping 算法:上网查阅了gift-wrapping 相关知识
不会使用java中的队列、列表:上网查阅了关于java的相关知识
不会构造动态的二维数组:上网查阅了关于java的相关知识
不会用JUnit测试抛出的异常:观看了习题课录播视频的相关内容
不会把JUnit4的jar包放入lib:在piazza询问了同学、助教
6 实验过程中收获的经验、教训、感想
6.1 实验过程中收获的经验和教训
(1) 学习新的编程语言时候,要学会与之前学过的语言进行类比
(2) 遇到不会的英文单词一定要立马查,不要靠猜词义,很容易理解错误
(3) 尽量不要使用数组,其扩展性不好,最好用列表等等
(4) 测试用例没通过时也有可能是测试用例有问题,在一开始就要认真检测试用例的正确性
6.2 针对以下方面的感受
(1)Java编程语言是否对你的口味?
感觉和之前我学过的C、Python有一定的差距,刚开始用有点不适应,但是“万事开头难”,相信在今后的学习里,会越来越适应,越来越熟练
(2)关于Eclipse IDE;
这个软件让我觉得最好的是,给出错误提示时,会有选项让我直接选择更改代码的方式,很多时候我不必再去上网搜索错误原因,上网搜索如何改正,可以节约很多时间
(3)关于Git和GitHub;
是一个很方便的保存代码的方式,以前我总是用电脑自带的Onedrive来保存文件,但Git和GitHub可以让我查看版本差异,可以查看更新日志,非常实用。
(4)关于CMU和MIT的作业;
除了读英文比较不适应,有时会理解错题意,其他的地方感觉难度、代码量和哈工大的差不多
(5) 关于本实验的工作量、难度、deadline;
作为第一次实验,我感觉难度是偏简单,但是其中有一个凸包问题卡了我很久,不过在了解gift-wrapping算法并自己动手实现以后,我感觉非常有成就感
(6) 关于初接触“软件构造”课程;
软件构造课让我重视以前我没有重视的地方,比如写上述的实验进度记录,每次阶段工作结束后都要git代码,让我受益匪浅
(7) 疫情期间,只能远程授课,个人在家里完成实验任务,你对该学习方式有什么想法?
尽管上课的内容是差不多的,但是在学校里能有同学一起学习、一起相互进步,而在家中就只能靠良好的自律性,自己动手。不过,多亏了网络的发达,能够让我在家中继续学习