软件构造Lab1复盘

发布时间 2023-03-31 12:55:26作者: Jayhawk

  实验一也已经结束一个多礼拜了,也摸了那么久的鱼了,现在是时候对实验一进行一个复盘了。

  首先呢,我想先说一下这次实验最大的收获。我觉得这次实验最大的收获就是熟悉了java语言,并且学习了git的基本使用方法。在完成每个问题并将项目上传到github上的过程中,我也是充分感受到了github在版本管理方面的便捷与优势,而且这也是以后工作中的必备技能,在本次实验学会的git使用方法感觉用处很大。

  接下来呢,我将从实验的各个阶段来回忆一下实验中的重点与注意事项。

  在环境配置上,首先是要安装JDK、IDEA与Git,这些都比较简单,在官网直接下载并进行安装即可。在安装jdk之后需要对其进行环境变量的配置,以便让每次程序运行就自动到安装JDK的bin目录下去搜索javac.exe和java.exe文件。在系统环境变量中新建一个叫“JAVA_HOME”的环境变量,变量值为 JDK 的安装路径。 然后在 Path 的环境变量中添加一个“%JAVA_HOME%bin”的变量值即可配置 好 jdk。IDEA与Git的安装也都十分简单,在IDEA中还需要安装Junit,在Git中还需要用git remote add指令进行远程仓库的连接。

  环境配置好后就该进入到了实验问题的解决。

一、Magic Squares

  Magic Squares是指满足每行、每列和两个对角线上各自的数字和都相等的 n*n 的矩阵。第一个问题的要求是根据给的 5 个 txt 文件,判断其是否为幻方,并在 generateMagicSquare()函数中生成一个幻方并写入 6.txt 文件中,同时判断生成的矩阵是否为幻方。

 

  在此问题中要求实现两个函数,isLegalMagicSquare()和generateMagicSquare()函数。

  isLegalMagicSquare()函数是用来判断一个矩阵是否是一个幻方,实现思路也比较简单,只需在读取正确格式的数据后,进行两次循环嵌套,并分别用整形变量 sumR、 sumC、sumDia1、sunDia2 来计算行、列、两个对角线数字的和是否相等,若全部相等,则 返回 true,否则,返回 false。

  generateMagicSquare()函数是用来创建一个幻方的。我学习了一下生成幻方的方法,选用了阶梯法来生成幻方。具体思路如下(示意图在下方):

  1、将 1 置于第一行中间。

  2、将下一个数字置于当前数字的右上角。如果已经处于方阵的边界,则放在方阵的对 边(如图 1 中的 2 和 4)。

  3、若出现下面两种情况,则将下一个数字放于当前数字的下方: 当前位置的右上角已经有一个数字(如图 2 中的 6 和 11)。 当前位置已经是方阵的右上方(如图 2 中的 16)。

  4、结束,如图 3.

 

  下图图是generateMagicSquare()的流程图,基本是基于阶梯法生成幻方的思路。

 

  在实验中要求中提出了两个疑问,即输入 n 为偶数和负数时会出现报错,输入偶数报错的原因是出现了数组越界,在函数中 row 的值会超过 n,导致在执行 magic[row][col] = i;这条指 令时会产生数组越界;输入负数时报错的原因是在创建数组是出现了数组负长度异常,直接无法创建数组。因此,只需在输入数据时添加判断是否为偶数或负数,若是,则提示错误并 且返回 false。

二、Turtle Graphics

  第二个问题需要我们 clone 已有程序,根据用例规约实现 TurtleSoup 类中的 各个方法,并调用写好的方法控制 turtle 绘制指定的图案,其中需要利用简单的 几何知识,最后可以自行创作,绘制出自己的 Personal Art。

  注意:由于要把 Turtle 放入 P2 包中,Turtle 中 package 需要加上 P2,如下: package P2.turtle; 在下面我将不解释Clone and import与上传至远程仓库部分,这部分只会运用到简单的git指令,我会专注于解答问题的过程。

 

1、Problem 3:Turtle graphics and drawSquare

  该问题需要实现根据指定的长度来画出正方形。 要实现只需调用四次 turtle.forward(sideLength)函数和 turtle.turn(90) 来让 turtle 每前进 sideLength 距离时便转 90 度来实现正方形的绘制,十分简单。

2、Problem 5: Drawing polygons

  该问题希望实现 calculateRegularPolygonAngle 函数与 drawRegularPolygon 函数,并 根据输入的边数和长度来绘制正多边形。首先 calculateRegularPolygonAngle 函数根据三角形内角公式(n-2)*180/n 能够很简单地实现。

