Added UCIReceiver and UCIListner, implemented a part of the UCI protocol

This commit is contained in:
Kai S. K. Engelbart 2019-07-19 22:16:02 +02:00
parent 495e784852
commit 2c6b801038
Signed by: kske
GPG Key ID: 8BEB13EC5DF7EF13
4 changed files with 277 additions and 41 deletions

View File

@ -35,6 +35,6 @@ public class UCIPlayer extends Player {
}
public void disconnect() {
handle.quit();
}
}

View File

@ -1,8 +1,6 @@
package dev.kske.chess.uci;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
/**
@ -14,60 +12,83 @@ import java.io.PrintWriter;
public class UCIHandle {
private final Process process;
private final BufferedReader in;
private final PrintWriter out;
private final UCIReceiver receiver;
private String name, author;
public UCIHandle(String enginePath) throws IOException {
process = new ProcessBuilder(enginePath).start();
in = new BufferedReader(new InputStreamReader(process.getInputStream()));
out = new PrintWriter(process.getOutputStream());
receiver = new UCIReceiver(process.getInputStream());
}
public void processInput() {
try {
while (in.ready())
parse(in.readLine());
} catch (IndexOutOfBoundsException ex) {
System.err.println("Too few arguments were provided!");
ex.printStackTrace();
} catch (IOException ex) {
ex.printStackTrace();
}
}
private void parse(String line) {
String command = line.substring(0, line.indexOf(' '));
switch (command) {
case "id":
parseId(line.substring(command.length() + 1));
break;
default:
System.err.printf("Unknown command '%s' found!%n", command);
}
}
private void parseId(String line) {
String param = line.substring(line.indexOf(' '));
String arg = line.substring(param.length() + 1);
switch (line) {
case "name":
name = arg;
break;
case "author":
author = arg;
break;
default:
System.err.printf("Unknown parameter '%s' for command 'id' found!%n", param);
}
public void start() {
uci();
new Thread(receiver).start();
}
/**
* 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");
}
/**
* 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");
}
/**
* Stops calculation as soon as possible.
*/
public void stop() {
out.println("stop");
}
/**
* Quits the engine process as soon as possible.
*/
public void quit() {
out.println("quit");
}
/**
* @return The name of the engine
*/
public String getName() { return name; }
/**
* @return The author of the engine
*/
public String getAuthor() { return author; }
}

View File

@ -0,0 +1,104 @@
package dev.kske.chess.uci;
import java.util.Map;
/**
* Project: <strong>Chess</strong><br>
* File: <strong>UCIListener.java</strong><br>
* Created: <strong>19.07.2019</strong><br>
* Author: <strong>Kai S. K. Engelbart</strong>
*/
public interface UCIListener {
/**
* Identifies the name of the engine.
*
* @param name The name of the engine
*/
void onIdName(String name);
/**
* Identifies the author of the engine.
*
* @param author The name of the engine's author
*/
void onIdAuthor(String author);
/**
* The engine is ready in UCI mode.
*/
void onUCIOk();
/**
* The engine has processed all inputs and is ready for new commands.
*/
void onReadyOk();
/**
* The engine has stopped searching and has found the best move.
*
* @param move The best moves the engine has found
*/
void onBestMove(String move);
/**
* The engine has stopped searching and has found the best move.
*
* @param move The best move the engine has found
* @param ponderMove The move the engine likes to ponder on
*/
void onBestMove(String move, String ponderMove);
/**
* The engine will check the copy protection now.
*/
void onCopyProtectionChecking();
/**
* The engine has successfully checked the copy protection.
*/
void onCopyProtectionOk();
/**
* The engine has encountered an error during copy protection checking.
*/
void onCopyProtectionError();
/**
* The engine will check the registration now.
*/
void onRegistrationChecking();
/**
* The engine has successfully checked the registration.
*/
void onRegistrationOk();
/**
* The engine has encountered an error during registration checking.
*/
void onRegistrationError();
/**
* The engine sends information to the GUI.
*
* @param additionalInfo Contains all pieces of information to be sent
*/
void onInfo(Map<String, String> additionalInfo);
/**
* Tells the GUI which parameters can be changed in the engine.
*
* @param name The name of the option
* @param type The GUI component through which the option should be set
* @param defaultVal The default value of this parameter
* @param minVal The minimum value of this parameter
* @param maxVal The maximum value of this parameter
* @param var A predefined value of this parameter
*/
void onOption(String name, GUIType type, String defaultVal, String minVal, String maxVal, String var);
public static enum GUIType {
CHECK, SPIN, COMBO, BUTTON, STRING
}
}

View File

@ -0,0 +1,111 @@
package dev.kske.chess.uci;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
/**
* Project: <strong>Chess</strong><br>
* File: <strong>UCIReceiver.java</strong><br>
* Created: <strong>19.07.2019</strong><br>
* Author: <strong>Kai S. K. Engelbart</strong>
*/
public class UCIReceiver implements Runnable {
private final BufferedReader in;
private UCIListener listener;
public UCIReceiver(InputStream in) {
this.in = new BufferedReader(new InputStreamReader(in));
}
@Override
public void run() {
try {
while (in.ready())
parse(in.readLine());
} catch (IndexOutOfBoundsException ex) {
System.err.println("Too few arguments were provided!");
ex.printStackTrace();
} catch (IOException ex) {
ex.printStackTrace();
}
}
private void parse(String line) {
String command = line.substring(0, line.indexOf(' '));
switch (command) {
case "id":
parseId(line.substring(command.length() + 1));
break;
case "uciok":
listener.onUCIOk();
break;
case "readyok":
listener.onReadyOk();
break;
// TODO: bestmove
case "copyprotection":
parseCopyProtection(line.substring(command.length() + 1));
break;
case "registration":
parseRegistration(line.substring(command.length() + 1));
break;
// TODO: info
// TODO: option
default:
System.err.printf("Unknown command '%s' found!%n", command);
}
}
private void parseId(String line) {
String param = line.substring(line.indexOf(' '));
String arg = line.substring(param.length() + 1);
switch (line) {
case "name":
listener.onIdName(arg);
break;
case "author":
listener.onIdAuthor(arg);
break;
default:
System.err.printf("Unknown parameter '%s' for command 'id' found!%n", param);
}
}
private void parseCopyProtection(String line) {
switch (line) {
case "checking":
listener.onCopyProtectionChecking();
break;
case "ok":
listener.onCopyProtectionOk();
break;
case "error":
listener.onCopyProtectionError();
break;
default:
System.err.printf("Unknown parameter '%s' for command 'copyprotection' found!%n", line);
}
}
private void parseRegistration(String line) {
switch (line) {
case "checking":
listener.onRegistrationChecking();
break;
case "ok":
listener.onRegistrationOk();
break;
case "error":
listener.onRegistrationError();
break;
default:
System.err.printf("Unknown parameter '%s' for command 'registration' found!%n", line);
}
}
public void setListener(UCIListener listener) { this.listener = listener; }
}