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.Fence.Orientation;
21 import cz.xelfi.quoridor.Player.Direction;
22 import java.io.IOException;
23 import java.io.StringReader;
24 import java.io.StringWriter;
25 import java.util.List;
26 import junit.framework.TestCase;
30 * @author Jaroslav Tulach <jtulach@netbeans.org>
32 public abstract class BoardCase extends TestCase {
33 protected Board board;
35 protected BoardCase(String n) {
37 board = Board.empty();
40 protected abstract Board move(Board b, int player, Player.Direction... where)
41 throws IllegalPositionException;
43 protected abstract Board fence(Board b, int player, char x, int y, Fence.Orientation orie)
44 throws IllegalPositionException;
46 protected abstract Board apply(Board b, Move move) throws IllegalPositionException;
49 public void testResignWhite() throws IllegalPositionException {
50 List<Player> list = board.getPlayers();
51 assertEquals ("Two", 2, list.size ());
52 Board b = board.apply(Move.RESIGN);
53 assertEquals(b.getPlayers().get(1), b.getWinner());
56 fail("No more moves allowed, the player resigned");
57 } catch (IllegalPositionException ex) {
60 assertNull("No player", b.getCurrentPlayer());
62 public void testResignBlack() throws IllegalPositionException {
63 List<Player> list = board.getPlayers();
64 assertEquals ("Two", 2, list.size ());
65 Board b = board.apply(Move.NORTH).apply(Move.RESIGN);
66 assertEquals(b.getPlayers().get(0), b.getWinner());
69 fail("No more moves allowed, the player resigned");
70 } catch (IllegalPositionException ex) {
73 assertNull("No player", b.getCurrentPlayer());
75 public void testTwoPlayers () {
76 List<Player> list = board.getPlayers();
77 assertEquals ("Two", 2, list.size ());
78 assertFalse ("Both are non-null", list.contains (null));
81 fail ("Modifications are not allowed");
82 } catch (UnsupportedOperationException ex) {
87 fail ("Modifications are not allowed");
88 } catch (UnsupportedOperationException ex) {
93 assertEquals (8, list.get (0).getXInternal());
94 assertEquals (0, list.get (0).getYInternal());
95 assertEquals (10, list.get (0).getFences ());
96 assertEquals (8, list.get (1).getXInternal());
97 assertEquals (16, list.get (1).getYInternal());
98 assertEquals (10, list.get (1).getFences ());
101 public void testFences () throws IllegalPositionException {
102 assertEquals ("No on board", 0, board.getFences ().size ());
104 board.getFences ().add (null);
105 fail ("Should be unmodifiable");
106 } catch (java.lang.UnsupportedOperationException ex) {
111 Board b = board.apply(Move.fence('A', 1, Orientation.HORIZONTAL));
112 assertEquals("One fence placed: ", 1, b.getFences().size());
113 Fence f = b.getFences().iterator().next();
114 assertEquals("Row", 1, f.getRow());
115 assertEquals("Column", 'A', f.getColumn());
119 Board b = board.apply(Move.fence('A', 1, Orientation.VERTICAL));
120 assertEquals("One fence placed: ", 1, b.getFences().size());
121 Fence f = b.getFences().iterator().next();
122 assertEquals("Row", 1, f.getRow());
123 assertEquals("Column", 'A', f.getColumn());
127 Board b = board.apply(Move.fence('H', 8, Orientation.HORIZONTAL));
128 assertEquals("One fence placed: ", 1, b.getFences().size());
129 Fence f = b.getFences().iterator().next();
130 assertEquals("Row", 8, f.getRow());
131 assertEquals("Column", 'H', f.getColumn());
135 Board b = board.apply(Move.fence('H', 8, Orientation.VERTICAL));
136 assertEquals("One fence placed: ", 1, b.getFences().size());
137 Fence f = b.getFences().iterator().next();
138 assertEquals("Row", 8, f.getRow());
139 assertEquals("Column", 'H', f.getColumn());
142 public void testTwoFencesInTheSamePosition() throws IllegalPositionException {
143 assertEquals ("No on board", 0, board.getFences ().size ());
144 Board one = board.apply(Move.fence('A', 1, Orientation.HORIZONTAL));
146 Board snd = one.apply(Move.fence('A', 1, Orientation.HORIZONTAL));
147 fail("Cannot place fence twice to the same place");
148 } catch (IllegalPositionException ex) {
153 public void testSelfDestructionForbidden() throws Exception {
156 b = fence(b, 0, 'D', 1, Orientation.VERTICAL);
157 b = move(b, 1, Player.Direction.SOUTH);
158 b = fence(b, 0, 'E', 1, Orientation.VERTICAL);
159 b = move(b, 1, Player.Direction.SOUTH);
161 b = fence(b, 0, 'E', 2, Orientation.HORIZONTAL);
162 fail ("Forbidden. Player 0 has no way to reach the end");
163 } catch (IllegalPositionException ex) {
168 public void testRealSelfDestructionForbidden() throws Exception {
172 " A B C D E F G H\n" +
173 " | | | | | | | |\n" +
174 " +*----------------------------------+\n" +
176 " 8--|-------+-------+-------+-------+ |--8\n" +
178 " 7--| + + + |-------+ | + |--7\n" +
180 " 6--| + + + + + | + + |--6\n" +
182 " 5--| + + + + |-------+ + |--5\n" +
184 " 4--| + + + + +-------+ + |--4\n" +
186 " 3--| + + + + + + | | |--3\n" +
188 " 2--| + + + + + + + + |--2\n" +
190 " 1--| + + + + + | +-------|--1\n" +
192 " +||||-------------------------------+\n" +
193 " | | | | | | | |\n" +
194 " A B C D E F G H\n" +
198 b = picture2board(b).toString();
199 Board begin = Board.valueOf(b);
202 Board bad = fence(begin, 0, 'G', 2, Orientation.HORIZONTAL);
203 fail("Not allowed move:\n" + bad.toString());
204 } catch (IllegalPositionException ex) {
208 public void testFourTimesInAgainstEachOtherResultsInInvalidPosition () throws Exception {
211 for (int i = 0; i < 3; i++) {
212 b = move(b, 0, Player.Direction.NORTH);
213 b = move(b, 1, Player.Direction.SOUTH);
216 b = move(b, 0, Player.Direction.NORTH);
218 b = move(b, 1, Player.Direction.SOUTH);
219 fail ("Now the positions of two players are supposed to be the same, this results in exception");
220 } catch (IllegalPositionException ex) {
225 public void testCanNorth() {
226 Move m = board.findMove(board.getCurrentPlayer(), 4, 1);
227 assertEquals("Go north", Move.NORTH, m);
229 public void testCanEast() {
230 Move m = board.findMove(board.getCurrentPlayer(), 5, 0);
231 assertEquals("Go east", Move.EAST, m);
233 public void testCanWest() {
234 Move m = board.findMove(board.getCurrentPlayer(), 3, 0);
235 assertEquals("Go west", Move.WEST, m);
237 public void testCannotWestAndNorth() {
238 Move m = board.findMove(board.getCurrentPlayer(), 3, 1);
239 assertNull("No way", m);
241 public void testCanJumpStraight () throws Exception {
244 for (int i = 0; i < 3; i++) {
245 b = move(b, 0, Player.Direction.NORTH);
246 b = move(b, 1, Player.Direction.SOUTH);
248 b = apply(b, Move.NORTH);
249 Move m = b.findMove(b.getPlayers().get(0), 4, 6);
250 assertEquals("N+N", Move.jump(Direction.NORTH, Direction.NORTH), m);
252 public void testCanJumSptraightAndTurn () throws Exception {
255 for (int i = 0; i < 3; i++) {
256 b = move(b, 0, Player.Direction.NORTH);
257 b = move(b, 1, Player.Direction.SOUTH);
259 b = apply(b, Move.fence('A', 1, Orientation.HORIZONTAL));
260 b = apply(b, Move.SOUTH);
261 b = apply(b, Move.fence('D', 5, Orientation.HORIZONTAL));
262 b = apply(b, Move.fence('A', 8, Orientation.HORIZONTAL));
264 Move m = b.findMove(b.getCurrentPlayer(), 4, 5);
265 assertNull("No N+N", m);
266 m = b.findMove(b.getCurrentPlayer(), 5, 4);
267 assertEquals("N+E is OK", Move.jump(Direction.NORTH, Direction.EAST), m);
270 public void testCrossFences () throws Exception {
271 Board b1 = board.fence (board.getPlayers ().get(0), 'A', 1, Fence.Orientation.HORIZONTAL);
274 b1.fence (b1.getPlayers ().get(1), 'A', 1, Fence.Orientation.VERTICAL);
275 fail ("This must fail, as the fences overlap");
276 } catch (IllegalPositionException ex) {
281 public void testPawnsCanJumpOverEachOther () throws Exception {
284 for (int i = 0; i < 3; i++) {
285 b = move(b, 0, Player.Direction.NORTH);
286 b = move(b, 1, Player.Direction.SOUTH);
289 b = move(b, 0, Player.Direction.NORTH);
292 b = move(b, 1, Player.Direction.SOUTH, Player.Direction.SOUTH);
295 public void testJumpBackForbidden() throws Exception {
298 for (int i = 0; i < 3; i++) {
299 b = move(b, 0, Player.Direction.NORTH);
300 b = move(b, 1, Player.Direction.SOUTH);
303 b = move(b, 0, Player.Direction.NORTH);
305 b = fence(b, 1, 'D', 6, Orientation.HORIZONTAL);
308 b = move(b, 0, Player.Direction.NORTH, Player.Direction.NORTH);
309 fail("Can't jump over a pawn when there is a fence");
310 } catch (IllegalPositionException ex) {
315 b = move(b, 0, Player.Direction.NORTH, Player.Direction.SOUTH);
316 fail("Can't bounce from the fence back neither");
317 } catch (IllegalPositionException ex) {
322 public void testCannotJumpOverFence () throws Exception {
323 Board b = fence (board, 0, 'D', 8, Fence.Orientation.HORIZONTAL);
324 assertEquals("One fence is present", 1, b.getFences().size());
325 final Fence f = b.getFences().iterator().next();
326 assertEquals("Row is 8", 8, f.getRow());
327 assertEquals("Column is D", 'D', f.getColumn());
329 move(b, 1, Player.Direction.SOUTH);
330 fail ("This shall not be allowed, as there is the fence");
331 } catch (IllegalPositionException ex) {
337 public void testSideJumpsNotAllowedWhenThereIsNoFence () throws Exception {
340 for (int i = 0; i < 3; i++) {
341 b = move(b, 0, Player.Direction.NORTH);
342 b = move(b, 1, Player.Direction.SOUTH);
345 b = move(b, 0, Player.Direction.NORTH);
348 b = move(b, 1, Player.Direction.SOUTH, Player.Direction.WEST);
349 fail ("Cannot just jump aside");
350 } catch (IllegalPositionException ex) {
355 public void testSideJumpsAllowedWhenThereAFence () throws Exception {
358 for (int i = 0; i < 3; i++) {
359 b = move(b, 0, Player.Direction.NORTH);
360 b = move(b, 1, Player.Direction.SOUTH);
363 b = move(b, 0, Player.Direction.NORTH);
365 assertEquals (8, b.getPlayers ().get (0).getXInternal());
366 assertEquals (8, b.getPlayers ().get (0).getYInternal());
368 b = fence(b, 0, 'D', 4, Fence.Orientation.HORIZONTAL);
370 // we can over jump to west
371 move(b, 1, Player.Direction.SOUTH, Player.Direction.WEST);
373 move(b, 1, Player.Direction.SOUTH, Player.Direction.EAST);
376 public void testPlaceAllFences() throws Exception {
379 public void testPlaceAllFences2() throws Exception {
383 private void doPlaceAllFences(int player) throws Exception {
387 for (int i = 1; i <= 5; i++) {
388 b = fence(b, player, 'A', i, Fence.Orientation.HORIZONTAL);
389 b = fence(b, player, 'D', i, Fence.Orientation.HORIZONTAL);
391 assertEquals("Two less" + i, cnt, b.getPlayers().get(player).getFences());
395 fence(b, player, 'F', 7, Fence.Orientation.VERTICAL);
396 fail("We shall run out of fences");
397 } catch (IllegalPositionException ex) {
402 public void testAlwaysHasToHaveAccessToEndLine () throws Exception {
405 b = b.fence (b.getPlayers ().get (0), 'E', 1, Fence.Orientation.HORIZONTAL);
406 b = b.fence (b.getPlayers ().get (0), 'F', 1, Fence.Orientation.VERTICAL);
409 b = b.fence (b.getPlayers ().get (0), 'D', 1, Fence.Orientation.VERTICAL);
410 fail ("This is not allowed as player 0 cannot now reach the final line");
411 } catch (IllegalPositionException ex) {
417 public void testEqualsOfPlayers () throws Exception {
418 Player p1 = new Player (1, 1, 10, Player.Direction.EAST);
419 Player p2 = new Player (1, 1, 10, Player.Direction.EAST);
420 Player p3 = new Player (2, 1, 10, Player.Direction.EAST);
421 Player p4 = new Player (1, 1, 10, Player.Direction.WEST);
422 Player p5 = new Player (1, 2, 10, Player.Direction.EAST);
423 Player p6 = new Player (1, 1, 5, Player.Direction.EAST);
425 assertEquals ("p1 == p2", p1, p2);
426 if (p2.equals (p3)) fail ();
427 if (p2.equals (p4)) fail ();
428 if (p2.equals (p5)) fail ();
429 if (p2.equals (p6)) fail ();
430 if (p3.equals (p6)) fail ();
431 if (p4.equals (p3)) fail ();
432 if (p6.equals (p3)) fail ();
433 if (p5.equals (p3)) fail ();
434 if (p5.equals (p3)) fail ();
435 if (p4.equals (p3)) fail ();
436 if (p3.equals (p4)) fail ();
437 if (p3.equals (p5)) fail ();
438 if (p4.equals (p5)) fail ();
439 if (p5.equals (p4)) fail ();
442 public void testEqualsOfFences () throws Exception {
443 Fence f1 = new Fence (1, 1, Fence.Orientation.HORIZONTAL);
444 Fence f2 = new Fence (1, 1, Fence.Orientation.HORIZONTAL);
445 Fence f3 = new Fence (3, 1, Fence.Orientation.HORIZONTAL);
446 Fence f4 = new Fence (1, 3, Fence.Orientation.HORIZONTAL);
447 Fence f5 = new Fence (1, 1, Fence.Orientation.VERTICAL);
449 assertEquals ("f1 == f2", f1, f2);
450 if (f1.equals (f3)) fail ();
451 if (f3.equals (f1)) fail ();
452 if (f5.equals (f1)) fail ();
453 if (f1.equals (f5)) fail ();
454 if (f4.equals (f1)) fail ();
455 if (f1.equals (f4)) fail ();
458 public void testEqualsOfBoards1 () throws Exception {
459 Board b1 = board.move (board.getPlayers ().get (0), Player.Direction.NORTH);
460 Board b2 = board.move (board.getPlayers ().get (0), Player.Direction.NORTH);
461 Board b3 = board.move (board.getPlayers ().get (0), Player.Direction.EAST);
463 if (b1.equals (b3)) fail ();
464 if (b3.equals (b1)) fail ();
466 assertEquals ("b1 == b2", b1, b2);
468 public void testEqualsOfBoards2 () throws Exception {
469 Board b1 = board.fence (board.getPlayers ().get (0), 'E', 3, Fence.Orientation.HORIZONTAL);
470 Board b2 = board.fence (board.getPlayers ().get (0), 'E', 3, Fence.Orientation.HORIZONTAL);
471 Board b3 = board.fence (board.getPlayers ().get (0), 'D', 3, Fence.Orientation.HORIZONTAL);
472 Board b4 = board.fence (board.getPlayers ().get (0), 'E', 4, Fence.Orientation.HORIZONTAL);
473 Board b5 = board.fence (board.getPlayers ().get (0), 'E', 3, Fence.Orientation.VERTICAL);
475 if (b1.equals (b3)) fail ();
476 if (b3.equals (b1)) fail ();
477 if (b1.equals (b4)) fail ();
478 if (b1.equals (b5)) fail ();
479 if (b5.equals (b1)) fail ();
480 if (b4.equals (b1)) fail ();
482 assertEquals ("b1 == b2", b1, b2);
484 public void testEqualsOfBoardsWhenJumpOver () throws Exception {
487 for (int i = 0; i < 3; i++) {
488 b = move(b, 0, Player.Direction.NORTH);
489 b = move(b, 1, Player.Direction.SOUTH);
492 Board b1 = move(b, 0, Player.Direction.NORTH);
494 Board b2 = move(b, 1, Player.Direction.SOUTH);
495 b2 = b2.move (b2.getPlayers ().get (0), Player.Direction.NORTH, Player.Direction.NORTH);
497 if (b1.equals (b2)) fail ("Not the same, pawns are reverted");
498 if (b2.equals (b1)) fail ("Not the same, pawns are reverted");
501 public void testMoveAltersCurrentPlayer() throws Exception {
502 assertEquals("First player ready", board.getCurrentPlayer(), board.getPlayers().get(0));
503 Board b = apply(board, Move.EAST);
505 for (int i = 0; i < 7; i++) {
506 assertEquals("Snd player ready", b.getCurrentPlayer(), b.getPlayers().get(1));
507 b = apply(b, Move.SOUTH);
508 assertEquals("First player ready", b.getCurrentPlayer(), b.getPlayers().get(0));
509 b = apply(b, Move.NORTH);
512 Board fin = b.apply(Move.NORTH).apply(Move.NORTH);
513 assertNotNull("There is a winner", fin.getWinner());
514 assertEquals("And the winner is", fin.getPlayers().get(0), fin.getWinner());
516 assertFalse("No next move can be applied", fin.isApplicable(Move.fence('D', 3, Fence.Orientation.HORIZONTAL)));
519 fin.apply(Move.EAST);
520 fail("No moves allow when we are in final position");
521 } catch (IllegalPositionException ex) {
527 public void testDetectInvalidFence() {
529 Move m = Move.fence('D', 9, Orientation.HORIZONTAL);
530 fail("Move shall not be allowed: " + m);
531 } catch (IllegalPositionException ex) {
536 public void testEqualityOfMoves() throws Exception {
538 for (Direction m1 : Direction.values()) {
539 for (Direction m2 : Direction.values()) {
540 Move both1 = Move.jump(m1, m2);
541 Move both2 = Move.jump(m1, m2);
542 Move opposite = Move.jump(m2, m1);
544 assertTrue("Both boths are equal", both1.equals(both2));
545 assertFalse("Not north", Move.NORTH.equals(both1));
546 assertFalse("Not east", Move.EAST.equals(both1));
547 assertFalse("Not west", Move.WEST.equals(both1));
548 assertFalse("Not south", Move.SOUTH.equals(both1));
552 assertFalse("Not equal to opposite", both1.equals(opposite));
556 Move f1 = Move.fence('D', 6, Orientation.HORIZONTAL);
557 Move f2 = Move.fence('D', 6, Orientation.HORIZONTAL);
558 Move f3 = Move.fence('D', 6, Orientation.VERTICAL);
559 Move f4 = Move.fence('E', 6, Orientation.VERTICAL);
560 Move f5 = Move.fence('E', 5, Orientation.VERTICAL);
562 assertEquals(f1, f2);
563 assertFalse(f1.equals(f3));
564 assertFalse(f4.equals(f5));
565 assertFalse(f3.equals(f5));
568 public void testBrokenWriteOfAGameDanVsJarda() throws Exception {
569 Board b = board.apply(Move.NORTH).apply(Move.SOUTH).
570 apply(Move.NORTH).apply(Move.SOUTH).
571 apply(Move.NORTH).apply(Move.SOUTH).
572 apply(Move.WEST).apply(Move.fence('C', 6, Orientation.HORIZONTAL)).
573 apply(Move.EAST).apply(Move.SOUTH).
574 apply(Move.fence('E', 2, Orientation.HORIZONTAL)).apply(Move.fence('E', 5, Orientation.HORIZONTAL)).
575 apply(Move.fence('F', 3, Orientation.VERTICAL)).apply(Move.fence('D', 6, Orientation.VERTICAL)).
576 apply(Move.jump(Direction.NORTH, Direction.EAST)).apply(Move.fence('F', 5, Orientation.VERTICAL)).
577 apply(Move.fence('E', 1, Orientation.VERTICAL)).apply(Move.fence('E', 4, Orientation.VERTICAL)).
578 apply(Move.fence('D', 8, Orientation.HORIZONTAL)).apply(Move.fence('D', 7, Orientation.HORIZONTAL)).
579 apply(Move.fence('D', 4, Orientation.HORIZONTAL)).apply(Move.fence('E', 8, Orientation.VERTICAL)).
580 apply(Move.fence('C', 3, Orientation.HORIZONTAL)).apply(Move.WEST).
581 apply(Move.fence('D', 2, Orientation.VERTICAL)).apply(Move.fence('A', 4, Orientation.HORIZONTAL)).
582 apply(Move.fence('B', 2, Orientation.HORIZONTAL)).apply(Move.WEST).
583 apply(Move.SOUTH).apply(Move.SOUTH).
584 apply(Move.SOUTH).apply(Move.WEST);
585 Board m = move(b, 0, Direction.WEST);
586 Board f = fence(m, 1, 'A', 1, Orientation.VERTICAL);
587 Board l = fence(f, 0, 'A', 3, Orientation.VERTICAL);
590 public void testTomasHolyCannotJumpWS() throws Exception {
596 Board b = apply(board, Move.NORTH);
597 b = apply(b, Move.SOUTH);
598 b = apply(b, Move.NORTH);
599 b = apply(b, Move.SOUTH);
600 b = apply(b, Move.NORTH);
601 b = apply(b, Move.SOUTH);
608 b = fence(b, 0, 'D', 3, Orientation.HORIZONTAL);
609 b = fence(b, 1, 'E', 6, Orientation.HORIZONTAL);
610 b = fence(b, 0, 'B', 6, Orientation.HORIZONTAL);
611 b = fence(b, 1, 'G', 3, Orientation.HORIZONTAL);
612 b = fence(b, 0, 'E', 3, Orientation.VERTICAL);
613 b = fence(b, 1, 'D', 4, Orientation.HORIZONTAL);
614 b = fence(b, 0, 'A', 4, Orientation.HORIZONTAL);
615 b = fence(b, 1, 'B', 5, Orientation.VERTICAL);
623 b = fence(b, 0, 'E', 1, Orientation.VERTICAL);
624 b = fence(b, 1, 'C', 5, Orientation.HORIZONTAL);
625 b = fence(b, 0, 'E', 5, Orientation.VERTICAL);
626 b = fence(b, 1, 'F', 2, Orientation.HORIZONTAL);
627 b = fence(b, 0, 'H', 2, Orientation.VERTICAL);
628 b = fence(b, 1, 'H', 1, Orientation.HORIZONTAL);
629 b = fence(b, 0, 'B', 3, Orientation.HORIZONTAL);
630 b = fence(b, 1, 'F', 1, Orientation.HORIZONTAL);
631 b = fence(b, 0, 'A', 1, Orientation.HORIZONTAL);
632 b = apply(b, Move.SOUTH);
640 b = apply(b, Move.WEST);
641 b = apply(b, Move.WEST);
642 b = apply(b, Move.WEST);
643 b = fence(b, 1, 'C', 8, Orientation.HORIZONTAL);
644 b = fence(b, 0, 'C', 1, Orientation.HORIZONTAL);
645 b = fence(b, 1, 'E', 8, Orientation.HORIZONTAL);
646 b = apply(b, Move.NORTH);
648 b = move(b, 1, Direction.WEST, Direction.SOUTH);
649 assertNotNull("Board is OK", b);
652 static String toPicture(Board b) throws IOException {
653 StringWriter sw = new StringWriter();
655 return sw.toString();
658 static Board picture2board(String text) throws IOException, IllegalPositionException {
659 StringReader sr = new StringReader(text);
660 return Board.read(sr);