2022年春季学期计算学部《软件构造》课程Lab 1实验报告

目录

1 实验目标概述... 1

2 实验环境配置... 1

3 实验过程... 1

3.1 Magic Squares. 1

3.1.1 isLegalMagicSquare(). 1

3.1.2 generateMagicSquare(). 1

3.2 Turtle Graphics. 1

3.2.1 Problem 1: Clone and import 2

3.2.2 Problem 3: Turtle graphics and drawSquare. 2

3.2.3 Problem 5: Drawing polygons. 2

3.2.4 Problem 6: Calculating Bearings. 2

3.2.5 Problem 7: Convex Hulls. 2

3.2.6 Problem 8: Personal art 2

3.2.7 Submitting. 2

3.3 Social Network. 2

3.3.1 设计/实现FriendshipGraph类... 2

3.3.2 设计/实现Person类... 2

3.3.3 设计/实现客户端代码main(). 2

3.3.4 设计/实现测试用例... 3

4 实验进度记录... 3

5 实验过程中遇到的困难与解决途径... 3

6 实验过程中收获的经验、教训、感想... 3

6.1 实验过程中收获的经验和教训(必答)... 3

6.2 针对以下方面的感受(必答)... 3

  1. 实验目标概述

本次实验通过求解四个问题,训练基本 Java 编程技能,能够利用 Java OO 开发基本的功能模块,能够阅读理解已有代码框架并根据功能需求补全代码,能够为所开发的代码编写基本的测试程序并完成测试,初步保证所开发代码的正确性。另一方面,利用 Git 作为代码配置管理的工具,学会 Git 的基本使用方法。

- 基本的 Java OO 编程

- 基于 Eclipse IDE 进行 Java 编程

- 基于 JUnit 的测试

- 基于 Git 的代码配置管理

  1. 实验环境配置

实验环境:

             系统:window10 64bit

             ide:Eclipse IDE for Eclipse Committers 2022-03

             编辑器:Visual Studio Code 2019

             构建工具:Apache Ant,Travis CI

             版本管理:git

             代码托管:Github

配置过程:

从OracleJDK官网下载JDK并解压到系统目录,并在~/.bash_profile中配置PATH、CLASSPATH和JAVA_HOME。

在使用Eclipse进行Junit单元测试时会出现org.junit不存在的情况,主要是由于junit没有正确导入,只需要右键项目->Build Path->Add Library并选择junit,导入junit4即可。

P4的Main.java中的main方法在运行前会检查是否启用assertion。只需要在run->Run Configurations中的arguments选项卡下的VM arguments中添加JVM参数“-ea”即可。

有时P1的MagicSquare.java中的main方法读取txt包下的矩阵文件时可能会读取不到,这是因为运行时运行的是class字节码文件,而编译时txt文件没有被复制到编译文件的位置导致无法读取。这时读取目录即可采用相对项目根目录读取,new File("").getCanonicalPath()获取的就是项目的根目录,若要获取src下P1包中 的txt文件夹下的1.txt的路径即可写成new File("").getCanonicalPath() + “/src/P1/txt/1.txt”

