Sources resurrected from long time past attempts and converted to maven
authorJaroslav Tulach <jtulach@netbeans.org>
Sun, 10 May 2009 20:15:24 +0200
changeset 0e062b569266f
child 1 45b2390e131c
Sources resurrected from long time past attempts and converted to maven
quoridor/pom.xml
quoridor/src/main/java/cz/xelfi/quoridor/Board.java
quoridor/src/main/java/cz/xelfi/quoridor/IllegalPositionException.java
quoridor/src/main/java/cz/xelfi/quoridor/View.java
quoridor/src/test/java/cz/xelfi/quoridor/BoardTest.java
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/quoridor/pom.xml	Sun May 10 20:15:24 2009 +0200
     1.3 @@ -0,0 +1,72 @@
     1.4 +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     1.5 +  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
     1.6 +  <modelVersion>4.0.0</modelVersion>
     1.7 +  <groupId>org.apidesign</groupId>
     1.8 +  <artifactId>quoridor</artifactId>
     1.9 +  <packaging>jar</packaging>
    1.10 +  <version>7.22.0</version>
    1.11 +  <url>http://quoridor.xelfi.cz</url>
    1.12 +  <!--
    1.13 +  <parent>
    1.14 +      <groupId>xelfi.cz</groupId>
    1.15 +      <artifactId>quoridor</artifactId>
    1.16 +      <relativePath>..</relativePath>
    1.17 +      <version>2.0</version>
    1.18 +  </parent>
    1.19 +  <ciManagement>
    1.20 +      <system>hudson</system>
    1.21 +      <url>http://hudson.apidesign.org/hudson/job/lookup</url>
    1.22 +  </ciManagement>
    1.23 +  <issueManagement>
    1.24 +      <system>issuezilla</system>
    1.25 +      <url>http://platform.netbeans.org/issues/</url>
    1.26 +  </issueManagement>
    1.27 +  <mailingLists>
    1.28 +      <mailingList>
    1.29 +          <name>Using the NetBeans Platform</name>
    1.30 +          <archive>http://openide.netbeans.org/servlets/SummarizeList?listName=dev</archive>
    1.31 +          <post>dev@openide.netbeans.org</post>
    1.32 +      </mailingList>
    1.33 +  </mailingLists>
    1.34 +  -->
    1.35 +    <build>
    1.36 +        <plugins>
    1.37 +            <plugin>
    1.38 +                <groupId>org.apache.maven.plugins</groupId>
    1.39 +                <artifactId>maven-compiler-plugin</artifactId>
    1.40 +                <version>2.0.2</version>
    1.41 +                <configuration>
    1.42 +                    <source>1.5</source>
    1.43 +                    <target>1.5</target>
    1.44 +                </configuration>
    1.45 +            </plugin>
    1.46 +            <plugin>
    1.47 +                <groupId>org.apache.maven.plugins</groupId>
    1.48 +                <artifactId>maven-javadoc-plugin</artifactId>
    1.49 +                <version>2.5</version>
    1.50 +                <!--
    1.51 +                <configuration>
    1.52 +                    <excludePackageNames>org.netbeans.modules.openide.util</excludePackageNames>
    1.53 +                    <overview>${basedir}/src/main/java/org/openide/util/lookup/doc-files/index.html</overview>
    1.54 +                </configuration>
    1.55 +                -->
    1.56 +            </plugin>
    1.57 +        </plugins>
    1.58 +    </build>
    1.59 +    <dependencies>
    1.60 +        <dependency>
    1.61 +            <groupId>org.netbeans.api</groupId>
    1.62 +            <artifactId>org-netbeans-modules-nbjunit</artifactId>
    1.63 +            <version>RELEASE65</version>
    1.64 +            <scope>test</scope>
    1.65 +        </dependency>
    1.66 +        <dependency>
    1.67 +            <groupId>org.netbeans.modules</groupId>
    1.68 +            <artifactId>org-netbeans-insane</artifactId>
    1.69 +            <version>RELEASE65</version>
    1.70 +            <scope>test</scope>
    1.71 +        </dependency>
    1.72 +    </dependencies>
    1.73 +    <name>Quoridor Library</name>
    1.74 +    <description>Quoridor library provides API to play the Quoridor game.</description>
    1.75 +</project>
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/quoridor/src/main/java/cz/xelfi/quoridor/Board.java	Sun May 10 20:15:24 2009 +0200
     2.3 @@ -0,0 +1,608 @@
     2.4 +/*
     2.5 + */
     2.6 +
     2.7 +package cz.xelfi.quoridor;
     2.8 +
     2.9 +/**
    2.10 + * This is a class that represents a snapshot of the game position,
    2.11 + * with all the placed and not-yet placed fences and player positions.
    2.12 + * It it can print itself to stream following the format defined at
    2.13 + * http://www.gamerz.net/pbmserv/quoridor.html
    2.14 + * and shall be able to read that format back. There class is immutable
    2.15 + * but it contains "move operations" that produce new Board position.
    2.16 + * 
    2.17 + * @author Jaroslav Tulach
    2.18 + */
    2.19 +public final class Board {
    2.20 +    /** players */
    2.21 +    private final java.util.List<Player> players;
    2.22 +    /** fences placed on board */
    2.23 +    private final java.util.Set<Fence> fences;
    2.24 +    /** occurpied bits (coordinates encoded by toIndex methods) 
    2.25 +                         [N]
    2.26 +               
    2.27 +        +-----------------------------------+
    2.28 +     6  |                                   |          
    2.29 +     5  |   +   +   +   +   +   +   +   +   |  
    2.30 +     4  |                                   |          
    2.31 +     3  |   +   +   +   +   +   +   +   +   |  
    2.32 +     2  |                                   |          
    2.33 +     1  |   +   +   +   +   +   +   +   +   |  
    2.34 +     0  |                                   |
    2.35 +     9  |   +   +   +   +   +   +   +   +   |
    2.36 +[W]  8  |                                   |     [E]
    2.37 +     7  |   +   +   +   +   +   +   +   +   |
    2.38 +     6  |                                   |
    2.39 +     5  |   +   +   +   +   +   +   +   +   |
    2.40 +     4  |                                   |
    2.41 +     3  |   +   +   +   +   +   +   +   +   |
    2.42 +     2  |                                   |
    2.43 +     1  |   +   +   +   +   +   +   +   +   |
    2.44 +     0  |                                   |
    2.45 +        +-----------------------------------+
    2.46 +          0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6
    2.47 +                         [S]
    2.48 +     
    2.49 +     * even indexes == position of the pawns
    2.50 +     * odd indexes  == centers of fences
    2.51 +     * even x odd   == side of a fence
    2.52 +     * odd x even   == side of a fence
    2.53 +     */
    2.54 +    private final java.util.BitSet occupied;
    2.55 +    
    2.56 +    /**
    2.57 +     * Creates a new instance of Board 
    2.58 +     */
    2.59 +    private Board (int x1, int y1, int f1, int x2, int y2, int f2) {
    2.60 +        this.players = java.util.Collections.unmodifiableList (java.util.Arrays.asList (new Player[] {
    2.61 +            new Player (x1, y1, f1, Player.Direction.NORTH),
    2.62 +            new Player (x2, y2, f2, Player.Direction.SOUTH),
    2.63 +        }));
    2.64 +        this.fences = java.util.Collections.emptySet ();
    2.65 +        try {
    2.66 +            this.occupied = computeOccupied (players, fences);
    2.67 +        } catch (IllegalPositionException ex) {
    2.68 +            throw new IllegalStateException (ex.getMessage ());
    2.69 +        }
    2.70 +    }
    2.71 +    
    2.72 +    /** Copy constructor that provides players and fences.
    2.73 +     */
    2.74 +    private Board (java.util.List<Player> players, java.util.Set<Fence> fences) 
    2.75 +    throws IllegalPositionException {
    2.76 +        this.players = java.util.Collections.unmodifiableList (players);
    2.77 +        this.fences = java.util.Collections.unmodifiableSet (fences);
    2.78 +        this.occupied = computeOccupied (players, fences);
    2.79 +        
    2.80 +        for (Player p : players) {
    2.81 +            if (!accessibleFinalLine (p, p.endDirection, occupied, new java.util.BitSet ())) {
    2.82 +                throw new IllegalPositionException ("Player " + p + " cannot reach " + p.endDirection + " side"); // NOI18N
    2.83 +            }
    2.84 +        }
    2.85 +    }
    2.86 +    
    2.87 +    /** Creates initial empty board with default positions of 
    2.88 +     * players.
    2.89 +     */
    2.90 +    public static Board createEmptyBoard () {
    2.91 +        return new Board (8, 0, 10, 8, 16, 10);
    2.92 +    }
    2.93 +    
    2.94 +    /** Returns players in the game.
    2.95 +     * @return player object
    2.96 +     */
    2.97 +    public java.util.List<Player> getPlayers () {
    2.98 +        return players;
    2.99 +    }
   2.100 +    
   2.101 +    /** The fences currently on board. 
   2.102 +     * 
   2.103 +     * @return immutable set of Fences
   2.104 +     */
   2.105 +    public java.util.Set<Fence> getFences () {
   2.106 +        return fences;
   2.107 +    }
   2.108 +    
   2.109 +    //
   2.110 +    // Moves
   2.111 +    // 
   2.112 +    
   2.113 +
   2.114 +    /** Moves the player in given direction. The direction usually
   2.115 +     * is one of Player.Direction constants, but in case the move
   2.116 +     * is a jump over another players pawn it can be followed by
   2.117 +     * another (usually, if there is no fence the same) direction.
   2.118 +     *
   2.119 +     * @param player the player to move
   2.120 +     * @param where one or two directions saying where
   2.121 +     * @return the new board
   2.122 +     * @exception IllegalPositionException if the move is not possible
   2.123 +     */
   2.124 +    public Board move (Player player, Player.Direction... where) throws IllegalPositionException {
   2.125 +        if (where.length != 1 && where.length != 2) {
   2.126 +            throw new IllegalPositionException ("Move over one or two Directions"); // NOI18N
   2.127 +        }
   2.128 +        
   2.129 +        int index = players.indexOf (player);
   2.130 +        Player[] arr = players.toArray (new Player[0]);
   2.131 +
   2.132 +        Player oneStep = newPosition (player, where[0]);
   2.133 +        
   2.134 +        if (where.length == 1) {
   2.135 +            arr[index] = oneStep;
   2.136 +            return new Board (java.util.Arrays.asList (arr), fences);
   2.137 +        }
   2.138 +
   2.139 +        // straight jump over
   2.140 +        for (Player p : players) {
   2.141 +            if (p.getX () == oneStep.getX () && p.getY() == oneStep.getY ()) {
   2.142 +                // ok, we are jumping over this one
   2.143 +                GO_ON: if (where[0] != where[1]) {
   2.144 +                    // first of all ensure that we cannot go straight
   2.145 +                    try {
   2.146 +                        newPosition (oneStep, where[0]);
   2.147 +                    } catch (IllegalPositionException ex) {
   2.148 +                        // ok
   2.149 +                        break GO_ON;
   2.150 +                    }
   2.151 +                    throw new IllegalPositionException ("You have to jump straight if there is no wall"); // NOI18N
   2.152 +                }
   2.153 +                arr[index] = newPosition (oneStep, where[1]);
   2.154 +                return new Board (java.util.Arrays.asList (arr), fences);
   2.155 +            }
   2.156 +        }
   2.157 +        throw new IllegalPositionException ("Cannot use multi direction when there is not oponent pawn"); // NOI18N
   2.158 +    }
   2.159 +    
   2.160 +    /** Places a fence into given position with specified orientation.
   2.161 +     * The faces postions are numbered 1-8 and A-H according to following
   2.162 +     * graph: <pre>
   2.163 +            H   G   F   E   D   C   B   A   
   2.164 +            |   |   |   |   |   |   |   |
   2.165 +        +-----------------------------------+
   2.166 +        |                                   |          
   2.167 +     1--|   +   +   +   +   +   +   +   +   |--1    
   2.168 +        |                                   |       
   2.169 +     2--|   +   +   +   +   +   +   +   +   |--2    
   2.170 +        |                                   |       
   2.171 +     3--|   +   +   +   +   +   +   +   +   |--3    
   2.172 +        |                                   |          
   2.173 +     4--|   +   +   +   +   +   +   +   +   |--4        
   2.174 +[E]     |                                   |     [W]
   2.175 +     5--|   +   +   +   +   +   +   +   +   |--5        
   2.176 +        |                                   |          
   2.177 +     6--|   +   +   +   +   +   +   +   +   |--6    
   2.178 +        |                                   |       
   2.179 +     7--|   +   +   +   +   +   +   +   +   |--7    
   2.180 +        |                                   |       
   2.181 +     8--|   +   +   +   +   +   +   +   +   |--8    
   2.182 +        |                                   |          
   2.183 +        +-----------------------------------+
   2.184 +            |   |   |   |   |   |   |   |
   2.185 +            H   G   F   E   D   C   B   A   
   2.186 +     * </pre>
   2.187 +     *
   2.188 +     *
   2.189 +     * @param player the player that wishes to place the position
   2.190 +     * @param x x-coordinate of the middle of the fence from 'A' to 'B'
   2.191 +     * @param y y-coordinate of the middle of the fence
   2.192 +     * @param orientation place the fence horizontally or vertically
   2.193 +     * @return the new board
   2.194 +     * @exception IllegalPositionException if the move is not possible
   2.195 +     */
   2.196 +    public Board fence (Player player, char x, int y, Fence.Orientation orientation) throws IllegalPositionException {
   2.197 +        if (player.getFences () == 0) {
   2.198 +            throw new IllegalPositionException ("Not enough fences: " + player); // NOI18N
   2.199 +        }
   2.200 +        
   2.201 +        if (x < 'A' || 'H' < x) {
   2.202 +            throw new IllegalPositionException ("x coordinate has to be from A to H"); // NOI18N
   2.203 +        }
   2.204 +        
   2.205 +        int index = players.indexOf (player);
   2.206 +        Player[] arr = players.toArray (new Player[0]);
   2.207 +        arr[index] = new Player (arr[index].getX (), arr[index].getY (), arr[index].getFences () - 1, arr[index].endDirection);
   2.208 +        
   2.209 +        java.util.HashSet<Fence> fen = new java.util.HashSet<Fence> (this.fences);
   2.210 +        fen.add (new Fence ((x - 'A') * 2 + 1, y * 2 - 1, orientation));
   2.211 +        
   2.212 +        return new Board (java.util.Arrays.asList (arr), fen);
   2.213 +    }
   2.214 +    
   2.215 +    /** Writes the board to the provided writer. 
   2.216 +     *
   2.217 +     *
   2.218 +            H   G   F   E   D   C   B   A   
   2.219 +            |   |   |   |   |   |   |   |
   2.220 +        +-----------------------------------+
   2.221 +        |                                   |          
   2.222 +     1--|   +   +   +   +   +   +   +   +   |--1        playerA (O)
   2.223 +        |       |                           |           Fences - 5
   2.224 +     2--|   +   |   +   +-------+-------+   |--2        ===========
   2.225 +        |       |       |                   |            | | | | |
   2.226 +     3--|-------+-------|-------+-------+   |--3        
   2.227 +        |               |                   |          
   2.228 +     4--|   +   +   +   +   +   +   +   +   |--4        
   2.229 +[E]     |               |                   |     [W]
   2.230 +     5--|   +   +   +   |   +   +   +-------|--5        
   2.231 +        |               |     y             |          
   2.232 +     6--|   +   +   +   +-------+   +   +   |--6        PlayerB (X)
   2.233 +        |                 a   O   a         |           Fences - 3
   2.234 +     7--|   +   +   +   +   +   +   +   +   |--7        ===========
   2.235 +        |                 b   X |           |            | | |
   2.236 +     8--|   +   +   +   +   +   |   +   +   |--8        
   2.237 +        |                     z |           |          
   2.238 +        +-----------------------------------+
   2.239 +            |   |   |   |   |   |   |   |
   2.240 +            H   G   F   E   D   C   B   A        *
   2.241 +     * @param w writer to write the board to
   2.242 +     * @exception IOException if communiction with writer fails
   2.243 +     */
   2.244 +    public void write (java.io.Writer w) throws java.io.IOException {
   2.245 +    }
   2.246 +    
   2.247 +    /** This will print the board with provided spacing.
   2.248 +     * This is example of 3:1 spacing: 
   2.249 +     * <pre>
   2.250 +     *  +---+
   2.251 +     *  |sss|
   2.252 +     *  +---+
   2.253 +     * </pre>
   2.254 +     * and this 4:2 spacing:
   2.255 +     * <pre>
   2.256 +     *  +----+
   2.257 +     *  |ssss|
   2.258 +     *  |ssss|
   2.259 +     *  +----+
   2.260 +     * </pre>
   2.261 +     */
   2.262 +    private void write (StringBuffer sb, int spaceX, int spaceY) {
   2.263 +        
   2.264 +        // TODO rethink
   2.265 +        int cellSizeX = 1 + spaceX;
   2.266 +        int cellSizeY = 1 + spaceY;
   2.267 +        
   2.268 +        StringBuffer[] data = new StringBuffer[1 + cellSizeX * 9];
   2.269 +        for (int i = 0; i < data.length; i++) {
   2.270 +            data[i] = new StringBuffer (34);
   2.271 +            
   2.272 +            for (int grid = 1; grid < 34; grid += 4) {
   2.273 +                data[i].setCharAt (grid, '+');
   2.274 +            }
   2.275 +        }
   2.276 +        
   2.277 +        for (Player p : players) {
   2.278 +            data[p.getY()].setCharAt(p.getY() * 2, 'P');
   2.279 +        }
   2.280 +        
   2.281 +        for (Fence f : fences) {
   2.282 +            switch (f.getOrientation()) {
   2.283 +                case HORIZONTAL:
   2.284 +                    for (int i = -1; i <= 1; i++) {
   2.285 +                        data[f.getY()].setCharAt (f.getX () + i, '-');
   2.286 +                    }
   2.287 +                    break;
   2.288 +                case VERTICAL:
   2.289 +                    for (int i = -1; i <= 1; i++) {
   2.290 +                        data[f.getY() + i].setCharAt (f.getX (), '|');
   2.291 +                    }
   2.292 +                    break;
   2.293 +                default: 
   2.294 +                    throw new IllegalStateException ("Unkown orientation: " + f.getOrientation ()); // NOI18N
   2.295 +            }
   2.296 +        }
   2.297 +        
   2.298 +        StringBuffer result = new StringBuffer (20 * 20);
   2.299 +        /*
   2.300 +        for (int i = 0; i < )
   2.301 +         */
   2.302 +    }
   2.303 +    
   2.304 +    //
   2.305 +    // Standard Methods
   2.306 +    // 
   2.307 +
   2.308 +    
   2.309 +    public int hashCode () {
   2.310 +        return occupied.hashCode ();
   2.311 +    }
   2.312 +    
   2.313 +    public boolean equals (Object o) {
   2.314 +        if (o instanceof Board) {
   2.315 +            Board b = (Board)o;
   2.316 +            return occupied.equals (b.occupied) && players.equals (b.players);
   2.317 +        }
   2.318 +        return false;
   2.319 +    }
   2.320 +    
   2.321 +    //
   2.322 +    // Validation methods
   2.323 +    //
   2.324 +
   2.325 +    /** Computes new position of a player and checks whether there is no
   2.326 +     * fence between the old and new.
   2.327 +     */
   2.328 +    private Player newPosition (Player old, Player.Direction direction) throws IllegalPositionException {
   2.329 +        return newPosition (old, direction, occupied);
   2.330 +    }
   2.331 +    
   2.332 +    
   2.333 +    private static Player newPosition (Player old, Player.Direction direction, java.util.BitSet occupied) throws IllegalPositionException {
   2.334 +        int nx = old.x;
   2.335 +        int ny = old.y;
   2.336 +        int fx = old.x;
   2.337 +        int fy = old.y;
   2.338 +        
   2.339 +        switch (direction) {
   2.340 +            case NORTH: 
   2.341 +                ny = old.y + 2;
   2.342 +                fy = old.y + 1;
   2.343 +                break;
   2.344 +            case SOUTH: 
   2.345 +                ny = old.y - 2; 
   2.346 +                fy = old.y - 1;
   2.347 +                break;
   2.348 +            case EAST: 
   2.349 +                nx = old.x + 2; 
   2.350 +                fx = old.x + 1;
   2.351 +                break;
   2.352 +            case WEST: 
   2.353 +                nx = old.x - 2; 
   2.354 +                fx = old.x - 1;
   2.355 +                break;
   2.356 +            default: throw new IllegalStateException ("Unknown direction: " + direction); // NOI18N
   2.357 +        }
   2.358 +        
   2.359 +        if (nx < 0 || nx > 16) throw new IllegalPositionException ("Wrong player position: " + nx + ":" + ny); // NOI18N
   2.360 +        if (ny < 0 || ny > 16) throw new IllegalPositionException ("Wrong player position: " + nx + ":" + ny); // NOI18N
   2.361 +        
   2.362 +        int fenceIndex = toIndex (fx, fy);
   2.363 +        if (occupied.get (fenceIndex)) {
   2.364 +            throw new IllegalPositionException ("You cannot go over fences"); // NOI18N
   2.365 +        }
   2.366 +        
   2.367 +        return new Player (nx, ny, old.getFences (), old.endDirection);
   2.368 +    }
   2.369 +    
   2.370 +    /** @param position the current position of the player
   2.371 +     * @param endDir the side the player wants to reach
   2.372 +     * @param fences bits set to 1 when fences are placed
   2.373 +     * @param reached bits on squares that were already reached (modified during run)
   2.374 +     * @return true if the end line can be reached
   2.375 +     */
   2.376 +    private static boolean accessibleFinalLine (Player position, Player.Direction endDir, java.util.BitSet fences, java.util.BitSet reached) {
   2.377 +        int index = toIndex (position);
   2.378 +        if (reached.get (index)) {
   2.379 +            // already visited without success
   2.380 +            return false;
   2.381 +        }
   2.382 +        
   2.383 +        switch (endDir) {
   2.384 +            case NORTH: 
   2.385 +                if (position.getY () == 8) return true;
   2.386 +                break;
   2.387 +            case SOUTH:
   2.388 +                if (position.getY () == 0) return true;
   2.389 +                break;
   2.390 +            case EAST:
   2.391 +                if (position.getX () == 0) return true;
   2.392 +                break;
   2.393 +            case WEST:
   2.394 +                if (position.getX () == 8) return true;
   2.395 +                break;
   2.396 +            default:
   2.397 +                throw new IllegalStateException ("Wrong direction: " + endDir); // NOI18N
   2.398 +        }
   2.399 +        
   2.400 +        reached.set (index);
   2.401 +        
   2.402 +        for (Player.Direction oneDirection : Player.Direction.values ()) {
   2.403 +            try {
   2.404 +                if (accessibleFinalLine (newPosition (position, oneDirection, fences), endDir, fences, reached)) {
   2.405 +                    return true;
   2.406 +                }
   2.407 +            } catch (IllegalPositionException ex) {
   2.408 +                // ok, try once more
   2.409 +            }
   2.410 +        }
   2.411 +        
   2.412 +        return false;
   2.413 +    }
   2.414 +    
   2.415 +    /** Computes mask of the occupried bits.
   2.416 +     */
   2.417 +    private static java.util.BitSet computeOccupied (
   2.418 +        java.util.Collection<Player> players, java.util.Collection<Fence> fences
   2.419 +    ) throws IllegalPositionException {
   2.420 +        java.util.BitSet occupied = new java.util.BitSet (17 * 17);
   2.421 +        
   2.422 +        for (Player p : players) {
   2.423 +            if (p.getX () % 2 == 1) throw new IllegalPositionException ("Wrong player position: " + p); // NOI18N
   2.424 +            if (p.getY () % 2 == 1) throw new IllegalPositionException ("Wrong player position: " + p); // NOI18N
   2.425 +            
   2.426 +            int index = toIndex (p);
   2.427 +            if (occupied.get (index)) {
   2.428 +                throw new IllegalPositionException ("There cannot be two players at " + p); // NOI18N
   2.429 +            }
   2.430 +            occupied.set (index);
   2.431 +        }
   2.432 +        
   2.433 +        for (Fence f : fences) {
   2.434 +            
   2.435 +            for (int i = -1; i <= 1; i++) {
   2.436 +                int index = toIndex (f, i);
   2.437 +                if (index < 0 || index > occupied.size ()) {
   2.438 +                    throw new IllegalPositionException ("Wrong fence position: " + f); // NOI18N
   2.439 +                }
   2.440 +                if (occupied.get (index)) {
   2.441 +                    throw new IllegalPositionException ("Fence collition: " + f); // NOI18N
   2.442 +                }
   2.443 +                
   2.444 +                occupied.set (index);
   2.445 +            }
   2.446 +            
   2.447 +        }
   2.448 +        
   2.449 +        return occupied;
   2.450 +    }
   2.451 +
   2.452 +    /** Converts twodimensional coordinates of player to one dimensional index.
   2.453 +     */
   2.454 +    private static int toIndex (Player p) {
   2.455 +        return toIndex (p.getX (), p.getY ());
   2.456 +    }
   2.457 +    
   2.458 +    /** Converts twodimensional coordinates of fence to one dimensional index.
   2.459 +     * @param f the fence
   2.460 +     * @param whichPart (-1, 0, 1) 
   2.461 +     */
   2.462 +    private static int toIndex (Fence f, int whichPart) {
   2.463 +        int x = f.getX ();
   2.464 +        int y = f.getY ();
   2.465 +        
   2.466 +        switch (f.getOrientation ()) {
   2.467 +            case HORIZONTAL: x += whichPart; break;
   2.468 +            case VERTICAL: y += whichPart; break;
   2.469 +            default: throw new IllegalStateException ("Wrong orientation: " + f.getOrientation ()); // NOI18N
   2.470 +        }
   2.471 +        
   2.472 +        return toIndex (x, y);
   2.473 +    }
   2.474 +    
   2.475 +    /** Diagonal conversion of two positive integers to one integer.
   2.476 +     * <pre>
   2.477 +     * y3 9
   2.478 +     * y2 5  8
   2.479 +     * y1 2  4  7
   2.480 +     * y0 0  1  3  6
   2.481 +     *   x0 x1 x2 x3
   2.482 +     * </pre>
   2.483 +     */
   2.484 +    private static int toIndex (int x, int y) {
   2.485 +        int max = x + y;
   2.486 +        int baseOnY0 = max * (max + 1) / 2;
   2.487 +        return baseOnY0 + y;
   2.488 +    }
   2.489 +    
   2.490 +    /** Defines properties (mostly position) of a player.
   2.491 +     */
   2.492 +    public static final class Player extends Object {
   2.493 +        private final int x;
   2.494 +        private final int y;
   2.495 +        /** number of fences this player has */
   2.496 +        private final int f;
   2.497 +        /** the direction of players end line */
   2.498 +        private final Direction endDirection;
   2.499 +        
   2.500 +         Player (int x, int y, int f, Player.Direction endDir) {
   2.501 +            this.x = x;
   2.502 +            this.y = y;
   2.503 +            this.f = f;
   2.504 +            this.endDirection = endDir;
   2.505 +        }
   2.506 +        
   2.507 +        
   2.508 +        /** Returns the x-coordinate of the player.
   2.509 +         * @return  number from 0 to 8
   2.510 +         */
   2.511 +        int getX () {
   2.512 +            return x;
   2.513 +        }
   2.514 +        
   2.515 +        /** Returns the y-coordinate of the player.
   2.516 +         * @return  number from 0 to 8
   2.517 +         */
   2.518 +        int getY () {
   2.519 +            return y;
   2.520 +        }
   2.521 +        
   2.522 +        /** @return number of fences this player still has 
   2.523 +         */
   2.524 +        int getFences () {
   2.525 +            return f;
   2.526 +        }
   2.527 +        
   2.528 +        public String toString () {
   2.529 +            return "Player[" + x + "," + y + "," + f + "," + endDirection + "]"; // NOI18N
   2.530 +        }
   2.531 +        
   2.532 +        public int hashCode () {
   2.533 +            return 8 * x + 2 * y + 4 * f + 7 + endDirection.hashCode ();
   2.534 +        }
   2.535 +        
   2.536 +        public boolean equals (Object o) {
   2.537 +            if (o instanceof Player) {
   2.538 +                Player p = (Player)o;
   2.539 +                return x == p.x && y == p.y && f == p.f && endDirection.equals (p.endDirection);
   2.540 +            }
   2.541 +            return false;
   2.542 +        }
   2.543 +        
   2.544 +        /** Possible directions of player's moves.
   2.545 +         */
   2.546 +        public enum Direction {
   2.547 +            NORTH, WEST, EAST, SOUTH
   2.548 +        }
   2.549 +    } // end of Player
   2.550 +    
   2.551 +    /** Defines a fence. Its position is defined as position of its
   2.552 +     * center (index from 0-8 in both directions) and its orientation
   2.553 +     * either horizontal or vertical.
   2.554 +     */
   2.555 +    public static final class Fence extends Object {
   2.556 +        private final int x, y;
   2.557 +        private final Orientation o;
   2.558 +        
   2.559 +        Fence (int x, int y, Orientation o) {
   2.560 +            this.x = x;
   2.561 +            this.y = y;
   2.562 +            this.o = o;
   2.563 +        }
   2.564 +        
   2.565 +        /** Midle coordinate of the fence.
   2.566 +         * @return 1-15
   2.567 +         */
   2.568 +        int getX () {
   2.569 +            return x;
   2.570 +        }
   2.571 +        
   2.572 +        /** Midle coordinate of the fence.
   2.573 +         * @return 1-15
   2.574 +         */
   2.575 +        int getY () {
   2.576 +            return y;
   2.577 +        }
   2.578 +        
   2.579 +        /** The orientation of the fence.
   2.580 +         */
   2.581 +        Orientation getOrientation () {
   2.582 +            return o;
   2.583 +        }
   2.584 +        
   2.585 +        public String toString () {
   2.586 +            return "Fence[" + x + "," + y + "," + o + "]"; // NOI18N
   2.587 +        }
   2.588 +        
   2.589 +        public int hashCode () {
   2.590 +            return 8 * x + 4 * y + 13 + o.hashCode ();
   2.591 +        }
   2.592 +        
   2.593 +        public boolean equals (Object o) {
   2.594 +            if (o instanceof Fence) {
   2.595 +                Fence f = (Fence)o;
   2.596 +                
   2.597 +                return x == f.x && y == f.y && getOrientation ().equals (f.getOrientation ());
   2.598 +            }
   2.599 +            return false;
   2.600 +        }
   2.601 +        
   2.602 +        /** The fences orientation. Either horizontal of vertical.
   2.603 +         */
   2.604 +        public static enum Orientation { 
   2.605 +            HORIZONTAL, VERTICAL;
   2.606 +            
   2.607 +            private Orientation () {
   2.608 +            }
   2.609 +        }
   2.610 +    }
   2.611 +}
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/quoridor/src/main/java/cz/xelfi/quoridor/IllegalPositionException.java	Sun May 10 20:15:24 2009 +0200
     3.3 @@ -0,0 +1,17 @@
     3.4 +/*
     3.5 + */
     3.6 +
     3.7 +package cz.xelfi.quoridor;
     3.8 +
     3.9 +/** Thrown when an illegal position is reached.
    3.10 + *
    3.11 + * @author Jaroslav Tulach
    3.12 + */
    3.13 +public final class IllegalPositionException extends java.lang.Exception {
    3.14 +    /**
    3.15 +     * @param msg the detail message.
    3.16 +     */
    3.17 +    IllegalPositionException (String msg) {
    3.18 +        super (msg);
    3.19 +    }
    3.20 +}
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/quoridor/src/main/java/cz/xelfi/quoridor/View.java	Sun May 10 20:15:24 2009 +0200
     4.3 @@ -0,0 +1,244 @@
     4.4 +/*
     4.5 + */
     4.6 +
     4.7 +package cz.xelfi.quoridor;
     4.8 +
     4.9 +import java.awt.BorderLayout;
    4.10 +import java.awt.Dimension;
    4.11 +import java.awt.Graphics2D;
    4.12 +import java.awt.Point;
    4.13 +import java.awt.event.MouseEvent;
    4.14 +import java.awt.event.MouseListener;
    4.15 +import java.awt.event.MouseMotionListener;
    4.16 +import java.awt.geom.Rectangle2D;
    4.17 +import javax.swing.JComponent;
    4.18 +import javax.swing.border.EmptyBorder;
    4.19 +
    4.20 +/**
    4.21 + *
    4.22 + * @author Jaroslav Tulach
    4.23 + */
    4.24 +public class View extends JComponent {
    4.25 +    /** fence size */
    4.26 +    private final static int SIZE_FENCE = 20;
    4.27 +    private final static int SIZE_FIELD = 50;
    4.28 +    
    4.29 +    private static final java.awt.Color[] PLAYER_COLORS = {
    4.30 +        java.awt.Color.WHITE,
    4.31 +        java.awt.Color.BLACK,
    4.32 +        java.awt.Color.RED,
    4.33 +        java.awt.Color.BLUE,
    4.34 +    };
    4.35 +    
    4.36 +    /** board to view */
    4.37 +    private Board board = Board.createEmptyBoard ();
    4.38 +    {
    4.39 +        try {
    4.40 +            board = board.fence (board.getPlayers ().get (0), 'A', 5, Board.Fence.Orientation.HORIZONTAL);
    4.41 +            board = board.fence (board.getPlayers ().get (0), 'A', 6, Board.Fence.Orientation.VERTICAL);
    4.42 +            board = board.fence (board.getPlayers ().get (0), 'C', 5, Board.Fence.Orientation.HORIZONTAL);
    4.43 +        } catch (IllegalPositionException ex) {
    4.44 +            ex.printStackTrace();
    4.45 +        }
    4.46 +    }
    4.47 +    /** number of player that can do the move */
    4.48 +    private int onMove;
    4.49 +    private Listener listener;
    4.50 +    /** non-null if we do drag and is the delta of the lefttop corner 
    4.51 +     * from the position of the mouse */
    4.52 +    private Point dragDelta;
    4.53 +    /** draw circle */
    4.54 +    private Point move;
    4.55 +    
    4.56 +    /** Creates a new instance of View */
    4.57 +    public View () {
    4.58 +        int s = (SIZE_FIELD + SIZE_FENCE) * 9;
    4.59 +        
    4.60 +        setPreferredSize (new Dimension (s, s));
    4.61 +        setBackground (java.awt.Color.GRAY.darker ().darker ());
    4.62 +        
    4.63 +        listener = new Listener ();
    4.64 +        addMouseListener(listener);
    4.65 +        addMouseMotionListener(listener);
    4.66 +    }
    4.67 +
    4.68 +    protected void paintComponent (java.awt.Graphics g) {
    4.69 +        Graphics2D g2 = (Graphics2D)g;
    4.70 +        
    4.71 +        g.setColor (getBackground ());
    4.72 +        g.fillRect (0, 0, getSize ().width, getSize ().height);
    4.73 +        
    4.74 +        // draw the empty boards
    4.75 +        g.setColor (java.awt.Color.GRAY);
    4.76 +        for (int i = 0; i < 9; i++) {
    4.77 +            for (int j = 0; j < 9; j++) {
    4.78 +                g.fillRect (
    4.79 +                    i * (SIZE_FIELD + SIZE_FENCE) + SIZE_FENCE / 2, 
    4.80 +                    j * (SIZE_FIELD + SIZE_FENCE) + SIZE_FENCE / 2, 
    4.81 +                    SIZE_FIELD, 
    4.82 +                    SIZE_FIELD
    4.83 +                );
    4.84 +            }        }
    4.85 +        
    4.86 +        // draw fences
    4.87 +        g.setColor (java.awt.Color.YELLOW.darker ());
    4.88 +        for (Board.Fence f : board.getFences ()) {
    4.89 +            Point b = findFence(f);
    4.90 +            switch (f.getOrientation ()) {
    4.91 +                case HORIZONTAL:
    4.92 +                    g.fillRect (b.x - SIZE_FIELD + 1, b.y + 1, SIZE_FIELD * 2 + SIZE_FENCE - 2, SIZE_FENCE - 2);
    4.93 +                    break;
    4.94 +                case VERTICAL:
    4.95 +                    g.fillRect (b.x + 1, b.y - SIZE_FIELD + 1, SIZE_FENCE - 2, SIZE_FIELD * 2 + SIZE_FENCE - 2);
    4.96 +                    break;
    4.97 +            }
    4.98 +        }
    4.99 +        
   4.100 +        int pindex = 0;
   4.101 +        for (Board.Player p : board.getPlayers ()) {
   4.102 +            Point place = findPlayer (p);
   4.103 +
   4.104 +            g.setColor (PLAYER_COLORS[pindex++]);
   4.105 +            g.fillArc (place.x, place.y, SIZE_FIELD, SIZE_FIELD, 0, 360);
   4.106 +            
   4.107 +        }
   4.108 +        if (move != null) {
   4.109 +            g.setColor (PLAYER_COLORS[onMove]);
   4.110 +            g.drawArc(move.x, move.y, SIZE_FIELD, SIZE_FIELD, 0, 360);
   4.111 +        }
   4.112 +    }
   4.113 +    
   4.114 +    /** Tries to move a player to given coordinates.
   4.115 +     */
   4.116 +    final Board tryMove (int player, int newX, int newY) {
   4.117 +        Point p = findPlayer (board.getPlayers().get (player));
   4.118 +
   4.119 +        int cmpX = compare (p.x, SIZE_FIELD, newX);
   4.120 +        int cmpY = compare (p.y, SIZE_FIELD, newY);
   4.121 +        
   4.122 +        if (cmpX == 0 && cmpY == 0) {
   4.123 +            return null;
   4.124 +        }
   4.125 +        try {
   4.126 +            if (cmpX == 0) {
   4.127 +                if (cmpY < 0 && cmpY > -3) {
   4.128 +                    return board.move (board.getPlayers().get (player), Board.Player.Direction.SOUTH);
   4.129 +                } 
   4.130 +                if (cmpY > 0 && cmpY < 3) {
   4.131 +                    return board.move (board.getPlayers().get (player), Board.Player.Direction.NORTH);
   4.132 +                }
   4.133 +                return null;
   4.134 +            }
   4.135 +
   4.136 +            if (cmpY == 0) {
   4.137 +                if (cmpX < 0 && cmpX > -3) {
   4.138 +                    return board.move (board.getPlayers().get (player), Board.Player.Direction.WEST);
   4.139 +                } 
   4.140 +                if (cmpX > 0 && cmpX < 3) {
   4.141 +                    return board.move (board.getPlayers().get (player), Board.Player.Direction.EAST);
   4.142 +                }
   4.143 +                return null;
   4.144 +            }
   4.145 +        } catch (IllegalPositionException ex) {
   4.146 +            return null;
   4.147 +        }
   4.148 +        
   4.149 +        return null;
   4.150 +    }
   4.151 +    
   4.152 +    private static int compare (int from, int length, int where) {
   4.153 +        return (where - from) / length;
   4.154 +    }
   4.155 +    
   4.156 +    /** computes middle point of a fence.
   4.157 +     */
   4.158 +    final Point findFence (Board.Fence f) {
   4.159 +        int bx = (f.getX () / 2 + 1) * (SIZE_FIELD + SIZE_FENCE) - SIZE_FENCE;
   4.160 +        int by = (f.getY () / 2 + 1) * (SIZE_FIELD + SIZE_FENCE) - SIZE_FENCE;
   4.161 +        
   4.162 +        return new Point (bx + SIZE_FENCE / 2, by + SIZE_FENCE / 2);
   4.163 +    }
   4.164 +    
   4.165 +    /** For a player computes left-top point of its square.
   4.166 +     */
   4.167 +    final Point findPlayer (Board.Player p) {
   4.168 +        int px = (p.getX () / 2 + 0) * (SIZE_FIELD + SIZE_FENCE);
   4.169 +        int py = (p.getY () / 2 + 0) * (SIZE_FIELD + SIZE_FENCE);
   4.170 +        
   4.171 +        return new Point (px + SIZE_FENCE / 2, py + SIZE_FENCE / 2);
   4.172 +    }
   4.173 +    
   4.174 +    /** Finds if the click on the component is activates a player.
   4.175 +     * @return null if not
   4.176 +     */
   4.177 +    final Board.Player findPlayer (int x, int y) {
   4.178 +        for (Board.Player p : board.getPlayers ()) {
   4.179 +            Point z = findPlayer(p);
   4.180 +
   4.181 +            if (
   4.182 +                z.x < x && x < z.x + SIZE_FIELD &&
   4.183 +                z.y < y && y < z.y + SIZE_FIELD
   4.184 +            ) {
   4.185 +                return p;
   4.186 +            }
   4.187 +        }
   4.188 +        return null;
   4.189 +    }
   4.190 +
   4.191 +    private final class Listener implements MouseListener, MouseMotionListener {
   4.192 +        public void mouseClicked(java.awt.event.MouseEvent mouseEvent) {
   4.193 +        }
   4.194 +
   4.195 +        public void mouseEntered(java.awt.event.MouseEvent mouseEvent) {
   4.196 +        }
   4.197 +
   4.198 +        public void mouseExited(java.awt.event.MouseEvent mouseEvent) {
   4.199 +        }
   4.200 +
   4.201 +        public void mousePressed(java.awt.event.MouseEvent mouseEvent) {
   4.202 +            Board.Player p = board.getPlayers ().get (onMove);
   4.203 +            Board.Player clicked = findPlayer (mouseEvent.getX (), mouseEvent.getY ());
   4.204 +            
   4.205 +            if (p.equals (clicked)) {
   4.206 +                // start drag
   4.207 +                Point delta = findPlayer (p);
   4.208 +                delta.x = mouseEvent.getX () - delta.x;
   4.209 +                delta.y = mouseEvent.getY () - delta.y;
   4.210 +                dragDelta = delta;
   4.211 +                repaint();
   4.212 +            }
   4.213 +        }
   4.214 +
   4.215 +        public void mouseReleased(java.awt.event.MouseEvent mouseEvent) {
   4.216 +            Board newBoard = tryMove (onMove, mouseEvent.getX(), mouseEvent.getY());
   4.217 +            if (newBoard != null) {
   4.218 +                board = newBoard;
   4.219 +                onMove = (onMove + 1) % newBoard.getPlayers().size();
   4.220 +            }
   4.221 +            dragDelta = null;
   4.222 +            move = null;
   4.223 +            repaint();
   4.224 +        }
   4.225 +
   4.226 +        public void mouseMoved(MouseEvent e) {
   4.227 +        }
   4.228 +
   4.229 +        public void mouseDragged(MouseEvent e) {
   4.230 +            if (dragDelta != null) {
   4.231 +                move = new Point (e.getX () - dragDelta.x, e.getY () - dragDelta.y);
   4.232 +                repaint ();
   4.233 +            }
   4.234 +        }
   4.235 +        
   4.236 +    }
   4.237 +    
   4.238 +    
   4.239 +    public static void main (String[] args) {
   4.240 +        javax.swing.JFrame f = new javax.swing.JFrame ();
   4.241 +        View v = new View ();
   4.242 +        f.getContentPane ().add (BorderLayout.CENTER, v);
   4.243 +        f.setDefaultCloseOperation (f.EXIT_ON_CLOSE);
   4.244 +        f.pack ();
   4.245 +        f.setVisible (true);
   4.246 +    }
   4.247 +}
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/quoridor/src/test/java/cz/xelfi/quoridor/BoardTest.java	Sun May 10 20:15:24 2009 +0200
     5.3 @@ -0,0 +1,259 @@
     5.4 +/*
     5.5 + * BoardTest.java
     5.6 + * JUnit based test
     5.7 + *
     5.8 + * Created on 19. b�ezen 2005, 20:34
     5.9 + */
    5.10 +
    5.11 +package cz.xelfi.quoridor;
    5.12 +
    5.13 +import junit.framework.*;
    5.14 +
    5.15 +import cz.xelfi.quoridor.Board.*;
    5.16 +
    5.17 +/** Checks default setup of empty board.
    5.18 + *
    5.19 + * @author Jaroslav Tulach
    5.20 + */
    5.21 +public class BoardTest extends TestCase {
    5.22 +    
    5.23 +    private Board board;
    5.24 +    
    5.25 +    public BoardTest (String testName) {
    5.26 +        super (testName);
    5.27 +    }
    5.28 +
    5.29 +    @Override
    5.30 +    protected void setUp () throws Exception {
    5.31 +        board = Board.createEmptyBoard ();
    5.32 +    }
    5.33 +
    5.34 +    public void testTwoPlayers () {
    5.35 +        java.util.List<Player> list = board.getPlayers ();
    5.36 +        assertEquals ("Two", 2, list.size ());
    5.37 +        assertFalse ("Both are non-null", list.contains (null));
    5.38 +        try {
    5.39 +            list.add (null);
    5.40 +            fail ("Modifications are not allowed");
    5.41 +        } catch (UnsupportedOperationException ex) {
    5.42 +            // ok
    5.43 +        }
    5.44 +        try {
    5.45 +            list.remove (0);
    5.46 +            fail ("Modifications are not allowed");
    5.47 +        } catch (UnsupportedOperationException ex) {
    5.48 +            // ok
    5.49 +        }
    5.50 +        
    5.51 +        
    5.52 +        assertEquals (8, list.get (0).getX());
    5.53 +        assertEquals (0, list.get (0).getY());
    5.54 +        assertEquals (10, list.get (0).getFences ());
    5.55 +        assertEquals (8, list.get (1).getX());
    5.56 +        assertEquals (16, list.get (1).getY());
    5.57 +        assertEquals (10, list.get (1).getFences ());
    5.58 +    }
    5.59 +    
    5.60 +    public void testFences () {
    5.61 +        assertEquals ("No on board", 0, board.getFences ().size ());
    5.62 +        try {
    5.63 +            board.getFences ().add (null);
    5.64 +            fail ("Should be unmodifiable");
    5.65 +        } catch (java.lang.UnsupportedOperationException ex) {
    5.66 +            // ok
    5.67 +        }
    5.68 +    }
    5.69 +    
    5.70 +    public void testFourTimesInAgainstEachOtherResultsInInvalidPosition () throws Exception {
    5.71 +        Board b = board;
    5.72 +        
    5.73 +        for (int i = 0; i < 3; i++) {
    5.74 +            b = b.move (b.getPlayers ().get (0), Board.Player.Direction.NORTH);
    5.75 +            b = b.move (b.getPlayers ().get (1), Board.Player.Direction.SOUTH);
    5.76 +        }
    5.77 +        
    5.78 +        b = b.move (b.getPlayers ().get (0), Board.Player.Direction.NORTH);
    5.79 +        try {
    5.80 +            b = b.move (b.getPlayers ().get (1), Board.Player.Direction.SOUTH);
    5.81 +            fail ("Now the positions of two players are supposed to be the same, this results in exception");
    5.82 +        } catch (IllegalPositionException ex) {
    5.83 +            // ok
    5.84 +        }
    5.85 +        
    5.86 +    }
    5.87 +
    5.88 +    public void testCrossFences () throws Exception {
    5.89 +        Board b1 = board.fence (board.getPlayers ().get(0), 'A', 1, Board.Fence.Orientation.HORIZONTAL);
    5.90 +        
    5.91 +        try {
    5.92 +            b1.fence (b1.getPlayers ().get(1), 'A', 1, Board.Fence.Orientation.VERTICAL);
    5.93 +            fail ("This must fail, as the fences overlap");
    5.94 +        } catch (IllegalPositionException ex) {
    5.95 +            // ok
    5.96 +        }
    5.97 +    }
    5.98 +    
    5.99 +    public void testPawnsCanJumpOverEachOther () throws Exception {
   5.100 +        Board b = board;
   5.101 +        
   5.102 +        for (int i = 0; i < 3; i++) {
   5.103 +            b = b.move (b.getPlayers ().get (0), Board.Player.Direction.NORTH);
   5.104 +            b = b.move (b.getPlayers ().get (1), Board.Player.Direction.SOUTH);
   5.105 +        }
   5.106 +        
   5.107 +        b = b.move (b.getPlayers ().get (0), Board.Player.Direction.NORTH);
   5.108 +        
   5.109 +        // jump over
   5.110 +        b = b.move (b.getPlayers ().get (1), Board.Player.Direction.SOUTH, Board.Player.Direction.SOUTH);
   5.111 +    }
   5.112 +
   5.113 +    public void testCannotJumpOverFence () throws Exception {
   5.114 +        Board b = board.fence (board.getPlayers ().get (0), 'D', 8, Board.Fence.Orientation.HORIZONTAL);
   5.115 +        try {
   5.116 +            b.move (board.getPlayers ().get (1), Player.Direction.SOUTH);
   5.117 +            fail ("This shall not be allowed, as there is the fence");
   5.118 +        } catch (IllegalPositionException ex) {
   5.119 +            // ok
   5.120 +        }
   5.121 +    }
   5.122 +    
   5.123 +
   5.124 +    public void testSideJumpsNotAllowedWhenThereIsNoFence () throws Exception {
   5.125 +        Board b = board;
   5.126 +        
   5.127 +        for (int i = 0; i < 3; i++) {
   5.128 +            b = b.move (b.getPlayers ().get (0), Board.Player.Direction.NORTH);
   5.129 +            b = b.move (b.getPlayers ().get (1), Board.Player.Direction.SOUTH);
   5.130 +        }
   5.131 +        
   5.132 +        b = b.move (b.getPlayers ().get (0), Board.Player.Direction.NORTH);
   5.133 +        
   5.134 +        try {
   5.135 +            b = b.move (b.getPlayers ().get (1), Board.Player.Direction.SOUTH, Board.Player.Direction.WEST);
   5.136 +            fail ("Cannot just jump aside");
   5.137 +        } catch (IllegalPositionException ex) {
   5.138 +            // ok
   5.139 +        }
   5.140 +    }
   5.141 +    
   5.142 +    public void testSideJumpsAllowedWhenThereAFence () throws Exception {
   5.143 +        Board b = board;
   5.144 +        
   5.145 +        for (int i = 0; i < 3; i++) {
   5.146 +            b = b.move (b.getPlayers ().get (0), Board.Player.Direction.NORTH);
   5.147 +            b = b.move (b.getPlayers ().get (1), Board.Player.Direction.SOUTH);
   5.148 +        }
   5.149 +        
   5.150 +        b = b.move (b.getPlayers ().get (0), Board.Player.Direction.NORTH);
   5.151 +        
   5.152 +        assertEquals (8, b.getPlayers ().get (0).getX ());
   5.153 +        assertEquals (8, b.getPlayers ().get (0).getY ());
   5.154 +        
   5.155 +        b = b.fence(b.getPlayers ().get (0), 'D', 4, Board.Fence.Orientation.HORIZONTAL);
   5.156 +        
   5.157 +        // we can over jump to west
   5.158 +        b.move (b.getPlayers ().get (1), Board.Player.Direction.SOUTH, Board.Player.Direction.WEST);
   5.159 +        // as well as east
   5.160 +        b.move (b.getPlayers ().get (1), Board.Player.Direction.SOUTH, Board.Player.Direction.EAST);
   5.161 +    }
   5.162 +    
   5.163 +    public void testAlwaysHasToHaveAccessToEndLine () throws Exception {
   5.164 +        Board b = board;
   5.165 +        
   5.166 +        b = b.fence (b.getPlayers ().get (0), 'E', 1, Board.Fence.Orientation.HORIZONTAL);
   5.167 +        b = b.fence (b.getPlayers ().get (0), 'F', 1, Board.Fence.Orientation.VERTICAL);
   5.168 +
   5.169 +        try {
   5.170 +            b = b.fence (b.getPlayers ().get (0), 'D', 1, Board.Fence.Orientation.VERTICAL);
   5.171 +            fail ("This is not allowed as player 0 cannot now reach the final line");
   5.172 +        } catch (IllegalPositionException ex) {
   5.173 +            // ok
   5.174 +        }
   5.175 +        
   5.176 +    }
   5.177 +    
   5.178 +    public void testEqualsOfPlayers () throws Exception {
   5.179 +        Board.Player p1 = new Board.Player (1, 1, 10, Board.Player.Direction.EAST);
   5.180 +        Board.Player p2 = new Board.Player (1, 1, 10, Board.Player.Direction.EAST);
   5.181 +        Board.Player p3 = new Board.Player (2, 1, 10, Board.Player.Direction.EAST);
   5.182 +        Board.Player p4 = new Board.Player (1, 1, 10, Board.Player.Direction.WEST);
   5.183 +        Board.Player p5 = new Board.Player (1, 2, 10, Board.Player.Direction.EAST);
   5.184 +        Board.Player p6 = new Board.Player (1, 1, 5, Board.Player.Direction.EAST);
   5.185 +        
   5.186 +        assertEquals ("p1 == p2", p1, p2);
   5.187 +        if (p2.equals (p3)) fail ();
   5.188 +        if (p2.equals (p4)) fail ();
   5.189 +        if (p2.equals (p5)) fail ();
   5.190 +        if (p2.equals (p6)) fail ();
   5.191 +        if (p3.equals (p6)) fail ();
   5.192 +        if (p4.equals (p3)) fail ();
   5.193 +        if (p6.equals (p3)) fail ();
   5.194 +        if (p5.equals (p3)) fail ();
   5.195 +        if (p5.equals (p3)) fail ();
   5.196 +        if (p4.equals (p3)) fail ();
   5.197 +        if (p3.equals (p4)) fail ();
   5.198 +        if (p3.equals (p5)) fail ();
   5.199 +        if (p4.equals (p5)) fail ();
   5.200 +        if (p5.equals (p4)) fail ();
   5.201 +        if (p5.equals ("Ahoj")) fail ();
   5.202 +    }
   5.203 +    
   5.204 +    public void testEqualsOfFences () throws Exception {
   5.205 +        Board.Fence f1 = new Board.Fence (1, 1, Board.Fence.Orientation.HORIZONTAL);
   5.206 +        Board.Fence f2 = new Board.Fence (1, 1, Board.Fence.Orientation.HORIZONTAL);
   5.207 +        Board.Fence f3 = new Board.Fence (3, 1, Board.Fence.Orientation.HORIZONTAL);
   5.208 +        Board.Fence f4 = new Board.Fence (1, 3, Board.Fence.Orientation.HORIZONTAL);
   5.209 +        Board.Fence f5 = new Board.Fence (1, 1, Board.Fence.Orientation.VERTICAL);
   5.210 +        
   5.211 +        assertEquals ("f1 == f2", f1, f2);
   5.212 +        if (f1.equals (f3)) fail ();
   5.213 +        if (f3.equals (f1)) fail ();
   5.214 +        if (f5.equals (f1)) fail ();
   5.215 +        if (f1.equals (f5)) fail ();
   5.216 +        if (f4.equals (f1)) fail ();
   5.217 +        if (f1.equals (f4)) fail ();
   5.218 +    }
   5.219 +    
   5.220 +    public void testEqualsOfBoards1 () throws Exception {
   5.221 +        Board b1 = board.move (board.getPlayers ().get (0), Board.Player.Direction.NORTH);
   5.222 +        Board b2 = board.move (board.getPlayers ().get (0), Board.Player.Direction.NORTH);
   5.223 +        Board b3 = board.move (board.getPlayers ().get (0), Board.Player.Direction.EAST);
   5.224 +        
   5.225 +        if (b1.equals (b3)) fail ();
   5.226 +        if (b3.equals (b1)) fail ();
   5.227 +        
   5.228 +        assertEquals ("b1 == b2", b1, b2);
   5.229 +    }
   5.230 +    public void testEqualsOfBoards2 () throws Exception {
   5.231 +        Board b1 = board.fence (board.getPlayers ().get (0), 'E', 3, Board.Fence.Orientation.HORIZONTAL);
   5.232 +        Board b2 = board.fence (board.getPlayers ().get (0), 'E', 3, Board.Fence.Orientation.HORIZONTAL);
   5.233 +        Board b3 = board.fence (board.getPlayers ().get (0), 'D', 3, Board.Fence.Orientation.HORIZONTAL);
   5.234 +        Board b4 = board.fence (board.getPlayers ().get (0), 'E', 4, Board.Fence.Orientation.HORIZONTAL);
   5.235 +        Board b5 = board.fence (board.getPlayers ().get (0), 'E', 3, Board.Fence.Orientation.VERTICAL);
   5.236 +        
   5.237 +        if (b1.equals (b3)) fail ();
   5.238 +        if (b3.equals (b1)) fail ();
   5.239 +        if (b1.equals (b4)) fail ();
   5.240 +        if (b1.equals (b5)) fail ();
   5.241 +        if (b5.equals (b1)) fail ();
   5.242 +        if (b4.equals (b1)) fail ();
   5.243 +        
   5.244 +        assertEquals ("b1 == b2", b1, b2);
   5.245 +    }
   5.246 +    public void testEqualsOfBoardsWhenJumpOver () throws Exception {
   5.247 +        Board b = board;
   5.248 +        
   5.249 +        for (int i = 0; i < 3; i++) {
   5.250 +            b = b.move (b.getPlayers ().get (0), Board.Player.Direction.NORTH);
   5.251 +            b = b.move (b.getPlayers ().get (1), Board.Player.Direction.SOUTH);
   5.252 +        }
   5.253 +        
   5.254 +        Board b1 = b.move (b.getPlayers ().get (0), Board.Player.Direction.NORTH);
   5.255 +        
   5.256 +        Board b2 = b.move (b.getPlayers ().get (1), Board.Player.Direction.SOUTH);
   5.257 +        b2 = b2.move (b2.getPlayers ().get (0), Board.Player.Direction.NORTH, Board.Player.Direction.NORTH);
   5.258 +        
   5.259 +        if (b1.equals (b2)) fail ("Not the same, pawns are reverted");
   5.260 +        if (b2.equals (b1)) fail ("Not the same, pawns are reverted");
   5.261 +    }
   5.262 +}