Magic Squares
在这里简要概述你对该任务的理解:
- 该实验主要包含两项任务:
- 编写isLegalMagicSquare()判断一个n×n的矩阵是否为Magic Square,如果是,返回true,否则返回false。
- 理解完善给定的generateMagicSquare()方法,针对n为奇数的幻方的生成算法进行理解完善。
- 幻方的特点:N 阶幻方是 n 个数字在一个正方形中的排列(通常为不同的整数)。所有行,所有列的数字和,以及两个对角线的和等于同一个常数。
1.isLegalMagicSquare()
(1)问题求解思路:
首先读取文件最大行数,最大列数,判断最大行数与最大列数是否相等,若相等则生成一个n*n的矩阵,并将该矩阵初始化为0之后加入数据,由于共有n行、n列以及两条对角线,于是用一个[2n+2]数组存储行之和列之和以及对角线之和,并在添加数据时判断是否为正整数,判断数据是否规范。
(2)设计思路
①使用java输入流进行文本读入,首先读取最大行数与最大列数并判断是否相等,若不等则返回不是矩阵的结果;
②将字符串按行读入并存入String数组,并在读取数据过程中进行数据合法性检验,若不是正整数则报错;
③以第一行为参考,计算出各行列及对角线的和判断各值是否相等,如果不等返回false并抛出和不相等的异常,在函数最后若无上述异常则说明幻方成立,返回true。
④main函数进行测试
⑤得到如下运行结果:
2.generateMagicSquare()
按步骤给出你的设计和实现思路/过程/结果。
- 设计思路
(1)使用罗伯法构造一个n为奇数的nxn幻方。罗伯法的算法具体为:
把1(或最小的数)放在第一行正中;按以下规律排列剩下的(n×n-1)个数
①每一个数放在前一个数的右上一格;
②如果这个数所要放的格已经超出了顶行那么就把它放在底行,仍然要放在右一列;
③如果这个数所要放的格已经超出了最右列那么就把它放在最左列,仍然要放在上一行;
④如果这个数所要放的格已经超出了顶行且超出了最右列,那么就把它放在底行且最左列;
⑤如果这个数所要放的格已经有数填入,那么就把它放在前一个数的下一行同一列的格内。
⑵对函数public static boolean generateMagicSquare(int n) 进行分析解读:
(3)对已有代码进行完善,当输入n为负数或者偶数时进行报错
(4)编写main函数进行测试
(5)输入n为15 生成如下所示6.txt
- 异常分析
- 创建数组时元素个数不能为负数;
2.分n次每次写n个数据,每次结束时不能在最后一行,否则row会++,n为偶数会在i%n==0时row++后填写magic[][]时出现越界情况,而函数从第一行开始,注定偶数行为结束行,因此n不能为偶数
Turtle Graphics
在这里简要概述你对该任务的理解。
- 理解:该任务要求我们根据代码注释提示补全代码,利用这些函数实现旋转,前进,换色等功能,实现一个绘制工具Trurtle Graphics。
- Problem 1: Clone and import
(1)访问https://github.com/rainywang/Spring2020_HITCS_SC_Lab1/tree/master/P2下载P2文件夹,获得任务代码;
(2)在本地创建git仓库:
(3)git init初始化本地仓库
(4)git add remote origin 添加远程库源
(5)在远程仓库创建master分支
(6)git pull origin master将远程仓库同步到本地
(7)git add->git commit->git push 将本地文件加入本地仓库,将本地仓库同步到远程仓库。
Problem 3: Turtle graphics and drawSquare
- 问题描述:当给定爬行长度sideLength,使little turtle画一个边长为sideLength的正方形。
- 求解思路:turtle前进sidelength,右转90度,循环四次.即为正方形。其中forward(int units) 的功能是向前平移units个单位;turn(double degrees) 的功能为顺时针转90°
Problem 5: Drawing polygons
- 问题描述及求解思路:
(1)calculateRegularPolygonAngle
给定正整数sides(>2)为边数,返回内角度数,通过数学公式return (double)180*(sides-2)/sides实现。
(2)public static int calculatePolygonSidesFromAngle(double angle)
给出浮点数angle(0<angel<180),返回以angle为内角度数的正n边形边数。
利用多边形外角和为360°,公式为:sides=360/(180-angle)。
(3)drawRegularPolygon
给定边数画多边形,调用calculateRegularPolygonAngle(sides)计算正多边形的内角为rotation,再调用turtle.forward和turtle.turn进行前进和转向n次即可得到n边形。
Problem 6: Calculating Bearings
- 问题描述:
计算当前向量与目标向量的夹角。其中当前向量由当前点、当前方向决定,目标方向由当前点、目标点决定,当前方向由当前方向与竖直向上方向(y轴正方向)的夹角表示,目标向量的方向由当前点与目标点的连线与竖直向上方向(y轴正方向)的夹角表示。
- 解决思路:
默认初始角度为0,然后从第一个点走向第二个点后,朝向不变,然后以此朝向作为下一次旋转的初始角度,再计算第二个点到第三个点的旋转角度,依次类推。先求当前点与目标点的连线与y轴夹角的正切值,tan=(targetX-currentX)/(targetY-currentY),然后调用Math库中的atan将其转化为弧度,再由公式——角度=弧度*180/π——求得角度值,即为当前向量与y轴正方向的夹角,与currentBearing(当前方向)作差,得到结果。
Problem 7: Convex Hulls
- 问题描述:
该题为凸包问题,给出一组点的坐标,求最少的点的集合,使得其他所有点都在这些点围成的闭合凸多边形内。
- 解决思路:
扫描list列表,根据坐标选出最左下角的点作为点B。添加一个点A,A位于B点稍下的位置。将(A,B)作为向量Vec1。
扫描所有的不处于凸包中的点,计算A点与该点之间的夹角,夹角通过两向量点击与向量的模计算cos然后通过acos函数获得,找到形成夹角最小的点,如果有多个选择距离当前直线距离最远的那个点(其实可以选择距离前一个点最远的点)。将点B作为新的A,点C作为新的B,再次循环。当新找到的节点是最左边的初始节点时结束循环。
Problem 8: Personal art
设计了一个螺旋图,该图形经过了900次循环,每次步长为原长的1/9,每次以循环变量的中间位十位为判断标准获得下一个线条颜色,最后调整前进方向,旋转80度,进入下一次循环。Submitting
- 将完成的项目复制到本地仓库中,输入git add .将所有文件全部加入本地仓库;
- 输入 git commit -m “备注” 指令,将文件暂存到本地目录并且添加备注说明;
- 输入 git push -u origin master指令,将本地仓库同步到远程仓库。
Social Network
在这里简要概述你对该任务的理解。
通过Person和FriendshipGraph两个类,模拟社交网络,提供添加节点以及节点之间添加边,并用BFS计算两节点之间最短路的功能。
- 设计/实现FriendshipGraph类
先建立一个Node类,存放有关点的相关信息,点代表的Person,点与点之间的边代表联系。采用邻接矩阵的方式来存储无向图,其中visited数组表示在广度优先搜索的时候,是否已经访问过,parent数组则存储着在搜索中父节点的下标。
- 设计/实现Person类
(1)用String name存放当前节点的名字;
(2)Set<Person> friends = new HashSet<Person>():存放以当前节点为起点的所有边的终点;
(3)boolean vis:在BFS中标记当前节点是否被访问过;
(4)public String name():返回当前节点的name属性值;
(5)public void add_friend(Person new_friend):向当前节点的friends集合中添加一个新节点,即在当前节点与目标节点之间添加一条单向边;
(6)public Set<Person> get_friends():返回当前节点的friends属性;
- 设计/实现客户端代码main()
public static void main(String[] args) {
FriendshipGraph graph = new FriendshipGraph();
Person rachel = new Person("Rachel");
Person ross = new Person("Ross");
Person ben = new Person("Ben");
Person kramer = new Person("Kramer");
graph.addVertex(rachel);
graph.addVertex(ross);
graph.addVertex(ben);
graph.addVertex(kramer);
graph.addEdge(rachel, ross);
graph.addEdge(ross, rachel);
graph.addEdge(ross, ben);
graph.addEdge(ben, ross);
System.out.println(graph.getDistance(rachel, ross));
System.out.println(graph.getDistance(rachel, ben));
System.out.println(graph.getDistance(rachel, rachel));
System.out.println(graph.getDistance(rachel, kramer));
}
- 设计/实现测试用例
1.AddEdge方法测试
@Test
public void addEdgeTest() {
Person a = new Person("A");
Person b = new Person("B");
FriendshipGraph graph = new FriendshipGraph();
graph.addVertex(a);
graph.addVertex(b);
//添加单向边
graph.addEdge(a, b);
assertTrue(a.getFriend().contains(b));
assertFalse(b.getFriend().contains(a));
//添加双向边
graph.addEdge(b, a);
assertTrue(b.getFriend().contains(a));
}
2.GetDistance测试
assertEquals(1, graph.getDistance(a, b));
assertEquals(-1, graph.getDistance(b, a));
assertEquals(2, graph.getDistance(a, c));
assertEquals(-1, graph.getDistance(c, a));
实验过程中收获的经验、教训、感想
- 实验过程中收获的经验和教训
这是初次接触软件构造课程,觉得很有难度。并且在之前没有使用过Git和GitHub,导致使用很不熟练。需要多加练习。同时这也是第一次用Java语言去解决问题,一定要注意其与C语言的共性和差异,不断动手实践,学以致用。同时在本次试验中,接触到了很多算法,例如BFS等,但是在应用的过程中仍然不太熟练,所以平时一定要注意归纳总结,把经典的算法牢记于心并学以致用。
2.针对以下方面的感受
(1)Java编程语言是否对你的口味?
在学习过C语言之后学习Java相对较容易,但是初次使用Java去解决实际的问题,还是有很多知识盲区,需要多多学习、积累经验。
(2)关于Eclipse IDE
Eclipse IDE使用较为方便,当编程出错时它会智能提供一些解决方案,给我们思路。
(3)关于Git和GitHub
第一次使用Git和GitHub,十分不熟练,并且GitHub访问不太稳定,但是他们是很强大且有用的学习工具,所以要好好使用它们。
(4)关于CMU和MIT的作业
第一次接收觉得难度较大,且为英文版,需要攻克。
(5)关于本实验的工作量、难度、deadline
实验还是很具有挑战性,有难度,希望可以适当延长每个实验的deadline,不至于太仓促。
(6)关于初接触“软件构造”课程
初次接触“软件构造”课程,觉得难度挺大,这是一门需要不断动手实践积累经验的课程,一定要动手去实践,希望实验的时间可以延长一些。