前言:
自学Java也有一段时间了,然而并没有任何的实战开发经验,于是便自己琢磨着开发五子棋游戏,在开发过程中遇到的第一个问题就是输赢的判断。其实从某个意义上来说这并不能算是一个真正的问题,因为很容易想到的一个“暴力”算法“就是每次落子后遍历棋盘的所有方向直到找到一个五子相连的情况,此时判断输赢。然而,这样的输赢判断很显然会给系统造成不必要的开销,而且如果棋盘够大的话算法的时间复杂度并不能让人满意(你可能会觉得谁没事开发五子棋弄个很大的棋盘,话虽如此,但追求最优的解决办法不是更加体现了一个开发者身上精益求精的精神吗?)。
但是,我的方案也并非十全十美,相比”暴力“求解的方式至少我觉得还是有所改进,想以此抛砖引玉,如果各位大佬或者小伙伴有更好的建议欢迎留言交流。
思路:
其实思路还是很简单的,首先游戏输赢机制的触发由当前棋盘上的最后一颗棋子及其周围的棋子决定(好像是废话,但是为我们思考提供了帮助),因此我们只需要关心这最后一颗棋子然后遍历它周围的棋子加上这颗棋子本身是否能相连成五颗,记住,这里以这颗棋子为中心很重要,因为这样方便代码实现也方便往下叙述。总共八个方向,加上中心棋子本身每个方向最多遍历四次,因为最极端的情况就是从外往中心数中间棋子刚好是第五颗。把思路弄懂后,实现并不难。
实现
/**
* 五子棋输赢判断的实现类
* @author: L
* 代码说明:
* 1.参数:以byte类型的二维数组来存放一个棋盘的所有数据,
* 原因是以0代表空位,以1代表玩家,以2代表电脑,byte类型完全足够,节省空间。
* 其中board代表棋盘数组,row代表当前棋子的行,col代表当前棋子的列,
* 即(row,col)构成中心棋子的坐标
* 2.可读性:代码用了尽可能多的注释,而且只要原理明白了,其实很简单
* 该类实现Gobang, 主要用到了Gobang里的一个常数即棋盘的尺寸BOARD_SIZE
* 如果想直接复用代码的小伙伴可直接将BOARD_SIZE替换成你的棋盘尺寸即可
* 或者替换成board[0].length(此处假设你的棋盘也是正方形)
*
*/
public class WinOrLose implements Gobang {
/*
* 纵向查找的方法
* 分为上下两个部分
* 其他方向上同理
*/
private static boolean winCol(byte[][] board, final int row, final int col) {
int rowCount = 1;
/*
* 向上查找
* col - i >= 0 是为了防止越界的条件
* board[row][col - i] == board[row][col] 由中心向外判断棋子是否相连的条件
*/
for (int i = 1; i <= 4; i++) {
if (col - i >= 0 && board[row][col - i] == board[row][col]) {
rowCount++; //如果相连,该方向上的棋子数加一
} else {
break; //如果遇到第一个空位或非己方棋子退出循环
}
}
//向下查找
//col + i < BOARD_SIZE 同样为了防止越界
for (int i =