2 * Quoridor server and related libraries
3 * Copyright (C) 2009-2010 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. Look for COPYING file in the top folder.
16 * If not, see http://www.gnu.org/licenses/.
18 package cz.xelfi.quoridor;
20 import cz.xelfi.quoridor.Player.Direction;
21 import java.util.ArrayList;
22 import java.util.Arrays;
23 import java.util.List;
25 /** Encapsulates one possible move that can be applied to existing {@link Board}
26 * by calling its {@link Board#apply} method.
28 * @author Jaroslav Tulach <jtulach@netbeans.org>
30 public final class Move extends Object {
31 final Direction[] direction;
34 private Move(Direction... arr) {
38 private Move(Fence f) {
47 /** Moves the player's figure to north */
48 public static final Move NORTH = new Move(Direction.NORTH);
49 /** Moves the player's figure to east */
50 public static final Move EAST = new Move(Direction.EAST);
51 /** Moves the player's figure to south */
52 public static final Move SOUTH = new Move(Direction.SOUTH);
53 /** Moves the player's figure to west */
54 public static final Move WEST = new Move(Direction.WEST);
55 /** Allows the player to resign the game */
56 public static final Move RESIGN = new Move();
58 /** Places a fence into given position with specified orientation.
59 * The faces postions are numbered 1-8 and A-H according to following
63 +-----------------------------------+
65 1--| + + + + + + + + |--1
67 2--| + + + + + + + + |--2
69 3--| + + + + + + + + |--3
71 4--| + + + + + + + + |--4
73 5--| + + + + + + + + |--5
75 6--| + + + + + + + + |--6
77 7--| + + + + + + + + |--7
79 8--| + + + + + + + + |--8
81 +-----------------------------------+
87 * @param column x-coordinate of the middle of the fence from 'A' to 'B'
88 * @param row y-coordinate of the middle of the fence
89 * @param orientation place the fence horizontally or vertically
90 * @return the new board
91 * @exception IllegalPositionException if the move is not possible
93 public static Move fence(char column, int row, Fence.Orientation orientation) throws IllegalPositionException {
94 if (column < 'A' || 'H' < column) {
95 throw new IllegalPositionException ("x coordinate has to be from A to H"); // NOI18N
97 if (row < 1 || row > 8) {
98 throw new IllegalPositionException ("y coordinate has to be from 1 to 8"); // NOI18N
100 return new Move(new Fence ((column - 'A') * 2 + 1, row * 2 - 1, orientation));
103 /** Moves the player in given directions. After applying
104 * the first direction, the pawn has to get on a position
105 * that is occupied by other player's pawn.
107 * @param where one or two directions saying where
108 * @return the new board
109 * @exception IllegalPositionException if the move is not possible
111 public static Move jump(Direction first, Direction second) {
112 return new Move(first, second);
115 /** Converts the value of the move string into valid move, if possible.
117 * @param move the string in format used by {@link #toString()}
118 * @return the move which's toString() returns the move parameter
119 * @throws IllegalPositionException raised in case the parameter does not
120 * represent a valid move
122 public static Move valueOf(String move) throws IllegalPositionException {
123 switch (move.length()) {
125 if (move.startsWith("H")) {
126 return Move.fence(move.charAt(1), move.charAt(2) - '0', Fence.Orientation.HORIZONTAL);
128 if (move.startsWith("V")) {
129 return Move.fence(move.charAt(1), move.charAt(2) - '0', Fence.Orientation.VERTICAL);
133 return Move.jump(Direction.valueOf(move.charAt(0)), Direction.valueOf(move.charAt(1)));
135 switch (move.charAt(0)) {
136 case 'N': return Move.NORTH;
137 case 'S': return Move.SOUTH;
138 case 'E': return Move.EAST;
139 case 'W': return Move.WEST;
142 if ("RESIGN".equals(move)) {
146 throw new IllegalPositionException(move);
150 public String toString() {
152 switch (fence.getOrientation()) {
153 case HORIZONTAL: return "H" + fence.getColumn() + fence.getRow();
154 case VERTICAL: return "V" + fence.getColumn() + fence.getRow();
156 throw new IllegalStateException();
158 if (direction == null) {
159 return "RESIGN"; // NOI18N
161 StringBuilder sb = new StringBuilder();
162 for (Direction d : direction) {
163 sb.append(d.name().charAt(0));
165 return sb.toString();
170 public boolean equals(Object obj) {
174 if (getClass() != obj.getClass()) {
177 final Move other = (Move) obj;
178 if (!Arrays.deepEquals(this.direction, other.direction)) {
181 if (this.fence != other.fence && (this.fence == null || !this.fence.equals(other.fence))) {
188 public int hashCode() {
190 hash = 47 * hash + Arrays.deepHashCode(this.direction);
191 hash = 47 * hash + (this.fence != null ? this.fence.hashCode() : 0);
195 public Move getMirrorMove(){
197 return new Move(new Fence(16-fence.getX(), fence.getY(), fence.getOrientation()));
199 if(direction == null)
201 int dirSize = direction.length;
202 Direction[] mirrorDirection = new Direction[dirSize];
203 for(int i = 0; i < dirSize; i++){
204 if(direction[i].equals(Direction.NORTH))
205 mirrorDirection[i] = Direction.NORTH;
206 else if(direction[i].equals(Direction.SOUTH))
207 mirrorDirection[i] = Direction.SOUTH;
208 else if(direction[i].equals(Direction.EAST))
209 mirrorDirection[i] = Direction.WEST;
210 else if(direction[i].equals(Direction.WEST))
211 mirrorDirection[i] = Direction.EAST;
213 return new Move(mirrorDirection);
217 static List<Move> allMovements() {
218 List<Move> arr = new ArrayList<Move>();
225 for (Direction d1 : Player.Direction.values()) {
226 for (Direction d2 : Player.Direction.values()) {
227 arr.add(Move.jump(d1, d2));