3.2Turtle Graphics
3.2.1 Problem 1: Clone and import
根据github网址加载zip,然后解压放到相应文件夹。在eclipse中f5刷新。或git中使用pull和clone命令下载到本地。init初始化本地仓库。可用add添加文件,commit加备注,push推送。
3.2.2 Problem 3: Turtle graphics and drawSquare
画一个方形:颜色设为黑色,设定边长sideLength,画一条sideLength长的线,然后转90°角,如此重复4次即可。
turtle.color(PenColor.BLACK);
for(int i=0; i<4; i++)
{
turtle.forward(sideLength);
turtle.turn(90);
}
3.2.3 Problem 5: Drawing polygons
根据多边形内角与边的关系:内角=(sides-2)*(180.0/sides)=180.0-360.0/sides.
public static double calculateRegularPolygonAngle(int sides) {//通过边数算内角
double a = 180 -(360.0/sides);
return a;
}
由此,对于多边形,可先前进一个sideLength边长,然后转动内角的补角,循环边数次即可。
注:首先转270°的目的在于将绘制起始方向由上朝向左.
public static void drawRegularPolygon(Turtle turtle, int sides, int sideLength) {//绘制多边形
turtle.turn(270);
double a = 180.0 -calculateRegularPolygonAngle(sides);
//a是内角的补角
for(int i=0; i<sides; i++)
{
turtle.forward(sideLength);
turtle.turn(a);
}
}
例如六边形drawRegularPolygon(turtle,6,50):
3.2.4 Problem 6: Calculating Bearings
3.2.4.1calculateBearingToPoint()
给定初始点方向与上方的角度,初始点和目标点坐标,计算出顺时针达到目标点需要转过的角度。利用Math中的atan2函数,通过正切值计算出竖直时的转动角度,然后与给定初角度相减,计算出需要转过的角度。
注:要将弧度转化为角度,并把角度限制在0-359°范围内。
public static double calculateBearingToPoint(double currentBearing,int currentX, int currentY,int targetX, int targetY) {
double angle = Math.atan2(targetX - currentX, targetY - currentY) * 180 / Math.PI - currentBearing;
while(angle < 0)
angle += 360;
while(angle > 360)
angle -= 360;
return angle;
}
3.2.4.2calculateBearings()
定义一个列表储存角度。函数输入为两个列表,分别储存点的横纵坐标。
循环取出两个list的同索引位的值为点坐标,调用calculateBearingToPoint(),初始角度0,计算角度add进角度list。
每循环一次更新初始角度,最后return角度的list。
public static List<Double> calculateBearings(List<Integer> xCoords, List<Integer> yCoords) {
ArrayList <Double>Angle = new ArrayList<Double>();
double currentAngle = 0;
for(int i = 0;i < xCoords.size()-1; i++)
{
Angle.add(calculateBearingToPoint(currentAngle, xCoords.get(i), yCoords.get(i), xCoords.get(i+1), yCoords.get(i+1)));
currentAngle = (currentAngle+Angle.get(i))%360.0;//更新角度
}
return Angle;
}
3.2.5 Problem 7: Convex Hulls
1.首先找到最左下角的点
2.以找到的点为基点,y轴正向为目前偏移角,开始依次找顺势针转角最小的点,记录这个点并将他加入到凸包集合中,以这次的偏向角累加上之前的角度度作为下一次的目前偏向角。
3.循环直到再次遇到最左下角为止退出。
计算偏向角函数:calculateBearingToPoint()。
部分代码:
public static Set<Point> convexHull(Set<Point> points) {
Set<Point> shellPoint = new HashSet<Point>();
Point minPoint = null;
double nowBearing;
double nextBearing;
double preBearing;
double nextLength;
Point nowPoint;
Point nextPoint = null;
if (!points.isEmpty()) {
// 元素小于3个时,必是凸包直接返回
if (points.size() <= 3)
return points;
// 求最左下元素
for (Point point : points) {
if (minPoint == null) {
minPoint = point;
continue;
}
if (minPoint.x() > point.x())
minPoint = point;
else if (minPoint.x() == point.x()) {
if (point.y() < minPoint.y())
minPoint = point;
}
}
......
}
......
}
3.2.6 Problem 8: Personal art
循环多次前进、旋转,设定颜色
例如:
public static void drawPersonalArt(Turtle turtle) {
int i;
for(i=0;i<400;i++)
{
switch (i%7) {
case 0:turtle.color(PenColor.BLUE);break;
case 1:turtle.color(PenColor.CYAN);break;
case 2:turtle.color(PenColor.GRAY);break;
case 3:turtle.color(PenColor.GREEN);break;
case 4:turtle.color(PenColor.MAGENTA);break;
case 5:turtle.color(PenColor.ORANGE);break;
case 6:turtle.color(PenColor.PINK);break;
case 7:turtle.color(PenColor.RED);break;
case 8:turtle.color(PenColor.YELLOW);break;
case 9:turtle.color(PenColor.BLACK);break;
}
turtle.turn(73);
turtle.forward(i*7/5);
}
}
3.3 Social Network
该任务要求设计一张社交网络图,基于连接人与人,并且能计算任意两人之间的联系情况。即数据结构图的建立与路径长。
3.3.1 设计/实现FriendshipGraph类
首先建立一个Person列表,用来储存人名。建立一个二维矩阵做图的邻接矩阵。建立Hashmap储存人名与此人在列表中的索引值这个键值对。
public ArrayList<Person> namelist = new ArrayList<Person>();//人名列表
public int edge[][] = new int[10000][10000]; //图的邻接矩阵
public HashMap<Person,Integer> name_location =new HashMap<Person,Integer>(); //人名与在列表中的索引键值对
3.3.1.1 addVertex(Person name)
如果人名列表里有人名与name相同,则给出错误提醒。否则,向列表添加名字,并且把这个名字-位置键值对放到map里。
namelist.add(name);
name_location.put(name, namelist.indexOf(name));//新加person键值对,人名-位置
3.3.1.2 addEdge(Person name1, Person name2)
利用键值对,通过名字获得其所在列表索引,对应与邻接矩阵值赋为1,代表两点相连。
public void addEdge(Person name1, Person name2) {//通过人名找到其邻接矩阵对应位置,然后设边长为1
int x,y;
x = name_location.get(name1);
y = name_location.get(name2);
edge[x][y] = 1;
}
3.3.1.3getDistance(Person name1, Person name2)
首先如果两人名相同,则返回0。不同,则用贪心算法(Dijkstra),把起点到所有点的距离都计算储存,找个最短的。然后遍历一遍,看以刚才距离最短的点为路的中转站会不会更近,不断更新循环。
部分代码:
for(int i=0; i<n-1; i++)//循环n-1次,每次都能加入一个点,最后每个点都已经加入
{
w = 0;
temp = 100;
for(int j=0; j<n; j++)
{
if(!S[j]&&cost[j]<temp)
{
temp = cost[j];
w = j;//
}
}
S[w] = true;//遍历寻找一个当前最小的cost[j]即边长
for(int v=0; v<n ;v++)
{
if(S[v]!=true)
{
sum = cost[w] + edge[w][v];
if(sum<cost[v])
{
cost[v] = sum;
}
}
}
}
3.3.2 设计/实现Person类
建立一个私有成员变量,设置构造函数,并且再建立一个getter方法。
public class Person {
private String nameString;
public String Getname()
{
return this.nameString;
}
public Person(String namString)
{
this.nameString = namString;
}
}
3.3.3 设计/实现客户端代码main()
依据实验手册,初始化邻接矩阵,增加person对象和边,计算最短距离,与正确结果验证是否正确。
public static void main(String[] args) {
FriendshipGraph graph = new FriendshipGraph();
for(int i=0; i<graph.edge.length; i++)//初始化矩阵值为1000
{
for(int j=0; j<graph.edge.length; j++)
{
graph.edge[i][j] = 1000;
}
}
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
}
添加的对象与边具体如下:
运行结果:
与should print的结果相同。