重构练习2:“疯狂连连看”程序中算法简化

来源:互联网 发布:ih5软件下载 编辑:程序博客网 时间:2024/04/28 14:49

“疯狂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;}

欢迎提出宝贵意见,共同学习提高。
尊重原创,欢迎转载,请注明出处。


0 0