- 第一部分 实验目标概述
- 第二部分 实验环境配置
- 第三部分 实验过程
- 3.1 Magic Squares
- 3.1.1 isLegalMagicSquare()
- 3.1.2 generateMagicSquare()
- 3.2Turtle Graphics
- 3.2.1Problem 1: Clone and import
- 3.2.2Problem 3: Turtle graphics and drawSquare
- 3.2.3Problem 5: Drawing polygons
- 3.2.4Problem 6: Calculating Bearings
- 3.2.5Problem 7: Convex Hulls
- 3.2.6Problem 8: Personal art
- 3.2.7Submitting
- 3.3Social Network
- 3.3.1设计/实现FriendshipGraph类
- 3.3.2设计/实现Person类
- 3.3.3设计/实现客户端代码main()
- 3.3.4设计/实现测试用例
- 感受
本次实验通过求解三个问题,训练基本 Java 编程技能,能够利用 Java 开发基本的功能模块,能够阅读理解已有代码框架并根据功能需求补全代码,能够为所开发的代码编写基本的测试程序并完成测试,初步保证所开发代码的正确性。 另一方面,利用 Git 作为代码配置管理的工具,学会 Git 的基本使用方法。
- 基于EclipseIDE进行Java编程
- 基于Junit的测试
- 基于Git的代码配置管理
这整个Lab1我都是在使用EclipseIDE进行的编程代码的书写和基础框架代码的导入,在之后我有幸用到了IDEA,它的智能和方便程度真的是我们的懒狗福音!
本次实验我在Win10环境下开发。编译Java代码的IDE我选择使用的是Eclipse-2021-06。Jdk版本使用的是Jdk11(在Window菜单下的Preference菜单中设置),相应的环境变量如下
因为实验要求使用JDK11,所以如果直接下载的是最新版的Eclipse。需要将JDK设置为JDK11,如下
`如果你像我一样第一次使用Java编程中的JUnit功能,也一定会遇到这个JUnit jar包的问题,解决方法如下:`
我的Java运行环境配置进行的较为顺利,但在配置Junit的时候遇到了一些困难。由于下载的版本问题,我的plugins文件夹下没有Junit的jar包,花费了一些时间找到这个问题所在。最后通过下载并且导入jar包很好地解决了这个问题。首先右键单击Trail1:
然后点击Java Build Path,点击Add External JARs,将下载好的jar包添加进去:
然后点击Add library,再点击Junit,选择Junit4即可。
好啦,到此为止我们进行Lab1的全部准备环境工作就完成啦! 第三部分 实验过程 3.1 Magic Squares
在开始这一部分之前让我先来简述一下这一块任务的概况以及我的理解
Magic Squares编程任务是编写一个程序读取矩阵文件,并判断这个矩阵是否为一个合法的幻方1。并且使用generateMagicsquare()方法来生成一个矩阵并且判断其是否为幻方。
3.1.1 isLegalMagicSquare()1. 设计思路
先针对输入进行合法检测,然后判断输入矩阵是否是一个合法的幻方。
2. 求解过程
首先,在文件读取时检测每一个输入的数字是否为正整数,根据预设的不同正则表达式2判断输入的非法数据违反了那种规则,给出相应的输出提示。
如果输入合法,则将数据存入一个二维List中,根据内层List的长度判断是否为矩阵,若为合法矩阵则判断是否符合幻方要求。
3. 运行结果
函数返回值为boolen是否为幻方以及输出错误类型。
1. 函数流程图
2. 异常含义以及解释
输入偶数时的异常:
java.lang.ArrayIndexOutOfBoundsException
原因:数组越界异常。当输入为偶数时,生成幻方的循环遍历到最后一行时会出现输入的倍数,这时会执行row ++操作,从而导致数组的第一个维度的溢出,因此抛出这个异常。我手绘了一下这个函数在较小规模下的运行个过程,如图18的位置
输入负数时的异常:
java.lang.NegativeArraySizeException
原因:数组大小负值异常。在对数组大小进行负值时输入为负数,抛出这个异常。这个就没截图分析了,想必是一个很基础的非法输入问题。
3. 函数拓展
为了使函数运行的更加美妙优雅,按照要求对函数进行拓展,其实这个拓展的目的就是让函数在运行的过程中不抛出异常,而是将异常的原因信息打印出来。
首先对输入的值进行判断,正如前面程序框图展示的那样,如果有违规输入,程序不会抛出异常而意外终止,而是自行结束程序,并且打印错误信息。
接下来,会将此方法产生的幻方通过输出流写入6.txt文件中,进行存储。
最后,将利用自己完成的islegalMagicsquare方法对生成的幻方进行检查,并且返回一个boolean值表明这个矩阵是否为一个合法幻方。
至此,P1部分就结束辣!
3.2Turtle Graphics这一部分非常好玩,我们可以根据下载下来的代码框架进行一些很有趣的画图操作,操作一直小海龟,小海龟所经过之处会留下一个痕迹来完成画画的功能。
Turtle Graphics任务需要我们使用海龟画图框架,来完成接下来的函数编程任务。我认为这一任务能够训练我们读规约的能力,以及根据规约信息使用函数接口的能力。
3.2.1Problem 1: Clone and import
首先到指定的网址去下载这个代码基础部分的压缩包
接下来一部分涉及到Git仓库的使用,我们通过Git指令可以在任务所在的文件夹建立一个本地仓库,然后让这个本地仓库追踪代码,记录每一个版本。
打开Bash,通过命令行进入代码所在文件夹,输入git init指令建立初始的本地仓库.git。
接下来进行代码编写时,通过git add指令跟踪任务文件,需要提交时,使用git commit -m ‘init’指令为版本命名并提交至本地仓库。
进行与Github远程仓库的连接。使用ssh-keygen.exe为本地生成一个ssh密钥3。之后进入Github的settings中的SSH and GPG keys配置界面,导入本地生成的ssh密钥。配置完成后在Bash中输入ssh -T git@github.com指令,如果导入成功则会有以下输出
运行git remote指令连接GitHub上的远程仓库,然后在Bash中输入git push origin master(默认只有一个master分支)指令将本地仓库的内容提交至GitHub远程仓库。
在代码的编写过程中,我会提醒自己经常将代码写一部分,进行测试通过后就push到Github上,养成一个良好的习惯。
3.2.2Problem 3: Turtle graphics and drawSquare
按ctrl键点击turtle类,查看类中定义的方法,发现类中又如下几个方法。通过读注释,分别查看每个方法的含义。不难认出,forward(int units)方法控制海龟前进units长;turn(double degrees)方法控制海龟转向;color(Pencolor color)方法可以改变画笔颜色。通过forward方法和turn方法可以画出这个正方形。
画出多边形,以画正多边形为例构造方法的输入参数为Turtle,边的数量以及边的长度。使用一个数学公式:
D
e
g
r
e
e
=
(
s
i
d
e
s
−
2
)
∗
180
s
i
d
e
s
Degree = frac {(sides - 2)*180}{sides}
Degree=sides(sides−2)∗180
根据计算出的角度以及给定的边长画出相应的正多边形。
这一部分在后续的代码中会有非常多的复用,所以在编写的时候需要非常小心的写,以免出现错误导致后面痛苦的Debug!
计算偏转的角度,角度为从y轴正向顺时针旋转的旋转角。分为四个象限和坐标轴分别进行计算进行计算,利用Math库中的两个函数Math.atan()和Math.toDegrees()完成计算。
凸包问题,这个问题的定义是找出点集Q的凸包(convex hull),凸包是指一个最小凸多边形,满足Q中的点或者在多边形边上或者在其内。我觉得这个问题是这一部分实验最难求解的一部分了。
**设计思路:**按照实验要求,使用礼品包装算法。先找到最下面的一个点,然后遍历整个图,算出这个点到所有点的极角,取值最小的哪一个为下一个加入凸包的点并作为下一次循环的操作起点。
**实现过程:**首先判断points集合是否为空,若为空则返回空集。接下来进行循环,外层循环推出条件是找到的下一个点和第一个点相同;内层循环则遍历整个点集,找到极角最小的那一个点,如果极角相同的话则选择距离最远的那一个点加入。
在实现的过程中,需要注意极角的更新问题。在调用calculateBearingToPoint方法时,传入的currentBearing参数应为上一次操作的点和下一个加入的点所夹而成的极角,所以需要对currentBearing进行更新。
在解决了上述问题之后程序也顺利的通过了测试。(Done的输出是为了方便知道那些测试用例通过了测试而哪些没有)
这一部分比较随意,所以我画了一个图形,然后将它反复旋转打印输出,形成一朵小雏菊。
首先在项目目录下打开Bash,之后使用git add指令和git commit指令跟踪src文件夹并且上传至本地仓库。
之后使用git push origin master指令将代码push到远程仓库Lab1。 
至此,P2部分的实验就完成辣,测试用例也通过。
这一部分就很简单啦,只需要设计两个类。实验要求我们完成一个社交关系记录图的任务,需要我们建立两个类。一个类是社交任务类(Person),另一个是社交关系图类(FriendshipGraph)类。然后通过在主方法中输入社交关系来构建这个关系图,并计算社交距离。
3.3.1设计/实现FriendshipGraph类
addVertex(Person p)方法:我使用List再存储每一个人的社交圈。在这个方法中先判断这个人是否已经存在在这个社交关系图中,若已经存在则输出重复添加,否则将其添加到这个图中。
addEdge(Person p1, Person p2)方法:首先判断p1和p2这两个人是否存在,若否,则输出不存在这两个人。接着判断是否已经建立p1和p2的关系,若是,则输入重复输入。若上述两种情况都不符合,则加入二人的关系。
由于题目要求设计的是无向图,所以要同时使用addEdge(p1, p2)和addEdge(p2, p1)这两条语句;若要拓展至有向图,则单向添加关系边即可。
getDistance(Person p1, Person p2)方法:使用广度搜索的方法。建立一个队列,将p1直接建立社交关系的人物入队,之后让队首人物出队,并将他的直接联系人入队。不断迭代这个过程,记录广搜的层数,即为两人的社交距离。若没有找到p2,则返回值-1表示两人没有社交关系。
main()方法:在主方法中,新建社交人物类和新的社交关系图,并且输入人名和关系,即可调用方法建立图和计算社交距离。
3.3.2设计/实现Person类类的成员变量:Person类中设置两个变量。String name用来存储这个社交任务类的名字;List connection = new ArrayList<>()用来存储这个人直接联系的其他人。
构造方法:存储这个人的名字。
Add(Person p)方法:在这个人社交关系中加入一个人。如果这个人被重复添加则输出重复添加,请输入一个不同的人。(非常尴尬,在后续的编程过程中忘记了有这么一个方法,所以没有用到)
main()方法中实现可以通过调用Person类和FriendshipGraph类中的构造方法来实现这个社交关系图需要实现的功能。例如,新建一个人名成员,添加单项或者双向的社交关系,再或者向社交关系图中加入新的社交人物并且输出人与人之间的社交距离。经过测试,输出结果与期望值相同。
测试用例设计如下,一共有八个人,分别为Rachel、Ross、Ben、Kramer、张小明、李雷、韩梅梅和王小红。测试到所有的情况包括自己和自己的关系,以及没有和其他人建立联系的情况。(手绘的,非常丑)
欧尅兄弟们,到这里实验的编程任务就告一段落了,这是我的第一个软构实验,充分感受到了Java和Clike语言之间编程思路的不同。c语言就是想写个马就直接写一个马让它跑,而Java语言得先写一个马厩,这就是我最直观的感受。
这次实验我在敲代码的时候经历了一个非常痛苦的debug阶段,就是包装类和基本数据类型之间的区别(例如Double和double)。包装类中重写了.equals()方法,这就是的两个包装类定义的变量不可以直接进行比较,这样的比价在Eclipse编译器中不会报错,程序也可以正常运行,但是结果就是不对,是一个对于Java新手和Eclipse编程用户的地狱级的考验。
Java中有很多可以直接使用的构造方法,就可以节省很多写一些基本的函数所花的时间。与c语言相比,构造方法可以饥饿生很多力气,而且面对对象编程的思路也更加的清晰和有趣。
攻略大概就是这么多,希望对大家有所帮助。
幻方:各行、各列以及对角线数字和相等的矩阵
↩︎正则表达式:这里简单描述一下正则表达式的作用。正则表达式将一些值对应为相应的字母和符号,以这些组合表达出匹配的类型。比如\d+.\d+表示一个任意小数(d表示0-9的数字,+表示至少一个)
↩︎ssh密钥:这个密钥的作用是让Github那边指导对应这个地址是你本人在操作Github,就相当于登录Github输入密码的作用一样
↩︎



