View Javadoc
1   /**************************************************************************
2    Copyright 2005 Webstersmalley
3   
4    Licensed under the Apache License, Version 2.0 (the "License");
5    you may not use this file except in compliance with the License.
6    You may obtain a copy of the License at
7   
8    http://www.apache.org/licenses/LICENSE-2.0
9   
10   Unless required by applicable law or agreed to in writing, software
11   distributed under the License is distributed on an "AS IS" BASIS,
12   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   See the License for the specific language governing permissions and
14   limitations under the License.
15   *************************************************************************/
16  /*
17   * Created on 23-Aug-2005
18   */
19  package com.webstersmalley.chessweb.model;
20  
21  import java.text.SimpleDateFormat;
22  import java.util.Date;
23  
24  /***
25   * Encapsulates a move. Has a source and a destination and a bunch of
26   * convenience methods.
27   * 
28   * @author Matthew Smalley
29   */
30  public final class Move {
31  
32      /*** DateFormat for the move history. */
33      private static final SimpleDateFormat FORMAT 
34          = new SimpleDateFormat("HH:mm:ss");
35  
36      /*** Source position. */
37      private Position source;
38  
39      /*** Destination position. */
40      private Position destination;
41  
42      /*** When this move was created. */
43      private long created;
44  
45      /*** Whether this move is a castling. */
46      private boolean castling;
47      
48      /***
49       * Constructor. Source and destination are passed in.
50       * 
51       * @param source
52       *            the source
53       * @param destination
54       *            the destination
55       */
56      public Move(final Position source, final Position destination) {
57          this.source = source;
58          this.destination = destination;
59          created = System.currentTimeMillis();
60      }
61  
62      /***
63       * @return Returns the created.
64       */
65      public long getCreated() {
66          return created;
67      }
68  
69      /***
70       * Calculates whether the path is clear. This does <i>not</i> take into
71       * account pieces which can jump (Knights).
72       * 
73       * @param board
74       *            the current state
75       * @return whether the path is clear.
76       */
77      public boolean isPathClear(final Board board) {
78          int xStep = 0;
79          int yStep = 0;
80          if (isDiagonal()) {
81              // Step is 1,1 or -1,1 or 1,-1 or -1,-1
82              xStep = (getXDifference() / getXMagnitude());
83              yStep = (getYDifference() / getYMagnitude());
84          } else if (isStraight()) {
85              if (getXMagnitude() > 0) {
86                  xStep = (getXDifference() / getXMagnitude());
87                  yStep = 0;
88              } else if (getYMagnitude() > 0) {
89                  xStep = 0;
90                  yStep = (getYDifference() / getYMagnitude());
91              }
92          }
93          Position nextStep;
94          try {
95              nextStep = (Position) source.clone();
96          } catch (CloneNotSupportedException e) {
97              throw new RuntimeException(e);
98          }
99          while (!nextStep.equals(destination)) {
100             nextStep.add(xStep, yStep);
101             if (nextStep.equals(destination)) {
102                 return true;
103             }
104             if (board.getAt(nextStep) != null) {
105                 return false;
106             }
107         }
108         return true;
109     }
110 
111     /***
112      * Whether the move is a diagonal. This is calculated by comparing the
113      * magnitude along both axes. If they are the same then the move is a
114      * diagonal.
115      * 
116      * @return whether the move is a diagonal.
117      */
118     public boolean isDiagonal() {
119         return (getXMagnitude() == getYMagnitude());
120     }
121 
122     /***
123      * Whether the move is straight. This is calculated by checking that one of
124      * the x-axis or y-axis magnitudes are 0.
125      * 
126      * @return whether the move is a straight line.
127      */
128     public boolean isStraight() {
129         return (getXMagnitude() == 0 || getYMagnitude() == 0);
130     }
131 
132     /***
133      * Return the xDifference. This is destination.getX() - source.getX();
134      * 
135      * @return the xDifference
136      */
137     public int getXDifference() {
138         return destination.getFileNumber() - source.getFileNumber();
139     }
140 
141     /***
142      * Return the yDifference. This is destination.getY() - source.getY();
143      * 
144      * @return the yDifference
145      */
146     public int getYDifference() {
147         return destination.getRank() - source.getRank();
148     }
149 
150     /***
151      * Return the xMagnitude. This is abs(destination.getX() - source.getX());
152      * 
153      * @return the xMagnitude
154      */
155     public int getXMagnitude() {
156         return Math.abs(getXDifference());
157     }
158 
159     /***
160      * Return the yMagnitude. This is abs(destination.getY() - source.getY());
161      * 
162      * @return the yMagnitude
163      */
164     public int getYMagnitude() {
165         return Math.abs(getYDifference());
166     }
167 
168     /***
169      * Returns the maximum magnitude. This is the maximum between getXMagnitude
170      * and getYMagnitude.
171      * 
172      * @return the maximum magnitude.
173      */
174     public int getMaximumMagnitude() {
175         return Math.max(getXMagnitude(), getYMagnitude());
176     }
177 
178     /***
179      * Returns the direction (magnitude 1) of the y direction.
180      * 
181      * @return the Y direction
182      */
183     public int getYDirection() {
184         if (getYDifference() == 0) {
185             throw new RuntimeException("Error - Y movement is 0. No direction");
186         }
187         return (getYDifference()) / Math.abs(getYDifference());
188     }
189 
190     /***
191      * @return Returns the destination.
192      */
193     public Position getDestination() {
194         return destination;
195     }
196 
197     /***
198      * @param destination
199      *            The destination to set.
200      */
201     public void setDestination(final Position destination) {
202         this.destination = destination;
203     }
204 
205     /***
206      * @return Returns the source.
207      */
208     public Position getSource() {
209         return source;
210     }
211 
212     /***
213      * @param source
214      *            The source to set.
215      */
216     public void setSource(final Position source) {
217         this.source = source;
218     }
219 
220     /***
221      * Returns a String representation of the move.
222      * 
223      * @return the representation.
224      */
225     public String toString() {
226         String date = FORMAT.format(new Date(created));
227         return "[" + date + "] " + source + " --> " + destination;
228     }
229 
230     /***
231      * @return Returns the castling.
232      */
233     public boolean isCastling() {
234         return castling;
235     }
236 
237     /***
238      * @param castling The castling to set.
239      */
240     public void setCastling(final boolean castling) {
241         this.castling = castling;
242     }
243 }