软件构造实验一

实验目标概述

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

  • 基本的Java OO编程

  • 基于Eclipse IDE进行Java编程

  • 基于JUnit的测试

  • 基于Git的代码配置管理

实验环境配置

简要陈述你配置本次实验所需开发、测试、运行环境的过程,必要时可以给出屏幕截图。

特别是要记录配置过程中遇到的问题和困难,以及如何解决的。

1)从助教给的压缩包中下载eclipse并安装,在使用Eclipse进行Junit单元测试时先右键项目->Build Path->Add Library并选择junit,导入junit4。

2)重新注册Git账号,并绑定Classroom建立自己的仓库,并将其clone到本地。

3)P1的MagicSquare.java中的main方法读取txt包下的测试文件时读取不到,使用相对路径读取文件总是找不到文件,使用绝对路径会由于项目提交之后路径发生改变而出错。所以,读取目录即可采用相对项目根目录读取的方式,用new File(“”).getCanonicalPath()获取项目的根目录,然后拼接字符串“/src/P1/txt/1.txt”即可获取src下P1包中 的txt文件夹下的1.txt测试文件。

在这里给出你的GitHub Lab1仓库的URL地址(Lab1-学号)。

https://github.com/ComputerScienceHIT/Lab1-1170300503

实验过程

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

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

Magic Squares

在这里简要概述你对该任务的理解。

该实验是判断一个矩阵是否是由正整数组成的方阵,并且文件中数字存储用“\t”划分,每行、每列及对角线数字之和均相等,如果是,则该矩阵是MagicSquare,否则不是。判断过程中,主要步骤是读取文件并分割字符串,判断输入是否合法,其次是对每行每列及对角线数字之和是否相等进行判断。

isLegalMagicSquare()

按步骤给出你的设计和实现思路/过程/结果。

1) 根据参数filename判断文件是否存在,如果不存在,返回false,结束;

2) 按行读取文件,记录读取行数;

3) 读取的每行数据按照“\t”分割,并判断分割后的每部分是否是数字,如果是数字,接着判断是否正整数,将每一个数字依次存入数组numbers,记录每行读取数字个数即列数并存入数组cols,否则返回false,结束;

4) 判断是否是方阵,若否,否则返回false,结束;

5) 记录对角线数字之和,并比较是否相等,若否,否则返回false,结束;

6) 判断每行每列数字之和是否都相等,若否,否则返回false,结束;

7) 返回true,结束。

结果:1.txt和2.txt矩阵以及生成的矩阵是MagicSquare,其余的不是。

generateMagicSquare()

按步骤给出你的设计和实现思路/过程/结果。

设计思路流程图如下:

该方法生成MagicSquare,如果输入的参数为偶数,在循环过程中会出现数组下标越界,抛出java.lang.ArrayIndexOutOfBoundsException异常,如果输入参数为父,则开始建立大小为负的数组,会抛出java.lang.NegativeArraySizeException异常。

Turtle Graphics

在这里简要概述你对该任务的理解。

通过控制乌龟的转向和划线的距离完成图形的绘制,相当于整个图形由一笔完成,绘图过程中只要控制好划线的方向和转向即可。其中两个坐标间距离的只需要套用公式,但是计算转向还要考虑到当前乌龟的方向。

Problem 1: Clone and import

如何从GitHub获取该任务的代码、在本地创建git仓库、使用git管理本地开发。

由于无法连接MIT的didit服务器,所以只能从:https://github.com/rainywang/Spring2019_HITCS_SC_Lab1/tree/master/P2获取代码。

打开git控制台,使用命令 git clone “https://github.com/rainywang/Spring2019_HITCS_SC_Lab1.git”

Problem 3: Turtle graphics and drawSquare

​ 首先,乌龟前行一段距离,即正方形的边长,然后转90,接着再爬行正方形的边长距离,转90度,爬行正方形的边长距离,转90度,最后爬行正方形的边长距离即可得到一个正方形。

Problem 5: Drawing polygons

​ 首先,计算出该多边形的外角,然后乌龟爬行多边形的边长距离,接着进行(n-1)次下列循环(n为多边形边数):转一个外角的度数,然后爬行一个多边形的边长距离。

Problem 6: Calculating Bearings

(1)calculateBearingToPoint():这个函数相对繁琐,因为需要分情况讨论,针对当前点和目的点的相对位置,分为横坐标相等、大于、小于三种情况,每种情况内又分别讨论纵坐标的相对情况,根据不同的相对位置关系,分别计算需要返回的转角度数。

