1 /** 2 * The chess framework library. 3 * More information is available at http://www.jinchess.com/. 4 * Copyright (C) 2002 Alexander Maryanovsky. 5 * All rights reserved. 6 * 7 * The chess framework library is free software; you can redistribute 8 * it and/or modify it under the terms of the GNU Lesser General Public License 9 * as published by the Free Software Foundation; either version 2 of the 10 * License, or (at your option) any later version. 11 * 12 * The chess framework library is distributed in the hope that it will 13 * be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 15 * General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public License 18 * along with the chess framework library; if not, write to the Free Software 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 */ 21 22 package free.chess; 23 24 25 /** 26 * An extension of the Move class for variants which have rules similar to 27 * regular chess. Mainly, it just defines the existance of concepts such as 28 * en-passant, short and long castling, captures and promotion. It provides two 29 * constructors, one which lets the caller to specify all the properties and 30 * another one which determines these properties by using the stardard chess 31 * rules. 32 */ 33 34 public class ChessMove extends Move{ 35 36 37 38 /** 39 * True if this move is an en-passant, false otherwise. 40 */ 41 42 private final boolean isEnPassant; 43 44 45 46 47 /** 48 * True if this move is a short castling move, false otherwise. 49 */ 50 51 private final boolean isShortCastling; 52 53 54 55 56 /** 57 * True if this move is a long castling move, false otherwise. 58 */ 59 60 private final boolean isLongCastling; 61 62 63 64 /** 65 * The captured piece, null if this move is not a capture. 66 */ 67 68 private final ChessPiece capturedPiece; 69 70 71 72 73 /** 74 * The piece to which the moving pawn was promoted. 75 */ 76 77 private final ChessPiece promotionTarget; 78 79 80 81 /** 82 * The file of the double pawn push, or -1 if the move isn't a double pawn 83 * push. 84 */ 85 86 private final int doublePawnPushFile; 87 88 89 90 91 /** 92 * Creates a new ChessMove with the given properties. If the move is not a 93 * promotion, the promotion target should be <code>null</code>. The 94 * <code>moveSAN</code> (the move in SAN format) argument may be 95 * <code>null</code>. <code>doublePawnPushFile</code> should be -1 if the move 96 * isn't a double pawn push. 97 */ 98 ChessMove(Square startingSquare, Square endingSquare, Player movingPlayer, boolean isEnPassant, boolean isShortCastling, boolean isLongCastling, ChessPiece capturedPiece, int doublePawnPushFile, ChessPiece promotionTarget, String moveSAN)99 public ChessMove(Square startingSquare, Square endingSquare, Player movingPlayer, 100 boolean isEnPassant, boolean isShortCastling, boolean isLongCastling, 101 ChessPiece capturedPiece, int doublePawnPushFile, ChessPiece promotionTarget, String moveSAN){ 102 103 super(startingSquare, endingSquare, movingPlayer, moveSAN); 104 105 if (startingSquare == null) 106 throw new IllegalArgumentException("Starting square may not be null"); 107 if (endingSquare == null) 108 throw new IllegalArgumentException("Ending square may not be null"); 109 110 this.promotionTarget = promotionTarget; 111 this.isEnPassant = isEnPassant; 112 this.isShortCastling = isShortCastling; 113 this.isLongCastling = isLongCastling; 114 this.capturedPiece = capturedPiece; 115 this.doublePawnPushFile = doublePawnPushFile; 116 } 117 118 119 120 121 122 /** 123 * Creates a new ChessMove from the given properties. The missing information 124 * (en-passant, castling and other information provided by the more complete 125 * constructor) is determined according to the rules of standard chess. 126 * The <code>moveSAN</code> (the move in SAN format) argument may be 127 * <code>null</code>. 128 * 129 * @throws IllegalArgumentException If the there is no piece at the starting 130 * square. 131 */ 132 ChessMove(Position pos, Square startingSquare, Square endingSquare, ChessPiece promotionTarget, String moveSAN)133 public ChessMove(Position pos, Square startingSquare, Square endingSquare, 134 ChessPiece promotionTarget, String moveSAN){ 135 136 super(startingSquare, endingSquare, pos.getCurrentPlayer(), moveSAN); 137 138 if (startingSquare == null) 139 throw new IllegalArgumentException("The starting square may not be null"); 140 141 if (endingSquare == null) 142 throw new IllegalArgumentException("The ending square may not be null"); 143 144 if (pos.getPieceAt(startingSquare) == null) 145 throw new IllegalArgumentException("The moving piece may not be null"); 146 147 Chess chess = Chess.getInstance(); 148 149 this.promotionTarget = promotionTarget; 150 this.isEnPassant = chess.isEnPassant(pos, startingSquare, endingSquare, promotionTarget); 151 this.isShortCastling = chess.isShortCastling(pos, startingSquare, endingSquare, promotionTarget); 152 this.isLongCastling = chess.isLongCastling(pos, startingSquare, endingSquare, promotionTarget); 153 this.capturedPiece = chess.getCapturedPiece(pos, startingSquare, endingSquare, promotionTarget, isEnPassant); 154 this.doublePawnPushFile = chess.getDoublePawnPushFile(pos, startingSquare, endingSquare); 155 } 156 157 158 159 160 161 /** 162 * Returns a string representing this move in the notation invented by 163 * Warren Smith. Refer to <A HREF="http://www.chessclub.com/chessviewer/smith.html">http://www.chessclub.com/chessviewer/smith.html</A> 164 * for a description of the notation. 165 * 166 * @return a string representing this move in the Warren Smith notation. 167 */ 168 getWarrenSmithString()169 public String getWarrenSmithString(){ 170 StringBuffer buf = new StringBuffer(); 171 buf.append(startingSquare.toString()); 172 buf.append(endingSquare.toString()); 173 174 if (isEnPassant()) 175 buf.append('E'); 176 else if (isShortCastling()) 177 buf.append('c'); 178 else if (isLongCastling()) 179 buf.append('C'); 180 else if (isCapture()){ 181 ChessPiece capturedPiece = getCapturedPiece(); 182 if (capturedPiece.isPawn()) 183 buf.append('p'); 184 else if (capturedPiece.isKnight()) 185 buf.append('n'); 186 else if (capturedPiece.isBishop()) 187 buf.append('b'); 188 else if (capturedPiece.isRook()) 189 buf.append('r'); 190 else if (capturedPiece.isQueen()) 191 buf.append('q'); 192 else if (capturedPiece.isKing()) 193 buf.append('k'); 194 } 195 196 if (isPromotion()){ 197 ChessPiece promotionTarget = getPromotionTarget(); 198 if (promotionTarget.isKnight()) 199 buf.append('N'); 200 else if (promotionTarget.isBishop()) 201 buf.append('B'); 202 else if (promotionTarget.isRook()) 203 buf.append('R'); 204 else if (promotionTarget.isQueen()) 205 buf.append('Q'); 206 } 207 208 return buf.toString(); 209 } 210 211 212 213 214 /** 215 * Returns the SAN representation of the move, or <code>null</code> if none 216 * was specified in the constructor. 217 */ 218 getSAN()219 public String getSAN(){ 220 return getStringRepresentation(); 221 } 222 223 224 225 226 227 /** 228 * Returns true if this move is a capture. 229 */ 230 isCapture()231 public boolean isCapture(){ 232 return (capturedPiece!=null); 233 } 234 235 236 237 238 /** 239 * Returns the piece captured by this move, or null if this move 240 * is not a capture. 241 */ 242 getCapturedPiece()243 public ChessPiece getCapturedPiece(){ 244 return capturedPiece; 245 } 246 247 248 249 250 /** 251 * Returns true if this move is a castling move, false otherwise. 252 */ 253 isCastling()254 public boolean isCastling(){ 255 return (isShortCastling||isLongCastling); 256 } 257 258 259 260 261 /** 262 * Returns true if this move is short castling move, false otherwise. 263 */ 264 isShortCastling()265 public boolean isShortCastling(){ 266 return isShortCastling; 267 } 268 269 270 271 /** 272 * Returns true if this move if a long castling move, false otherwise. 273 */ 274 isLongCastling()275 public boolean isLongCastling(){ 276 return isLongCastling; 277 } 278 279 280 281 /** 282 * Returns true if this move is an en-passant move, false otherwise. 283 */ 284 isEnPassant()285 public boolean isEnPassant(){ 286 return isEnPassant; 287 } 288 289 290 291 292 293 /** 294 * Returns true if this move is a promotion. 295 */ 296 isPromotion()297 public boolean isPromotion(){ 298 return promotionTarget != null; 299 } 300 301 302 303 304 /** 305 * Returns the piece to which the moving pawn was promoted, or null if this 306 * move is not a promotion. 307 */ 308 getPromotionTarget()309 public ChessPiece getPromotionTarget(){ 310 return promotionTarget; 311 } 312 313 314 315 /** 316 * Returns the double pawn push file of this move, or -1 if this move isn't 317 * a double pawn push. 318 */ 319 getDoublePawnPushFile()320 public int getDoublePawnPushFile(){ 321 return doublePawnPushFile; 322 } 323 324 325 326 327 /** 328 * Returns a textual representation of this ChessMove based on the move data. 329 */ 330 getMoveString()331 public String getMoveString(){ 332 if (isShortCastling()) 333 return "O-O"; 334 else if (isLongCastling()) 335 return "O-O-O"; 336 else{ 337 String moveString = getStartingSquare().toString() + getEndingSquare().toString(); 338 if (isPromotion()) 339 return moveString+"="+getPromotionTarget().toShortString(); 340 else 341 return moveString; 342 } 343 } 344 345 346 } 347