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
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
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 }