P2的TurtleSoup.java中有一个convexHull()方法,求一组给定点点最小凸包,可采用Wikipedia上的gift wrapping算法。P3的FriendshipGraph.java中有getDistance()方法,求给定两个点在有向图中的最短距离,可用邻接矩阵(List)存储邻接关系,并使用广度优先搜索,记录遍历的层数即可。P4的getMentionedUsers()方法,找出一组给定的tweet的text中提到(@-mentioned)的用户。可使用正则表达式匹配,按照给定的规则(1-140字符,有效字符为大小写字母、数字、下划线和-,且前后不得紧邻有效的字符),正则表达式为“(?<![A-Za-z0-9_-])@[A-Za-z0-9_-]{1,140}(?![A-Za-z0-9_-])”,其中使用了零宽断言来规定前后紧邻的字符。P4的guessFollowsGraph()方法猜测一组tweets中的关注关系,除了给定的@-mentioned可以判断以外,我还使用如果提到相同的话题(#-mentioned),那么两人互相关注的判断。

由于Lab0中要求脱离Eclipse独立构建,而Maven和Gradle都使用了配置式依赖导入,而且默认的目录结构与要求结构不符(要求src与test平级),故选用Apache Ant构建。

安装Apache Ant需要将下载下来的压缩包解压到系统目录,并在~/.bash_profile中配置环境变量ANT_HOME和PATH。

使用Ant构建需要在项目根目录下新建配置文件build.xml。

这里有一个问题是,由于在Eclipse中test测试类与其他文件都在同一包下,而项目中需要将测试文件与其它文件分开,单独放在test文件夹中。就需要编译成class时将test和src下的文件编译到同一个目录下,而且要保证src和test目录的包结构相同。

用Ant运行P2时可能会报“Cannot load com.apple.laf.AquaLookAndFeel”的错误,这是因为Ant使用默认的JVM运行时,无法加载系统的界面库,需要转换为系统的JVM运行。在build.xml中运行P2的java标签下加入属性fork=”true”即可。

使用Ant运行P4的Main和其它测试类同样需要开启断言。在对应的java标签和junit标签下加上” <jvmarg value="-ea"/>”标签即可。

由于Lab0还提到了Travis-CI自动构建,于是就尝试了一下。在项目根目录下新建.travis.xml文件,指定language、jdk、install和script。jdk需要指定为oraclejdk11,否则可能由于版本问题无法构建。Travis CI默认支持Maven、Gradle和Ant,取决于根目录下的配置文件。将Travis CI与Github关联,将项目push到Github后,Travis CI就会自动开启一个虚拟机,并按照配置文件构建项目并实时输出日志。

在这里给出你的GitHub Lab1仓库的URL地址。

https://github.com/ComputerScienceHIT/HIT-Lab1-L180300101

  1. 实验过程

请仔细对照实验手册,针对四个问题中的每一项任务,在下面各节中记录你的实验过程、阐述你的设计思路和问题求解思路,可辅之以示意图或关键源代码加以说明(但无需把你的源代码全部粘贴过来!)。

为了条理清晰,可根据需要在各节增加三级标题。

    1. Magic Squares

要求验证某个读入的矩阵是否是幻方,读入的文件要求数字间以\t分割且都是正整数,幻方要求为方阵且行列对角线之和相等。

      1. isLegalMagicSquare()

设计与实现:

首先初始化一个List<List<Integer>>二维List以存储矩阵,使用文件输入缓冲流BufferedReader从目标文件中读取一个矩阵,并将按行读入的String分割转换为List<Integer>,存入二维List中。该步骤可能由于文件不存在而造成IOException,或者存在负数、小数或者不是用“\t”分割而造成NumberFormatException。读取完成后验证该矩阵是否为方阵,如果不是,输出错误并返回false,最后再分别计算各行、各列以及对角线之和,如果相等,则为Magic Square,否则不是,输出错误并返回false。

结果:

             以下为在main方法中调用五次isLegalMagicSquare()验证txt文本的结果:

             以下检测矩阵1.txt

true

     

     

以下检测矩阵2.txt

true

     

     

以下检测矩阵3.txt

该矩阵不是方阵!

false

     

     

以下检测矩阵4.txt

文件数字不规范!请检查文件!

java.lang.NumberFormatException

            at P1.MagicSquare.convertTointList(MagicSquare.java:116)

            at P1.MagicSquare.readFromFile(MagicSquare.java:79)

            at P1.MagicSquare.isLegalMagicSquare(MagicSquare.java:53)

            at P1.MagicSquare.main(MagicSquare.java:24)

false

     

     

以下检测矩阵5.txt

文件数字不规范!请检查文件!

java.lang.NumberFormatException: For input string: "12673   12796"

at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)

            at java.base/java.lang.Integer.parseInt(Integer.java:652)

            at java.base/java.lang.Integer.parseInt(Integer.java:770)

            at P1.MagicSquare.convertTointList(MagicSquare.java:115)

            at P1.MagicSquare.readFromFile(MagicSquare.java:79)

            at P1.MagicSquare.isLegalMagicSquare(MagicSquare.java:53)

            at P1.MagicSquare.main(MagicSquare.java:24)

false

      1. generateMagicSquare()

设计与实现:

             给出的代码使用Merzirac法生成奇阶幻方:

  1. 首先向第一行正中的方格内填写1
  2. 以下依次向右上角的方格内填写2、3、4……
  1. 若右上角的方格内已经有数字,则向下移动一格继续填写
  2. 若右上角的方格超出矩阵的行,则移到矩阵下一列的最下端继续填写
  3. 若右上角的方格超出矩阵的列,则移到矩阵下一行的最左端继续填写

