“疯狂Android讲义(第二版)”第18章介绍了一个完整的小游戏“疯狂连连看”,虽然能正常工作, 但不少地方可以改进。出于练习的目的,我打算对源代码逐步进行重构。
问题二:实现过于繁琐,代码量较多
解决二:化繁为简,提高效率
在“疯狂连连看”的程序中,GameService接口和GameServiceImpl类是整个游戏逻辑实现的核心。它们所实现的最繁琐的功能就是“判断两张图案相同的牌是否可以相连”。根据此游戏的规则,可以相连能够分为4种情形:
1 两张方块位于同一条水平线,可直接相连
2 两张方块位于同一条垂直线,可直接相连
3 两张方块以两条线段相连,就是有一个拐角
4 两张方块以三条线段相连,就是有两个拐角
对于情形3和4,书中所采用的方法需要考虑两张方块的相对位置,然后获取方块的四周的通道(指一张牌上下左右四个方向上的空白方块),接着根据相对位置,判断这些通道是否有交点,从而得出两张方块能够连接的路径。这种实现过于繁琐,代码量较多。经过分析,做出以下改进:
1 合并上下通道为垂直通道,合并左右通道为水平通道。用垂直通道和水平通道来判断交点。采用这种方式可无需考虑两张方块的相对位置,大大降低了复杂度。
2 对于情形4,需要判断位于平行通道上两个方块是否能够被一条线段连接。只要找到一对方块,即可返回;没有必要遍历所有方块。
程序示例:(下面代码片段中用到的其它函数未做改动,可参考原书所带的源程序)
1 得到水平通道和垂直通道
private List<Point> getHorizontalChannel(Point p, int min, int max, int pieceWidth)
{
List<Point> result = getLeftChannel(p, min, pieceWidth);
List<Point> resultRight = getRightChannel(p, max, pieceWidth);
result.addAll(resultRight);
return result;
}
private List<Point> getVerticalChannel(Point p, int min, int max, int pieceWidth)
{
List<Point> result = getUpChannel(p, min, pieceWidth);
List<Point> resultDown = getDownChannel(p, max, pieceWidth);
result.addAll(resultDown);
return result;
}
2 利用水平通道和垂直通道,判断两张方块是否能相连
/**
* 获取两个不在同一行或者同一列的座标点的直角连接点, 即只有一个转折点
*
* @param point1 第一个点
* @param point2 第二个点
* @return 两个不在同一行或者同一列的座标点的直角连接点
*/
private Point getCornerPoint(Point point1, Point point2, int pieceWidth, int pieceHeight)
{
int heightMax = (gameConfig.getYSize() + 1) * pieceHeight + gameConfig.getBeginImageY();
int widthMax = (gameConfig.getXSize() + 1) * pieceWidth + gameConfig.getBeginImageX();
List<Point> p1HorizontalChannel = getHorizontalChannel(point1, 0, widthMax, pieceWidth);
List<Point> p1VerticalChannel = getVerticalChannel(point1, 0, heightMax, pieceHeight);
List<Point> p2HorizontalChannel = getHorizontalChannel(point2, 0, widthMax, pieceWidth);
List<Point> p2VerticalChannel = getVerticalChannel(point2, 0, heightMax, pieceHeight);
Point linkPoint1 = getWrapPoint(p1HorizontalChannel, p2VerticalChannel);
Point linkPoint2 = getWrapPoint(p2HorizontalChannel, p1VerticalChannel);
return (linkPoint1 == null) ? linkPoint2 : linkPoint1;
}
/**
* 获取两个转折点的情况
*
* @param point1
* @param point2
* @return Map对象的每个key-value对代表一种连接方式,
* 其中key、value分别代表第1个、第2个连接点
*/
private Map<Point, Point> getLinkPoints(Point point1, Point point2,
int pieceWidth, int pieceHeight)
{
Map<Point, Point> result = new HashMap<Point, Point>();
int heightMax = (gameConfig.getYSize() + 1) * pieceHeight + gameConfig.getBeginImageY();
int widthMax = (gameConfig.getXSize() + 1) * pieceWidth + gameConfig.getBeginImageX();
List<Point> p1HorizontalChannel = getHorizontalChannel(point1, 0, widthMax, pieceWidth);
List<Point> p1VerticalChannel = getVerticalChannel(point1, 0, heightMax, pieceHeight);
List<Point> p2HorizontalChannel = getHorizontalChannel(point2, 0, widthMax, pieceWidth);
List<Point> p2VerticalChannel = getVerticalChannel(point2, 0, heightMax, pieceHeight);
Map<Point, Point> vLinkPoints = getXLinkPoints(p1VerticalChannel, p2VerticalChannel, pieceHeight);
Map<Point, Point> hLinkPoints = getYLinkPoints(p1HorizontalChannel, p2HorizontalChannel, pieceWidth);
result.putAll(vLinkPoints);
result.putAll(hLinkPoints);
return result;
}
欢迎提出宝贵意见,共同学习提高。
尊重原创,欢迎转载,请注明出处。