quoridor/src/main/java/cz/xelfi/quoridor/Move.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Tue, 14 Sep 2010 08:56:13 +0200
changeset 264 d60370059c3c
parent 253 ee02205edf13
permissions -rw-r--r--
Changing headers to GPLv3
     1 /*
     2  * Quoridor server and related libraries
     3  * Copyright (C) 2009-2010 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
     4  *
     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.
     8  *
     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.
    13  *
    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/.
    17  */
    18 package cz.xelfi.quoridor;
    19 
    20 import cz.xelfi.quoridor.Player.Direction;
    21 import java.util.ArrayList;
    22 import java.util.Arrays;
    23 import java.util.List;
    24 
    25 /** Encapsulates one possible move that can be applied to existing {@link Board}
    26  * by calling its {@link Board#apply} method.
    27  *
    28  * @author Jaroslav Tulach <jtulach@netbeans.org>
    29  */
    30 public final class Move extends Object {
    31     final Direction[] direction;
    32     final Fence fence;
    33 
    34     private Move(Direction... arr) {
    35         direction = arr;
    36         fence = null;
    37     }
    38     private Move(Fence f) {
    39         fence = f;
    40         direction = null;
    41     }
    42     private Move() {
    43         fence = null;
    44         direction = null;
    45     }
    46 
    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();
    57 
    58     /** Places a fence into given position with specified orientation.
    59      * The faces postions are numbered 1-8 and A-H according to following
    60      * graph: <pre>
    61             H   G   F   E   D   C   B   A
    62             |   |   |   |   |   |   |   |
    63         +-----------------------------------+
    64         |                                   |
    65      1--|   +   +   +   +   +   +   +   +   |--1
    66         |                                   |
    67      2--|   +   +   +   +   +   +   +   +   |--2
    68         |                                   |
    69      3--|   +   +   +   +   +   +   +   +   |--3
    70         |                                   |
    71      4--|   +   +   +   +   +   +   +   +   |--4
    72 [E]     |                                   |     [W]
    73      5--|   +   +   +   +   +   +   +   +   |--5
    74         |                                   |
    75      6--|   +   +   +   +   +   +   +   +   |--6
    76         |                                   |
    77      7--|   +   +   +   +   +   +   +   +   |--7
    78         |                                   |
    79      8--|   +   +   +   +   +   +   +   +   |--8
    80         |                                   |
    81         +-----------------------------------+
    82             |   |   |   |   |   |   |   |
    83             H   G   F   E   D   C   B   A
    84      * </pre>
    85      *
    86      *
    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
    92      */
    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
    96         }
    97         if (row < 1 || row > 8) {
    98             throw new IllegalPositionException ("y coordinate has to be from 1 to 8"); // NOI18N
    99         }
   100         return new Move(new Fence ((column - 'A') * 2 + 1, row * 2 - 1, orientation));
   101     }
   102 
   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.
   106      *
   107      * @param where one or two directions saying where
   108      * @return the new board
   109      * @exception IllegalPositionException if the move is not possible
   110      */
   111     public static Move jump(Direction first, Direction second) {
   112         return new Move(first, second);
   113     }
   114 
   115     /** Converts the value of the move string into valid move, if possible.
   116      *
   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
   121      */
   122     public static Move valueOf(String move) throws IllegalPositionException {
   123         switch (move.length()) {
   124             case 3:
   125             if (move.startsWith("H")) {
   126                 return Move.fence(move.charAt(1), move.charAt(2) - '0', Fence.Orientation.HORIZONTAL);
   127             }
   128             if (move.startsWith("V")) {
   129                 return Move.fence(move.charAt(1), move.charAt(2) - '0', Fence.Orientation.VERTICAL);
   130             }
   131             break;
   132             case 2:
   133                 return Move.jump(Direction.valueOf(move.charAt(0)), Direction.valueOf(move.charAt(1)));
   134             case 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;
   140                 }
   141             case 6:
   142                 if ("RESIGN".equals(move)) {
   143                     return Move.RESIGN;
   144                 }
   145         }
   146         throw new IllegalPositionException(move);
   147     }
   148 
   149     @Override
   150     public String toString() {
   151         if (fence != null) {
   152             switch (fence.getOrientation()) {
   153                 case HORIZONTAL: return "H" + fence.getColumn() + fence.getRow();
   154                 case VERTICAL: return "V" + fence.getColumn() + fence.getRow();
   155             }
   156             throw new IllegalStateException();
   157         } else {
   158             if (direction == null) {
   159                 return "RESIGN"; // NOI18N
   160             }
   161             StringBuilder sb = new StringBuilder();
   162             for (Direction d : direction) {
   163                 sb.append(d.name().charAt(0));
   164             }
   165             return sb.toString();
   166         }
   167     }
   168 
   169     @Override
   170     public boolean equals(Object obj) {
   171         if (obj == null) {
   172             return false;
   173         }
   174         if (getClass() != obj.getClass()) {
   175             return false;
   176         }
   177         final Move other = (Move) obj;
   178         if (!Arrays.deepEquals(this.direction, other.direction)) {
   179             return false;
   180         }
   181         if (this.fence != other.fence && (this.fence == null || !this.fence.equals(other.fence))) {
   182             return false;
   183         }
   184         return true;
   185     }
   186 
   187     @Override
   188     public int hashCode() {
   189         int hash = 3;
   190         hash = 47 * hash + Arrays.deepHashCode(this.direction);
   191         hash = 47 * hash + (this.fence != null ? this.fence.hashCode() : 0);
   192         return hash;
   193     }
   194 
   195     public Move getMirrorMove(){
   196         if(fence != null){
   197             return new Move(new Fence(16-fence.getX(), fence.getY(), fence.getOrientation()));
   198         }
   199         if(direction == null)
   200             return new Move();
   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;
   212         }
   213         return new Move(mirrorDirection);
   214     }
   215 
   216 
   217     static List<Move> allMovements() {
   218         List<Move> arr = new ArrayList<Move>();
   219         
   220         arr.add(Move.EAST);
   221         arr.add(Move.WEST);
   222         arr.add(Move.NORTH);
   223         arr.add(Move.SOUTH);
   224         
   225         for (Direction d1 : Player.Direction.values()) {
   226             for (Direction d2 : Player.Direction.values()) {
   227                 arr.add(Move.jump(d1, d2));
   228             }
   229         }
   230         return arr;
   231     }
   232 }