/* $Id$ Copyright (C) 2006-2007 by David Cotton 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 2 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, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package fr.free.jchecs.core; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static fr.free.jchecs.core.BoardFactory.State.EMPTY; import static fr.free.jchecs.core.BoardFactory.State.STARTING; import static fr.free.jchecs.core.BoardFactory.Type.ARRAY; import static fr.free.jchecs.core.FENUtils.toBoard; import static fr.free.jchecs.core.Piece.BLACK_KNIGHT; import static fr.free.jchecs.core.Piece.BLACK_PAWN; import static fr.free.jchecs.core.Piece.WHITE_BISHOP; import static fr.free.jchecs.core.Piece.WHITE_KNIGHT; import static fr.free.jchecs.core.Piece.WHITE_PAWN; import static fr.free.jchecs.core.Piece.WHITE_QUEEN; import static fr.free.jchecs.core.SANUtils.SAN_VALIDATOR; import static fr.free.jchecs.core.SANUtils.toMove; import static fr.free.jchecs.core.SANUtils.toSAN; import java.util.regex.Pattern; import org.junit.Test; /** * Tests unitaires de la classe utilitaire pour la notation SAN. * * @author David Cotton */ public final class SANUtilsTest { /** Chaine FEN d'une position avec une prise ambiguë venant d'un cavalier. */ private static final String AMBIGUOUS_KNIGHT_FEN = "rnbqk1nr/ppp2ppp/3p4/2b1p3/2N5/5N2/PPPPPPPP/R1BQKB1R w KQkq - 6 3"; /** Chaine FEN d'une position avec une prise ambiguë venant d'un pion. */ private static final String AMBIGUOUS_PAWN_FEN = "r1b1kbnr/pppp1ppp/4p3/6q1/1n6/P1P1P3/1P1P1PPP/RNBQKBNR w KQkq - 6 3"; /** Chaine FEN d'une position avec une prise ambiguë venant d'une reine. */ private static final String AMBIGUOUS_QUEEN_FEN = "8/k7/8/1Q1p1Q2/8/5Q2/8/7K w - - 40 40"; /** * Pour que JUnit puisse instancier les tests. */ public SANUtilsTest() { // Rien de spécifique... } /** * Teste l'expression de validation d'une chaîne SAN. */ @Test public void testSANValidator() { final Pattern regexp = SAN_VALIDATOR; // Gestion des roques... assertTrue(regexp.matcher("0-0").matches()); assertTrue(regexp.matcher("0-0-0").matches()); assertTrue(regexp.matcher("0-0-0#").matches()); // Répétitions... assertFalse(regexp.matcher("0-00-0").matches()); // Espaces en trop... assertFalse(regexp.matcher(" 0-0 ").matches()); // Des "o" majuscules plutôt que des zéros... assertFalse(regexp.matcher("O-O").matches()); assertFalse(regexp.matcher("O-O-O").matches()); // Mouvements de pions sans prise, avec promotion... assertTrue(regexp.matcher("a8Q").matches()); assertTrue(regexp.matcher("c1K").matches()); assertTrue(regexp.matcher("h1Q+").matches()); assertTrue(regexp.matcher("h1Q++").matches()); assertTrue(regexp.matcher("h1Q#").matches()); assertTrue(regexp.matcher("f8Q(=)").matches()); // Le "=" pour noter une promotion, fréquent dans PGN, ne fait pas partie de SAN. assertFalse(regexp.matcher("c1=K").matches()); // Rangs incompatibles avec une promotion... assertFalse(regexp.matcher("b7Q").matches()); assertFalse(regexp.matcher("g3R").matches()); // Colonnes ou rangs inconnus... assertFalse(regexp.matcher("ab2Q").matches()); assertFalse(regexp.matcher("i4Q").matches()); // Mouvements de pions sans prise et sans promotion... assertTrue(regexp.matcher("e5").matches()); assertTrue(regexp.matcher("h8").matches()); assertTrue(regexp.matcher("e5").matches()); // Colonnes ou rangs inconnus... assertFalse(regexp.matcher("a0").matches()); assertFalse(regexp.matcher("bc3").matches()); assertFalse(regexp.matcher("c9").matches()); assertFalse(regexp.matcher("f12").matches()); // Mouvements de pions avec prise et sans promotion... assertTrue(regexp.matcher("gxf8").matches()); assertTrue(regexp.matcher("axb3+").matches()); assertTrue(regexp.matcher("cxd3 e.p.").matches()); assertTrue(regexp.matcher("cxd6 e.p.").matches()); // Rang incompatible pour une prise en passant... assertFalse(regexp.matcher("cxd7 e.p.").matches()); assertFalse(regexp.matcher("gxh2 e.p.").matches()); // Notation de la prise en passant erronée... assertFalse(regexp.matcher("dxe3 ep").matches()); assertFalse(regexp.matcher("fxd6 e.p").matches()); // Mouvements de pions avec prise et avec promotion... assertTrue(regexp.matcher("cxd8Q").matches()); // Colonne de départ manquante (obligatoire d'après SAN pour les prises avec pion). assertFalse(regexp.matcher("xd8Q").matches()); // Mouvements de pièces sans prise... assertTrue(regexp.matcher("Ke1").matches()); assertTrue(regexp.matcher("Qd3++").matches()); assertTrue(regexp.matcher("Nef3").matches()); assertTrue(regexp.matcher("N5d7").matches()); assertTrue(regexp.matcher("Qe2f3").matches()); // Levée d'ambiguïté erronée... assertFalse(regexp.matcher("Njh2").matches()); assertFalse(regexp.matcher("N9b7").matches()); // Promotion d'une pièce ?! assertFalse(regexp.matcher("Rh8Q").matches()); // Mouvements de pièces avec prise... assertTrue(regexp.matcher("Kxe1(=)").matches()); assertTrue(regexp.matcher("Qf5xd5(=)").matches()); assertTrue(regexp.matcher("Nexf3").matches()); assertTrue(regexp.matcher("N5xd7").matches()); // Marqueur de prise mal placé... assertFalse(regexp.matcher("Nxef3").matches()); // Prise en passant avec une pièce !? assertFalse(regexp.matcher("Bxe6 e.p.").matches()); } /** * Teste la convertion chaine SAN / mouvement. */ @Test public void testToMove() { MoveGenerator etat = BoardFactory.valueOf(ARRAY, STARTING); try { Move mvt = toMove(etat, "e3"); assertEquals(new Move(WHITE_PAWN, Square.valueOf("e2"), Square.valueOf("e3")), mvt); etat = etat.derive(mvt, true); mvt = toMove(etat, "Na6"); assertEquals(new Move(BLACK_KNIGHT, Square.valueOf("b8"), Square.valueOf("a6")), mvt); etat = etat.derive(mvt, true); mvt = toMove(etat, "Bc4"); assertEquals(new Move(WHITE_BISHOP, Square.valueOf("f1"), Square.valueOf("c4")), mvt); etat = etat.derive(mvt, true); mvt = toMove(etat, "c5"); assertEquals(new Move(BLACK_PAWN, Square.valueOf("c7"), Square.valueOf("c5")), mvt); etat = etat.derive(mvt, true); mvt = toMove(etat, "Qf3"); assertEquals(new Move(WHITE_QUEEN, Square.valueOf("d1"), Square.valueOf("f3")), mvt); etat = etat.derive(mvt, true); mvt = toMove(etat, "b6"); assertEquals(new Move(BLACK_PAWN, Square.valueOf("b7"), Square.valueOf("b6")), mvt); etat = etat.derive(mvt, true); mvt = toMove(etat, "Qxf7++"); assertEquals(new Move(WHITE_QUEEN, Square.valueOf("f3"), Square.valueOf("f7"), BLACK_PAWN), mvt); etat = etat.derive(mvt, true); } catch (final SANException e) { fail(e.toString()); } assertFalse(etat.isWhiteActive()); assertTrue(etat.isInCheck(false)); try { etat = BoardFactory.valueOf(ARRAY, EMPTY).derive(toBoard(AMBIGUOUS_PAWN_FEN)); Move mvt = toMove(etat, "cxb4"); assertEquals(new Move(WHITE_PAWN, Square.valueOf("c3"), Square.valueOf("b4"), BLACK_KNIGHT), mvt); etat = BoardFactory.valueOf(ARRAY, EMPTY).derive(toBoard(AMBIGUOUS_KNIGHT_FEN)); mvt = toMove(etat, "Nfxe5"); assertEquals(new Move(WHITE_KNIGHT, Square.valueOf("f3"), Square.valueOf("e5"), BLACK_PAWN), mvt); etat = BoardFactory.valueOf(ARRAY, EMPTY).derive(toBoard(AMBIGUOUS_QUEEN_FEN)); mvt = toMove(etat, "Qf5xd5(=)"); assertEquals(new Move(WHITE_QUEEN, Square.valueOf("f5"), Square.valueOf("d5"), BLACK_PAWN), mvt); } catch (final FENException e) { fail(e.toString()); } catch (final SANException e) { fail(e.toString()); } } /** * Teste la convertion mouvement / chaine SAN. */ @Test public void testToSAN() { MoveGenerator etat = BoardFactory.valueOf(ARRAY, STARTING); Move mvt = new Move(WHITE_PAWN, Square.valueOf("e2"), Square.valueOf("e3")); assertEquals("e3", toSAN(etat, mvt)); etat = etat.derive(mvt, true); mvt = new Move(BLACK_KNIGHT, Square.valueOf("b8"), Square.valueOf("a6")); assertEquals("Na6", toSAN(etat, mvt)); etat = etat.derive(mvt, true); mvt = new Move(WHITE_BISHOP, Square.valueOf("f1"), Square.valueOf("c4")); assertEquals("Bc4", toSAN(etat, mvt)); etat = etat.derive(mvt, true); mvt = new Move(BLACK_PAWN, Square.valueOf("c7"), Square.valueOf("c5")); assertEquals("c5", toSAN(etat, mvt)); etat = etat.derive(mvt, true); mvt = new Move(WHITE_QUEEN, Square.valueOf("d1"), Square.valueOf("f3")); assertEquals("Qf3", toSAN(etat, mvt)); etat = etat.derive(mvt, true); mvt = new Move(BLACK_PAWN, Square.valueOf("b7"), Square.valueOf("b6")); assertEquals("b6", toSAN(etat, mvt)); etat = etat.derive(mvt, true); mvt = new Move(WHITE_QUEEN, Square.valueOf("f3"), Square.valueOf("f7"), BLACK_PAWN); assertEquals("Qxf7++", toSAN(etat, mvt)); try { etat = BoardFactory.valueOf(ARRAY, EMPTY).derive(toBoard(AMBIGUOUS_KNIGHT_FEN)); mvt = new Move(WHITE_KNIGHT, Square.valueOf("f3"), Square.valueOf("e5"), BLACK_PAWN); assertEquals("Nfxe5", toSAN(etat, mvt)); etat = BoardFactory.valueOf(ARRAY, EMPTY).derive(toBoard(AMBIGUOUS_PAWN_FEN)); mvt = new Move(WHITE_PAWN, Square.valueOf("c3"), Square.valueOf("b4"), BLACK_KNIGHT); assertEquals("cxb4", toSAN(etat, mvt)); etat = BoardFactory.valueOf(ARRAY, EMPTY).derive(toBoard(AMBIGUOUS_QUEEN_FEN)); mvt = new Move(WHITE_QUEEN, Square.valueOf("f5"), Square.valueOf("d5"), BLACK_PAWN); assertEquals("Qf5xd5(=)", toSAN(etat, mvt)); } catch (final FENException e) { fail(e.toString()); } } }