给出的代码没有对2.1步骤进行判断,而是使用当前填入的数字是否是行列数的倍数来决定,如果是行列数的倍数,则右上角必然有数字,需要下移。


流程图如下:

结果:

以下为main方法中调用generateMagicSquare()方法并使用3.1.1中的方法检验的结果:

调用参数为5时:

要求2:以下测试generateMagicSquare()方法:

17 24    1     8     15   

23 5     7     14    16   

4  6     13    20    22   

10 12    19    21    3    

11 18    25    2     9    

以下检测矩阵6.txt

true

调用参数为6时:

要求2:以下测试generateMagicSquare()方法:

请输入偶数值!

java.lang.ArrayIndexOutOfBoundsException: Index 6 out of bounds for length 6

   at P1.MagicSquare.generateMagicSquare(MagicSquare.java:199)

   at P1.MagicSquare.main(MagicSquare.java:37)

false

调用参数为-7时:

要求2:以下测试generateMagicSquare()方法:

请输入正整数!

java.lang.NegativeArraySizeException: -7

   at P1.MagicSquare.generateMagicSquare(MagicSquare.java:196)

   at P1.MagicSquare.main(MagicSquare.java:37)

false

    1. Turtle Graphics

该题估计起源于Python的turtle库,控制一个小乌龟在屏幕上爬行,画出各种图案。MIT用Java改写,提供了基础接口的实现(如forward和turn等),需要我们自己实现更加高级一点的接口。

      1. Problem 1: Clone and import

在本地新建一个文件夹,使用终端cd到该文件夹中,git clone,将整个项目clone下来(git不允许下载单文件)。并将其中的P2文件夹复制到自己的项目目录中,在src下与P1平级。接着在Eclipse中继续开发即可。

      1. Problem 3: Turtle graphics and drawSquare

该Problem要求使用现有的接口(forward和turn)实现drawSquare方法,要求该方法调用时,根据给定的变长画出一个正方形。使用一个简单的for循环即可解决。

      1. Problem 5: Drawing polygons

该Problem需要实现两个方法:calculateRegularPolygonAngle()和drawRegularPolygon()方法,并使用Junit测试。calculateRegularPolygonAngle()方法要求根据给定的边数作为参数,计算出对应的正多边形的内角。只需要使用公式insideAngle=(sides-2)×180sides 即可,由于insideAngle为double类型,而参与计算的数字都是int整型,如果直接计算可能会发生截断,需要在写成2d或180d即可转为浮点运算。drawRegularPolygon()方法要求以变长与边数作为参数,控制turtle画出正多边形。使用循环即可,计算角度时可调用calculateRegularPolygonAngle()方法计算,唯一要注意的就是turtle旋转的角是外角,而不是计算出来的内角。

      1. Problem 6: Calculating Bearings

该Problem需要实现两个方法:calculateBearingToPoint()和calculateBearings()方法,并进行Junit测试。calculateBearingToPoint()方法要求计算在当前点、当前朝向的情况下,顺时针转向目标点所需要转动的角度。给定的参数有当前朝向的度数、当前点的X与Y值和目标点的X与Y值,当前朝向的度数以向上方为0度。基本是个数学问题,比较繁琐,分多种情况讨论即可,需要用到反正切函数Math.atan2方法。calculateBearings()方法的参数为两个List,第一个List中为X的值,第二个为Y的值,需要返回一个List,包含所有需要转动的角度。只需要遍历两个集合,调用calculateBearingToPoint()方法即可,可设置一个变量里路当前朝向的角度。

      1. Problem 7: Convex Hulls

该Problem涉及一个著名的图形学概念:凸包。凸包可以理解为给定的点集的一个子集,该子集中点点连线可以将全集都囊括在内。要求实现的convexHull()方法就是在给定的Point的Set中寻找一个最小的凸包。由于是最小的凸包,如果同一条直线上的多个点都是凸包边界上的点,只取两端的点以保证最小。可使用gift wrapping(礼物包装)算法。从最左上(左下)角的点开始,逐个扫描点集中的点,选取与当前朝向偏角最小的点加入结果集,并将其作为下一个当前点继续循环。如果有多个点都是最小转角的点,则选择距离最远的点即可。

      1. Problem 8: Personal art


