255 lines
6.4 KiB
Java
255 lines
6.4 KiB
Java
package dev.kske.chess.uci;
|
|
|
|
import java.io.IOException;
|
|
import java.io.PrintWriter;
|
|
import java.util.List;
|
|
import java.util.StringJoiner;
|
|
|
|
import dev.kske.chess.board.Move;
|
|
|
|
/**
|
|
* Project: <strong>Chess</strong><br>
|
|
* File: <strong>UCIHandle.java</strong><br>
|
|
* Created: <strong>18.07.2019</strong><br>
|
|
*
|
|
* @since Chess v0.3-alpha
|
|
* @author Kai S. K. Engelbart
|
|
*/
|
|
public class UCIHandle {
|
|
|
|
private final Process process;
|
|
private final PrintWriter out;
|
|
private final UCIReceiver receiver;
|
|
|
|
/**
|
|
* Creates an instance of {@link UCIHandle}. The engine process is started
|
|
* and
|
|
* passed to a new {@link UCIReceiver}.
|
|
*
|
|
* @param enginePath the path to the engine executable
|
|
* @throws IOException if the engine process could not be started
|
|
*/
|
|
public UCIHandle(String enginePath) throws IOException {
|
|
process = new ProcessBuilder(enginePath).start();
|
|
out = new PrintWriter(process.getOutputStream(), true);
|
|
receiver = new UCIReceiver(process.getInputStream());
|
|
}
|
|
|
|
/**
|
|
* Starts the {@link UCIReceiver} used to gather engine output.
|
|
*/
|
|
public void start() {
|
|
new Thread(receiver, "UCI Receiver").start();
|
|
uci();
|
|
}
|
|
|
|
/**
|
|
* Tells the engine to use UCI.
|
|
*/
|
|
public void uci() {
|
|
out.println("uci");
|
|
}
|
|
|
|
/**
|
|
* Switches the debug mode of the engine on or off.
|
|
*
|
|
* @param debug Enables debugging if set to {@code true}, disables it
|
|
* otherwise
|
|
*/
|
|
public void debug(boolean debug) {
|
|
out.println("debug " + (debug ? "on" : "off"));
|
|
}
|
|
|
|
/**
|
|
* Synchronized the engine with the GUI
|
|
*/
|
|
public void isready() {
|
|
out.println("isready");
|
|
}
|
|
|
|
/**
|
|
* Signifies a button press to the engine.
|
|
*
|
|
* @param name The name of the button
|
|
*/
|
|
public void setOption(String name) {
|
|
out.println("setoption name " + name);
|
|
}
|
|
|
|
/**
|
|
* Changes an internal parameter of the engine.
|
|
*
|
|
* @param name The name of the parameter
|
|
* @param value The value of the parameter
|
|
*/
|
|
public void setOption(String name, String value) {
|
|
out.printf("setoption name %s value %s%n", name, value);
|
|
}
|
|
|
|
/**
|
|
* Registers the engine
|
|
*
|
|
* @param name The name the engine should be registered with
|
|
* @param code The code the engine should be registered with
|
|
*/
|
|
public void register(String name, String code) {
|
|
out.printf("register %s %s%n", name, code);
|
|
}
|
|
|
|
/**
|
|
* Tells the engine to postpone the registration.
|
|
*/
|
|
public void registerLater() {
|
|
out.println("register later");
|
|
}
|
|
|
|
/**
|
|
* Tells the engine that the next search will be from a different game.
|
|
*/
|
|
public void uciNewGame() {
|
|
out.println("ucinewgame");
|
|
}
|
|
|
|
/**
|
|
* Sets up the position in its initial state.
|
|
*/
|
|
public void positionStartpos() {
|
|
out.println("position startpos");
|
|
}
|
|
|
|
/**
|
|
* Sets up the position described in the FEN string.
|
|
*
|
|
* @param fen FEN representation of the current board
|
|
*/
|
|
public void positionFEN(String fen) {
|
|
out.println("position fen " + fen);
|
|
}
|
|
|
|
/**
|
|
* Sets up the position described by a list of moves.
|
|
*
|
|
* @param moves the moves to execute from the starting position to reach the
|
|
* desired position
|
|
*/
|
|
public void positionMoves(List<Move> moves) {
|
|
StringJoiner joiner = new StringJoiner(" ");
|
|
moves.forEach(m -> joiner.add(m.toLAN()));
|
|
out.println("position moves " + joiner);
|
|
}
|
|
|
|
/**
|
|
* Starts calculating on the current position.
|
|
*/
|
|
public void go() {
|
|
out.println("go");
|
|
}
|
|
|
|
/**
|
|
* Starts calculating on the current position.
|
|
* This command has multiple optional parameters which will only be included
|
|
* in
|
|
* the call if they are not {@code null}, greater than zero or {@code true}
|
|
* for
|
|
* {@code searchMoves}, all integer parameters and all boolean parameters
|
|
* respectively.
|
|
*
|
|
* @param searchMoves restrict the search to these moves only
|
|
* @param ponder start the search in ponder mode
|
|
* @param wTime the amount of milliseconds left on white's clock
|
|
* @param bTime the amount of milliseconds left on black's clocks
|
|
* @param wInc white's increment per move in milliseconds
|
|
* @param bInc black's increment per move in milliseconds
|
|
* @param movesToGo the number of moves left until the next time control
|
|
* @param depth the maximal amount of plies to search
|
|
* @param nodes the maximal amount of nodes to search
|
|
* @param mate the amount of moves in which to search for a mate
|
|
* @param moveTime the exact search time
|
|
* @param infinite search until the {@code stop} command
|
|
*/
|
|
public void go(
|
|
List<Move> searchMoves, boolean ponder, int wTime, int bTime, int wInc,
|
|
int bInc, int movesToGo, int depth, int nodes, int mate,
|
|
int moveTime, boolean infinite
|
|
) {
|
|
StringJoiner joiner = new StringJoiner(" ");
|
|
joiner.add("go");
|
|
|
|
if (searchMoves != null && !searchMoves.isEmpty()) {
|
|
joiner.add("searchmoves");
|
|
searchMoves.forEach(m -> joiner.add(m.toLAN()));
|
|
}
|
|
if (ponder)
|
|
joiner.add("ponder");
|
|
if (wTime > 0) {
|
|
joiner.add("wtime");
|
|
joiner.add(String.valueOf(wTime));
|
|
}
|
|
if (bTime > 0) {
|
|
joiner.add("btime");
|
|
joiner.add(String.valueOf(bTime));
|
|
}
|
|
if (wInc > 0) {
|
|
joiner.add("winc");
|
|
joiner.add(String.valueOf(wInc));
|
|
}
|
|
if (bInc > 0) {
|
|
joiner.add("bind");
|
|
joiner.add(String.valueOf(bInc));
|
|
}
|
|
if (movesToGo > 0) {
|
|
joiner.add("movestogo");
|
|
joiner.add(String.valueOf(movesToGo));
|
|
}
|
|
if (depth > 0) {
|
|
joiner.add("depth");
|
|
joiner.add(String.valueOf(depth));
|
|
}
|
|
if (nodes > 0) {
|
|
joiner.add("nodes");
|
|
joiner.add(String.valueOf(nodes));
|
|
}
|
|
if (mate > 0) {
|
|
joiner.add("mate");
|
|
joiner.add(String.valueOf(mate));
|
|
}
|
|
if (moveTime > 0) {
|
|
joiner.add("movetime");
|
|
joiner.add(String.valueOf(moveTime));
|
|
}
|
|
if (infinite)
|
|
joiner.add("infinite");
|
|
out.println(joiner);
|
|
}
|
|
|
|
/**
|
|
* Stops calculation as soon as possible.
|
|
*/
|
|
public void stop() {
|
|
out.println("stop");
|
|
}
|
|
|
|
/**
|
|
* Tells the engine that the user has played the expected move.
|
|
*/
|
|
public void ponderHit() {
|
|
out.println("ponderhit");
|
|
}
|
|
|
|
/**
|
|
* Quits the engine process as soon as possible.
|
|
*/
|
|
public void quit() {
|
|
out.println("quit");
|
|
}
|
|
|
|
/**
|
|
* Registers a UCI listener.
|
|
*
|
|
* @param listener the UCI listener to register
|
|
*/
|
|
public void registerListener(UCIListener listener) {
|
|
receiver.registerListener(listener);
|
|
}
|
|
}
|