From d3422f1853d85da5dff208079c8ceaaf8e7f37b1 Mon Sep 17 00:00:00 2001 From: Astesana Date: Tue, 12 Dec 2023 12:10:56 +0100 Subject: [PATCH] Fixes a bug when standard input returned a null line. This bug occurred in lichess interface when switching network. The UCI app was no more able to read commands but doesn't quit (the main thread died but not the worker threads). Also adapts to games-core API changes --- README.md | 2 +- pom.xml | 2 +- .../jchess/uci/MoveGeneratorSupplier.java | 2 +- .../com/fathzer/jchess/uci/PerftTask.java | 4 +-- src/main/java/com/fathzer/jchess/uci/UCI.java | 34 +++++++++++-------- 5 files changed, 25 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index d9016b1..2165a9f 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ It also can be used to test move generator's performance as it outputs the numbe *playleaves* plays, when used with *legal*, the leave moves. These moves are always played when using pseudo-legal moves. *playleaves* can be replaced by the shortcut *pl*. *cut* is followed by the number of seconds allowed to process the test. This number should be strictly positive. Default is Integer.MAX_VALUE. **Please note:** - - **This command is optional**, only engines that implement *com.fathzer.jchess.uci.TestableMoveGeneratorSupplier* interface support it. + - **This command is optional**, only engines that implement *com.fathzer.games.perft.TestableMoveGeneratorBuilder* interface support it. - **This command requires the *com.fathzer.jchess.uci.UCI.readTestData()* method to be overridden** in order to return a non empty test data set. A way to easily do that is to add the [com.fathzer::jchess-perft-dataset](https://central.sonatype.com/artifact/com.fathzer/jchess-perft-dataset) artifact to your classpath, then override *readTestData*: ```java diff --git a/pom.xml b/pom.xml index 93cfdb8..b7685a1 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ com.fathzer games-core - 0.0.5-SNAPSHOT + 0.0.6-SNAPSHOT org.junit.jupiter diff --git a/src/main/java/com/fathzer/jchess/uci/MoveGeneratorSupplier.java b/src/main/java/com/fathzer/jchess/uci/MoveGeneratorSupplier.java index 9aac645..817c0a9 100644 --- a/src/main/java/com/fathzer/jchess/uci/MoveGeneratorSupplier.java +++ b/src/main/java/com/fathzer/jchess/uci/MoveGeneratorSupplier.java @@ -5,7 +5,7 @@ import com.fathzer.games.MoveGenerator; /** An interface of engines able to build instances of move generator. - *
The instance supplied are initialized on the current engine position. + *
The instance supplied is initialized to the current engine position. * @param The class of the moves returned by the move generator. */ public interface MoveGeneratorSupplier extends Supplier> { diff --git a/src/main/java/com/fathzer/jchess/uci/PerftTask.java b/src/main/java/com/fathzer/jchess/uci/PerftTask.java index 7ec0175..4b6193d 100644 --- a/src/main/java/com/fathzer/jchess/uci/PerftTask.java +++ b/src/main/java/com/fathzer/jchess/uci/PerftTask.java @@ -5,7 +5,7 @@ import com.fathzer.games.MoveGenerator; import com.fathzer.games.perft.PerfT; import com.fathzer.games.perft.PerfTResult; -import com.fathzer.games.util.ContextualizedExecutor; +import com.fathzer.games.util.exec.ContextualizedExecutor; import com.fathzer.jchess.uci.parameters.PerfTParameters; class PerftTask extends LongRunningTask> { @@ -29,7 +29,7 @@ public PerfTResult get() { this.perft.setPlayLeaves(false); } } - return perft.divide(params.getDepth(), engine::get); + return perft.divide(params.getDepth(), engine.get()); } } diff --git a/src/main/java/com/fathzer/jchess/uci/UCI.java b/src/main/java/com/fathzer/jchess/uci/UCI.java index e2a6876..49bb7fb 100644 --- a/src/main/java/com/fathzer/jchess/uci/UCI.java +++ b/src/main/java/com/fathzer/jchess/uci/UCI.java @@ -2,6 +2,7 @@ import java.io.BufferedReader; import java.io.BufferedWriter; +import java.io.EOFException; import java.io.FileWriter; import java.io.IOException; import java.io.InputStreamReader; @@ -24,10 +25,11 @@ import java.util.function.Supplier; import java.util.stream.Collectors; -import com.fathzer.games.perft.TestableMoveGeneratorSupplier; +import com.fathzer.games.MoveGenerator; import com.fathzer.games.perft.MoveGeneratorChecker; import com.fathzer.games.perft.PerfTResult; import com.fathzer.games.perft.PerfTTestData; +import com.fathzer.games.perft.TestableMoveGeneratorBuilder; import com.fathzer.jchess.uci.option.CheckOption; import com.fathzer.jchess.uci.option.Option; import com.fathzer.jchess.uci.parameters.GoParameters; @@ -39,7 +41,7 @@ *
It does not support all UCI commands and contains some extensions. Please have a look at the project's README file. * @see Engine */ -public class UCI implements Runnable { +public class UCI implements Runnable, AutoCloseable { private static final BufferedReader IN = new BufferedReader(new InputStreamReader(System.in)); private static final String MOVES = "moves"; private static final String ENGINE_CMD = "engine"; @@ -277,8 +279,9 @@ private String toString(M move) { } protected void doPerfStat(Deque tokens) { - if (! (getEngine() instanceof TestableMoveGeneratorSupplier)) { + if (! (getEngine() instanceof TestableMoveGeneratorBuilder)) { debug("test is not supported by this engine"); + return; } final Optional params = parse(PerfStatsParameters::new, PerfStatsParameters.PARSER, tokens); if (params.isPresent()) { @@ -288,11 +291,11 @@ protected void doPerfStat(Deque tokens) { debug("You may override readTestData to read some data"); return; } - doPerfStat(testData, (TestableMoveGeneratorSupplier)getEngine(), params.get()); + doPerfStat(testData, (TestableMoveGeneratorBuilder)getEngine(), params.get()); } } - private void doPerfStat(Collection testData, TestableMoveGeneratorSupplier engine, PerfStatsParameters params) { + private > void doPerfStat(Collection testData, TestableMoveGeneratorBuilder engine, PerfStatsParameters params) { final MoveGeneratorChecker test = new MoveGeneratorChecker(testData); test.setErrorManager(e-> out(e,0)); test.setCountErrorManager(e -> out("Error for "+e.getStartPosition()+" expected "+e.getExpectedCount()+" got "+e.getActualCount())); @@ -364,7 +367,6 @@ public void run() { final String command=getNextCommand(); log(">",command); if ("quit".equals(command) || "q".equals(command)) { - backTasks.close(); break; } final Deque tokens = new LinkedList<>(Arrays.asList(command.split(" "))); @@ -419,14 +421,13 @@ private synchronized void log(boolean append, String... messages) { */ protected String getNextCommand() { String line; - if (System.console() != null) { - line = System.console().readLine(); - } else { - try { - line = IN.readLine(); - } catch (IOException e) { - throw new UncheckedIOException(e); - } + try { + line = System.console() == null ? IN.readLine() : System.console().readLine(); + if (line==null) { + throw new EOFException("End of system input has been reached"); + } + } catch (IOException e) { + throw new UncheckedIOException(e); } return line.trim(); } @@ -449,4 +450,9 @@ protected void debug(CharSequence message) { System.out.println(message.toString()); } } + + @Override + public void close() { + backTasks.close(); + } }