2019-07-19 22:16:02 +02:00
|
|
|
package dev.kske.chess.uci;
|
|
|
|
|
|
|
|
import java.io.BufferedReader;
|
|
|
|
import java.io.IOException;
|
|
|
|
import java.io.InputStream;
|
|
|
|
import java.io.InputStreamReader;
|
2019-07-20 06:36:56 +02:00
|
|
|
import java.util.Arrays;
|
|
|
|
import java.util.HashMap;
|
|
|
|
import java.util.Map;
|
2019-07-22 07:29:58 +02:00
|
|
|
import java.util.StringJoiner;
|
2019-07-20 06:36:56 +02:00
|
|
|
|
2019-07-22 08:59:13 +02:00
|
|
|
import dev.kske.chess.uci.UCIOption.GUIType;
|
2019-07-19 22:16:02 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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() {
|
2019-07-22 07:29:58 +02:00
|
|
|
String line;
|
|
|
|
while (!Thread.currentThread().isInterrupted())
|
|
|
|
try {
|
2019-07-22 21:40:25 +02:00
|
|
|
if ((line = in.readLine()) != null && !line.isEmpty()) parse(line);
|
2019-07-22 07:29:58 +02:00
|
|
|
} catch (IndexOutOfBoundsException ex) {
|
|
|
|
System.err.println("Too few arguments were provided!");
|
|
|
|
ex.printStackTrace();
|
|
|
|
} catch (IOException ex) {
|
|
|
|
ex.printStackTrace();
|
|
|
|
}
|
2019-07-19 22:16:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private void parse(String line) {
|
2019-07-22 07:29:58 +02:00
|
|
|
int spaceIndex = line.indexOf(' ');
|
|
|
|
String command = spaceIndex == -1 ? line : line.substring(0, spaceIndex);
|
2019-07-19 22:16:02 +02:00
|
|
|
switch (command) {
|
|
|
|
case "id":
|
|
|
|
parseId(line.substring(command.length() + 1));
|
|
|
|
break;
|
|
|
|
case "uciok":
|
|
|
|
listener.onUCIOk();
|
|
|
|
break;
|
|
|
|
case "readyok":
|
|
|
|
listener.onReadyOk();
|
|
|
|
break;
|
2019-07-22 14:51:24 +02:00
|
|
|
case "bestmove":
|
|
|
|
parseBestMove(line.substring(command.length() + 1));
|
|
|
|
break;
|
2019-07-19 22:16:02 +02:00
|
|
|
case "copyprotection":
|
|
|
|
parseCopyProtection(line.substring(command.length() + 1));
|
|
|
|
break;
|
|
|
|
case "registration":
|
|
|
|
parseRegistration(line.substring(command.length() + 1));
|
|
|
|
break;
|
2019-07-20 06:36:56 +02:00
|
|
|
case "info":
|
|
|
|
parseInfo(line.substring(command.length() + 1));
|
|
|
|
break;
|
|
|
|
case "option":
|
|
|
|
parseOption(line.substring(command.length() + 1));
|
|
|
|
break;
|
2019-07-19 22:16:02 +02:00
|
|
|
default:
|
|
|
|
System.err.printf("Unknown command '%s' found!%n", command);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void parseId(String line) {
|
2019-07-21 14:35:14 +02:00
|
|
|
String param = line.substring(0, line.indexOf(' '));
|
2019-07-19 22:16:02 +02:00
|
|
|
String arg = line.substring(param.length() + 1);
|
2019-07-21 14:35:14 +02:00
|
|
|
switch (param) {
|
2019-07-19 22:16:02 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-22 14:51:24 +02:00
|
|
|
private void parseBestMove(String line) {
|
|
|
|
String[] tokens = line.split(" ");
|
|
|
|
String move = tokens[0];
|
|
|
|
|
|
|
|
// Ponder move
|
|
|
|
if (tokens.length == 3) listener.onBestMove(move, tokens[2]);
|
|
|
|
else listener.onBestMove(move);
|
|
|
|
}
|
|
|
|
|
2019-07-19 22:16:02 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-20 06:36:56 +02:00
|
|
|
private void parseInfo(String line) {
|
|
|
|
String[] tokens = line.split(" ");
|
|
|
|
Map<String, String> additionalInfo = new HashMap<>();
|
|
|
|
|
|
|
|
for (int i = 0; i < tokens.length; i++)
|
|
|
|
switch (tokens[i]) {
|
|
|
|
// Single parameter info
|
|
|
|
case "depth":
|
|
|
|
case "seldepth":
|
|
|
|
case "time":
|
|
|
|
case "nodes":
|
|
|
|
case "multipv":
|
|
|
|
case "currmove":
|
|
|
|
case "currmovenumber":
|
|
|
|
case "hashfull":
|
|
|
|
case "nps":
|
|
|
|
case "tbhits":
|
|
|
|
case "sbhits":
|
|
|
|
case "cpuload":
|
|
|
|
case "string":
|
|
|
|
additionalInfo.put(tokens[i], tokens[++i]);
|
|
|
|
break;
|
|
|
|
// TODO: pv
|
|
|
|
// TODO: score
|
|
|
|
// TODO: refutation
|
|
|
|
// TODO: currline
|
|
|
|
default:
|
|
|
|
System.err.printf("Unknown parameter '%s' for command 'info' found!%n", tokens[i]);
|
|
|
|
}
|
|
|
|
listener.onInfo(additionalInfo);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void parseOption(String line) {
|
|
|
|
String[] tokens = line.split(" ");
|
2019-07-22 08:59:13 +02:00
|
|
|
UCIOption option = new UCIOption();
|
2019-07-20 06:36:56 +02:00
|
|
|
|
|
|
|
for (int i = 0; i < tokens.length; i++)
|
|
|
|
switch (tokens[i]) {
|
|
|
|
case "name":
|
2019-07-22 08:59:13 +02:00
|
|
|
StringJoiner name = new StringJoiner(" ");
|
2019-07-22 07:29:58 +02:00
|
|
|
while (!Arrays.asList("type", "default", "min", "max", "var").contains(tokens[i + 1]))
|
|
|
|
name.add(tokens[++i]);
|
2019-07-22 08:59:13 +02:00
|
|
|
option.name = name.toString();
|
2019-07-20 06:36:56 +02:00
|
|
|
break;
|
|
|
|
case "type":
|
2019-07-22 08:59:13 +02:00
|
|
|
option.type = GUIType.valueOf(tokens[++i].toUpperCase());
|
2019-07-22 07:29:58 +02:00
|
|
|
break;
|
|
|
|
case "default":
|
|
|
|
// Default string may be empty
|
2019-07-22 08:59:13 +02:00
|
|
|
option.defaultVal = i == tokens.length - 1 ? "" : tokens[++i];
|
2019-07-20 06:36:56 +02:00
|
|
|
break;
|
2019-07-22 07:29:58 +02:00
|
|
|
case "min":
|
2019-07-22 08:59:13 +02:00
|
|
|
option.minVal = tokens[++i];
|
2019-07-20 06:36:56 +02:00
|
|
|
break;
|
2019-07-22 07:29:58 +02:00
|
|
|
case "max":
|
2019-07-22 08:59:13 +02:00
|
|
|
option.maxVal = tokens[++i];
|
2019-07-20 06:36:56 +02:00
|
|
|
break;
|
|
|
|
case "var":
|
2019-07-22 08:59:13 +02:00
|
|
|
option.varList.add(tokens[++i]);
|
2019-07-20 06:36:56 +02:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
System.err.printf("Unknown parameter '%s' for command 'option' found!%n", tokens[i]);
|
|
|
|
}
|
2019-07-22 08:59:13 +02:00
|
|
|
listener.onOption(option);
|
2019-07-20 06:36:56 +02:00
|
|
|
}
|
|
|
|
|
2019-07-19 22:16:02 +02:00
|
|
|
public void setListener(UCIListener listener) { this.listener = listener; }
|
|
|
|
}
|