人机对弈之前,计算机首先需要具备能够判断双方所走的步骤是否合法的功能,这里使用棋盘类GameBoard来实现相关的功能。
首先将对弈的棋盘看成是一个8*8的二维数组,每一个单元格对应一个数组下标,并且单元格中存储该单元格中棋子的颜色。棋盘模型如图所示:
棋盘类的总体代码:
package gameboard;
public class GameBoard {
public final static int BLACK = -1;
public final static int WHITE = 1;
public final static int EMPTY = 0;
private int[][] gameBoard = new int[8][8];
private int blackNum,whiteNum;
public GameBoard(){
blackNum = 0;
whiteNum = 0;
for(int i = 0; i < gameBoard.length; i++){
for(int j = 0; j < gameBoard[0].length; j++){
gameBoard[i][j] = EMPTY;
}
}
}
//将棋盘指定格子设置成指定颜色
public void setBoard(int x, int y, int color){
gameBoard[x][y] = color;
if(color == BLACK && blackNum < 10){
blackNum++;
}else if(color == WHITE && whiteNum < 10){
whiteNum++;
}
}
public int getGameBoard(int hIndex, int vIndex){
return gameBoard[hIndex][vIndex];
}
//判断步骤是否合法
public boolean isLeagleMove(int hIndex, int vIndex, int color){
boolean isLeagle = true;
//与该棋子(x,y)相邻棋子的个数
int adjacentNumber = 0;
int adjacentHIndex = -1;
int adjacentVIndex = -1;
//查看位置是否被占用以及黑白的goal area
if(gameBoard[hIndex][vIndex] != 0 ||
(color == WHITE && (vIndex == 0 || vIndex == 7)) ||
(color == BLACK && (hIndex == 0 || hIndex ==7)) ||
(hIndex == 0 && vIndex == 0) ||
(hIndex == 7 && vIndex == 0) ||
(hIndex == 0 && vIndex == 7) ||
(hIndex == 7 && vIndex == 7)){
isLeagle = false;
//判断将要放的位置是否有相邻的棋子,如果有相邻两个以上的棋子则位置不合法,若只有一个相邻的棋子,则继续判断,若没有相邻棋子,则位置合法
}else{
gameBoard[hIndex][vIndex] = color;
//internal area
if(hIndex != 0 && vIndex != 0 && hIndex != 7 && vIndex != 7){
for(int x = hIndex - 1; x <= hIndex + 1; x++){
if(gameBoard[x][vIndex - 1] == gameBoard[hIndex][vIndex]){
adjacentNumber++;
if(adjacentNumber >= 2){
//在返回前 ,将棋盘还原
gameBoard[hIndex][vIndex] = EMPTY;
return false;
}
adjacentHIndex = x;
adjacentVIndex = vIndex - 1;
}
if(gameBoard[x][vIndex + 1] == gameBoard[hIndex][vIndex]){
adjacentNumber++;
if(adjacentNumber >= 2){
gameBoard[hIndex][vIndex] = EMPTY;
return false;
}
adjacentHIndex = x;
adjacentVIndex = vIndex + 1;
}
}
if(gameBoard[hIndex - 1][vIndex] == gameBoard[hIndex][vIndex]){
adjacentNumber++;
if(adjacentNumber >= 2){
gameBoard[hIndex][vIndex] = EMPTY;
return false;
}
adjacentHIndex = hIndex - 1;
adjacentVIndex = vIndex;
}
if(gameBoard[hIndex + 1][vIndex] == gameBoard[hIndex][vIndex]){
adjacentNumber++;
if(adjacentNumber >= 2){
gameBoard[hIndex][vIndex] = EMPTY;
return false;
}
adjacentHIndex = hIndex + 1;
adjacentVIndex = vIndex;
}
//white left goal area
}else if(hIndex == 0){
for(int y = vIndex - 1; y <= vIndex + 1; y++){
if(gameBoard[1][y] == gameBoard[hIndex][vIndex]){
adjacentNumber++;
if(adjacentNumber >= 2){
gameBoard[hIndex][vIndex] = EMPTY;
return false;
}
adjacentHIndex = 1;
adjacentVIndex = y;
}
}
if(gameBoard[0][vIndex - 1] == gameBoard[hIndex][vIndex]){
adjacentNumber++;
if(adjacentNumber >= 2){
gameBoard[hIndex][vIndex] = EMPTY;
return false;
}
adjacentHIndex = 0;
adjacentVIndex = vIndex - 1;
}
if(gameBoard[0][vIndex + 1] == gameBoard[hIndex][vIndex]){
adjacentNumber++;
if(adjacentNumber >= 2){
gameBoard[hIndex][vIndex] = EMPTY;
return false;
}
adjacentHIndex = 0;
adjacentVIndex = vIndex + 1;
}
//white right goal area
}else if(hIndex == 7){
for(int y = vIndex - 1; y <= vIndex + 1; y++){
if(gameBoard[6][y] == gameBoard[hIndex][vIndex]){
adjacentNumber++;
if(adjacentNumber >= 2){
gameBoard[hIndex][vIndex] = EMPTY;
return false;
}
adjacentHIndex = 6;
adjacentVIndex = y;
}
}
if(gameBoard[7][vIndex - 1] == gameBoard[hIndex][vIndex]){
adjacentNumber++;
if(adjacentNumber >= 2){
gameBoard[hIndex][vIndex] = EMPTY;
return false;
}
adjacentHIndex = 7;
adjacentVIndex = vIndex - 1;
}
if(gameBoard[7][vIndex + 1] == gameBoard[hIndex][vIndex]){
adjacentNumber++;
if(adjacentNumber >= 2){
gameBoard[hIndex][vIndex] = EMPTY;
return false;
}
adjacentHIndex = 7;
adjacentVIndex = vIndex + 1;
}
//black top goal area
}else if(vIndex == 0){
for(int x = hIndex - 1; x <= hIndex + 1; x++){
if(gameBoard[x][1] == gameBoard[hIndex][vIndex]){
adjacentNumber++;
if(adjacentNumber >= 2){
gameBoard[hIndex][vIndex] = EMPTY;
return false;
}
adjacentHIndex = x;
adjacentVIndex = 1;
}
}
if(gameBoard[hIndex - 1][0] == gameBoard[hIndex][vIndex]){
adjacentNumber++;
if(adjacentNumber >= 2){
gameBoard[hIndex][vIndex] = EMPTY;
return false;
}
adjacentHIndex = hIndex - 1;
adjacentVIndex = 0;
}
if(gameBoard[hIndex + 1][0] == gameBoard[hIndex][vIndex]){
adjacentNumber++;
if(adjacentNumber >= 2){
gameBoard[hIndex][vIndex] = EMPTY;
return false;
}
adjacentHIndex = hIndex + 1;
adjacentVIndex = 0;
}
//black bottom goal area
}else if(vIndex == 7){
for(int x = hIndex - 1; x <= hIndex + 1; x++){
if(gameBoard[x][6] == gameBoard[hIndex][vIndex]){
adjacentNumber++;
if(adjacentNumber >= 2){
gameBoard[hIndex][vIndex] = EMPTY;
return false;
}
adjacentHIndex = x;
adjacentVIndex = 6;
}
}
if(gameBoard[hIndex - 1][7] == gameBoard[hIndex][vIndex]){
adjacentNumber++;
if(adjacentNumber >= 2){
gameBoard[hIndex][vIndex] = EMPTY;
return false;
}
adjacentHIndex = hIndex - 1;
adjacentVIndex = 7;
}
if(gameBoard[hIndex + 1][7] == gameBoard[hIndex][vIndex]){
adjacentNumber++;
if(adjacentNumber >= 2){
gameBoard[hIndex][vIndex] = EMPTY;
return false;
}
adjacentHIndex = hIndex + 1;
adjacentVIndex = 7;
}
}
}
//check the adjacent node to see whether it has two adjacent node
if(adjacentHIndex != -1){
adjacentNumber = 0;
if(adjacentHIndex != 0 && adjacentVIndex != 0 && adjacentHIndex != 7 && adjacentVIndex != 7){
for(int x = adjacentHIndex - 1; x <= adjacentHIndex + 1; x++){
if(gameBoard[x][adjacentVIndex - 1] == gameBoard[adjacentHIndex][adjacentVIndex]){
adjacentNumber++;
if(adjacentNumber >= 2){
gameBoard[hIndex][vIndex] = EMPTY;
return false;
}
}
if(gameBoard[x][adjacentVIndex + 1] == gameBoard[adjacentHIndex][adjacentVIndex]){
adjacentNumber++;
if(adjacentNumber >= 2){
gameBoard[hIndex][vIndex] = EMPTY;
return false;
}
}
}
if(gameBoard[adjacentHIndex - 1][adjacentVIndex] == gameBoard[adjacentHIndex][adjacentVIndex]){
adjacentNumber++;
if(adjacentNumber >= 2){
gameBoard[hIndex][vIndex] = EMPTY;
return false;
}
}
if(gameBoard[adjacentHIndex + 1][adjacentVIndex] == gameBoard[adjacentHIndex][adjacentVIndex]){
adjacentNumber++;
if(adjacentNumber >= 2){
gameBoard[hIndex][vIndex] = EMPTY;
return false;
}
}
//white left goal area
}else if(adjacentHIndex == 0){
for(int y = adjacentVIndex - 1; y <= adjacentVIndex + 1; y++){
if(gameBoard[1][y] == gameBoard[adjacentHIndex][adjacentVIndex]){
adjacentNumber++;
if(adjacentNumber >= 2){
gameBoard[hIndex][vIndex] = EMPTY;
return false;
}
}
}
if(gameBoard[0][adjacentVIndex - 1] == gameBoard[adjacentHIndex][adjacentVIndex]){
adjacentNumber++;
if(adjacentNumber >= 2){
gameBoard[hIndex][vIndex] = EMPTY;
return false;
}
}
if(gameBoard[0][adjacentVIndex + 1] == gameBoard[adjacentHIndex][adjacentVIndex]){
adjacentNumber++;
if(adjacentNumber >= 2){
gameBoard[hIndex][vIndex] = EMPTY;
return false;
}
}
//white right goal area
}else if(adjacentHIndex == 7){
for(int y = adjacentVIndex - 1; y <= adjacentVIndex + 1; y++){
if(gameBoard[6][y] == gameBoard[adjacentHIndex][adjacentVIndex]){
adjacentNumber++;
if(adjacentNumber >= 2){
gameBoard[hIndex][vIndex] = EMPTY;
return false;
}
}
}
if(gameBoard[7][adjacentVIndex - 1] == gameBoard[adjacentHIndex][adjacentVIndex]){
adjacentNumber++;
if(adjacentNumber >= 2){
gameBoard[hIndex][vIndex] = EMPTY;
return false;
}
}
if(gameBoard[7][adjacentVIndex + 1] == gameBoard[adjacentHIndex][adjacentVIndex]){
adjacentNumber++;
if(adjacentNumber >= 2){
gameBoard[hIndex][vIndex] = EMPTY;
return false;
}
}
//black top goal area
}else if(adjacentVIndex == 0){
for(int x = adjacentHIndex - 1; x <= adjacentHIndex + 1; x++){
if(gameBoard[x][1] == gameBoard[adjacentHIndex][adjacentVIndex]){
adjacentNumber++;
if(adjacentNumber >= 2){
gameBoard[hIndex][vIndex] = EMPTY;
return false;
}
}
}
if(gameBoard[adjacentHIndex - 1][0] == gameBoard[adjacentHIndex][adjacentVIndex]){
adjacentNumber++;
if(adjacentNumber >= 2){
gameBoard[hIndex][vIndex] = EMPTY;
return false;
}
}
if(gameBoard[adjacentHIndex + 1][0] == gameBoard[adjacentHIndex][adjacentVIndex]){
adjacentNumber++;
if(adjacentNumber >= 2){
gameBoard[hIndex][vIndex] = EMPTY;
return false;
}
}
//black bottom goal area
}else if(adjacentVIndex == 7){
for(int x = adjacentHIndex - 1; x <= adjacentHIndex + 1; x++){
if(gameBoard[x][6] == gameBoard[adjacentHIndex][adjacentVIndex]){
adjacentNumber++;
if(adjacentNumber >= 2){
gameBoard[hIndex][vIndex] = EMPTY;
return false;
}
}
}
if(gameBoard[adjacentHIndex - 1][7] == gameBoard[adjacentHIndex][adjacentVIndex]){
adjacentNumber++;
if(adjacentNumber >= 2){
gameBoard[hIndex][vIndex] = EMPTY;
return false;
}
}
if(gameBoard[adjacentHIndex + 1][7] == gameBoard[adjacentHIndex][adjacentVIndex]){
adjacentNumber++;
if(adjacentNumber >= 2){
gameBoard[hIndex][vIndex] = EMPTY;
return false;
}
}
}
}
// gameBoard[hIndex][vIndex] = EMPTY;
return isLeagle;
}
public int getBlackNum(){
return blackNum;
}
public int getWhiteNum(){
return whiteNum;
}
public void addWhiteNum(){
whiteNum++;
}
public void addBlackNum(){
blackNum++;
}
//将指定坐标点还原
public void undo(int hIndex, int vIndex) {
this.setBoard(hIndex, vIndex, EMPTY);
}
}
这其中的核心方法是isLeagleMove(int hIndex,int vIndex, int color);其中hIndex与vIndex分别是将要放置的棋子位置的横纵坐标,color为棋子颜色。本人采用的策略是首先判断(hIndex,vIndex)处是否有其他棋子,以及(hIndex,vIndex)是否属于其中一方的老家,如是,则另一方不可以将棋子放在这里。最后还需要判断(hIndex,vIndex)是否是四个顶点,如果是四个顶点,不是合法步骤。这些都是在方法的第一个if语句中实现的。
这个方法的难点是判断将(hIndex,vIndex)放入color颜色棋子后会不会与棋盘上的其他棋子构成cluster(也就是(一)中的(6)规则)。这里分两种情况考虑,即(hIndex,vIndex)是边界点与非边界点两种情况。两种情况下遍历周围棋子的坐标不同,边界点情况下相邻单元格有5个,非边界点情况下相邻单元格有8个。采用adjacentNumber来记录相邻的棋子数,如果在遍历过程中发现adjacentNumber已经大于2,则此时已经构成了cluster,该步骤不合法。若遍历结束后发现adjacentNumber等于1,这说明有一个相邻节点,但此时不能确定是否构成了cluster,因为与(hIndex,vIndex)相邻的那个节点也有可能与其他节点构成cluster,这种情况如图红框所示,因此还需要继续判断与(hIndex,vIndex)相邻的那个单元格的adjacentNumber,如果它的adjacentNumber=2,则该步骤也不合法,若adjacentNumber=1,则合法。具体见代码实现。最后需要注意的是判断完成后需要把单元格还原。因为这里只是判断,并没有真正落下棋子。