目录
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. 5
3.2.1 Problem 1: Clone and import 5
3.2.2 Problem 3: Turtle graphics and drawSquare. 5
3.2.3 Problem 5: Drawing polygons. 5
3.2.4 Problem 6: Calculating Bearings. 5
3.2.5 Problem 7: Convex Hulls. 6
3.2.6 Problem 8: Personal art 6
3.2.7 Submitting. 6
3.3 Social Network. 7
3.3.1 设计/实现FriendshipGraph类... 7
3.3.2 设计/实现Person类... 7
3.3.3 设计/实现客户端代码main(). 7
3.3.4 设计/实现测试用例... 8
4 实验进度记录... 8
5 实验过程中遇到的困难与解决途径... 8
6 实验过程中收获的经验、教训、感想... 9
6.1 实验过程中收获的经验和教训(必答)... 9
6.2 针对以下方面的感受(必答)... 9
- 实验目标概述
- 学会基本的Java面向对象编程;
- 学会使用IDEA进行Java编程;
- 学会使用基于Junit的单元测试;
- 学会使用基于Git的代码配置管理。
- 实验环境配置
本次实验我首先安装了JDK,并下载安装了IntelliJ IDEA作为IDE。安装JDK后,需要添加JAVA_HOME以及CLASSPATH环境变量,并将JDK可执行文件目录添加到Path环境变量中。安装完成后,在PowerShell中输入javac,看到有javac.exe的输出,表明安装正确。
然后打开IDEA创建项目,安装JUnit Generator插件,然后按照项目要求创建P1、P2、P3目录,并在P1目录下新建MagicSquare类。此时,遇到问题:在MagicSquare.java中创建好main函数后,点击运行会出错,错误信息为“错误: 找不到或无法加载主类 MagicSquare”,如图1所示。
图1 MagicSquare.java运行出错
这一问题的解决方法是:进入File菜单的Project Structure对话框,添加P1、P2、P3文件夹为Content Root,如图2所示,此后运行正常。
图2 添加P1、P2、P3目录为Content Root
我的GitHub Lab1仓库的URL地址是:
https://github.com/ComputerScienceHIT/HIT-Lab1-120L02****(为保护隐私,已删去后四位)
- 实验过程
- Magic Squares
该任务主要要求我们设计一个功能完备的函数,用来打开给定的txt文件并判断其中的矩阵是否符合Magic Square的定义。设计这个函数时,需要考虑到整个执行过程中可能遇到的各种情况,并按要求进行处理。
-
-
- isLegalMagicSquare()
-
这一函数主要功能可分为三大部分:读取并存储txt文件中的内容,判断读入的内容格式是否满足要求,以及在符合要求的情况下,再判断读入的矩阵是否符合Magic Square的定义。
对于读入txt文件这一部分,首先要处理打开文件时可能出现的IOException,因此使用一个try-with-resources块完成打开文件的操作,并使用一个BufferedReader对象进行文件的整行读取,使用一个字符串列表保存每一行的内容。此部分的代码如图1所示。
图1 读取txt文件部分代码
读入txt文件后,需要判断txt文件中的内容是否满足要求。首先排除空文件的情况,即当存储各行内容的字符串列表长度为0时,打印错误信息并返回false。在排除空文件后,将读入内容的行数作为矩阵的行数和列数(记作N),并逐行解析读入的数据。在解析每一行时,首先使用String.split()方法,用分隔符”t”分割当前行,如果分割后得到的数组长度与N不相等,说明当前行的内容不符合格式要求,此时打印错误信息并返回false。然后,在一个try-catch块中尝试使用Integer.valueOf()方法解析分割后得到的字符串数组中的每一个元素为Integer类型并进行存储,一旦捕获到NumberFormatException异常,说明当前元素无法被正确解析,此时打印错误信息并返回false。然后,再检查解析后得到的整数是否为正整数,如果解析后得到的整数不是正整数,那么打印错误信息并返回false。这些步骤完成后,就得到了一个行、列数相等的非空矩阵。
此时进入判断读入的矩阵是否符合Magic Square的定义这一部分。在这一部分中,只需要首先算出第一行数字之和作为参考值,然后在循环中判断各行、各列数字之和并与参考值进行比较,若不一致则打印错误信息并返回false;最后在一个循环中检查两个对角线元素之和是否都等于参考值,若不一致则打印错误信息并返回false。在程序最后,返回true即可。
-
-
- generateMagicSquare()
-
此函数的流程图如图2所示。
图2 generateMagicSquare函数流程图
该函数根据输入的奇数n生成一个n*n的Magic Square的步骤是:首先将当前行设为最上面一行,将当前列设为正中间一列,然后在循环中依次填入1至n*n这n*n个数。循环中,首先在当前行和当前列所确定的位置处填上当前数,然后更改当前行和当前列,规则是:首先判断当前是否正好已经填了n的倍数个数,如果是的话,那么将当前行设为当前行下面一行。否则,判断当前行是否是最上面一行,如果是的话,那么设当前行为最下面一行,否则设当前行为当前行上面一行;然后判断当前列是否是最右侧一列,如果是的话,那么设当前列为最左侧一列,否则设当前列为当前列右侧一列。然后继续循环填数,最后得到的就是一个符合定义的Magic Square。
如果输入数字n为偶数,那么程序会抛出一个ArrayIndexOutOfBoundsException异常,这个异常说明发生了数组越界访问,这是因为n为偶数时,if (i % n == 0) row++;这段代码总会有一次使得row超过数组的最大下标,从而引起异常。
当输入数字n为负数时,程序会抛出一个NegativeArraySizeException异常,这说明声明数组时提供的数组长度为负数,这个异常是int magic[][] = new int[n][n];这行代码抛出的。
-
- Turtle Graphics
此任务主要让我们练习使用git clone命令克隆仓库,然后根据任务要求完成各函数,并运行提供的JUnit单元测试。
-
-
- Problem 1: Clone and import
-
使用git clone GitHub - rainywang/Spring2022_HITCS_SC_Lab1命令,可将仓库中的代码克隆到本地。使用git init新建本地仓库,使用git add .命令添加工作区的文件到暂存区,使用git commit -m ‘…’命令把暂存区中的代码提交到版本库,使用git push命令将本地仓库中的文件推送到远程仓库。
-
-
- Problem 3: Turtle graphics and drawSquare
-
本任务较为简单,在drawSquare函数中让turtle对象前进四次、转三个90度的弯即可画出一个正方形。
-
-
- Problem 5: Drawing polygons
-
本任务首先根据多边形内角公式完成calculateRegularPolygonAngle函数,并调用此函数完成drawRegularPolygon函数即可。需要注意的一点是,绘制多边形时,每次转弯的角度不是drawRegularPolygon函数的返回值,而是180度减去drawRegularPolygon函数返回的角度。
-
-
- Problem 6: Calculating Bearings
-
本任务首先完成calculateBearingToPoint函数,在该函数中首先利用Math.atan2函数计算出从当前点到目标点的方位角,然后根据当前的方位角计算出需要向右转的角度。需要注意的是,如果有当前方位角≤目标方位角<360,则需要旋转的角度就是(目标方位角-当前方位角);否则,需要旋转的角度就是(360+目标方位角-当前方位角)。然后,完成calculateBearings函数,在其中只需要调用calculateBearingToPoint函数,计算出每个点之间需要旋转的角度即可。
-
-
- Problem 7: Convex Hulls
-
本任务需要完成convexHull函数,它返回给定点集的凸包。首先可以考虑边界情况,即当给定点集只有0,1或2个点时,只需要返回该点集本身即可。当集合中的点大于等于3个时,可以使用Gift-Wrapping算法求其凸包,即首先找出左上方的点,然后维护一个从当前点前往,所需旋转角最小的点和到所需最小旋转角的点的最长距离。每次都寻找下一个从当前点前往,所需旋转角最小且距离最远的点,这个点就是凸包上的下一个点。当找到的凸包上的下一个点是出发时的点,也就是集合中左上方的点时,寻找完毕。
-
-
- Problem 8: Personal art
-
本任务中,我使用了turtle对象的forward, turn和color方法,绘制出了包含两种颜色的EC这两个字母,效果图如图3所示。
图3 Personal Art
-
-
- Submitting
-
使用git add .命令添加工作区的文件到暂存区,使用git commit -m ‘…’命令把暂存区中的代码提交到版本库,使用git push命令将本地仓库中的文件推送到远程仓库。
-
- Social Network
该任务让我们设计FriendshipGraph类和Person类并实现FriendshipGraph类的三个成员方法,体验面向对象程序设计的过程,并学习自己使用JUnit设计和进行代码的单元测试。
-
-
- 设计/实现FriendshipGraph类
-
FriendshipGraph类支持三个功能:添加顶点、添加边,以及计算两点间的最短路径长度。添加顶点时,需要判断是否有同名的Person对象已经被添加过,所以可以添加一个HashSet
由于FriendshipGraph类不需要支持其他操作,所以添加顶点操作只需要将Person对象及其名字分别添加到两个HashSet中,不需要进行其他动作。添加边时只需要将终点的Person对象添加到起点Person对象的邻接表中。求两点间最短路径长度的操作,可以使用广度优先搜索来实现,将起点到自身的距离设为0,每次遍历顶点的邻接表时,邻接表中的每个顶点到起点的距离都设为父顶点到起点的距离+1.从起点开始搜索,当前遍历到的顶点恰好为终点顶点时,返回它到起点的距离即可。如果没有访问到终点,说明起点和终点并不连同,则只需要在函数最后返回-1.
-
-
- 设计/实现Person类
-
Person类需要包含接收一个String对象作为参数的构造函数,该String对象指定Person的名字,并且不能为空。同时,还要添加一个ArrayList
-
-
- 设计/实现客户端代码main()
-
在客户端代码中,声明一个FriendshipGraph对象以及若干Person对象,添加Person对象到图中,然后添加若干边,使得其中一个Person对象与其他Person对象都不连通。打印各Person对象之间的距离,查看运行结果。
-
-
- 设计/实现测试用例
-
测试addVertex方法时,首先添加三个Person对象。然后将其中一个Person对象再次添加,使用assertThrows来断言代码会抛出一个IllegalArgumentException异常。然后,添加另一个同名但为新构造的Person对象,同样断言代码会抛出一个IllegalArgumentException异常。
测试addEdge方法时,分别测试起点未被添加过、终点未被添加过、起点和终点相同这三种情况,均断言代码会抛出一个IllegalArgumentException异常。然后,选定一个Person对象,新建一个ArrayList
测试getDistance方法时,仍然分别测试起点未被添加过和终点未被添加过的情况,均断言代码会抛出一个IllegalArgumentException异常。然后添加若干顶点,分别测试两点间连同和不连通时函数的输出。



