/* DroidFish - An Android chess program. Copyright (C) 2011 Peter Ă–sterlund, peterosterlund2@gmail.com This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.petero.droidfish.gamelogic; import java.util.ArrayList; import java.util.List; import junit.framework.TestCase; public class PositionTest extends TestCase { public PositionTest() { } /** * Test of getPiece method, of class Position. */ public void testGetPiece() throws ChessParseError { Position pos = new Position(); int result = pos.getPiece(0); assertEquals(result, Piece.EMPTY); pos = TextIO.readFEN(TextIO.startPosFEN); result = pos.getPiece(0); assertEquals(result, Piece.WROOK); for (int x = 0; x < 8; x++) { for (int y = 0; y < 2; y++) { int p1 = pos.getPiece(Position.getSquare(x, y)); int p2 = pos.getPiece(Position.getSquare(x, 7-y)); int bwDiff = Piece.BPAWN - Piece.WPAWN; assertEquals(p2, p1 + bwDiff); } } } /** * Test of getIndex method, of class Position. */ public void testGetIndex() { for (int x = 0; x < 8; x++) { for (int y = 0; y < 8; y++) { int sq = Position.getSquare(x, y); int x2 = Position.getX(sq); int y2 = Position.getY(sq); assertEquals(x, x2); assertEquals(y, y2); } } } /** * Test of setPiece method, of class Position. */ public void testSetPiece() { Position instance = new Position(); assertEquals(Piece.EMPTY, instance.getPiece(Position.getSquare(0, 0))); instance.setPiece(Position.getSquare(3, 4), Piece.WKING); assertEquals(Piece.WKING, instance.getPiece(Position.getSquare(3, 4))); } /** * Test of makeMove method, of class Position. */ public void testMakeMove() throws ChessParseError { Position pos = TextIO.readFEN(TextIO.startPosFEN); Position origPos = new Position(pos); assertTrue(pos.equals(origPos)); Move move = new Move(Position.getSquare(4,1), Position.getSquare(4,3), Piece.EMPTY); UndoInfo ui = new UndoInfo(); pos.makeMove(move, ui); assertEquals(pos.whiteMove, false); assertEquals(-1, pos.getEpSquare()); assertEquals(Piece.EMPTY, pos.getPiece(Position.getSquare(4,1))); assertEquals(Piece.WPAWN, pos.getPiece(Position.getSquare(4,3))); assertTrue(!pos.equals(origPos)); int castleMask = (1 << Position.A1_CASTLE) | (1 << Position.H1_CASTLE) | (1 << Position.A8_CASTLE) | (1 << Position.H8_CASTLE); assertEquals(castleMask,pos.getCastleMask()); pos.unMakeMove(move, ui); assertEquals(pos.whiteMove, true); assertEquals(Piece.WPAWN, pos.getPiece(Position.getSquare(4,1))); assertEquals(Piece.EMPTY, pos.getPiece(Position.getSquare(4,3))); assertTrue(pos.equals(origPos)); String fen = "r1bqk2r/2ppbppp/p1n2n2/1pP1p3/B3P3/5N2/PP1P1PPP/RNBQK2R w KQkq b6 0 2"; pos = TextIO.readFEN(fen); assertEquals(fen, TextIO.toFEN(pos)); origPos = new Position(pos); assertEquals(Position.getSquare(1,5), pos.getEpSquare()); // Test capture move = new Move(Position.getSquare(0, 3), Position.getSquare(1,4), Piece.EMPTY); pos.makeMove(move, ui); assertEquals(-1, pos.getEpSquare()); assertEquals(Piece.WBISHOP, pos.getPiece(Position.getSquare(1,4))); assertEquals(Piece.EMPTY, pos.getPiece(Position.getSquare(0,3))); pos.unMakeMove(move, ui); assertTrue(pos.equals(origPos)); // Test castling move = new Move(Position.getSquare(4, 0), Position.getSquare(6,0), Piece.EMPTY); pos.makeMove(move, ui); assertEquals(Piece.WROOK, pos.getPiece(Position.getSquare(5,0))); assertEquals(Piece.EMPTY, pos.getPiece(Position.getSquare(7,0))); castleMask = (1 << Position.A8_CASTLE) | (1 << Position.H8_CASTLE); assertEquals(castleMask,pos.getCastleMask()); assertEquals(-1, pos.getEpSquare()); pos.unMakeMove(move, ui); assertTrue(pos.equals(origPos)); // Test castling rights (king move) move = new Move(Position.getSquare(4, 0), Position.getSquare(4,1), Piece.EMPTY); pos.makeMove(move, ui); castleMask = (1 << Position.A8_CASTLE) | (1 << Position.H8_CASTLE); assertEquals(castleMask,pos.getCastleMask()); assertEquals(-1, pos.getEpSquare()); pos.unMakeMove(move, ui); assertTrue(pos.equals(origPos)); // Test castling rights (rook move) move = new Move(Position.getSquare(7, 0), Position.getSquare(6,0), Piece.EMPTY); pos.makeMove(move, ui); castleMask = (1 << Position.A1_CASTLE) | (1 << Position.A8_CASTLE) | (1 << Position.H8_CASTLE); assertEquals(castleMask,pos.getCastleMask()); assertEquals(-1, pos.getEpSquare()); pos.unMakeMove(move, ui); assertTrue(pos.equals(origPos)); // Test en passant move = new Move(Position.getSquare(2, 4), Position.getSquare(1,5), Piece.EMPTY); pos.makeMove(move, ui); assertEquals(Piece.WPAWN, pos.getPiece(Position.getSquare(1,5))); assertEquals(Piece.EMPTY, pos.getPiece(Position.getSquare(2,4))); assertEquals(Piece.EMPTY, pos.getPiece(Position.getSquare(1,4))); pos.unMakeMove(move, ui); assertTrue(pos.equals(origPos)); // Test castling rights loss when rook captured pos.setPiece(Position.getSquare(6,2), Piece.BKNIGHT); pos.setWhiteMove(false); Position origPos2 = new Position(pos); move = new Move(Position.getSquare(6,2), Position.getSquare(7,0), Piece.EMPTY); pos.makeMove(move, ui); castleMask = (1 << Position.A1_CASTLE) | (1 << Position.A8_CASTLE) | (1 << Position.H8_CASTLE); assertEquals(castleMask,pos.getCastleMask()); assertEquals(-1, pos.getEpSquare()); pos.unMakeMove(move, ui); assertTrue(pos.equals(origPos2)); } /** * Test of makeMove method, of class Position. */ public void testPromotion() throws ChessParseError { String fen = "r1bqk2r/1Pppbppp/p1n2n2/2P1p3/B3P3/5N2/Pp1P1PPP/R1BQK2R w KQkq - 0 1"; Position pos = TextIO.readFEN(fen); assertEquals(fen, TextIO.toFEN(pos)); Position origPos = new Position(pos); assertEquals(origPos, pos); Move move = new Move(Position.getSquare(1, 6), Position.getSquare(0,7), Piece.WQUEEN); UndoInfo ui = new UndoInfo(); pos.makeMove(move, ui); assertEquals(Piece.EMPTY, pos.getPiece(Position.getSquare(1,6))); assertEquals(Piece.WQUEEN, pos.getPiece(Position.getSquare(0,7))); pos.unMakeMove(move, ui); assertEquals(origPos, pos); move = new Move(Position.getSquare(1, 6), Position.getSquare(1,7), Piece.WKNIGHT); ui = new UndoInfo(); pos.makeMove(move, ui); assertEquals(Piece.EMPTY, pos.getPiece(Position.getSquare(1,6))); assertEquals(Piece.WKNIGHT, pos.getPiece(Position.getSquare(1,7))); pos.unMakeMove(move, ui); assertEquals(origPos, pos); pos.setWhiteMove(false); origPos = new Position(pos); move = new Move(Position.getSquare(1, 1), Position.getSquare(2, 0), Piece.BROOK); ui = new UndoInfo(); pos.makeMove(move, ui); assertEquals(Piece.EMPTY, pos.getPiece(Position.getSquare(1,1))); assertEquals(Piece.BROOK, pos.getPiece(Position.getSquare(2,0))); pos.unMakeMove(move, ui); assertEquals(origPos, pos); } /** * Test move counters, of class Position. */ public void testMoveCounters() throws ChessParseError { String fen = "r1bqk2r/2ppbppp/p1n2n2/1pP1p3/B3P3/5N2/PP1P1PPP/RNBQK2R w KQkq b6 0 7"; Position pos = TextIO.readFEN(fen); Move move = TextIO.stringToMove(pos, "Nc3"); UndoInfo ui = new UndoInfo(); pos.makeMove(move, ui); assertEquals(1, pos.halfMoveClock); assertEquals(7, pos.fullMoveCounter); pos.unMakeMove(move, ui); move = TextIO.stringToMove(pos, "O-O"); pos.makeMove(move, ui); assertEquals(1, pos.halfMoveClock); // Castling does not reset 50 move counter assertEquals(7, pos.fullMoveCounter); pos.unMakeMove(move, ui); move = TextIO.stringToMove(pos, "a3"); pos.makeMove(move, ui); assertEquals(0, pos.halfMoveClock); // Pawn move resets 50 move counter assertEquals(7, pos.fullMoveCounter); pos.unMakeMove(move, ui); move = TextIO.stringToMove(pos, "Nxe5"); pos.makeMove(move, ui); assertEquals(0, pos.halfMoveClock); // Capture move resets 50 move counter assertEquals(7, pos.fullMoveCounter); pos.unMakeMove(move, ui); move = TextIO.stringToMove(pos, "cxb6"); pos.makeMove(move, ui); assertEquals(0, pos.halfMoveClock); // EP capture move resets 50 move counter assertEquals(7, pos.fullMoveCounter); pos.unMakeMove(move, ui); move = TextIO.stringToMove(pos, "Kf1"); pos.makeMove(move, ui); assertEquals(1, pos.halfMoveClock); // Loss of castling rights does not reset 50 move counter assertEquals(7, pos.fullMoveCounter); pos.unMakeMove(move, ui); Move firstMove = TextIO.stringToMove(pos, "Nc3"); UndoInfo firstUi = new UndoInfo(); pos.makeMove(move, firstUi); move = TextIO.stringToMove(pos, "O-O"); pos.makeMove(move, ui); assertEquals(2, pos.halfMoveClock); assertEquals(8, pos.fullMoveCounter); // Black move increases fullMoveCounter pos.unMakeMove(move, ui); pos.unMakeMove(firstMove, firstUi); fen = "8/8/8/4k3/8/8/2p5/5K2 b - - 47 68"; pos = TextIO.readFEN(fen); move = TextIO.stringToMove(pos, "c1Q"); pos.makeMove(move, ui); assertEquals(0, pos.halfMoveClock); // Pawn promotion resets 50 move counter assertEquals(69, pos.fullMoveCounter); } /** * Test of drawRuleEquals, of class Position. */ public void testDrawRuleEquals() throws ChessParseError { Position pos = TextIO.readFEN(TextIO.startPosFEN); Position origPos = new Position(pos); UndoInfo ui = new UndoInfo(); pos.makeMove(TextIO.stringToMove(pos, "Nf3"), ui); assertEquals(false, pos.drawRuleEquals(origPos)); pos.makeMove(TextIO.stringToMove(pos, "Nf6"), ui); assertEquals(false, pos.drawRuleEquals(origPos)); pos.makeMove(TextIO.stringToMove(pos, "Ng1"), ui); assertEquals(false, pos.drawRuleEquals(origPos)); pos.makeMove(TextIO.stringToMove(pos, "Ng8"), ui); assertEquals(true, pos.drawRuleEquals(origPos)); assertEquals(false, pos.equals(origPos)); // Move counters have changed String fen = "r1bqkb1r/pppp1ppp/2n2n2/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R w KQkq - 0 1"; pos = TextIO.readFEN(fen); origPos = new Position(pos); pos.makeMove(TextIO.stringToMove(pos, "Ke2"), ui); assertEquals(false, pos.drawRuleEquals(origPos)); pos.makeMove(TextIO.stringToMove(pos, "Be7"), ui); assertEquals(false, pos.drawRuleEquals(origPos)); pos.makeMove(TextIO.stringToMove(pos, "Ke1"), ui); assertEquals(false, pos.drawRuleEquals(origPos)); pos.makeMove(TextIO.stringToMove(pos, "Bf8"), ui); assertEquals(false, pos.drawRuleEquals(origPos)); // Not equal, castling rights lost pos = TextIO.readFEN(TextIO.startPosFEN); pos.makeMove(TextIO.stringToMove(pos, "c4"), ui); pos.makeMove(TextIO.stringToMove(pos, "a6"), ui); pos.makeMove(TextIO.stringToMove(pos, "c5"), ui); pos.makeMove(TextIO.stringToMove(pos, "b5"), ui); assertEquals(Position.getSquare(1, 5), pos.getEpSquare()); origPos = new Position(pos); pos.makeMove(TextIO.stringToMove(pos, "Nc3"), ui); pos.makeMove(TextIO.stringToMove(pos, "Nc6"), ui); pos.makeMove(TextIO.stringToMove(pos, "Nb1"), ui); pos.makeMove(TextIO.stringToMove(pos, "Nb8"), ui); assertEquals(false, pos.drawRuleEquals(origPos)); // Not equal, en passant rights lost } /** * Test of hashCode method, of class Position. */ public void testHashCode() throws ChessParseError { Position pos = TextIO.readFEN(TextIO.startPosFEN); long h1 = pos.zobristHash(); assertEquals(h1, pos.computeZobristHash()); UndoInfo ui = new UndoInfo(); Move move = TextIO.stringToMove(pos, "e4"); pos.makeMove(move, ui); assertTrue(h1 != pos.zobristHash()); pos.unMakeMove(move, ui); assertTrue(h1 == pos.zobristHash()); pos.setWhiteMove(!pos.whiteMove); long h4 = pos.zobristHash(); assertEquals(h4, pos.computeZobristHash()); assertTrue(h1 != pos.zobristHash()); pos.setWhiteMove(!pos.whiteMove); assertTrue(h1 == pos.zobristHash()); pos.setCastleMask(0); assertTrue(h1 != pos.zobristHash()); pos = TextIO.readFEN("rnbqkbnr/pppp1ppp/8/2P1p3/8/8/PP1PPPPP/RNBQKBNR b KQkq - 0 1"); h1 = pos.zobristHash(); assertEquals(h1, pos.computeZobristHash()); String[] moves = { "b5", "Nc3", "Nf6", "Nb1", "Ng8", "Nc3", "Nf6", "Nb1", "Ng8", "Nc3", "d5", "cxd6", "Qxd6", "h4", "Be6", "h5", "Nc6", "h6", "o-o-o", "hxg7", "Nf6", "gxh8Q", "Be7" }; List<UndoInfo> uiList = new ArrayList<UndoInfo>(); List<Long> hashList = new ArrayList<Long>(); List<Move> moveList = new ArrayList<Move>(); for (int i = 0; i < moves.length; i++) { uiList.add(new UndoInfo()); Move m = TextIO.stringToMove(pos, moves[i]); moveList.add(m); pos.makeMove(m, uiList.get(i)); long h = pos.zobristHash(); assertEquals(h, pos.computeZobristHash()); hashList.add(h); } assertTrue(!hashList.get(0).equals(hashList.get(4))); assertTrue(hashList.get(4).equals(hashList.get(8))); for (int i = moves.length - 1; i >= 0; i--) { pos.unMakeMove(moveList.get(i), uiList.get(i)); long h = pos.zobristHash(); assertEquals(h, pos.computeZobristHash()); assertEquals(h, i > 0 ? hashList.get(i - 1) : h1); } } /** * Test of getKingSq method, of class Position. */ public void testGetKingSq() throws ChessParseError { Position pos = TextIO.readFEN(TextIO.startPosFEN); assertEquals(TextIO.getSquare("e1"), pos.getKingSq(true)); assertEquals(TextIO.getSquare("e8"), pos.getKingSq(false)); pos = TextIO.readFEN("r1bq1bnr/ppppkppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R w KQ - 0 4"); assertEquals(TextIO.getSquare("e1"), pos.getKingSq(true)); assertEquals(TextIO.getSquare("e7"), pos.getKingSq(false)); UndoInfo ui = new UndoInfo(); pos.makeMove(TextIO.stringToMove(pos, "o-o"), ui); assertEquals(TextIO.getSquare("g1"), pos.getKingSq(true)); assertEquals(TextIO.getSquare("e7"), pos.getKingSq(false)); pos.makeMove(TextIO.stringToMove(pos, "Kd6"), ui); assertEquals(TextIO.getSquare("g1"), pos.getKingSq(true)); assertEquals(TextIO.getSquare("d6"), pos.getKingSq(false)); } public void testNullMove() throws ChessParseError { Move nullMove = new Move(0, 0, 0); UndoInfo ui = new UndoInfo(); Position pos = TextIO.readFEN(TextIO.startPosFEN); Position origPos = new Position(pos); pos.makeMove(nullMove, ui); assertEquals(false, pos.whiteMove); assertEquals(true, pos.a1Castle()); assertEquals(Piece.WROOK, pos.getPiece(0)); pos.unMakeMove(nullMove, ui); assertTrue(pos.equals(origPos)); pos = TextIO.readFEN("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w Kkq - 5 1"); origPos = new Position(pos); pos.makeMove(nullMove, ui); assertEquals(false, pos.whiteMove); assertEquals(false, pos.a1Castle()); assertEquals(Piece.WROOK, pos.getPiece(0)); assertEquals(0, pos.halfMoveClock); pos.unMakeMove(nullMove, ui); assertTrue(pos.equals(origPos)); pos = TextIO.readFEN("7k/8/8/8/8/8/4P3/K7 w - - 5 1"); origPos = new Position(pos); pos.makeMove(nullMove, ui); assertEquals(false, pos.whiteMove); assertEquals(false, pos.a1Castle()); assertEquals(0, pos.halfMoveClock); assertEquals(0, pos.getKingSq(true)); assertEquals(63, pos.getKingSq(false)); UndoInfo ui2 = new UndoInfo(); pos.makeMove(nullMove, ui2); assertEquals(true, pos.whiteMove); assertEquals(false, pos.a1Castle()); assertEquals(0, pos.halfMoveClock); assertEquals(0, pos.getKingSq(true)); assertEquals(63, pos.getKingSq(false)); pos.unMakeMove(nullMove, ui2); assertEquals(false, pos.whiteMove); assertEquals(false, pos.a1Castle()); assertEquals(0, pos.halfMoveClock); assertEquals(0, pos.getKingSq(true)); assertEquals(63, pos.getKingSq(false)); pos.unMakeMove(nullMove, ui); assertTrue(pos.equals(origPos)); pos = TextIO.readFEN("5k2/8/4R1K1/8/8/8/8/8 b - - 5 1"); origPos = new Position(pos); pos.makeMove(nullMove, ui); assertEquals(true, pos.whiteMove); assertEquals(false, pos.a1Castle()); assertEquals(0, pos.halfMoveClock); pos.unMakeMove(nullMove, ui); assertTrue(pos.equals(origPos)); } }