mirror of
https://github.com/peterosterlund2/droidfish.git
synced 2025-01-31 01:20:46 +01:00
DroidFish: Implemented support for external UCI engines.
This commit is contained in:
parent
a1fdce1942
commit
c653ef8ec2
|
@ -44,6 +44,10 @@
|
|||
android:title="@string/option_select_book">
|
||||
</item>
|
||||
<item
|
||||
android:id="@+id/select_engine"
|
||||
android:title="@string/option_select_engine">
|
||||
</item>
|
||||
<item
|
||||
android:id="@+id/set_color_theme"
|
||||
android:title="@string/option_color_theme">
|
||||
</item>
|
||||
|
|
|
@ -1,14 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">DroidFish</string>
|
||||
<string-array name="engine_texts">
|
||||
<item>Stockfish</item>
|
||||
<item>CuckooChess</item>
|
||||
</string-array>
|
||||
<string-array name="engine_values">
|
||||
<item>stockfish</item>
|
||||
<item>cuckoochess</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="engine_threads_texts">
|
||||
<item>Automatisch</item>
|
||||
<item>1</item>
|
||||
|
@ -414,8 +407,6 @@ wenn Sie es nicht aktiv nutzen.\
|
|||
<string name="prefs_autoSwapSides_title">Automatischer Seitenwechsel</string>
|
||||
<string name="prefs_autoSwapSides_summary">Seiten beim Start einer neuen Partie automatisch wechseln (Einstellung <i>Ansicht drehen</i> ignorieren)</string>
|
||||
<string name="prefs_engine_settings">Engine-Einstellungen</string>
|
||||
<string name="prefs_engine_title">Schach-Engine</string>
|
||||
<string name="prefs_engine_summary">Auswahl der Schach-Engine</string>
|
||||
<string name="prefs_strength_title">Spielstärke</string>
|
||||
<string name="prefs_ponderMode_title">Vorausberechnung</string>
|
||||
<string name="prefs_ponderMode_summary">Vorausberechnung von Zügen durch die Engine, wenn der Spieler am Zug ist</string>
|
||||
|
|
|
@ -1,15 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">DroidFish</string>
|
||||
<string-array name="engine_texts">
|
||||
<item>Stockfish</item>
|
||||
<item>CuckooChess</item>
|
||||
</string-array>
|
||||
<string-array name="engine_values">
|
||||
<item>stockfish</item>
|
||||
<item>cuckoochess</item>
|
||||
</string-array>
|
||||
<string name="engine_default">stockfish</string>
|
||||
|
||||
<string-array name="engine_threads_texts">
|
||||
<item>Automatic</item>
|
||||
|
@ -305,6 +296,7 @@ you are not actively using the program.\
|
|||
<string name="edit_move_counters">Edit Move Counters</string>
|
||||
<string name="internal_book"><Internal Book></string>
|
||||
<string name="select_opening_book_file">Select opening book file</string>
|
||||
<string name="select_chess_engine">Select Chess Engine</string>
|
||||
<string name="select_pgn_file">Select PGN file to open</string>
|
||||
<string name="select_pgn_file_save">Save to PGN file</string>
|
||||
<string name="select_scid_file">Select Scid file to open</string>
|
||||
|
@ -401,6 +393,9 @@ you are not actively using the program.\
|
|||
<string name="after_selected">After Selected</string>
|
||||
<string name="replace_selected">Replace Selected</string>
|
||||
<string name="engine">Engine</string>
|
||||
<string name="engine_error">Engine error</string>
|
||||
<string name="stockfish_engine">Stockfish</string>
|
||||
<string name="cuckoochess_engine">CuckooChess</string>
|
||||
|
||||
<string name="err_too_few_spaces">Too few spaces</string>
|
||||
<string name="err_invalid_piece">Invalid piece</string>
|
||||
|
@ -425,6 +420,7 @@ you are not actively using the program.\
|
|||
<string name="option_force_computer_move">Force Computer Move</string>
|
||||
<string name="option_draw">Claim/Offer/Accept Draw</string>
|
||||
<string name="option_select_book">Select Opening Book</string>
|
||||
<string name="option_select_engine">Select Chess Engine</string>
|
||||
<string name="option_color_theme">Set Color Theme</string>
|
||||
<string name="option_about">About / Help</string>
|
||||
|
||||
|
@ -434,8 +430,6 @@ you are not actively using the program.\
|
|||
<string name="prefs_autoSwapSides_title">Auto Swap Sides</string>
|
||||
<string name="prefs_autoSwapSides_summary">Automatically swap sides when new game started. Also overrides Flip Board setting</string>
|
||||
<string name="prefs_engine_settings">Engine Settings</string>
|
||||
<string name="prefs_engine_title">Engine</string>
|
||||
<string name="prefs_engine_summary">Chess Engine</string>
|
||||
<string name="prefs_strength_title">Strength</string>
|
||||
<string name="prefs_ponderMode_title">Pondering</string>
|
||||
<string name="prefs_ponderMode_summary">Let engine think while waiting for opponent\'s move</string>
|
||||
|
|
|
@ -18,14 +18,6 @@
|
|||
</PreferenceCategory>
|
||||
<PreferenceCategory
|
||||
android:title="@string/prefs_engine_settings">
|
||||
<ListPreference
|
||||
android:key="engine"
|
||||
android:title="@string/prefs_engine_title"
|
||||
android:summary="@string/prefs_engine_summary"
|
||||
android:entryValues="@array/engine_values"
|
||||
android:entries="@array/engine_texts"
|
||||
android:defaultValue="@string/engine_default">
|
||||
</ListPreference>
|
||||
<org.petero.droidfish.SeekBarPreference
|
||||
android:key="strength"
|
||||
android:defaultValue="1000"
|
||||
|
|
|
@ -160,6 +160,7 @@ public class DroidFish extends Activity implements GUIInterface {
|
|||
|
||||
private final static String bookDir = "DroidFish";
|
||||
private final static String pgnDir = "DroidFish" + File.separator + "pgn";
|
||||
private final static String engineDir = "DroidFish" + File.separator + "uci";
|
||||
private BookOptions bookOptions = new BookOptions();
|
||||
private PGNOptions pgnOptions = new PGNOptions();
|
||||
|
||||
|
@ -732,6 +733,10 @@ public class DroidFish extends Activity implements GUIInterface {
|
|||
removeDialog(SELECT_BOOK_DIALOG);
|
||||
showDialog(SELECT_BOOK_DIALOG);
|
||||
return true;
|
||||
case R.id.select_engine:
|
||||
removeDialog(SELECT_ENGINE_DIALOG);
|
||||
showDialog(SELECT_ENGINE_DIALOG);
|
||||
return true;
|
||||
case R.id.set_color_theme:
|
||||
showDialog(SET_COLOR_THEME_DIALOG);
|
||||
return true;
|
||||
|
@ -1004,16 +1009,17 @@ public class DroidFish extends Activity implements GUIInterface {
|
|||
static private final int ABOUT_DIALOG = 2;
|
||||
static private final int SELECT_MOVE_DIALOG = 3;
|
||||
static private final int SELECT_BOOK_DIALOG = 4;
|
||||
static private final int SELECT_PGN_FILE_DIALOG = 5;
|
||||
static private final int SELECT_PGN_FILE_SAVE_DIALOG = 6;
|
||||
static private final int SET_COLOR_THEME_DIALOG = 7;
|
||||
static private final int GAME_MODE_DIALOG = 8;
|
||||
static private final int SELECT_PGN_SAVE_NEWFILE_DIALOG = 9;
|
||||
static private final int MOVELIST_MENU_DIALOG = 10;
|
||||
static private final int THINKING_MENU_DIALOG = 11;
|
||||
static private final int GO_BACK_MENU_DIALOG = 12;
|
||||
static private final int GO_FORWARD_MENU_DIALOG = 13;
|
||||
static private final int FILE_MENU_DIALOG = 14;
|
||||
static private final int SELECT_ENGINE_DIALOG = 5;
|
||||
static private final int SELECT_PGN_FILE_DIALOG = 6;
|
||||
static private final int SELECT_PGN_FILE_SAVE_DIALOG = 7;
|
||||
static private final int SET_COLOR_THEME_DIALOG = 8;
|
||||
static private final int GAME_MODE_DIALOG = 9;
|
||||
static private final int SELECT_PGN_SAVE_NEWFILE_DIALOG = 10;
|
||||
static private final int MOVELIST_MENU_DIALOG = 11;
|
||||
static private final int THINKING_MENU_DIALOG = 12;
|
||||
static private final int GO_BACK_MENU_DIALOG = 13;
|
||||
static private final int GO_FORWARD_MENU_DIALOG = 14;
|
||||
static private final int FILE_MENU_DIALOG = 15;
|
||||
|
||||
@Override
|
||||
protected Dialog onCreateDialog(int id) {
|
||||
|
@ -1225,6 +1231,45 @@ public class DroidFish extends Activity implements GUIInterface {
|
|||
AlertDialog alert = builder.create();
|
||||
return alert;
|
||||
}
|
||||
case SELECT_ENGINE_DIALOG: {
|
||||
String[] fileNames = findFilesInDirectory(engineDir, null);
|
||||
final int numFiles = fileNames.length;
|
||||
final String[] items = new String[numFiles + 2];
|
||||
final String[] ids = new String[numFiles + 2];
|
||||
ids[0] = "stockfish"; items[0] = getString(R.string.stockfish_engine);
|
||||
ids[1] = "cuckoochess"; items[1] = getString(R.string.cuckoochess_engine);
|
||||
String sep = File.separator;
|
||||
String base = Environment.getExternalStorageDirectory() + sep + engineDir + sep;
|
||||
for (int i = 0; i < numFiles; i++) {
|
||||
ids[i+2] = base + fileNames[i];
|
||||
items[i+2] = fileNames[i];
|
||||
}
|
||||
String currEngine = ctrl.getEngine();
|
||||
int defaultItem = 0;
|
||||
for (int i = 0; i < ids.length; i++) {
|
||||
if (ids[i].equals(currEngine)) {
|
||||
defaultItem = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setTitle(R.string.select_chess_engine);
|
||||
builder.setSingleChoiceItems(items, defaultItem, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int item) {
|
||||
if ((item < 0) || (item >= ids.length))
|
||||
return;
|
||||
Editor editor = settings.edit();
|
||||
String engine = ids[item];
|
||||
editor.putString("engine", engine);
|
||||
editor.commit();
|
||||
dialog.dismiss();
|
||||
int strength = settings.getInt("strength", 1000);
|
||||
setEngineStrength(engine, strength);
|
||||
}
|
||||
});
|
||||
AlertDialog alert = builder.create();
|
||||
return alert;
|
||||
}
|
||||
case SELECT_PGN_FILE_DIALOG: {
|
||||
final String[] fileNames = findFilesInDirectory(pgnDir, null);
|
||||
final int numFiles = fileNames.length;
|
||||
|
@ -1773,6 +1818,13 @@ public class DroidFish extends Activity implements GUIInterface {
|
|||
Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reportEngineError(String errMsg) {
|
||||
String msg = String.format("%s: %s",
|
||||
getString(R.string.engine_error), errMsg);
|
||||
Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void computerMoveMade() {
|
||||
if (soundEnabled) {
|
||||
|
|
|
@ -67,6 +67,9 @@ public interface GUIInterface {
|
|||
/** Report UCI engine name. */
|
||||
public void reportEngineName(String engine);
|
||||
|
||||
/** Report UCI engine error message. */
|
||||
public void reportEngineError(String errMsg);
|
||||
|
||||
/** Called when computer made a move. GUI can notify user, for example by playing a sound. */
|
||||
public void computerMoveMade();
|
||||
|
||||
|
|
|
@ -25,7 +25,6 @@ import java.util.ArrayList;
|
|||
|
||||
import org.petero.droidfish.book.BookOptions;
|
||||
import org.petero.droidfish.book.DroidBook;
|
||||
import org.petero.droidfish.engine.cuckoochess.CuckooChessEngine;
|
||||
import org.petero.droidfish.gamelogic.Move;
|
||||
import org.petero.droidfish.gamelogic.MoveGen;
|
||||
import org.petero.droidfish.gamelogic.Pair;
|
||||
|
@ -292,10 +291,10 @@ public class DroidComputerPlayer {
|
|||
/** Stop the engine process. */
|
||||
public final synchronized void shutdownEngine() {
|
||||
if (uciEngine != null) {
|
||||
uciEngine.shutDown();
|
||||
uciEngine = null;
|
||||
engineMonitor.interrupt();
|
||||
engineMonitor = null;
|
||||
uciEngine.shutDown();
|
||||
uciEngine = null;
|
||||
}
|
||||
engineState.state = MainState.DEAD;
|
||||
}
|
||||
|
@ -543,15 +542,20 @@ public class DroidComputerPlayer {
|
|||
myAssert(searchRequest != null);
|
||||
|
||||
engineName = "Computer";
|
||||
if ("cuckoochess".equals(searchRequest.engine))
|
||||
uciEngine = new CuckooChessEngine();
|
||||
else
|
||||
uciEngine = new StockFishJNI();
|
||||
uciEngine = UCIEngineBase.getEngine(searchRequest.engine, new UCIEngine.Report() {
|
||||
@Override
|
||||
public void reportError(String errMsg) {
|
||||
if (errMsg != null) {
|
||||
listener.reportEngineError(errMsg);
|
||||
}
|
||||
}
|
||||
});
|
||||
uciEngine.initialize();
|
||||
|
||||
final UCIEngine uci = uciEngine;
|
||||
engineMonitor = new Thread(new Runnable() {
|
||||
public void run() {
|
||||
monitorLoop();
|
||||
monitorLoop(uci);
|
||||
}
|
||||
});
|
||||
engineMonitor.start();
|
||||
|
@ -569,16 +573,17 @@ public class DroidComputerPlayer {
|
|||
private final static long guiUpdateInterval = 100;
|
||||
private long lastGUIUpdate = 0;
|
||||
|
||||
private final void monitorLoop() {
|
||||
private final void monitorLoop(UCIEngine uci) {
|
||||
while (true) {
|
||||
int timeout = getReadTimeout();
|
||||
UCIEngine uci = uciEngine;
|
||||
if (uci == null)
|
||||
return;
|
||||
String s = uci.readLineFromEngine(timeout);
|
||||
if (Thread.currentThread().isInterrupted())
|
||||
return;
|
||||
processEngineOutput(s);
|
||||
String s = uci.readLineFromEngine(timeout);
|
||||
if ((s == null) || Thread.currentThread().isInterrupted())
|
||||
return;
|
||||
processEngineOutput(uci, s);
|
||||
if (Thread.currentThread().isInterrupted())
|
||||
return;
|
||||
notifyGUI();
|
||||
if (Thread.currentThread().isInterrupted())
|
||||
return;
|
||||
|
@ -586,7 +591,10 @@ public class DroidComputerPlayer {
|
|||
}
|
||||
|
||||
/** Process one line of data from the engine. */
|
||||
private final synchronized void processEngineOutput(String s) {
|
||||
private final synchronized void processEngineOutput(UCIEngine uci, String s) {
|
||||
if (Thread.currentThread().isInterrupted())
|
||||
return;
|
||||
|
||||
if (s == null) {
|
||||
shutdownEngine();
|
||||
return;
|
||||
|
@ -595,17 +603,13 @@ public class DroidComputerPlayer {
|
|||
if (s.length() == 0)
|
||||
return;
|
||||
|
||||
UCIEngine uci = uciEngine;
|
||||
if (uci == null)
|
||||
return;
|
||||
switch (engineState.state) {
|
||||
case READ_OPTIONS: {
|
||||
if (readUCIOption(s)) {
|
||||
if (!"cuckoochess".equals(engineState.engine))
|
||||
uci.setOption("Hash", 16);
|
||||
uci.initOptions();
|
||||
uci.setOption("Ponder", false);
|
||||
uci.writeLineToEngine("ucinewgame");
|
||||
uciEngine.writeLineToEngine("isready");
|
||||
uci.writeLineToEngine("isready");
|
||||
engineState.state = MainState.WAIT_READY;
|
||||
}
|
||||
break;
|
||||
|
@ -642,7 +646,7 @@ public class DroidComputerPlayer {
|
|||
case STOP_SEARCH: {
|
||||
String[] tokens = tokenize(s);
|
||||
if (tokens[0].equals("bestmove")) {
|
||||
uciEngine.writeLineToEngine("isready");
|
||||
uci.writeLineToEngine("isready");
|
||||
engineState.state = MainState.WAIT_READY;
|
||||
}
|
||||
break;
|
||||
|
@ -860,6 +864,9 @@ public class DroidComputerPlayer {
|
|||
|
||||
/** Notify GUI about search statistics. */
|
||||
private final synchronized void notifyGUI() {
|
||||
if (Thread.currentThread().isInterrupted())
|
||||
return;
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
if (now < lastGUIUpdate + guiUpdateInterval)
|
||||
return;
|
||||
|
|
183
DroidFish/src/org/petero/droidfish/engine/ExternalEngine.java
Normal file
183
DroidFish/src/org/petero/droidfish/engine/ExternalEngine.java
Normal file
|
@ -0,0 +1,183 @@
|
|||
package org.petero.droidfish.engine;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
public class ExternalEngine extends UCIEngineBase {
|
||||
private File engineFileName;
|
||||
private static final String exePath = "/data/data/org.petero.droidfish/engine.exe";
|
||||
private final Report report;
|
||||
private Process engineProc;
|
||||
private Thread stdInThread;
|
||||
private Thread stdErrThread;
|
||||
private List<String> inLines;
|
||||
|
||||
public ExternalEngine(String engine, Report report) {
|
||||
this.report = report;
|
||||
engineFileName = new File(engine);
|
||||
engineProc = null;
|
||||
stdInThread = null;
|
||||
stdErrThread = null;
|
||||
inLines = new LinkedList<String>();
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
@Override
|
||||
protected void startProcess() {
|
||||
try {
|
||||
copyFile(engineFileName, new File(exePath));
|
||||
chmod(exePath);
|
||||
ProcessBuilder pb = new ProcessBuilder(exePath);
|
||||
engineProc = pb.start();
|
||||
|
||||
// Start a thread to read stdin
|
||||
stdInThread = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Process ep = engineProc;
|
||||
if (ep == null)
|
||||
return;
|
||||
InputStream is = ep.getInputStream();
|
||||
InputStreamReader isr = new InputStreamReader(is);
|
||||
BufferedReader br = new BufferedReader(isr);
|
||||
String line;
|
||||
try {
|
||||
while ((line = br.readLine()) != null) {
|
||||
if ((ep == null) || Thread.currentThread().isInterrupted())
|
||||
return;
|
||||
synchronized (inLines) {
|
||||
inLines.add(line);
|
||||
inLines.notify();
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
stdInThread.start();
|
||||
|
||||
// Start a thread to ignore stderr
|
||||
stdErrThread = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
byte[] buffer = new byte[128];
|
||||
while (true) {
|
||||
Process ep = engineProc;
|
||||
if ((ep == null) || Thread.currentThread().isInterrupted())
|
||||
return;
|
||||
try {
|
||||
ep.getErrorStream().read(buffer);
|
||||
} catch (IOException e) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
stdErrThread.start();
|
||||
} catch (IOException ex) {
|
||||
report.reportError(ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
@Override
|
||||
public void initOptions() {
|
||||
setOption("Hash", 16);
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
@Override
|
||||
public void setStrength(int strength) {
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
@Override
|
||||
public String readLineFromEngine(int timeoutMillis) {
|
||||
try {
|
||||
synchronized (inLines) {
|
||||
if (inLines.size() == 0) {
|
||||
Thread inThread = stdInThread;
|
||||
if ((inThread == null) || !inThread.isAlive())
|
||||
return null;
|
||||
inLines.wait(timeoutMillis);
|
||||
}
|
||||
}
|
||||
synchronized (inLines) {
|
||||
if (inLines.size() > 0) {
|
||||
String ret = inLines.get(0);
|
||||
inLines.remove(0);
|
||||
// System.out.printf("Engine -> GUI: %s\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
@Override
|
||||
public void writeLineToEngine(String data) {
|
||||
// System.out.printf("GUI -> Engine: %s\n", data);
|
||||
data += "\n";
|
||||
try {
|
||||
Process ep = engineProc;
|
||||
if (ep != null)
|
||||
ep.getOutputStream().write(data.getBytes());
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
@Override
|
||||
public void shutDown() {
|
||||
super.shutDown();
|
||||
if (engineProc != null)
|
||||
engineProc.destroy();
|
||||
engineProc = null;
|
||||
if (stdInThread != null)
|
||||
stdInThread.interrupt();
|
||||
if (stdErrThread != null)
|
||||
stdErrThread.interrupt();
|
||||
}
|
||||
|
||||
private final static void copyFile(File from, File to) throws IOException {
|
||||
if (to.exists() && (from.length() == to.length()) && (from.lastModified() == to.lastModified()))
|
||||
return;
|
||||
if (to.exists())
|
||||
to.delete();
|
||||
to.createNewFile();
|
||||
FileChannel inFC = null;
|
||||
FileChannel outFC = null;
|
||||
try {
|
||||
inFC = new FileInputStream(from).getChannel();
|
||||
outFC = new FileOutputStream(to).getChannel();
|
||||
long cnt = outFC.transferFrom(inFC, 0, inFC.size());
|
||||
if (cnt < inFC.size())
|
||||
throw new IOException("File copy failed");
|
||||
} finally {
|
||||
if (inFC != null) { try { inFC.close(); } catch (IOException ex) {} }
|
||||
if (outFC != null) { try { outFC.close(); } catch (IOException ex) {} }
|
||||
to.setLastModified(from.lastModified());
|
||||
}
|
||||
}
|
||||
|
||||
private final void chmod(String exePath) throws IOException {
|
||||
Process proc = Runtime.getRuntime().exec(new String[]{"chmod", "744", exePath});
|
||||
try {
|
||||
proc.waitFor();
|
||||
} catch (InterruptedException e) {
|
||||
proc.destroy();
|
||||
throw new IOException("chmod failed");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -23,18 +23,19 @@ public class StockFishJNI extends UCIEngineBase {
|
|||
System.loadLibrary("stockfishjni");
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
@Override
|
||||
public void setStrength(int strength) {
|
||||
public final void initOptions() {
|
||||
setOption("Hash", 16);
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
@Override
|
||||
public final void setStrength(int strength) {
|
||||
setOption("Skill Level", strength/50);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a line from the process.
|
||||
* @param timeoutMillis Maximum time to wait for data
|
||||
* @return The line, without terminating newline characters,
|
||||
* or empty string if no data available,
|
||||
* or null if I/O error.
|
||||
*/
|
||||
/** @inheritDoc */
|
||||
@Override
|
||||
public final String readLineFromEngine(int timeoutMillis) {
|
||||
String ret = readFromProcess(timeoutMillis);
|
||||
|
@ -46,14 +47,15 @@ public class StockFishJNI extends UCIEngineBase {
|
|||
return ret;
|
||||
}
|
||||
|
||||
/** Write a line to the process. \n will be added automatically. */
|
||||
/** @inheritDoc */
|
||||
@Override
|
||||
public final synchronized void writeLineToEngine(String data) {
|
||||
// System.out.printf("GUI -> Engine: %s\n", data);
|
||||
writeToProcess(data + "\n");
|
||||
}
|
||||
|
||||
/** Start the child process. */
|
||||
/** @inheritDoc */
|
||||
@Override
|
||||
protected final native void startProcess();
|
||||
|
||||
/**
|
||||
|
|
|
@ -20,15 +20,24 @@ package org.petero.droidfish.engine;
|
|||
|
||||
public interface UCIEngine {
|
||||
|
||||
/** For reporting engine error messages. */
|
||||
public interface Report {
|
||||
/** Report error message to GUI. */
|
||||
void reportError(String errMsg);
|
||||
}
|
||||
|
||||
/** Start engine. */
|
||||
public void initialize();
|
||||
|
||||
/** Initialize default options. */
|
||||
public void initOptions();
|
||||
|
||||
/** Shut down engine. */
|
||||
public void shutDown();
|
||||
|
||||
/**
|
||||
* Read a line from the engine.
|
||||
* @param timeoutMillis Maximum time to wait for data
|
||||
* @param timeoutMillis Maximum time to wait for data.
|
||||
* @return The line, without terminating newline characters,
|
||||
* or empty string if no data available,
|
||||
* or null if I/O error.
|
||||
|
|
|
@ -2,10 +2,21 @@ package org.petero.droidfish.engine;
|
|||
|
||||
import java.util.HashMap;
|
||||
|
||||
import org.petero.droidfish.engine.cuckoochess.CuckooChessEngine;
|
||||
|
||||
public abstract class UCIEngineBase implements UCIEngine {
|
||||
|
||||
private boolean processAlive;
|
||||
|
||||
public static UCIEngine getEngine(String engine, Report report) {
|
||||
if ("cuckoochess".equals(engine))
|
||||
return new CuckooChessEngine(report);
|
||||
else if ("stockfish".equals(engine))
|
||||
return new StockFishJNI();
|
||||
else
|
||||
return new ExternalEngine(engine, report);
|
||||
}
|
||||
|
||||
protected UCIEngineBase() {
|
||||
processAlive = false;
|
||||
}
|
||||
|
@ -21,7 +32,7 @@ public abstract class UCIEngineBase implements UCIEngine {
|
|||
}
|
||||
|
||||
@Override
|
||||
public final void shutDown() {
|
||||
public void shutDown() {
|
||||
if (processAlive) {
|
||||
writeLineToEngine("quit");
|
||||
processAlive = false;
|
||||
|
|
|
@ -51,12 +51,8 @@ public class CuckooChessEngine extends UCIEngineBase {
|
|||
private NioInputStream inFromEngine;
|
||||
private Thread engineThread;
|
||||
|
||||
public CuckooChessEngine() {
|
||||
try {
|
||||
pos = TextIO.readFEN(TextIO.startPosFEN);
|
||||
} catch (ChessParseError ex) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
public CuckooChessEngine(Report report) {
|
||||
pos = null;
|
||||
moves = new ArrayList<Move>();
|
||||
quit = false;
|
||||
try {
|
||||
|
@ -64,14 +60,12 @@ public class CuckooChessEngine extends UCIEngineBase {
|
|||
engineToGui = Pipe.open();
|
||||
inFromEngine = new NioInputStream(engineToGui);
|
||||
} catch (IOException e) {
|
||||
report.reportError(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
@Override
|
||||
public void setStrength(int strength) {
|
||||
setOption("strength", strength);
|
||||
}
|
||||
|
||||
protected final void startProcess() {
|
||||
engineThread = new Thread(new Runnable() {
|
||||
public void run() {
|
||||
|
@ -87,6 +81,17 @@ public class CuckooChessEngine extends UCIEngineBase {
|
|||
engineThread.start();
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
@Override
|
||||
public final void initOptions() {
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
@Override
|
||||
public final void setStrength(int strength) {
|
||||
setOption("strength", strength);
|
||||
}
|
||||
|
||||
private final void mainLoop(NioInputStream is, NioPrintStream os) {
|
||||
String line;
|
||||
while ((line = is.readLine()) != null) {
|
||||
|
@ -97,6 +102,7 @@ public class CuckooChessEngine extends UCIEngineBase {
|
|||
}
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
@Override
|
||||
public final String readLineFromEngine(int timeoutMillis) {
|
||||
if ((engineThread != null) && !engineThread.isAlive())
|
||||
|
@ -110,6 +116,7 @@ public class CuckooChessEngine extends UCIEngineBase {
|
|||
return ret;
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
@Override
|
||||
public final synchronized void writeLineToEngine(String data) {
|
||||
// System.out.printf("GUI -> Engine: %s\n", data);
|
||||
|
@ -224,6 +231,13 @@ public class CuckooChessEngine extends UCIEngineBase {
|
|||
sPar.infinite = true;
|
||||
}
|
||||
}
|
||||
if (pos == null) {
|
||||
try {
|
||||
pos = TextIO.readFEN(TextIO.startPosFEN);
|
||||
} catch (ChessParseError ex) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
if (ponder) {
|
||||
engine.startPonder(pos, moves, sPar);
|
||||
} else {
|
||||
|
|
|
@ -157,6 +157,11 @@ public class DroidChessController {
|
|||
}
|
||||
}
|
||||
|
||||
/** Return current engine identifier. */
|
||||
public final synchronized String getEngine() {
|
||||
return engine;
|
||||
}
|
||||
|
||||
/** Notify controller that preferences has changed. */
|
||||
public final synchronized void prefsChanged() {
|
||||
updateBookHints();
|
||||
|
@ -649,6 +654,8 @@ public class DroidChessController {
|
|||
tmpPos.makeMove(ponderMove, ui);
|
||||
}
|
||||
for (Move m : pv.pv) {
|
||||
if (m == null)
|
||||
break;
|
||||
String moveStr = TextIO.moveToString(tmpPos, m, false);
|
||||
buf.append(String.format(" %s", moveStr));
|
||||
tmpPos.makeMove(m, ui);
|
||||
|
@ -701,6 +708,15 @@ public class DroidChessController {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reportEngineError(final String errMsg) {
|
||||
gui.runOnUIThread(new Runnable() {
|
||||
public void run() {
|
||||
gui.reportEngineError(errMsg);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/** Discard current search. Return true if GUI update needed. */
|
||||
|
|
|
@ -90,4 +90,7 @@ public interface SearchListener {
|
|||
|
||||
/** Report engine name. */
|
||||
public void notifyEngineName(String engineName);
|
||||
|
||||
/** Report engine error. */
|
||||
public void reportEngineError(String errMsg);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user