一.Piece类
Piece代表棋子类,每一枚棋子都有对应的位置坐标和对应的阵营(Alliance)(黑子或者白子)。
我们需要限制棋子的移动位置,限制因素有很多,比如它所属阵营,它的本身属性,移动的位置处是否有其他子占用等等。所以我们需要定义棋子的合法移动抽象方法(calculateLegalMoves)来计算合法移动。
public class abstract Piece{
protected final int piecePosition;
protected final Alliance pieceAlliance; //导入枚举类型Alliance
Piece(final int piecePosition, final ALLiance pieceAlliance) {
this.pieceAlliance = pieceAlliance;
this.piecePosition = piecePosition;
}
public Alliance getPieceAlliance(){
return this.pieceAlliance;
}
public abstract List<Move> calculateLegalMoves(final Board board);
}
public enum Alliance {
WHITE,
BLACK;
}
二.Knight类
Knight是骑士,即为棋子马🐎。它的走法规则如图所示:
例如这个棋盘,骑士的位置在棋盘的位置坐标是d4。它的合法位置分别是c6,e6,b5,f5,b3,c2,e2,f3,一共八个坐标。我们的算法是将棋盘映射到格子编号,第一行从左往右数分别是0,1,2,3,4,5,6,7,对应的骑士位置即为35,其中合法位置f5即为29。但是我们还需要考虑两种情况:第一种是合法位置被敌方占据从而变成不合法位置,第二种合法位置超出棋盘范围(例如骑士在b8,它的合法位置只有一个为d7。考虑到整个棋盘的对称性,我们把当前骑士的位置编号记为0,从右向左编号依次增大。所有的合法位置编号即为:-17,-15,-10,-6,6,10,15,17。
然后循环遍历所有偏移位置,候选目的地坐标等于当前位置加上偏移量。循环过程中需要加入判断,除去那些不在棋盘内的候选目的地坐标,还需判断候选目的地坐标受否被其他棋子占用。
最后我们需要考虑边缘情况,
public class Knight extends Piece {
private final static int[] CANDIDATE_MOVE_COORDINATES = {-17,-15,-10,-6,6,10,15,17}//候选的合法位置编号列表(编号为相对于当前位置的偏移量)
Knight(final int piecePosition, final Alliance pieceAlliance){
super(piecePosition,pieceAlliance);
}
@Override
public List<Move>calculateLegalMoves(Board board){
int candidateDestinationCoorainate; //候选目的地坐标
final List<Move> legalMoves = new ArratList<>();
for(final int currentCandidate : CANDIDATE_MOVE_COORDINATES) { //for循环依次筛选列表中的位置是否真正合法
candidateDestinationCoorainate = this.piecePosition + currentCandidate; //目标位置是当前位置加上偏移量
//如果是有效的位置
if(isValidTileCoordinate(candidateDestination)){
final Tile candidateDestinationTile = board.getTile(candidateDestinationCoordinate);//目标位置和所选的位置一致
if(!candidateDestinationTile.isTileOccupied()){//所选的位置没有被棋子占领
legalMoves.add(new Move());//Move类,后续会提到
}
//如果选中的位置被占领
else{
final Piece pieceAtDestination = candidateDestinationTile.getPiece();
final Alliance pieceAlliance = pieceAtDestination.getPieceAlliance();
if(this.pieceAlliance != pieceAlliance){//判断是否为敌方占领该位置
legalMoves.add(new Move());
}
}
}
}
return ImmutableList.copyOf(legalMoves);
}
将判断是否超出棋盘范围重构到BoardUtils类中:
public class BoardUtils{
public static final boolean[] FIRST_COLUMN = null;
//抛出运行时异常,防止被实例化
private BoardUtils(){
throw new
private boolean isValidTileCoordinate(int coordinate){ //是否超出棋盘
return coordinate >=0 && coordinate < 64;
}
}
判断骑士的合法位置这种算法其实可以用到所有棋子上,只需要按照游戏的规则将不同编号的格子放到列表中。需要充分考虑边界合法问题以及是否被其他棋子占领,若敌方棋子占领需要考虑是否进行攻击吃掉对方棋子自己独自占领目标位置。
由于代码量比较多,只是放了部分关键代码,后期还会不断完善修正。