接下来,在 drawRegularPolygon 函数中只需调用边数次的前进和转(180-内角度数)即 可实现正多边形的绘制。

 3、Problem 6: Calculating Bearings

  该问题首先希望解决,已知起点和当前朝向角度,想知道到终点需要转动的角度。例如 如果海龟在(0,1)朝向 30 度,并且必须到达(0,0)它必须再转动 150 度。

  首先我进行了两点间的距离计算,并且根据两点形成的直角三角形的一个角的 sin 值求 出该角的大小,在对点的类型进行分类,根据目标点在当前点的上下左右关系和图形的几何关系来计算出该转的角度,最后再减去当前的角度,若小于 0 则加上 360 度,得到最终的结果。并且要对函数进行junit测试,在junit测试中也完美通过。

  在此基础上,要实现 calculateBearings 函数,此函数会提供一组点的集合,需要计算这些点从第一个到第二个点、第二个点到底三个点……之间的旋转的角度。

  有了之前的基础,要实现该函数也比较轻松。只需进行 n-1 次从 i = 1 开始的循环,在每次循环中将第 i 个点作为该次的终点,将上一次的终点作为该次的起点,调用 calculateBearings 函数计算两点间的角度, 并把每次结束的角度作为下次的起始角度,同时把每次的角度存入一个 ArrayList 当中,最 后再返回该 ArrayList 即可实现效果。

4、Problem 7: Convex Hulls

  此问题要求解决凸包问题,凸包(Convex Hull)是一个计算几何(图形学)中的概念。 在一个实数向量空间 V 中,对于给定集合 X,所有包含 X 的凸集的交集 S 被称为 X 的凸包。 X 的凸包可以用 X 内所有点( X1 ,. . . ,Xn )的凸组合来构造。凸包问题就是根据给定若干点的坐标,求出该集合凸包的点的集合。本次将采用 Gift−Wrapping 算法来解决凸包问题。

   首先,在点集合中点的数量小于等于 3 时,其本身就是它的凸包,因此只需返回该点集 合本身。在点的数量大于等于 3 的时候运用 Gift−Wrapping 算法。

  对 Gift−Wrapping 算法的描述:我们发现任意凸包上的点,你会发现以该点建立一个极 角坐标系,该点连结其它所有点的极角中,该点顺时针方向的第一凸包点到该点极角最小, 例如 P0,到所有点的极角中 P0P1 极角最小。 在此算法中,先找到点集合最左上的一个点,则这个点必定在凸包上然后遍历调用上个 问题中的 calculateBearingToPoint 函数,计算该点到其余所有点的旋转角度,找出最小的那 个点,即为与其相邻的另一个凸包上的点。反复执行该流程,直至新的一个相邻的点为最开 始的点,则终止。此时得到点的集合即为该点集合的凸包。

  简单来理解就是在平面中想象一根绳子,从一个点开始将所有的点都包起来,在绳上的点即为凸包上的点。

5、Problem 8: Personal art

  此问题要求绘制一个个人创意图形,我选择的是画一个彩色的风车,实现也十分简单,只需循环几次偏转角度和走直线函数以及变换颜色函数即可实现。效果如下:

 

三、Social Network

 

  在本问题中要求设计一张社交网络图,能够实现在图中添加人、添加人与人之间的连接,并且能计算任意两个人之间的联络情况,即两人之间是否相连,若相连,两人之间的距离是多少。实现网络图基于两个类,分别是 FriendshipGraph 类,即管理社交网络图中人物关系的类和 Person 类,即表示人物的类。

1、设计/实现 FriendshipGraph 类

  该类的实际意义是一张社交网络图,包括了代表每个 Person 的点的 ArrayList、 以及建立点和点间的联系和计算距离的方法。

其中 Vertex 记录了关系图中的每一个 Person 类,而在每一个 Person 类中又包含着 next 信息,即他的邻接边。 addVertex 函数就是在 FriendshipGraph 类中的 Vertex 中添加一个 Person 类,addEdge 则是在传入的两个 Person 类中,将第二个 Person 类传入第一个 Person 类的 next 中,即在给第一个 Person 类添加一条连接第二个 Person 类的边。

在getDistance ()函数中,是要计算任意两个 Person 之间的“距离”,若没有任何社 交关系则输出“-1”。利用 BFS 算法,在搜索到边时加 1 即可,搜索到目标点退 出;特殊情况根据要求输出 0 或-1。

 

 

2、设计/实现 Person 类

 

  该类的设计意义是将每个人对应到一个 Person 对象,在其中存储了每个人的 姓名信息并且有一个 ArrayList 记录了关系图中连接的其他人的 Person 信息,即在关系图中的邻接边。同时利用一个 HashSet 来进行判断是否有重复 Name 的成员,若有则提出警告。

 

3、设计/实现测试用例

  在测试类中,我设立了 5 个函数,分别是 addVertexTest 函数,用来判断 addVertex 函数功能是否正确;addEdgeTest 函数,用来判断 addEdge 函数功能是 否正确;SameNameTest 函数,用来检测输入相同名字是是否会提出错误; GraphTest1 函数,用一个简单图来检验 getDistance 函数的功能;GraphTest2 函 数,用一个较为复杂的图来检验 getDistance 函数的功能。下面是简单图和复杂图的示意图

 

四、总结

  做完实验一我也收获很多,再看看现在的实验二,就觉得实验一难度其实并不高,实验一主要是让你熟悉一门语言与开发工具,感觉难度设置较为合理,而实验二就该开始进行类的设计了。好了,该继续写实验二了,过后应该还会继续在博客里总结软件构造的知识点和复习内容,还有实验二实验三的复盘。