diff --git a/examples/fen.txt b/examples/fen.txt new file mode 100644 index 000000000..f9c9ce27d --- /dev/null +++ b/examples/fen.txt @@ -0,0 +1 @@ +rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1 diff --git a/examples/pom.xml b/examples/pom.xml index a1de3f159..4cc377711 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -12,6 +12,14 @@ jqf-examples JQF: Feedback-directed Quickcheck for Java - Sample generators and benchmark tests + + + lila-maven + lichess/scalachess artifacts + https://raw.githubusercontent.com/ornicar/lila-maven/master + + + com.pholser @@ -128,6 +136,11 @@ 24.1-jre test + + org.lichess + scalachess_2.12 + 8.6.8 + diff --git a/examples/src/main/java/edu/berkeley/cs/jqf/examples/chess/FENGenerator.java b/examples/src/main/java/edu/berkeley/cs/jqf/examples/chess/FENGenerator.java new file mode 100644 index 000000000..6b1774c4b --- /dev/null +++ b/examples/src/main/java/edu/berkeley/cs/jqf/examples/chess/FENGenerator.java @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2018, The Regents of the University of California + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package edu.berkeley.cs.jqf.examples.chess; + +import com.pholser.junit.quickcheck.generator.GenerationStatus; +import com.pholser.junit.quickcheck.generator.Generator; +import com.pholser.junit.quickcheck.random.SourceOfRandomness; + +/** + * @author Rohan Padhye + */ +public class FENGenerator extends Generator { + + public FENGenerator() { + super(String.class); + } + + @Override + public String generate(SourceOfRandomness r, GenerationStatus g) { + return String.join(" ", generateBoard(r), generateColor(r), generateCastles(r), + generateEnPassant(r), generateHalfMoveClock(r), generateFullMoveClock(r)); + } + + private char[] pieces = { 'K', 'Q', 'R', 'B', 'N', 'P', 'k', 'q', 'r', 'b', 'n', 'p'}; + + private String generateBoard(SourceOfRandomness r) { + String[] rows = new String[8]; + for (int i = 0; i < 8; i++) { + String row = ""; + for (int j = 0; j < 8; j++) { + if (r.nextBoolean()) { + // empty square + int skip = r.nextInt(0, 8-j); + j += skip; + row += String.valueOf(skip+1); // Upper bound is exclusive + } else { + // piece + row += pieces[r.nextInt(pieces.length)]; + } + } + rows[i] = row; + } + return String.join("/", rows); + } + + private String generateColor(SourceOfRandomness r) { + return r.nextBoolean() ? "w" : "b"; + } + + private String generateCastles(SourceOfRandomness r) { + if (r.nextBoolean()) { + return "-"; + } + String castle = ""; + if (r.nextBoolean()) { + castle += "K"; + } + if (r.nextBoolean()) { + castle += "Q"; + } + if (r.nextBoolean()) { + castle += "k"; + } + if (r.nextBoolean()) { + castle += "q"; + } + if (castle.isEmpty()) { + castle = "-"; + } + return castle; + } + + private String generateEnPassant(SourceOfRandomness r) { + if (r.nextBoolean()) { + return "-"; + } + char x = r.nextChar('a', 'i'); // Upper-bound is exclusive + int y = r.nextInt(1, 9); // Upper-bound is exclusive + return String.valueOf(x) + String.valueOf(y); + } + + private String generateHalfMoveClock(SourceOfRandomness r) { + return Integer.toString(r.nextInt(0, 50)); + } + + private String generateFullMoveClock(SourceOfRandomness r) { + return Integer.toString(r.nextInt(1, 100)); + } +} diff --git a/examples/src/test/java/edu/berkeley/cs/jqf/examples/chess/FENTest.java b/examples/src/test/java/edu/berkeley/cs/jqf/examples/chess/FENTest.java new file mode 100644 index 000000000..d5ded4851 --- /dev/null +++ b/examples/src/test/java/edu/berkeley/cs/jqf/examples/chess/FENTest.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2018, The Regents of the University of California + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package edu.berkeley.cs.jqf.examples.chess; + +import chess.Situation; +import chess.format.Forsyth; +import com.pholser.junit.quickcheck.From; +import edu.berkeley.cs.jqf.examples.common.ArbitraryLengthStringGenerator; +import edu.berkeley.cs.jqf.fuzz.Fuzz; +import edu.berkeley.cs.jqf.fuzz.JQF; +import org.junit.Assume; +import org.junit.Test; +import org.junit.runner.RunWith; +import scala.Option; + +import static org.junit.Assume.*; +import static org.junit.Assert.*; +import static org.hamcrest.Matchers.*; + +/** + * @author Rohan Padhye + */ +@RunWith(JQF.class) +public class FENTest { + + public static final String INITIAL_FEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"; + + @Test + public void test() { + testWithString(INITIAL_FEN); + } + + @Test + public void debug() { + debugWithString(INITIAL_FEN); + debugWithString("Q"); + } + + private Situation parseFEN(String fen) { + Option situation = Forsyth.$less$less(fen); + Assume.assumeTrue(situation.isDefined()); + return situation.get(); + } + + @Fuzz + public void testWithString(@From(ArbitraryLengthStringGenerator.class) String fen) { + Situation situation = parseFEN(fen); + assumeTrue(situation.playable(true)); + assertThat(situation.moves().size(), greaterThan(0)); + } + + @Fuzz + public void debugWithString(@From(ArbitraryLengthStringGenerator.class) String fen) { + Situation situation = parseFEN(fen); + System.out.println(situation.moves().values()); + } + + @Fuzz + public void testWithGenerator(@From(FENGenerator.class) String fen) { + testWithString(fen); + } + + @Fuzz + public void debugWithGenerator(@From(FENGenerator.class) String fen) { + System.out.println(fen);//debugWithString(fen); + } +} diff --git a/examples/src/test/java/edu/berkeley/cs/jqf/examples/chess/MoveTest.java b/examples/src/test/java/edu/berkeley/cs/jqf/examples/chess/MoveTest.java new file mode 100644 index 000000000..fb82a435a --- /dev/null +++ b/examples/src/test/java/edu/berkeley/cs/jqf/examples/chess/MoveTest.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2018, The Regents of the University of California + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package edu.berkeley.cs.jqf.examples.chess; + +import chess.Move; +import chess.Situation; +import chess.variant.Standard$; +import com.pholser.junit.quickcheck.generator.InRange; +import com.pholser.junit.quickcheck.generator.Size; +import edu.berkeley.cs.jqf.fuzz.Fuzz; +import edu.berkeley.cs.jqf.fuzz.JQF; +import org.junit.runner.RunWith; +import scala.collection.IndexedSeq; + +/** + * @author Rohan Padhye + */ +@RunWith(JQF.class) +public class MoveTest { + + private Situation initial = Situation.apply(Standard$.MODULE$); + + @Fuzz + public void tryMoves(@InRange(minInt=0) int @Size(min=1, max=20)[] choices) { + Situation state = initial; + Move lastMove = null; + for (int i = 0; i < choices.length; i++) { + IndexedSeq moves = state.moves().values().flatten((x) -> x).toIndexedSeq(); + int k = choices[i] % moves.size(); + lastMove = moves.apply(k); + state = lastMove.situationAfter(); + //System.out.print(Dumper.apply(lastMove)); + //System.out.print(" "); + } + //System.out.println(); + } + +}