(2)calculateBearings():循环(n-1)次(n为所有点的个数):调用calculateBearingToPoint()方法,计算转角,其中角度为当前乌龟的角度;然后更新当前乌龟的角度,计算方法是:上一次乌龟的角度加上转角度数,如果结果度数大于360度,则减去360度即可。

Problem 7: Convex Hulls

​ 如果点的个数小于4,则所有点都是要找的点,否则:

1) 找到当前最左下的点为起始点和终结点,并加入结果集

2) 执行如下循环,直到终结点等于起始点:

​ 计算当前点到其余每个点的转角度数,然后遍历,找出转角度数相同的点,如果转角度数相同的点不止一个,先将这些点加入temPoints集合,然后遍历该集合,找出距离当前点最远的那个点即为下一个要找的点,将其更新为当前点,并加入结果集。

Problem 8: Personal art

​ 首先进行三次循环,每次划线距离60,转角120度,画出一个三角形;然后循环六次,每次划线120,转角60度,画出一个边长2倍的六边形;然后为了效果更佳美观,循环上述操作59次,每一遍循环转角62.11度,防止线的重合。

Submitting

如何通过Git提交当前版本到GitHub上你的Lab1仓库。

首先,将eclipse文件中的P2包复制更新到本地仓库,然后右键运行Git Bash here,依次输入下列三行命令:

git add .

git commit -m “lab1_P3”

git push origin master

Social Network

在这里简要概述你对该任务的理解。

将每个人看做一个点,有关系的人用线(有向或无向)连接,模拟社交网络。其中比较有难度的是两个人之间最短距离getDistance()函数的编写,这里用到的广度优先算法,并在循环中记录每一层关系中人的个数以判断广搜的层数即距离。

设计/实现FriendshipGraph类

给出你的设计和实现思路/过程/结果。

首先定义ArrayList<ArrayList>类型的可变长度的数组,用0和1来存储每个人之间的关系,也方便社交网络从无向图扩展到有向图,定义ArrayList类型的可变长度的数组来存储每个人。然后是各个函数的构造。

设计/实现Person类

给出你的设计和实现思路/过程/结果。

这里设计较为简单,只用名字来唯一标识每个人,然后设计了参数为name的默认构造方法,以及getName()和setName()方法。

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

给出你的设计和实现思路/过程/结果。

首先,new 一个FriendshipGraph对象,接着new四个不同名字的Person并以此添加到FriendshipGraph网络社交图中,然后根据设计的社交网络图,调用addEdge()方法添加有向边,最后调用getDistance函数计算并输出人与人之间的距离。

设计/实现测试用例

给出你的设计和实现思路/过程/结果。

测试用例为实验指导文档给出的测试用例,创建了四个姓名不同的Person对象,然后分别调用了addVertex(); addEdge() 和graph.getDistance()方法,结果测试完美通过。

Tweet Tweet

请自行组织子目录结构。

Eclipse中为方便测试,将Test.java文件一并放入了同一个包下,目录结构如下:

然后,各个函数完成后,在本地仓库下建立test文件夹,在该文件夹下建立P3文件夹,将所有的Test.java文件复制到该文件夹下,目录结构如下:

src

​ P3

​ FriendshipGraph.java

​ Person.java

test

​ P3

​ FriendshipGraphTest.java

Problem 1: Extracting data from tweets

(1) getTimespan():如果tweets为空,则返回null,结束,否则:

​ 定义minTweet和maxTweet,初值均设置为第一个Tweet,然后遍历Tweet集合,得到每一个Tweet的Timestamp(),分别和minTweet、maxTweet比较,找出最早和最晚的Tweet;循环结束后,最晚的Tweet时间和最早Tweet时间跨度即为结果。

(2) getMentionedUsers():如果tweets为空,则返回null,结束,否则:

​ 建立Set\集合,遍历Tweet:得到每一条Tweet的text内容,然后根据正则表达式抽取其中符合要求的MentionedUsers,如果找到了这样的MentionedUsers,就放入set结果集;最终返回set结果集。

Problem 2: Filtering lists of tweets

(1) writtenBy():建立ArrayList\结果集,然后遍历tweets:得到每一个Tweet的作者,将作者名和参数username进行比较,如果一致,则将该Tweet加入结果集;最终返回结果集。

(2) inTimespan():建立List\结果集,得到timespan的初始和结束时间,然后遍历tweets:得到每一个Tweet的instant,如果在timespan的初始和结束时间之间,则将该Tweet存入结果集;最终返回结果集。

