chessai

college code for ai playing chess in java

git clone https://9o.is/git/chessai.git

ChessRules.java

(11611B)


      1 package chess;
      2 
      3 import chess.utils.ChessColor;
      4 import chess.utils.ChessDirection;
      5 import chess.utils.ChessType;
      6 
      7 import java.util.Arrays;
      8 
      9 /**
     10  * Check
     11  */
     12 public enum ChessRules {
     13 
     14     INSTANCE;
     15 
     16     private ChessState state;
     17     private ChessCoordinate src;
     18     private ChessCoordinate dest;
     19 
     20     private ChessPiece srcPiece;
     21     private ChessPiece destPiece;
     22     private ChessType srcType;
     23 
     24     private boolean evaluating = false;
     25     private boolean bPawnCanDoubleMove = true;
     26     private boolean wPawnCanDoubleMove = true;
     27 
     28     private boolean log = true;
     29 
     30     public void setState(ChessState state) {
     31         this.state = state;
     32     }
     33 
     34     public void setSrc(ChessCoordinate src) {
     35         this.src = src;
     36         this.srcPiece = !src.invalid() ?
     37                 ChessPiece.find(state.get(src)) : null;
     38         this.srcType = srcPiece != null ? srcPiece.getType() : null;
     39     }
     40 
     41     public void setDest(ChessCoordinate dest) {
     42         this.dest = dest;
     43         this.destPiece = !dest.invalid() ?
     44                 ChessPiece.find(state.get(dest)) : null;
     45     }
     46 
     47     public void setLog(boolean log) {
     48         this.log = log;
     49     }
     50 
     51     public void setEvaluating(boolean evaluating) {
     52         this.evaluating = evaluating;
     53     }
     54 
     55     public void setbPawnCanDoubleMove(boolean bPawnCanDoubleMove) {
     56         if(!evaluating)
     57             this.bPawnCanDoubleMove = bPawnCanDoubleMove;
     58     }
     59 
     60     public void setwPawnCanDoubleMove(boolean wPawnCanDoubleMove) {
     61         if(!evaluating)
     62             this.wPawnCanDoubleMove = wPawnCanDoubleMove;
     63     }
     64 
     65     // CHECK
     66     public void applyCaptureRule() {
     67         // are the source and destination pieces different colors?
     68         if(srcPiece.getColor() != destPiece.getColor() &&
     69                 srcPiece != ChessPiece.NA &&
     70                 destPiece != ChessPiece.NA) {
     71 
     72             // CAPTURE!
     73             // TODO handle player points here
     74 
     75             System.out.println(ChessRules.class + ": CAPTURED -> " +
     76                     srcPiece + src + destPiece + dest);
     77         }
     78     }
     79 
     80     // CHECK
     81     public boolean validMove() {
     82         return pieceMoves() &&
     83                 srcHasPiece() &&
     84                 insideBoard() &&
     85                 unoccupiedSpace() &&
     86                 legalSkip() &&
     87                 validRookMove() &&
     88                 validKnightMove() &&
     89                 validBishopMove() &&
     90                 validQueenMove() &&
     91                 validKingMove() &&
     92                 validPawnMove();
     93     }
     94 
     95     /*
     96     * Checks if the piece moved. It cannot stay in same spot.
     97     */
     98     private boolean pieceMoves() {
     99         if(src.equals(dest)) {
    100             logFailure("pieceMoves");
    101             return false;
    102         }
    103         return true;
    104     }
    105 
    106     /*
    107     * Checks if source coordinate has a chess piece.
    108     */
    109     private boolean srcHasPiece() {
    110         if(srcPiece == ChessPiece.NA) {
    111             logFailure("srcHasPiece");
    112             return false;
    113         }
    114         return true;
    115     }
    116 
    117     /*
    118     * Checks if the destination coordinate is inside the chess
    119     * board.
    120     */
    121     private boolean insideBoard() {
    122         if(dest.invalid()) {
    123             logFailure("insideBoard");
    124             return false;
    125         }
    126         return true;
    127     }
    128 
    129     /*
    130     * Checks if player moved a chess piece onto one of his own pieces.
    131     */
    132     private boolean unoccupiedSpace() {
    133         // are the source and destination pieces same color?
    134         if(srcPiece.getColor() == destPiece.getColor()) {
    135             logFailure("unoccupiedSpace");
    136             return false;
    137         }
    138         return true;
    139     }
    140 
    141     /*
    142     * Checks if source piece skips over other pieces when moving.
    143     */
    144     private boolean legalSkip() {
    145         // Knight is an exception.
    146         if(srcType==ChessType.KNIGHT)
    147             return true;
    148 
    149         final int hor = dest.getFile() - src.getFile();
    150         final int ver = dest.getRank() - src.getRank();
    151 
    152         int rank = dest.getRank();
    153         int file = dest.getFile();
    154 
    155         if(hor != 0) {
    156             if(hor > 0) file--;
    157             else file++;
    158         }
    159         if(ver != 0) {
    160             if(ver > 0) rank--;
    161             else rank++;
    162         }
    163 
    164         while (src.getFile() != file || src.getRank() != rank) {
    165 
    166             final byte pieceValue =
    167                     state.get(new ChessCoordinate((char)file, rank));
    168             ChessPiece check = ChessPiece.find(pieceValue);
    169 
    170             if(check != ChessPiece.NA) {
    171                 logFailure("legalSkip");
    172                 return false;
    173             }
    174 
    175             if(hor != 0) {
    176                 if(hor > 0) file--;
    177                 else file++;
    178             }
    179             if(ver != 0) {
    180                 if(ver > 0) rank--;
    181                 else rank++;
    182             }
    183         }
    184         return true;
    185     }
    186 
    187     private boolean validRookMove(){
    188         //Rank must be the same exclusive or file must be the
    189         // same for a rook to move
    190         if(srcType==ChessType.ROOK){
    191             if(rookMove())
    192                 return true;
    193 
    194             logFailure("validRookMove");
    195             return false;
    196         }
    197         return true;
    198     }
    199 
    200     private boolean validKnightMove(){
    201         if(srcType==ChessType.KNIGHT){
    202             final int rankDiff = Math.abs(src.getRank()-dest.getRank());
    203             final int fileDiff = Math.abs(src.getFile()-dest.getFile());
    204 
    205             if((rankDiff == 2 && fileDiff == 1) ||
    206                     (rankDiff == 1 && fileDiff == 2)) {
    207                 return true;
    208             }
    209 
    210             logFailure("validKnightMove");
    211             return false;
    212         }
    213         return true;
    214     }
    215 
    216     /*
    217      * Pawns can also move 2 spaces on first turn
    218      * Pawns can also capture en passant
    219      * Still functional without these features though
    220      */
    221     private boolean validPawnMove(){
    222         if(srcType==ChessType.PAWN){
    223             //Pawn move up one
    224             if (srcPiece.getColor() == ChessColor.WHITE){
    225 
    226                 if(src.getRank()+2 == dest.getRank() &&
    227                         src.getFile() == dest.getFile() &&
    228                         wPawnCanDoubleMove &&
    229                         destPiece == ChessPiece.NA) {
    230                     return true;
    231                 }
    232 
    233                 if(src.getRank()+1 == dest.getRank() &&
    234                         src.getFile() == dest.getFile() &&
    235                         destPiece == ChessPiece.NA){
    236 
    237                     setwPawnCanDoubleMove(false);
    238                     return true;
    239                 }
    240 
    241                 //Pawn capture
    242                 if(src.getRank()+1 == dest.getRank() &&
    243                         Math.abs(src.getFile()-dest.getFile()) == 1 &&
    244                         srcPiece.getColor() != destPiece.getColor() &&
    245                         destPiece != ChessPiece.NA) {
    246 
    247                     setwPawnCanDoubleMove(false);
    248                     return true;
    249                 }
    250             } else {
    251 
    252                 if(src.getRank() == dest.getRank()+2 &&
    253                         src.getFile() == dest.getFile() &&
    254                         bPawnCanDoubleMove &&
    255                         destPiece == ChessPiece.NA) {
    256                     return true;
    257                 }
    258 
    259                 if(src.getRank() == dest.getRank()+1 &&
    260                         src.getFile() == dest.getFile()&&
    261                         destPiece == ChessPiece.NA) {
    262 
    263                     setbPawnCanDoubleMove(false);
    264                     return true;
    265                 }
    266 
    267                 //Pawn capture
    268                 if(src.getRank() == dest.getRank()+1 &&
    269                         Math.abs(src.getFile()-dest.getFile()) == 1 &&
    270                         srcPiece.getColor() != destPiece.getColor() &&
    271                         destPiece != ChessPiece.NA){
    272 
    273                     setbPawnCanDoubleMove(false);
    274                     return true;
    275                 }
    276             }
    277             logFailure("validPawnMove");
    278             return false;
    279         }
    280         return true;
    281     }
    282 
    283     private boolean validBishopMove(){
    284         if(srcType==ChessType.BISHOP){
    285             if(bishopMove())
    286                 return true;
    287 
    288             logFailure("validBishopMove");
    289             return false;
    290         }
    291         return true;
    292     }
    293 
    294     private boolean validKingMove(){
    295         if(srcType==ChessType.KING){
    296             if(src.getRank()-dest.getRank() < 2 &&
    297                     src.getFile()-dest.getFileNumber() < 2) {
    298                 return true;
    299             }
    300 
    301             logFailure("validKingMove");
    302             // TODO Moves that get the king captured are invalid
    303             return false;
    304         }
    305         return true;
    306     }
    307 
    308     private boolean validQueenMove() {
    309         if(srcType == ChessType.QUEEN){
    310             if(!(rookMove() ^ bishopMove())) {
    311                 logFailure("validQueenMove");
    312                 return false;
    313             }
    314         }
    315         return true;
    316     }
    317 
    318     public ChessDirection[] possibleDirections() {
    319         if(srcType==ChessType.PAWN)   return pawnDirections();
    320         if(srcType==ChessType.ROOK)   return rookDirections();
    321         if(srcType==ChessType.BISHOP) return bishopDirections();
    322         if(srcType==ChessType.KNIGHT) return knightDirections();
    323         if(srcType==ChessType.QUEEN)  return queenDirections();
    324         if(srcType==ChessType.KING)   return kingDirections();
    325         else
    326             return new ChessDirection[]{};
    327     }
    328 
    329     private ChessDirection[] pawnDirections() {
    330         return new ChessDirection[] {
    331                 ChessDirection.FORWARD,
    332                 ChessDirection.FORWARD_LEFT,
    333                 ChessDirection.FORWARD_RIGHT
    334         };
    335     }
    336 
    337     private ChessDirection[] rookDirections() {
    338         return new ChessDirection[] {
    339                 ChessDirection.FORWARD,
    340                 ChessDirection.BACK,
    341                 ChessDirection.LEFT,
    342                 ChessDirection.RIGHT
    343         };
    344     }
    345 
    346     private ChessDirection[] bishopDirections() {
    347         return new ChessDirection[] {
    348                 ChessDirection.FORWARD_LEFT,
    349                 ChessDirection.FORWARD_RIGHT,
    350                 ChessDirection.BACK_LEFT,
    351                 ChessDirection.BACK_RIGHT
    352         };
    353     }
    354 
    355     private ChessDirection[] knightDirections() {
    356         return new ChessDirection[] {
    357                 ChessDirection.KNIGHT_LEFT_FORWARD,
    358                 ChessDirection.KNIGHT_LEFT_BACK,
    359                 ChessDirection.KNIGHT_RIGHT_FORWARD,
    360                 ChessDirection.KNIGHT_RIGHT_BACK,
    361                 ChessDirection.KNIGHT_FORWARD_LEFT,
    362                 ChessDirection.KNIGHT_FORWARD_RIGHT,
    363                 ChessDirection.KNIGHT_BACK_LEFT,
    364                 ChessDirection.KNIGHT_BACK_RIGHT
    365         };
    366     }
    367 
    368     private ChessDirection[] queenDirections() {
    369         return concat(bishopDirections(), rookDirections());
    370     }
    371 
    372     private ChessDirection[] kingDirections() {
    373         return queenDirections();
    374     }
    375 
    376     private boolean rookMove() {
    377         return src.getRank() == dest.getRank() ^
    378                 src.getFile() == dest.getFile();
    379     }
    380 
    381     private boolean bishopMove() {
    382         final int rankDiff = Math.abs(src.getRank()-dest.getRank());
    383         final int fileDiff = Math.abs(src.getFile()-dest.getFile());
    384 
    385         return rankDiff == fileDiff;
    386     }
    387 
    388     private void logFailure(String method) {
    389         if(log)
    390             System.err.println(ChessRules.class + ": FAILURE -> "+
    391                     method+" test --- Move: "+
    392                     srcPiece+src+dest);
    393     }
    394 
    395     // TODO where should this be placed?
    396     private static <T> T[] concat(T[] first, T[] second) {
    397         T[] result = Arrays.copyOf(first, first.length + second.length);
    398         System.arraycopy(second, 0, result, first.length, second.length);
    399         return result;
    400     }
    401 }