目录:
2.1 Problem 1: Clone and import
2.2 Problem 3: Turtle graphics and drawSquare
2.3 Problem 5: Drawing polygons
2.4 Problem 6: Calculating Bearings
正文:
1.Magic Squares
该实验主要分为2部分:实现magicsquare的判断和阅读并修改实现magicsquare的生成代码。
其中第一个部分主要由读取文件和判断2个部分组成。读取文件要注意java的代码实现以及对非法字符的识别(可以采用正则表达式快速实现)。判断部分大体分为行、列、斜对角的和是否相等的判断,可以分别用3个函数来判断,最终判断是否都返回true。
1.1 isLegalMagicSquare()
- 读取文件:java是一行一行的读取文件字符串。用squareL列表存储所有数字的字符串。读取文件的主要步骤:创建filename的File变量fd,然后创建fd的FileReader变量,再根据这个变量创建BufferReader变量读取文件流。每读一行就将其根据“\t”分割为一个个数字的字符串储存在aquareL内,同时用n存储行数备用。直到读取的一行字符串为null停止,文件读取完毕,关闭BufferReader、FileReader,进入下一步。
-
转换字符串数组为int类型的数组。首先将字符串列表转换为字符串数组方便定位,然后循环每一个元素,同时开始检查合法性(首先判断是否含有小数和负数,通过检查字符串是否含有“-”和“.”;然后判断是否含有“ ”,如果含有那说明其中有些地方不按照“\t”分割;然后通过正则表达式判断[^1-9\\t],含有其他非法字符则不容许下一步),多次判断是为了可以识别错误类型。检查都通过就可以转换为int类型并存放到数组里。最后还需要检查是否为行列相等的矩阵,将转换后的数组大小与n2比较即可。
//判断是否为小数或负数 if(square[i].contains(".") || square[i].contains("-")){ System.out.println("包含非正整数"); return false; } //判断是否不为\t分割 if(square[i].contains(" ")){ System.out.println("非\\t分割"); return false; } //判断是否含有其他字符 if(square[i].matches("[^1-9\\t]")){ System.out.println("包含非法字符"); return false; }
-
判断该矩阵是否为Magic。先计算第一行的总和为标准,通过3个函数分别判断行、列、斜角是否总和相等,内部都是只要发现总和不等便中断并返回false。最后将3个函数的结果&&赋给result,返回result。
1.2 generateMagicSquare()
1.判断输入边数,偶数和负数则函数退出。
2.创建文件操作相关的变量:File、FileWriter、BufferWriter。
3.生成MagicSquare。
//生成magic square
int magic[][] = new int[n][n]; //初始化二维数组
int row = 0, col = n / 2, i, j, square = n * n; //从magic[0][n/2]开始
for (i = 1; i <= square; i++) { //遍历n方次,i逐次加一,遍历完生成结束
magic[row][col] = i; //将magic[row][col]赋值,且赋值从1开始依次递增1
if (i % n == 0)
row++; //当每遍历过n个数时,下一次赋值在当次赋值位置的同列下一行
else { //若未遍历过n个数,则
if (row == 0) //若行数为0,下一次赋值在最后一行
row = n - 1;
else //行数不为0就每次减一
row--;
if (col == (n - 1)) //若列数为n-1,下一次赋值在第0列
col = 0;
else //列数不为n-1就每次加一
col++;
}
}
4.将生成的数组以“\t”分割写入文件6.txt中,如果到行尾则不写“\t”,写入完成关闭FileWriter、BufferWriter结束。
以下为1-5和6的测试结果:
2.Turtle Graphics
该任务要理解和利用接口的操作,用给的turtle按照程序走对路。难点有二:其一是小数除法需要注意,有时需要强转为浮点数类型;其二是求解凸包问题的算法,不好想不好实现。
2.1 Problem 1: Clone and import
- 访问github仓库并且将代码下载到指定文件夹
- 在idea内创建本地仓库,需要指定一个空文件夹,然后生成仓库
- Git常用有commit(将代码提交到本地仓库)、push(将本地仓库的该分支提交到远程仓库)、checkout(切换到另一个分支)、rebase(将分支并到另一个分支末尾)、merge(将两个分支合并)。
- Git提交是每完成一个阶段性任务提交一次,并且写好标签。Master分支在某个部分完成时才更新。每开一个新任务就开一个分支,并且在其上工作。
2.2 Problem 3: Turtle graphics and drawSquare
主要调用turtle的forward和turn方法:画正方形需要调用4次前进和转90度,一个循环即可。
2.3 Problem 5: Drawing polygons
- 首先计算该多边形的内角。利用之前实现的calculateRegularPolygonAngle函数计算。公式
- 如果是三角形则先转30度,如果是四边形则不转,如果是5及以上的边数则转450-计算的内角度数。
- Turtle前进、旋转180-内角度数,重复sides次。
2.4 Problem 6: Calculating Bearings
- 首先完成calculateBearingToPoint,可以计算当前点到目标点需要转的角度
- 首先计算相对位置,x=targetX-currentX,y=targetY-currentY
- 计算与x轴的夹角(-180~180),利用math.atan2和math.todegree。
- 将x轴为基准的度数转换为以y轴为基准的度数。
- 计算需要旋转的度数
- 返回求得的需要旋转的度数。
- 先创建一个数组bearings存放double类型的值,用来存放旋转的角度
- 遍历xCoords和yCoords列表,分别计算相邻两项之间转动的角度,利用calculateBearingToPoint方便计算,存储到bearings。
- 返回bearings
2.5 Problem 7: Convex Hulls
先将points集合转换为列表pointList方便操作。
- 首先要排除集合中只有0/1/2个点的情况,直接调用size方法检查元素个数,小于三直接返回points集合。如果有超过两个点,下一步。
- 遍历列表寻找y最小的点,如果有相同的y,取x最小的点。计该点为P0
- 建立stack存放是凸包的点集,首先将P0放入,将该点作为基准,寻找其他点中和该点夹角最小的点(调用calculateBearingToPoint),如遇见相同度数的点,取距离最大的点。记为p2.
- 将p2加入stack,同时在每次循环寻找的点集中去掉p2,重复上述循环,直到又一次加入P0.
- 将stack转换为set,返回该集合。
算法思路如图:
2.6 Problem 8: Personal art
计划画出多个正六边形错位旋转形成的复杂图案。
- 计算正六边形内角度数(calculateRegularPolygonAngle),加一赋给angle作为每次turtle旋转的角度。
- 设置6种颜色放入列表中循环使用。
- 循环让turtle前进,转向,每完成6次转向
- 边长减一,直到边长为1停止。
2.7 Submitting
完成后在P2分支上提交一次,然后将P2rebase到master分支上,然后将master分支更新到P2所处的位置,将其push到GitHub,完成提交。
3.Social Network
该任务要求创建Person和FriendShipGrapgh类,分别代表人物和画出的有向图。其中person只需要存储姓名,重写equal方法即可。FriendShipGrapgh需要存包含的person列表(点集)和单向图(使用链表存取每个人的关系对象,再使用列表存取这些链表)。最后还需要用广度优先搜索查询路径长度。
3.1 设计/实现FriendshipGraph类
由分析可知:
属性:
List<Person> persons,存放图中的人物点集;
List<LinkedList>relation,存放人物之间的关系(单向)
Int relationNumber,存放关系总数(边数)
方法:
- 构造方法两个,无参和带参构造
- addvertex:首先判断persons内是否含有该人物,若含有则直接返回,否则将该人物加入点集persons,并且在relation中加入以该人物为首位元素的链表。
- Addedge:首先遍历persons,若没有起始人物或目标人物,直接返回,否则在relation中寻找以起始人物为第一元素的链表,判断链表内是否含有目标人物,含有则直接返回,不含有则在尾端加上,维护relationNumber。
- Getdistance;采用BFS,创建距离列表赋初值为-1,创建一个队列加入起始人物,设置其距离为0,开始遍历队列。查询该人物的所有关系对象,如果没有加入到队列则加入,并且将其对应的距离列表的值改为前者的值加一。直至遍历完成,查找目标人物对应的距离并返回,如果队列内查不到说明无法达到,输出-1.
3.2 设计/实现Person类
属性:
String name,存储人物名字
方法:
- 有参和无参构造方法
- Equals:判断人物名字是否相等,返回boolean。
- Get:获取对象的名字
3.3 设计/实现客户端代码main()
按照手册实例创建main,输出为:
3.4 设计/实现测试用例
- addvertex方法测试:按照手册加入4个人物,通过比对persons的值确认。首先测试正常情况,然后测试重复加入同一人的情况。测试结果都与预期相符。
- Addedge方法测试:加入4个人物,加入rachel->ross,ross->rachel两条边,比对graph的relation确认。首先测试正常情况,然后加入rachel->rachel测试,然后加入不存在的jack测试是否可以加入边,最后测试是否可以重复加同一条边。结果与预期相符。
- Getdistance测试:加入加入4个人物,加入rachel->ross,ross->rachel,ross->ben,ben->ross4条边。首先测试rachel到rachel,rachel到可达的ben,kramer到不可达的ben.然后测试加入ben->kramer后kramer到ben的距离是否为-1.结果与预期相符。