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