From 6d0b6e1944de28252fd97c6ff4ceee11e4585a70 Mon Sep 17 00:00:00 2001 From: Fathzer Date: Wed, 27 Mar 2024 14:13:42 +0100 Subject: [PATCH] Start implementing info support --- .../com/fathzer/jchess/uci/BestMoveReply.java | 30 ---- .../java/com/fathzer/jchess/uci/Engine.java | 2 +- .../java/com/fathzer/jchess/uci/GoReply.java | 146 ++++++++++++++++++ src/main/java/com/fathzer/jchess/uci/UCI.java | 2 +- .../jchess/uci/helper/AbstractEngine.java | 8 +- 5 files changed, 152 insertions(+), 36 deletions(-) delete mode 100644 src/main/java/com/fathzer/jchess/uci/BestMoveReply.java create mode 100644 src/main/java/com/fathzer/jchess/uci/GoReply.java diff --git a/src/main/java/com/fathzer/jchess/uci/BestMoveReply.java b/src/main/java/com/fathzer/jchess/uci/BestMoveReply.java deleted file mode 100644 index a8fdfc8..0000000 --- a/src/main/java/com/fathzer/jchess/uci/BestMoveReply.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.fathzer.jchess.uci; - -import java.util.Optional; - -public class BestMoveReply { - private final UCIMove move; - private final UCIMove ponderMove; - - public BestMoveReply(UCIMove move) { - this(move, null); - } - - public BestMoveReply(UCIMove move, UCIMove ponderMove) { - this.move = move; - this.ponderMove = ponderMove; - } - - public Optional getMove() { - return Optional.ofNullable(move); - } - - public Optional getPonderMove() { - return Optional.ofNullable(ponderMove); - } - - @Override - public String toString() { - return "bestmove "+(move==null?"(none)":move)+(ponderMove==null?"":(" "+ponderMove)); - } -} diff --git a/src/main/java/com/fathzer/jchess/uci/Engine.java b/src/main/java/com/fathzer/jchess/uci/Engine.java index 48fa5cb..94ead6c 100644 --- a/src/main/java/com/fathzer/jchess/uci/Engine.java +++ b/src/main/java/com/fathzer/jchess/uci/Engine.java @@ -105,7 +105,7 @@ default List> getOptions() { * @param params The go parameters. * @return A long running task able to compute the engine's move. */ - LongRunningTask go(GoParameters params); + LongRunningTask go(GoParameters params); /** Tests whether a position is set. * @return true if a position is set diff --git a/src/main/java/com/fathzer/jchess/uci/GoReply.java b/src/main/java/com/fathzer/jchess/uci/GoReply.java new file mode 100644 index 0000000..ce7423c --- /dev/null +++ b/src/main/java/com/fathzer/jchess/uci/GoReply.java @@ -0,0 +1,146 @@ +package com.fathzer.jchess.uci; + +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.function.Function; + +/** The reply to a go request. + */ +public class GoReply { + /** A score.*/ + public sealed interface Score { + /** Gets the UCI representation of a score. + * @return a String + */ + String toUCI(); + } + /** An exact score expressed in centipawns. + * @param cp The number of centipawns + */ + public final record CpScore (int cp) implements Score { + @Override + public String toUCI() { + return "cp "+cp; + } + } + /** A lower bound score expressed in centipawns. + * @param cp The number of centipawns + */ + public final record LowerScore (int cp) implements Score { + @Override + public String toUCI() { + return "lowerbound "+cp; + } + } + /** An upper bound score expressed in centipawns. + * @param cp The number of centipawns + */ + public final record UpperScore (int cp) implements Score { + @Override + public String toUCI() { + return "upperbound "+cp; + } + } + /** A mate score. + * @param moveNumber The number of moves (not plies) before mate. A negative number if engine is mated. + */ + public final record MateScore (int moveNumber) implements Score { + @Override + public String toUCI() { + return "mate "+moveNumber; + } + } + + /** The information attached to the reply (the information returned in info lines). + */ + public static class Info { + private final int depth; + private List extraMoves; + private Function>> pvBuilder; + private Function> scoreBuilder; + + /** Constructor. + * @param depth The search depth. + */ + public Info(int depth) { + this.depth = depth; + this.extraMoves = Collections.emptyList(); + this.pvBuilder = m -> Optional.empty(); + this.scoreBuilder = m -> Optional.empty(); + } + + public int getDepth() { + return depth; + } + + public List getExtraMoves() { + return extraMoves; + } + + public void setExtraMoves(List extraMoves) { + this.extraMoves = extraMoves; + } + + public Function>> getPvBuilder() { + return pvBuilder; + } + + public void setPvBuilder(Function>> pvBuilder) { + this.pvBuilder = pvBuilder; + } + + public Function> getScoreBuilder() { + return scoreBuilder; + } + + public void setScoreBuilder(Function> scoreBuilder) { + this.scoreBuilder = scoreBuilder; + } + } + + private final UCIMove bestMove; + private final UCIMove ponderMove; + private Info info; + + public GoReply(UCIMove move) { + this(move, null); + } + + public GoReply(UCIMove move, UCIMove ponderMove) { + this.bestMove = move; + this.ponderMove = ponderMove; + } + + public Optional getMove() { + return Optional.ofNullable(bestMove); + } + + public Optional getPonderMove() { + return Optional.ofNullable(ponderMove); + } + + public Optional getInfo() { + return Optional.ofNullable(info); + } + + @Override + /** Gets the uci representation of the reply. + * @return a String + * @see #getMainInfoString() + */ + public String toString() { + return "bestmove "+(bestMove==null?"(none)":bestMove)+(ponderMove==null?"":(" "+ponderMove)); + } + + /** Gets the uci info line to return just before sending the reply. + * @return The line or an empty optional if no information is available + */ + public Optional getMainInfoString() { + if (info==null) { + return Optional.empty(); + } + //TODO + return Optional.of("depth "+info.depth); + } +} diff --git a/src/main/java/com/fathzer/jchess/uci/UCI.java b/src/main/java/com/fathzer/jchess/uci/UCI.java index be24ca8..66cd57b 100644 --- a/src/main/java/com/fathzer/jchess/uci/UCI.java +++ b/src/main/java/com/fathzer/jchess/uci/UCI.java @@ -190,7 +190,7 @@ protected void doGo(Deque tokens) { } else { final Optional goOptions = parse(GoParameters::new, GoParameters.PARSER, tokens); if (goOptions.isPresent()) { - final LongRunningTask task = engine.go(goOptions.get()); + final LongRunningTask task = engine.go(goOptions.get()); final boolean started = doBackground(() -> out(task.get().toString()), task::stop); if (!started) { debug("Engine is already working"); diff --git a/src/main/java/com/fathzer/jchess/uci/helper/AbstractEngine.java b/src/main/java/com/fathzer/jchess/uci/helper/AbstractEngine.java index cc11e46..50897f8 100644 --- a/src/main/java/com/fathzer/jchess/uci/helper/AbstractEngine.java +++ b/src/main/java/com/fathzer/jchess/uci/helper/AbstractEngine.java @@ -12,7 +12,7 @@ import com.fathzer.games.ai.iterativedeepening.IterativeDeepeningEngine; import com.fathzer.games.ai.time.TimeManager; import com.fathzer.games.ai.transposition.TranspositionTable; -import com.fathzer.jchess.uci.BestMoveReply; +import com.fathzer.jchess.uci.GoReply; import com.fathzer.jchess.uci.Engine; import com.fathzer.jchess.uci.LongRunningTask; import com.fathzer.jchess.uci.UCIMove; @@ -113,16 +113,16 @@ public void move(UCIMove move) { } @Override - public LongRunningTask go(GoParameters options) { + public LongRunningTask go(GoParameters options) { return new LongRunningTask<>() { @Override - public BestMoveReply get() { + public GoReply get() { final UCIEngineSearchConfiguration c = new UCIEngineSearchConfiguration<>(timeManager); final UCIEngineSearchConfiguration.EngineConfiguration previous = c.configure(engine, options, board); final List candidates = options.getMoveToSearch().stream().map(AbstractEngine.this::toMove).toList(); final M move = engine.getBestMove(board, candidates.isEmpty() ? null : candidates); c.set(engine, previous); - return new BestMoveReply(move==null ? null : toUCI(move)); + return new GoReply(move==null ? null : toUCI(move)); } @Override