任务一:能够从五个已经提供的txt文档中读入数据,来判断输入的数据能否构成一个MagicSquare,若是则返回true,若不是则返回false且说明原因。MagicSquare是一个正方形图形,他的每一行、每一列和对角线的数字之和都相等。
任务二:对给出的generateMagicSquare函数进行扩充,使之能够产生一个MagicSquare并且将其输入到文本6.txt中,然后对其判断是否为MagicSquare。并且满足若输入的为奇数能产生MagicSquare,而输入偶数或者负数会返回false。
-
-
- isLegalMagicSquare()
-
思路:先利用filereader和BufferedReader读入txt中数据,读入后,首先需要判断读入的数据能否构成一个矩阵,根据实验手册,需要判断的三张错误分别为矩阵中某些数字不是正整数,行列数不相等、并非矩阵,不是以\t作为分隔符。对三种错误进行判断并输出返回false。当没有这些错误时,分别计算矩阵每一行、每一列、对角线的和是否相等来判断能否构成MagicSquare,若是并返回true。
过程:
先用\t分割
eachlline=temp1.split("\t");
1、判断是不是方阵
if(eachlline.length!=linenum)
{
System.out.println(fileName+"NOT SQUARE");
return false;
2、有某些非正整数,同时对是否有非\t作判断
if (eachlline[i].contains("-")) {//存在负数
System.out.println(fileName + " EXIST NEGATIVE");
return false;
}
else if (eachlline[i].contains(".")) {//存在分数
System.out.println(fileName + " EXIST FLOAT");
return false;
}
else if(!eachlline[i].matches("[0-9]+")) {//存在非数字的字符,如果有非\t符分割会在这里提示
System.out.println(fileName + " NOT NUMBER,IT COULD CONTAIN ' ' OR OTHERS");
return false;
}
else if(Integer.parseInt(eachlline[i])==0) {//存在0
System.out.println(fileName + " EXIST ZERO");
return false;
}
}
3、判断行列对角线的值是否相等
先存入二维数组,计算对角线值再与每行每列作比较
for(j=0;j<len1;j++)
{
s3=s3+SQUARE[j][j];
}
for(j=0;j<len1;j++)
{
for(m=0;m<len1;m++)
{
s1=s1+SQUARE[j][m];
}
if(s1!=s3)
{
return false;
}
s1=0;
}
for(j=0;j<len1;j++)
{
for(m=0;m<len1;m++)
{
s2=s2+SQUARE[m][j];
}
if(s2!=s3)
{
return false;
}
s2=0;
}
return true;
结果:
结果:1、2是,3不是方阵,4有负数,5不是方阵
-
-
- generateMagicSquare()
-
流程图:
思路:生成函数已给出,只需要增加部分功能:(1) 将产生的magic square写入文件\src\P1\txt\6.txt中;(2) 当输入的n不合法时(n为偶数、n为负数等),不要该函数抛出异常并非法退出,而是提示错误并“优雅的”退出——函数输出false结束。所以我们只需要在开始判断是否满足n的合法输入并且增加写入文件的操作。
过程:while (n <= 0 || n % 2 == 0) {//n不为正奇数数时输出false
System.out.println("FALSE");
n = sc.nextInt();
}
判断输入是否是正奇数。
File file = new File("src/P1/txt/6.txt");
PrintWriter output = new PrintWriter(file);
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++)
output.print(magic[i][j] + "\t");
output.println();
}
output.close();
写入文件。
注:该函数是罗伯法,详见巧填幻方——罗伯法 - 知乎 (zhihu.com)
-
- Turtle Graphics
这次任务是为了实现一个绘图工具Trurtle Graphics,需要我们完成的任务为:画出一个正方形,计算正多边形内角,由正多边形内角得到边数,计算从一个点到另外一个点所需要转过的角度,给定一系列点计算每次转过的角度并返回在集合中,计算一系列点中的凸包,调用函数绘制图形,使用junit进行单元测试。
-
-
- Problem 1: Clone and import
-
首先打开实验手册提供的网站,从上面下载P2的包,并解压导入idea中。
本地仓库由链接了git的idea建立,即使用idea中vcs->创建git仓库,再由git的commit进行提交。
-
-
- Problem 3: Turtle graphics and drawSquare
-
重复前进转弯90即可:
for(int i=0;i<4;i++)
{
turtle.forward(sideLength);
turtle.turn(90);
}
计算正多边形内角只需根据正多边形内角=(边数-2)/sides写出calculateRegularPolygonAngle (int sides)
然后画正多边形只需调用此函数即可:
public static void drawRegularPolygon(Turtle turtle, int sides, int sideLength) {
//throw new RuntimeException("implement me!");
double angle=calculateRegularPolygonAngle(sides);
for (int i=0;i<sides;i++)
{
turtle.turn(180-angle);
turtle.forward(sideLength);
}
}
计算前进方向的偏转角需要调用atan2函数得到弧度,然后调用toDegree转换成角度,考虑到只能顺时针转,需要给负值加360度。
public static double calculateBearingToPoint(double currentBearing, int currentX, int currentY,
int targetX, int targetY) {
//throw new RuntimeException("implement me!");
double x=targetX-currentX;
double y=targetY-currentY;
double theta=Math.atan2(y,x);
theta=theta*180/Math.PI;
double Bearing=90-theta-currentBearing;
if(Bearing<0)
return Bearing+360;
return Bearing;
}
Gift wrapping algorithm:先找到最左下角的点加入集合,然后比较剩余点到此点的偏转角,找到偏转角最小的加入集合,当偏转角相同时,需要找到最长的一条边的点加入集合。
public static Set<Point> convexHull(Set<Point> points) {
//throw new RuntimeException("implement me!");
int index=0;
ArrayList<Point> Convexlist=new ArrayList<Point>() ;
ArrayList<Point> Oringin=new ArrayList<Point>() ;
Oringin.addAll(points);
int len=Oringin.size();
if(len<4)
return points;
Point temp=Oringin.get(0);
for(Point p:points)
{
if(p.x()<temp.x())
{
temp=p;
}
else if (p.x()==temp.x()&&p.y()<temp.y())
{
temp=p;
}
}
int count=0;
Convexlist.add(temp);
Oringin.remove(temp);
Point start=temp;
Point pointfront=temp;
do {
if(count==1)
{
Oringin.add(start);
}
double tempangle=360;
double tempdis=0;
for(Point p1:Oringin)
{
double angleval=calculateBearingToPoint(0,(int)pointfront.x(),(int)pointfront.y(),(int)p1.x(),(int)p1.y());
double disval=((int)pointfront.x()-(int)p1.x())*((int)pointfront.x()-(int)p1.x())+((int)pointfront.y()-(int)p1.y())*((int)pointfront.y()-(int)p1.y());
if(tempangle>angleval)
{
temp=p1;
tempangle=angleval;
tempdis=disval;
}
else if(tempangle==angleval&&tempdis<disval)
{
temp=p1;
tempangle=angleval;
tempdis=disval;
}
}
Convexlist.add(temp);
Oringin.remove(temp);
pointfront=temp;
count++;
}while(Convexlist.get(Convexlist.size()-1)!=start);
Set<Point> result=new HashSet<Point>();
result.addAll(Convexlist);
return result;
}
public static void drawPersonalArt(Turtle turtle) {
//throw new RuntimeException("implement me!");
drawRegularPolygon(turtle,17,40);//正十七边形
}
本次任务要求实现Person和FriendshipGraph两个类,用FriendshipGraph来构建Person之间的关系来模拟社交网络,能够计算出每两个Person之间的最短路径。
- 2. 1.设计/实现FriendshipGraph类
思路:功能有1、创建一个邻接表(表示图)2、增加顶点和增加边3、计算距离
1、创建邻接表
public HashMap<Person,ArrayList<Person>> namelist=new HashMap<Person,ArrayList<Person>>();//存储每个人和他们的朋友
2、增加顶点和增加边
public void addVertex(Person p)//增加点
{
if(namelist.containsKey(p))
{
System.out.println(p.getname()+" has been used");
System.exit(0);
}
else namelist.put(p,new ArrayList<Person>());
}
public void addEdge(Person myname0,Person myname1)//增加边
{
if(!namelist.containsKey(myname0)) {
System.out.println(myname0+"do not exist");
System.exit(0);
}
else if(!namelist.containsKey(myname1)){
System.out.println(myname1+"do not exist");
System.exit(0);
}
namelist.get(myname0).add(myname1);
}
3、计算距离
使用广度优先搜索,创建visited数组保存访问过的点,创建map二元组建立各个点到源点关系,创建queue1作为队列。
- 源点入队列,进入已visited数组,进入map,对应值为0.
- 每次取出队列顶点,将其未访问的好友进行入queue1和入map,改好友p的map对应值为队首对应值加一,如果遇到这个好友恰是终点返回这个好友的map值。
- 如果队空了还没有返回-1.
public int getDistance(Person myname0,Person myname1)
{
Queue<Person> queue1=new LinkedList<Person>();
ArrayList<Person> visited=new ArrayList<Person>();
if(myname0==myname1)return 0;
queue1.offer(myname0);
Person temp;
Map<Person,Integer> map=new HashMap<>();
map.put(myname0,0);
int dis=0;
while (!queue1.isEmpty())
{
temp=queue1.poll();
dis=map.get(temp);
for(Person p:namelist.get(temp))
{
if(!visited.contains(p))
{
map.put(p,dis+1);
visited.add(p);
queue1.offer(p);
if(p==myname1)
return map.get(myname1);
}
}
}
return -1;
}
结果:
-
-
- 设计/实现Person类
-
思路:Person类应该能记录人名,同时由于实验要求知道是否同名会报错,应该让Person有一个静态集合存人名。
过程:
1、建立一个集合存所有人
if(allpeople==null)
{
allpeople=new HashSet<String>();
}
else if(allpeople.contains(myname))
{
System.out.println(myname+" has been used");
System.exit(0);
}
allpeople.add(myname);
this.myname=myname;
2、建立返回人名的功能
public String getname()
{
return myname;
}
3、建立判断是否已经存入该名字的功能(设计时想给friendshipgraph类使用,实际并未用上)
public boolean exist(String name)
{
return allpeople.contains(name);
}
}
-
-
- 设计/实现客户端代码main()
-
原报告已有主体,这里仅修改一点。
public static void main(String arg[]){
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));
//should print 1
System.out.println(graph.getDistance(rachel, ben));
//should print 2
System.out.println(graph.getDistance(rachel, rachel));
//should print 0
System.out.println(graph.getDistance(rachel, kramer));
//should print -1
System.out.println("IF Ross = Rachel");
ross=new Person("Rachel");
}
}
-
-
- 设计/实现测试用例
-
思路:对addVertex ,addEdge ,getDistance三个功能进行测试。对于addVertex,设计test用例addVertextest,在里面建立四个Person对象全部执行addVertex,然后判断allpeople里面是都有这些对象即可。对于addEdge,只需设计test用例addEdgetest,在里面同样建立四个Person对象,执行addVertex后,执行addEdge然后判断他们的朋友中是否包含彼此即可。对于getDistance,只需设计test用例getDistancetest,在里面建立五个Person对象,执行addVertex后,执行addEdge后,使得三种距离等价类都存在,即距离为-1,距离为0,距离为正整数。
过程:
- addVertextest:
public void addVertextest() {
Person zhao = new Person("zhao");
Person qian = new Person("qian");
Person sun = new Person("sun");
Person li = new Person("li");
G.addVertex(zhao);
G.addVertex(qian);
G.addVertex(sun);
G.addVertex(li);
assertTrue(G.namelist.containsKey(zhao));
assertTrue(G.namelist.containsKey(qian));
assertTrue(G.namelist.containsKey(sun));
assertTrue(G.namelist.containsKey(li));
}
2、addEdgetest:
public void addEdgetest() {
Person zhao = new Person("zhao");
Person qian = new Person("qian");
Person sun = new Person("sun");
Person li = new Person("li");
G.addVertex(zhao);
G.addVertex(qian);
G.addVertex(sun);
G.addVertex(li);
G.addEdge(zhao, qian);
G.addEdge(sun, li);
G.addEdge(qian, zhao);
G.addEdge(li, sun);
G.addEdge(zhao, li);
G.addEdge(li, zhao);
assertTrue(G.namelist.get(zhao).contains(qian));
assertTrue(G.namelist.get(zhao).contains(li));
assertTrue(G.namelist.get(qian).contains(zhao));
assertTrue(G.namelist.get(sun).contains(li));
assertTrue(G.namelist.get(li).contains(sun));
assertTrue(G.namelist.get(li).contains(zhao));
assertTrue(G.namelist.get(sun).contains(li));
assertTrue(!G.namelist.get(zhao).contains(sun));
}
3、getDistancetes
public void getDistancetest()
{
Person zhao = new Person("zhao");
Person qian = new Person("qian");
Person sun = new Person("sun");
Person li = new Person("li");
Person zhou=new Person("zhou");
G.addVertex(zhao);
G.addVertex(qian);
G.addVertex(sun);
G.addVertex(li);
G.addVertex(zhou);
G.addEdge(zhao, qian);
G.addEdge(sun, li);
G.addEdge(qian, zhao);
G.addEdge(li, sun);
G.addEdge(zhao, li);
G.addEdge(li, zhao);
int zero=G.getDistance(zhao,zhao);
int neone=G.getDistance(zhao,zhou);
int a=G.getDistance(zhao,li);
int b=G.getDistance(zhao,qian);
int c=G.getDistance(zhao,sun);
int d=G.getDistance(qian,li);
int e=G.getDistance(sun,li);
int f=G.getDistance(qian,sun);
assertEquals(0,zero);
assertEquals(-1,neone);
assertEquals(1,a);
assertEquals(1,b);
assertEquals(1,e);
assertEquals(2,d);
assertEquals(2,c);
assertEquals(3,f);
}
}