实现drawPersonalArt(),可以自己画一些有趣的东西,可作出一些简单的图形之后偏移一个较小的角度,并循环,即可作出较美观的花纹。

      1. Submitting

在项目的根目录打开终端,使用git add .命令将所有文件的改变存储在暂存去,再使用git commit -m “提交内容”将暂存区的内容提交到本地的版本库,创建一个新的版本。最后使用git push origin master将本地版本库的master分支推送到远程服务器(origin)的master分支上,这里的远程服务器就是GitHub的服务器。

    1. Social Network

要求实现一个模拟的社交网络,形成一个图结构,可以向图中添加点(人)和边(关系),并且可以计算各个点之间最短的距离。

      1. 设计/实现FriendshipGraph类

FriendshipGraph类是社交网络的抽象,描述了一个社交网络关系图。描述图有两种方法:邻接表和邻接矩阵,为了计算距离方便使用邻接矩阵。由于图中的点数不是固定的,故使用List嵌套,描述邻接矩阵的属性类型为List<List<Integer>>,并添加一个List<Person>来存储当前的图中的点。所有属性私有,并添加相应的setter/getter方法。根据示例代码,该类需要实现addVertex()方法、addEdge()方法和getDistance()方法。addVertex()方法用于向图中添加一个点,由于不可重复添加,添加之前需要首先验证该点是否已存在,是则跑出异常。添加人还需要扩充邻接矩阵。addEdge()方法是在两点之间添加一条边,由于要求中说明添加社交关系需要调用addEdge()两次,所以addEdge()方法仅添加一条有向边。getDistance()方法用于计算两个点之间点最短距离。由于有向路的权值都为1,仅需要采用广度优先遍历,记录遍历的层次即可,遍历到目标点时到层次即为最短的距离。

      1. 设计/实现Person类

该类为对社交网络中的点(人)点抽象。根据示例代码,仅需添加属性name并加入getter/setter即可。

      1. 设计/实现客户端代码main()

客户端代码直接使用说明中给出的示例代码,输出如下:

1

2

0

-1

和预期输出相同

      1. 设计/实现测试用例


测试用例使用如下的图:

共测试两个方法:getDistance()方法和addVertex()方法。getDistance()测试是否可以得到合理的输出。addVertex()主要测试当添加相同的人时抛出异常。

  1. 实验进度记录

请使用表格方式记录你的进度情况,以超过半小时的连续编程时间为一行。

每次结束编程时,请向该表格中增加一行。不要事后胡乱填写。

不要嫌烦,该表格可帮助你汇总你在每个任务上付出的时间和精力,发现自己不擅长的任务,后续有意识的弥补。

日期

时间段

任务

实际完成情况

2022-05-01

13:00~

编写完成问题1,并添加了Ant自动化构建

编写完成问题2,并完成了Travis CI在线

编写完成问题3,将junit整合进ant

按计划完成

2022-05-03

14:00~

审查全部实验,补上测试用例

修改了凸包问题的算法

按计划完成

2022-05-06

18:00~

完成实验报告

按计划完成

  1. 实验过程中遇到的困难与解决途径

遇到的困难

解决途径

不懂convexHull()的意义与实现算法

Google搜索,Wikipedia搜索

不会使用正则表达式匹配字符串

菜鸟教程速成

  1. 实验过程中收获的经验、教训、感想
    1. 实验过程中收获的经验和教训(必答)

深入理解了工程的构建方式与在线持续集成(CI)的方式,代码版本管理方式,单元测试的编写,更接近现代工程的管理。了解了Git的运作方式,提交和版本的概念与运用等。

    1. 针对以下方面的感受(必答)

Java语言被设计为一门完全的面向对象的语言,故思维模式比较接近正常人的思维过程,易于理解和掌握。Java的IDE使用的Eclipse是一个开源的项目,由Eclipse基金会负责维护,由于是开源项目,自我感觉没有商业软件Intellij IDEA用起来顺手。Git是版本管理软件,而Github是Git项目的托管平台,Github Classroom确实方便了计算机专业的教学。CMU和MIT的题目出的比较有水平,简单的作业融合了比较前沿的知识和背景,简单而有深度。实验的工作量较大,但不是很难,而且时间充裕,足够完成并优化。软件构造确确实实是一门教授写出更精彩代码的课程,实验都这么有水平

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值