(3) containing():建立List\结果集,如果tweets为空,则返回null,结束,否则:遍历tweets:得到每个Tweet的text,并将每个字符转化为小写字母,遍历List\ words集合,如果text包含了words集合其中一个String,则将该Tweet加入结果集,并进行下一次外层循环;最终返回结果集。

Problem 3: Inferring a social network

(1) guessFollowsGraph():建立Map<String, Set\> 结果集和Set\ followers集合,构造提取Follows的正则表达式,然后遍历tweets:建立new HashSet<>()存储followers,获取每个Tweet的text,然后用正则表达式进行匹配,如果有follower,就将其加入followers集合,匹配完成后,如果followers集合不为空,就将该Tweet的作者名和对应的followers集合加入map结果集;最终返回map结果集。

(2) influencers():建立Map<String, Integer> influenceMap,遍历followsGraph:将username先加入influenceMap,然后得到 该Tweet的followers集合并统计人数,最后将结果更新到influenceMap中;遍历完成后创建Comparator对象,遍历influenceMap根据每个tweet的followers人数比较影响力大小并排序,最后将排序结果加入结果集并返回即可。

Problem 4: Get smarter

这里判断每一个tweet用户的followers时除了直接添加@到的人之外,还根据Triadic closure原则和是否有Common hashtags添加followers。前者的判断是每次在循环内部增加一次循环搜索,后者主要是用正则表达式提取text里的hashtags,然后判断是否和当前tweet用户有相同的,如果有,则该tweet用户是当前tweet用户的follower。

实验进度记录

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

日期 时间段 任务 实际完成情况
2019-02-26 14:00-18:32 完成整个P1和P2的Problem1-4 延期一个小时半完成
2019-02-26 18:35-19:03 编写P2的Problem5 按计划完成
2019-02-26 19:15-19:46 编写P2的Problem6 按计划完成
2019-02-28 前天19:30-10:12 编写P3 延期半天完成
2019-02-28 19:20-20:48 编写P4的Problem1 按计划完成
2019-03-02 10:00-14:40 编写P4、完善P2 推迟一天完成
2019-03-04 16:30-17:04 Lab1代码的完善及个别方法的优化 按计划完成

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

遇到的难点 解决途径
P1实验中测试文件的读取以及生成矩阵写入文件 采用相对项目根目录读取的方式,用new File(“”).getCanonicalPath()获取项目的根目录,然后拼接src下具体文件路径 “/src/P1/txt/1.txt”
P2 Convex Hulls中对凸包上同一条直线出现多个点情况的处理 如果出现最少角度的直线上出现多个点,则先将这些点加入一个暂存的集合,循环完毕,遍历该集合,找出该集合中这些点到当前点的距离最大的那个点,即为下一个要找的点。
P4中对每一个Tweet用户的求followers方法及其改进 首先提取text中符合要求的followers用户名需要使用正则表达式,由于之前没学习过正则表达式,所以在这里花了一晚上的时间先补充了这部分的知识;其次是求解followers方法的改进中,在根据Triadic closure原则添加用户时,需要在当前循环内再次遍历tweets集合,构建正则表达式,根据text的内容再次匹配。

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

实验过程中收获的经验和教训

利用一些工具如:Git、eclipse、Junit单元测试等能够显著的提高编程效率,熟悉工程的管理、了解Git的运作方式也至关重要。

针对以下方面的感受

(1) Java编程语言是否对你的口味?yes

(2) 关于Eclipse IDE:

自认为Eclipse 是一个比较上手的免费IDE,平时写java代码时基本都是使用的eclipse,所以相对来说,对eclipse的使用已经相对熟练。

(3) 关于Git和GitHub

​ 之前没有使用过Git,对其还是相对陌生的,但是实验要求不高,只需要 掌握git的几个比较常用的命令即可;github平时接触过,但运用也不是 特别熟练,还需要课下勤于使用。

(4) 关于CMU和MIT的作业

​ 由于已经有了java语言基础,所以这次实验感觉不是很难,方法的解决 思路也都基本清晰明了,只是个别问题的细节处理还需要注意。

(5) 关于本实验的工作量、难度、deadline

​ 第一次实验的安排很合理,难度适合,时间充足。

(6) 关于初接触“软件构造”课程

​ 对最近课程讲解的都是一些理论知识内容比较感兴趣,希望进一步学习 更多具体的相关知识。