A partial (but still usable) java implementation of the chess UCI protocol with pluggable chess engines.
This library requires Java 17+ and is available in Maven central.
- First create a class that implements the
com.fathzer.jchess.uci.Engineinterface.
Let's say this implementation class isMyEngine. - Launch the
com.fathzer.jchess.uci.UCIclass:
// Create your engine
final Engine = new MyEngine();
// Launch UCI interface
try (UCI uci = new UCI(engine)) {
uci.run();
}If you plan to use the perft and test commands described below, launch the ExtendedUCI class instead of UCI.
That's all!
This implementation does not directly support the following commands (but you can add them in your own com.fathzer.jchess.uci.UCI subclass):
- Dont miss the ShredderChess Annual Barbeque: This command was in the original specification ... But was a joke.
- register: As a promoter of open source free sofware, I will not encourage you to develop software that requires registration.
- ponderhit is not yet implemented.
- Only depth, score and pv are implemented in info lines preceding go reply.
It also does not recognize commands starting with unknown token (to be honest, it's not very hard to implement but seemed a very bad, error prone, idea to me).
The following extensions are implemented in UCI class:
- It can accept different engines, that can be selected using the engine command. You can view these engines as plugins.
- engine [engineId] lists the available engines' ids or changes the engine if engineId is provided.
- q is a shortcut for standard quit command
The ExtendedUCI class implements the following extensions in addition of the standard commands:
- d [fen] displays a textual representation of the game. If the command is followed by fen, the command displays the representation of a game in the Forsyth–Edwards Notation.
Please note this command is optional, only engines that implementcom.fathzer.jchess.uci.extended.Displayableinterface support it. - perft depth [threads nb] [legal] [playleaves] runs perft test and displays the divide result.
depth is mandatory and is the search depth of the perft algorithm. It should be strictly positive.
threads is followed by the number of threads used to process the queries. This number should be strictly positive. Default is 1. threads can be replaced by the shortcut t.
legal uses legal moves from the move generator instead of the default pseudo-legal moves. legal can be replaced by the shortcut l.
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.
Please note this command is optional, only engines that implementcom.fathzer.jchess.uci.extended.MoveGeneratorSupplierinterface support it.
If the engine implements thecom.fathzer.jchess.uci.extended.MoveToUCIConverterinterface, the divide result displays moves in UCI format, otherwise the move's toString method is used. - test depth [threads nb] [legal] [playleaves] [cut s] runs a move generator test based on perft.
It can also be used to test move generator's performance as it outputs the number of moves generated per second.
depth is mandatory and is the search depth of the perft algorithm. It should be strictly positive.
threads is followed by the number of threads used to process the test. This number should be strictly positive. Default is 1. threads can be replaced by the shortcut t.
legal uses legal moves from the move generator instead of the default pseudo-legal moves. legal can be replaced by the shortcut l.
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.games.perft.TestableMoveGeneratorBuilderinterface support it. - This command requires the
com.fathzer.jchess.uci.extended.ExtendedUCI.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 artifact to your classpath, then overridereadTestData:
- This command is optional, only engines that implement
protected Collection<PerfTTestData> readTestData() {
try (InputStream stream = MyUCISubclass.class.getResourceAsStream("/com/fathzer/jchess/perft/Perft.txt")) {
return new PerfTParser().withStartPositionPrefix("position fen").withStartPositionCustomizer(s -> s+" 0 1").read(stream, StandardCharsets.UTF_8);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}At program startup (when uci.run() is called), if the uciInitCommands system property is set, it is used as the path of a file that contains an uci command per line.
Every commands are executed once, before starting to listen to the standard input for commands issued by the GUI.
Override the com.fathzer.jchess.uci.UCI or com.fathzer.jchess.uci.extended.ExtendedUCI classes and use its addCommand method to add your own custom commands.
Then instantiate your UCI subclass and launch its run method.
UCI protocol uses standard input and output console to communicate which is effective ... but not really modern.
If you want another way to exchange messages, you can subclass the UCI class and override the getNextCommand and/or the out (and debug if you send debug messages) methods.
If you do not use the com.fathzer.jchess.uci.extended and com.fathzer.jchess.uci.helper packages, you can exclude the com.fathzer:games-core dependency.
- Verify the engine is protected against strange client behavior (like changing the position during a go request).
- Implement support for pondering.