The Location Class
Set 3
回答以下问题时,请假定以下陈述。
Location loc1 = new Location(4, 3);
Location loc2 = new Location(3, 4);
如何访问loc1的行值?
- 回答:使用getRow()函数,即可访问。
- 代码:
//@file: GridWorldCode\framework\info\gridworld\grid\Location.java
// @line: 110~112
public int getRow()
{
return row;
}
执行以下语句后,b的值是什么?
boolean b = loc1.equals(loc2);
- 回答:b=false;
- 代码:
//@file: GridWorldCode\framework\info\gridworld\grid\Location.java
// @line: 205~212
public boolean equals(Object other)
{
if (!(other instanceof Location))
return false;
Location otherLoc = (Location) other;
return getRow() == otherLoc.getRow() && getCol() == otherLoc.getCol();
}
执行以下语句后,loc3的值是什么?
Location loc3 = loc2.getAdjacentLocation(Location.SOUTH);
- 回答:loc3的坐标为(4,4);
- 代码:
//@file: GridWorldCode\framework\info\gridworld\grid\Location.java
// @line: 130~169
public Location getAdjacentLocation(int direction)
{
// reduce mod 360 and round to closest multiple of 45
int adjustedDirection = (direction + HALF_RIGHT / 2) % FULL_CIRCLE;
if (adjustedDirection < 0)
adjustedDirection += FULL_CIRCLE;
adjustedDirection = (adjustedDirection / HALF_RIGHT) * HALF_RIGHT;
int dc = 0;
int dr = 0;
if (adjustedDirection == EAST)
dc = 1;
else if (adjustedDirection == SOUTHEAST)
{
dc = 1;
dr = 1;
}
else if (adjustedDirection == SOUTH)
dr = 1;
else if (adjustedDirection == SOUTHWEST)
{
dc = -1;
dr = 1;
}
else if (adjustedDirection == WEST)
dc = -1;
else if (adjustedDirection == NORTHWEST)
{
dc = -1;
dr = -1;
}
else if (adjustedDirection == NORTH)
dr = -1;
else if (adjustedDirection == NORTHEAST)
{
dc = 1;
dr = -1;
}
return new Location(getRow() + dr, getCol() + dc);
}
执行以下语句后,dir的值是什么?
int dir = loc1.getDirectionToward(new Location(6, 5);
- 回答:dir=135° ;从坐标图可以直观看出,(6,5)位于(4,3)的东南方(坐标系向下建立)。
- 代码:
//@file:GridWorldCode\framework\info\gridworld\grid\Location.java
//@line: 178~190
public int getDirectionToward(Location target)
{
int dx = target.getCol() - getCol(); //2
int dy = target.getRow() - getRow(); //-2
int angle = (int) Math.toDegrees(Math.atan2(-dy, dx));
int compassAngle = RIGHT - angle;
compassAngle += HALF_RIGHT / 2;
if (compassAngle < 0)
compassAngle += FULL_CIRCLE;
return (compassAngle / HALF_RIGHT) * HALF_RIGHT;
}
getAdjacentLocation方法如何知道要返回哪个相邻位置?
- 回答:由代码可知,该函数传入的参数是一个角度值,因此方向已经被确定了。由参数direction确定位置,随后找到在给定方向相对位置为1的位置.
- 代码:
// @file: GridWorldCode\framework\info\gridworld\grid\Location.java
// @line: 130-169
public Location getAdjacentLocation(int direction)
{
// reduce mod 360 and round to closest multiple of 45
int adjustedDirection = (direction + HALF_RIGHT / 2) % FULL_CIRCLE;
if (adjustedDirection < 0)
adjustedDirection += FULL_CIRCLE;
adjustedDirection = (adjustedDirection / HALF_RIGHT) * HALF_RIGHT;
int dc = 0;
int dr = 0;
if (adjustedDirection == EAST)
dc = 1;
else if (adjustedDirection == SOUTHEAST)
{
dc = 1;
dr = 1;
}
else if (adjustedDirection == SOUTH)
dr = 1;
else if (adjustedDirection == SOUTHWEST)
{
dc = -1;
dr = 1;
}
else if (adjustedDirection == WEST)
dc = -1;
else if (adjustedDirection == NORTHWEST)
{
dc = -1;
dr = -1;
}
else if (adjustedDirection == NORTH)
dr = -1;
else if (adjustedDirection == NORTHEAST)
{
dc = 1;
dr = -1;
}
return new Location(getRow() + dr, getCol() + dc);
}
The Grid Interface
Set 4
如何获得网格中对象的数量?如何获得有界网格中的空位置计数?
- 回答:使用grid.getOccupiedLocations()函数,可以找到所有被占有的单元格的位置,再用size()函数计算出函数返回数组中元素的准确个数,这样一来就可以获得网格中对象的数量。 而空位置数量 = 总单元格数(grid的长的数目(grid.getNumRows()) * grid的宽的数目(grid.getNumCols()) ) - 已经被占用的单元格数(grid.getOccupiedLocation.size())
- 代码:
// @file: GridWorldCode\framework\info\gridworld\grid\BoundedGrid.java
//@line: 66-83
public ArrayList<Location> getOccupiedLocations()
{
ArrayList<Location> theLocations = new ArrayList<Location>();
for (int r = 0; r < getNumRows(); r++)
{
for (int c = 0; c < getNumCols(); c++)
{
// If there's an object at this location, put it in the array.
Location loc = new Location(r, c);
if (get(loc) != null)
theLocations.add(loc);
}
}
return theLocations;
}
如何检查位置(10,10)是否在网格中?
- 回答:isValid(Location loc)函数,如果一个点在grid内返回true,否则返回false;可以通过判断isValid((10,10))的返回值是true还是false来判断是不是在grid内
- 代码:
// @file: GridWorldCode\framework\info\gridworld\grid\BoundedGrid.java
// @line: 60-64
public boolean isValid(Location loc)
{
return 0 <= loc.getRow() && loc.getRow() < getNumRows()
&& 0 <= loc.getCol() && loc.getCol() < getNumCols();
}
Grid包含函数声明,但函数中未提供任何代码。为什么?在哪里可以找到这些函数的实现?
- 回答:(1)从Grid文件的定义中,可以发现,Grid并不是一个完整的类,而是一个接口,所以Grid并不会提供相应具体的方法来让我们使用,而是只提供了一个方法模型;(2)而其他的类可以通过对这个接口的继承,来实现对方法的调用;同时在不同的类中,不同的继承,可能来自同一个借口的函数的功能也是不一样的。 从 AbstractGrid类, BoundedGrid类和 UnboundedGrid类中找到Grid对应方法的实现
- 代码:
// @file: GridWorldCode\framework\info\gridworld\grid\BoundedGrid.java
// @line: 29
public class BoundedGrid<E> extends AbstractGrid<E>
// @file: GridWorldCode\framework\info\gridworld\grid\BoundedGrid.java
// @line: 85-91
public E get(Location loc)
{
if (!isValid(loc))
throw new IllegalArgumentException("Location " + loc
+ " is not valid");
return (E) occupantArray[loc.getRow()][loc.getCol()]; // unavoidable warning
}
所有返回多个对象的函数都将它们返回到ArrayList中。您认为将对象返回到数组中会更好吗?解释你的答案。
- 回答:我认为用数组不会更好。因为ArrayList是动态的,没有固定的大小,可以在需要时候增加或者减少来降低内存空间的使用;而array不可以,array是静态的,只能固定长度,不方便进行数据的删减,同时也可能会造成大量内存空间的浪费或者泄露。
- 代码:
// @file: GridWorldCode\framework\info\gridworld\grid\BoundedGrid.java
// @line: 66-83
public ArrayList<Location> getOccupiedLocations()
{
ArrayList<Location> theLocations = new ArrayList<Location>();
// Look at all grid locations.
for (int r = 0; r < getNumRows(); r++)
{
for (int c = 0; c < getNumCols(); c++)
{
// If there's an object at this location, put it in the array.
Location loc = new Location(r, c);
//实现ArrayList的动态加长
if (get(loc) != null)
theLocations.add(loc);
}
}
return theLocations;
}
The Actor Class
Set 5
列出每个actor的三个属性。
- 回答:三个属性分别是location、direction、color 。
- 代码:
// @file: GridWorldCode\framework\info\gridworld\actor\Actor.java
// @line: 31-34
private Grid<Actor> grid;
private Location location;
private int direction;
private Color color;
构造一个actor时,它的方向和颜色是什么?
- 回答:当构造一个新的actor类型的对象时候,方向会被默认置为:**North,**颜色会被默认置为:**Blue **
- 代码:
// @file: GridWorldCode\framework\info\gridworld\actor\Actor.java
// @line: 37-45
public Actor()
{
color = Color.BLUE;
direction = Location.NORTH;
grid = null;
location = null;
}
为什么认为Actor类是作为类而不是接口创建的?
- 回答:因为actor这个类中,不仅定义了方法,而且还对方法进行了具体的实现,所以这个actor是一个类,如果actor是以一个接口的话,那么定义的这些方法再进行实现是不允许被实现的。
- 代码:
// @file: GridWorldCode\framework\info\gridworld\actor\Actor.java
该文件中的函数都有具体实现,因此我认为此题不需要贴上代码。
actor是否可以先将自己放入网格两次而不先将其自身移除?actor可以两次将自己从网格中移除吗?可以将actor放置到网格中,将其自身移除然后放回去吗?
- 回答:
(1)不可以,一个actor不可以连续添加两次 (2)不可以,一个actor只允许被删除一次(3)可以,一个actor先被加入,后被删除,随后再加入,自始至终都是这个actor实体在进行行动,同时也没有出现多次出现以及多次被删除的情况。 - 代码:
//写一个ActRunner类对该问题进行检验
public class ActorRunner
{
public static void main(String[] args)
{
ActorWorld world = new ActorWorld();
Actor a = new Actor();
//(1)test
world.add(a);
//world.add(a);错误
//(2) test
a.removeSelfFromGrid();
//a.removeSelfFromGrid(); 错误
//(3) test
world.add(a);//正确
world.add(new Rock());
world.show();
}
}
actor如何向右旋转90度?
- 回答:使用actor.setDirection(getDirection() + Location.RIGHT)方法进行实现右转90°
- 代码:
// @file: GridWorldCode\framework\info\gridworld\actor\Actor.java
// @line: 80-86
public void setDirection(int newDirection)
//输入90就可以使actor右转九十度
{
direction = newDirection % Location.FULL_CIRCLE;
if (direction < 0)
direction += Location.FULL_CIRCLE;
}
Extending the Actor Class
Set 6
canMove方法中的哪条语句可确保bug不会试图移出网格?
- 回答:使用isValid()方法保证bug不出界。
// @file: GridWorldCode\framework\info\gridworld\actor\Bug.java
// @line: 98-99
if (!gr.isValid(next))
return false;
canMove方法中的哪条语句确定bug不会进入岩石?
- 代码:
// @file: GridWorldCode\framework\info\gridworld\actor\Bug.java
// @line: 101
return (neighbor == null) || (neighbor instanceof Flower);
return (neighbor == null) || (neighbor instanceof Flower);
可以通过canMove方法调用Grid接口的哪些方法,为什么?
- 回答:使用到的接口有isValid()函数和get()函数,这两个函数前者确保bug可以进行正常的移动,后者保证bug可以避开岩石或者再次走到花上面;
- 代码:
// @file: GridWorldCode\framework\info\gridworld\actor\Bug.java
// @line: 78-79和101
if (gr.isValid(next))
moveTo(next);
// 和
return (neighbor == null) || (neighbor instanceof Flower);
canMove方法调用Location类的哪个方法,为什么?
- 回答:getAdjacentLocation()函数。调用这个函数作用是为了找到bug下一个可以移动的位置。
- 代码:
// @file: GridWorldCode\framework\info\gridworld\actor\Bug.java
// @line: 97
Location next = loc.getAdjacentLocation(getDirection());
在canMove方法中调用了从Actor类继承的哪些方法?
- 回答:从Actor类中继承过来三个函数:getGrid()、getLocation()、getDirection()
- 代码:
// @file: GridWorldCode\framework\info\gridworld\actor\Bug.java
// @line: 64、76、96
setDirection(getDirection() + Location.HALF_RIGHT);
Location loc = getLocation();
Location loc = getLocation();
当bug正前方的位置不在网格中时,在move方法中会发生什么?
- 回答:当bug前面的位置位于grid外面时候,使用move方法会让bug把自己从grid中移除
- 代码:
// @file: GridWorldCode\framework\info\gridworld\actor\Bug.java
// @line:78-81
if (gr.isValid(next))
moveTo(next);
else
removeSelfFromGrid();
是move方法中需要变量loc,还是可以通过多次调用getLocation()来避免变量loc?
- 回答:move方法中需要变量loc,因为在bug移动过程中,bug的location会被多次改变,从而需要一个变量loc来标记每一次bug移动之前的位置,同时判断下一个位置是否可以进行移动;同时这个loc还可以用于放置一朵花 。
- 代码:
// @file: GridWorldCode\framework\info\gridworld\actor\Bug.java
// @line:76-77
Location loc = getLocation();
Location next = loc.getAdjacentLocation(getDirection());
您为什么认为bug掉落的花朵与bug的颜色相同?
- 回答:这个是由bug类定义的,bug移动之后会在bug移动之前那个位置放置一朵与自身颜色相同的花
- 代码:
//@file: GridWorldCode\framework\info\gridworld\actor\Flower.java
//@fileGridWorldCode\framework\info\gridworld\actor\Bug.java
//@line:46-49(flower)和82-83(bug)
public Flower(Color initialColor)
{
setColor(initialColor);
}
Flower flower = new Flower(getColor());//设置花的颜色与bug相同
flower.putSelfInGrid(gr, loc);//找到bug移动之前的位置放置花
当bug从网格中移出时,会否将花朵放到先前的位置?
- 回答:不会,当bug调用从actor类中继承的removeSelfFromGrid()函数移除bug的时候,并未涉及到有产生花的方法;
- 代码:
// @file: GridWorldCode\framework\info\gridworld\actor\Actor.java
// @line:133-146
public void removeSelfFromGrid()
{
if (grid == null)
throw new IllegalStateException(
"This actor is not contained in a grid.");
if (grid.get(location) != this)
throw new IllegalStateException(
"The grid contains a different actor at location "
+ location + ".");
grid.remove(location);
grid = null;
location = null;
}
move方法中的哪条语句将花放到bug的先前位置的网格中?
- 代码:
// @file:
GridWorldCode\framework\info\gridworld\actor\Bug.java
// @line:)82-83
Flower flower = new Flower(getColor());//产生花并设置好花的颜色
flower.putSelfInGrid(gr, loc);//将花放置到bug的上一个移动位置上
如果bug需要旋转180度,应该调用turn方法多少次?
- 回答:共4次;由于turn一次就只能旋转45°,所以就需要进行4次旋转。
- 代码:
// @file: GridWorldCode\framework\info\gridworld\actor\Actor.java
// @line:61-65
public void turn()
{
setDirection(getDirection() + Location.HALF_RIGHT);
}