讲讲消灭星星的算法实现思路吧
这个游戏的关键算法是选取同色区域。
我的方法是每个方块是一个对象,包含几项属性:自身所在的行,自身所在的列,自身的颜色。
还加了一个id作备用,暂时没用到。
基本思路是递归,显而易见。
首先准备两个列表。
一个用来装被检查过了的方块,因为左边方块的右边就等于右边方块的左边,如果不检查的话就无限递归到溢出了。
另一个用来装与传入方块颜色相同的方块,留待递归完成后作为返回值。
然后传入第一个方块,分别检查它四个方向上的方块,如果颜色和它相同的话就用对应方向上的方块来进行下一次递归。
上方检测举例,其他方向同理:
private static void checkUp(Block block) { // 越界(上方不存在方块)则跳出。 if ((block.getRow()-1) < 0) { return; } // 获取上方方块。 Block blockUpside = GameSurfaceView.blockList[block.getRow()-1][block.getColumn()]; // 如果方块不存在或者颜色不同就跳出。 if (blockUpside == null || blockUpside.getColor() != block.getColor()) { return; } // 下一次递归。 checkFourSides(blockUpside); }
跳出递归的唯一条件是当前方块有没有被检查过,因为考虑到单一职责原则,我把方块对比的代码都放到了单个方向检测的方法里了,包括是否越界和颜色是否相同还有对应方向上的方块存不存在。
这些是找到了对应方向上的方块才有讨论的必要的。
比如我看到的那个C++的条件判断是这样的……
//递归求解 void MyRecursion(LinkList _head1, LinkList _head2, int _x, int _y, int number) { if ((_x >= 10) || (_x < 0) || (_y >= 10) || (_y < 0) || (MyTraverseLinkList(_head2, _x, _y)) || (0 == MyArray[_x][_y])) { return; } else { MyInsertLinkList(_head2, _x, _y); if ((MyArray[_x][_y] == number)) { MyInsertLinkList(_head1, _x, _y); if ((_x - 1) >= 0) //递归 - 上 { MyRecursion(_head1, _head2, _x - 1, _y, number); } if ((_y - 1) >= 0) //递归 - 左 { MyRecursion(_head1, _head2, _x, _y - 1, number); } if ((_x + 1) < 10) //递归 - 下 { MyRecursion(_head1, _head2, _x + 1, _y, number); } if ((_y + 1) < 10) //递归 - 右 { MyRecursion(_head1, _head2, _x, _y + 1, number); } } } }
里面还有重复的边界判断。
而且这哥们的起名姿势很有特点。
如果一个方法只做一件事的话,思路就清晰多了,像这样。
/** 递归,不停检查四面。*/ private void checkFourSides(Block block) { // 如果当前方块已被检查过,则跳出当前递归。 if (isChecked(block)) { return; } // 标记当前方块为已被检查过。 checkedBlocks.add(block); // 将当前方块加入同色列表。 blocksInSameColor.add(block); // 检查上下左右的方块。 checkUp(block); checkDown(block); checkLeft(block); checkRight(block); }
于是像这样,当检查方法碰到边界,或者碰到了不存在的方块,或者周围已经没有颜色相同的方块了的时候,递归停止。
最后同色列表里保存的就是首尾相连的一片同色方块了。
然后把整个算法封装起来,再对外暴露一个接口就搞定了。
/** 获取存有与当前方块颜色相同首尾相连的一片方块的列表。*/ public static ArrayList<Block> getBlocksInSameColor(Block selectedBlock) { // 初始化两个缓存列表。 checkedBlocks = new ArrayList<Block>(); blocksInSameColor = new ArrayList<Block>(); // 执行递归。 checkFourSides(selectedBlock); return blocksInSameColor; }