DroidFish: Made it possible to change the engine hash table size.

This commit is contained in:
Peter Osterlund 2012-07-24 01:04:43 +00:00
parent bb3cff5298
commit 04f1225d3e
10 changed files with 131 additions and 50 deletions

View File

@ -2,6 +2,7 @@
<resources>
<string name="app_name">DroidFish</string>
<string name="engine_threads_default">1</string>
<string name="engine_hash_default">16</string>
<string name="moves_per_session_default">60</string>
<string name="time_control_default">120000</string>
<string name="time_increment_default">0</string>
@ -220,6 +221,8 @@ you are not actively using the program.\
<string name="prefs_ponderMode_summary">Let engine think while waiting for opponent\'s move. Supported by most engines.</string>
<string name="prefs_threads_title">Threads</string>
<string name="prefs_threads_summary">Number of engine threads (CPU cores) to use. Not supported by all engines.</string>
<string name="prefs_hash_title">Hash Table</string>
<string name="prefs_hash_summary">Hash table size in megabytes</string>
<string name="prefs_time_control">Time Control</string>
<string name="prefs_movesPerSession_title">Moves</string>
<string name="prefs_movesPerSession_summary">Number of moves between time controls</string>
@ -364,6 +367,18 @@ you are not actively using the program.\
<item>3</item>
<item>4</item>
</string-array>
<string-array name="engine_hash_texts">
<item>16 MB</item>
<item>32 MB</item>
<item>64 MB</item>
<item>128 MB</item>
</string-array>
<string-array name="engine_hash_values">
<item>16</item>
<item>32</item>
<item>64</item>
<item>128</item>
</string-array>
<string-array name="moves_per_session_texts">
<item>Whole Game</item>
<item>1 move</item>

View File

@ -44,7 +44,15 @@
android:entries="@array/engine_threads_texts"
android:defaultValue="@string/engine_threads_default">
</ListPreference>
</PreferenceCategory>
<ListPreference
android:key="hashMB"
android:title="@string/prefs_hash_title"
android:summary="@string/prefs_hash_summary"
android:entryValues="@array/engine_hash_values"
android:entries="@array/engine_hash_texts"
android:defaultValue="@string/engine_hash_default">
</ListPreference>
</PreferenceCategory>
<PreferenceCategory
android:title="@string/prefs_time_control">
<ListPreference

View File

@ -149,7 +149,6 @@ public class DroidFish extends Activity implements GUIInterface {
// FIXME!!! Better behavior if engine is terminated. How exactly?
// FIXME!!! Handle PGN non-file intents with more than one game.
// FIXME!!! File load/save of FEN data
// FIXME!!! Make engine hash size configurable.
private ChessBoard cb;
private static DroidChessController ctrl = null;
@ -191,7 +190,7 @@ public class DroidFish extends Activity implements GUIInterface {
private final static String gtbDefaultDir = "DroidFish" + File.separator + "gtb";
private BookOptions bookOptions = new BookOptions();
private PGNOptions pgnOptions = new PGNOptions();
private EGTBOptions egtbOptions = new EGTBOptions();
private EngineOptions engineOptions = new EngineOptions();
private long lastVisibleMillis; // Time when GUI became invisible. 0 if currently visible.
private long lastComputationMillis; // Time when engine last showed that it was computing.
@ -783,10 +782,11 @@ public class DroidFish extends Activity implements GUIInterface {
bookOptions.random = (settings.getInt("bookRandom", 500) - 500) * (3.0 / 500);
setBookOptions();
egtbOptions.hints = settings.getBoolean("tbHints", false);
egtbOptions.hintsEdit = settings.getBoolean("tbHintsEdit", false);
egtbOptions.rootProbe = settings.getBoolean("tbRootProbe", true);
egtbOptions.engineProbe = settings.getBoolean("tbEngineProbe", true);
engineOptions.hashMB = getHashMB();
engineOptions.hints = settings.getBoolean("tbHints", false);
engineOptions.hintsEdit = settings.getBoolean("tbHintsEdit", false);
engineOptions.rootProbe = settings.getBoolean("tbRootProbe", true);
engineOptions.engineProbe = settings.getBoolean("tbEngineProbe", true);
String gtbPath = settings.getString("gtbPath", "");
gtbPath = gtbPath.trim();
if (gtbPath.length() == 0) {
@ -794,8 +794,8 @@ public class DroidFish extends Activity implements GUIInterface {
String sep = File.separator;
gtbPath = extDir.getAbsolutePath() + sep + gtbDefaultDir;
}
egtbOptions.gtbPath = gtbPath;
setEgtbOptions();
engineOptions.gtbPath = gtbPath;
setEngineOptions();
setEgtbHints(cb.getSelectedSquare());
updateThinkingInfo();
@ -820,6 +820,19 @@ public class DroidFish extends Activity implements GUIInterface {
ctrl.prefsChanged();
}
/** Get hash size in MB from settings, but reduce size to an amount that the device can handle. */
private final int getHashMB() {
int hashMB = getIntSetting("hashMB", 16);
if (hashMB > 16) {
int maxMem = (int)(Runtime.getRuntime().maxMemory() / (1024*1024));
if (maxMem < 16)
maxMem = 16;
if (hashMB > maxMem)
hashMB = maxMem;
}
return hashMB;
}
private void updateButtons() {
boolean largeButtons = settings.getBoolean("largeButtons", false);
Resources r = getResources();
@ -918,14 +931,14 @@ public class DroidFish extends Activity implements GUIInterface {
private boolean egtbForceReload = false;
private final void setEgtbOptions() {
ctrl.setEgtbOptions(new EGTBOptions(egtbOptions));
Probe.getInstance().setPath(egtbOptions.gtbPath, egtbForceReload);
private final void setEngineOptions() {
ctrl.setEngineOptions(new EngineOptions(engineOptions));
Probe.getInstance().setPath(engineOptions.gtbPath, egtbForceReload);
egtbForceReload = false;
}
private final void setEgtbHints(int sq) {
if (!egtbOptions.hints || (sq < 0)) {
if (!engineOptions.hints || (sq < 0)) {
cb.setSquareDecorations(null);
return;
}

View File

@ -1,14 +1,16 @@
package org.petero.droidfish;
/** Endgame tablebase probing options. */
public final class EGTBOptions {
/** Engine options, including endgame tablebase probing options. */
public final class EngineOptions {
public int hashMB; // Engine hash table size in MB
public boolean hints; // Hints when playing/analyzing
public boolean hintsEdit; // Hints in "edit board" mode
public boolean rootProbe; // Only search optimal moves at root
public boolean engineProbe; // Let engine use EGTB
public String gtbPath; // GTB directory path
public EGTBOptions() {
public EngineOptions() {
hashMB = 16;
hints = false;
hintsEdit = false;
rootProbe = false;
@ -16,7 +18,8 @@ public final class EGTBOptions {
gtbPath = "";
}
public EGTBOptions(EGTBOptions other) {
public EngineOptions(EngineOptions other) {
hashMB = other.hashMB;
hints = other.hints;
hintsEdit = other.hintsEdit;
rootProbe = other.rootProbe;
@ -28,9 +31,10 @@ public final class EGTBOptions {
public boolean equals(Object o) {
if ((o == null) || (o.getClass() != this.getClass()))
return false;
EGTBOptions other = (EGTBOptions)o;
EngineOptions other = (EngineOptions)o;
return ((hints == other.hints) &&
return ((hashMB == other.hashMB) &&
(hints == other.hints) &&
(hintsEdit == other.hintsEdit) &&
(rootProbe == other.rootProbe) &&
(engineProbe == other.engineProbe) &&

View File

@ -23,7 +23,7 @@ import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import org.petero.droidfish.EGTBOptions;
import org.petero.droidfish.EngineOptions;
import org.petero.droidfish.book.BookOptions;
import org.petero.droidfish.book.DroidBook;
import org.petero.droidfish.gamelogic.Move;
@ -47,7 +47,7 @@ public class DroidComputerPlayer {
private final Context context;
private final SearchListener listener;
private final DroidBook book;
private EGTBOptions egtbOptions;
private EngineOptions engineOptions;
/** Set when "ucinewgame" needs to be sent. */
private boolean newGame = false;
@ -242,7 +242,7 @@ public class DroidComputerPlayer {
this.context = context;
this.listener = listener;
book = DroidBook.getInstance();
egtbOptions = new EGTBOptions();
engineOptions = new EngineOptions();
engineState = new EngineState();
searchRequest = null;
}
@ -270,8 +270,8 @@ public class DroidComputerPlayer {
book.setOptions(options);
}
public final void setEgtbOptions(EGTBOptions options) {
egtbOptions = options;
public final void setEngineOptions(EngineOptions options) {
engineOptions = options;
}
/** Return all book moves, both as a formatted string and as a list of moves. */
@ -331,7 +331,7 @@ public class DroidComputerPlayer {
/** Decide what moves to search. Filters out non-optimal moves if tablebases are used. */
private final ArrayList<Move> movesToSearch(SearchRequest sr) {
ArrayList<Move> moves = null;
if (egtbOptions.rootProbe)
if (engineOptions.rootProbe)
moves = Probe.getInstance().findOptimal(sr.currPos);
if (moves != null) {
sr.searchMoves = moves;
@ -422,9 +422,14 @@ public class DroidComputerPlayer {
}
private void killOldEngine(String engine) {
if (engine.equals(engineState.engine))
return;
shutdownEngine();
boolean needShutDown = !engine.equals(engineState.engine);
if (!needShutDown) {
UCIEngine uci = uciEngine;
if (uci != null)
needShutDown = !uci.optionsOk(engineOptions);
}
if (needShutDown)
shutdownEngine();
}
/** Tell engine to stop searching. */
@ -662,7 +667,7 @@ public class DroidComputerPlayer {
switch (engineState.state) {
case READ_OPTIONS: {
if (readUCIOption(uci, s)) {
uci.initOptions(egtbOptions);
uci.initOptions(engineOptions);
uci.writeLineToEngine("ucinewgame");
uci.writeLineToEngine("isready");
engineState.setState(MainState.WAIT_READY);

View File

@ -27,7 +27,7 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.channels.FileChannel;
import org.petero.droidfish.EGTBOptions;
import org.petero.droidfish.EngineOptions;
import org.petero.droidfish.R;
import android.content.Context;
@ -91,7 +91,9 @@ public class ExternalEngine extends UCIEngineBase {
@Override
public void run() {
try {
engineProc.waitFor();
Process ep = engineProc;
if (ep != null)
ep.waitFor();
isRunning = false;
if (!startedOk)
report.reportError(context.getString(R.string.failed_to_start_engine));
@ -161,15 +163,34 @@ public class ExternalEngine extends UCIEngineBase {
}
}
private int hashMB = -1;
private String gaviotaTbPath = "";
private boolean optionsInitialized = false;
/** @inheritDoc */
@Override
public void initOptions(EGTBOptions egtbOptions) {
super.initOptions(egtbOptions);
setOption("Hash", 16);
if (egtbOptions.engineProbe) {
setOption("GaviotaTbPath", egtbOptions.gtbPath);
public void initOptions(EngineOptions engineOptions) {
super.initOptions(engineOptions);
hashMB = engineOptions.hashMB;
setOption("Hash", engineOptions.hashMB);
if (engineOptions.engineProbe) {
gaviotaTbPath = engineOptions.gtbPath;
setOption("GaviotaTbPath", engineOptions.gtbPath);
setOption("GaviotaTbCache", 8);
}
optionsInitialized = true;
}
/** @inheritDoc */
@Override
public boolean optionsOk(EngineOptions engineOptions) {
if (!optionsInitialized)
return true;
if (hashMB != engineOptions.hashMB)
return false;
if (haveOption("gaviotatbpath") && !gaviotaTbPath.equals(engineOptions.gtbPath))
return false;
return true;
}
/** @inheritDoc */

View File

@ -18,7 +18,7 @@
package org.petero.droidfish.engine;
import org.petero.droidfish.EGTBOptions;
import org.petero.droidfish.EngineOptions;
public interface UCIEngine {
@ -32,7 +32,11 @@ public interface UCIEngine {
public void initialize();
/** Initialize default options. */
public void initOptions(EGTBOptions egtbOptions);
public void initOptions(EngineOptions engineOptions);
/** Return true if engine options have correct values.
* If false is returned, engine will be restarted. */
public boolean optionsOk(EngineOptions engineOptions);
/** Shut down engine. */
public void shutDown();

View File

@ -21,7 +21,7 @@ package org.petero.droidfish.engine;
import java.util.HashMap;
import java.util.HashSet;
import org.petero.droidfish.EGTBOptions;
import org.petero.droidfish.EngineOptions;
import org.petero.droidfish.engine.cuckoochess.CuckooChessEngine;
import android.content.Context;
@ -62,7 +62,7 @@ public abstract class UCIEngineBase implements UCIEngine {
}
@Override
public void initOptions(EGTBOptions egtbOptions) {
public void initOptions(EngineOptions engineOptions) {
isUCI = true;
}
@ -84,6 +84,11 @@ public abstract class UCIEngineBase implements UCIEngine {
allOptions.add(optName);
}
/** Return true if engine has option optName. */
protected boolean haveOption(String optName) {
return allOptions.contains(optName);
}
@Override
public void setOption(String name, int value) {
setOption(name, String.format("%d", value));

View File

@ -25,7 +25,7 @@ import chess.Position;
import chess.TextIO;
import java.util.ArrayList;
import org.petero.droidfish.EGTBOptions;
import org.petero.droidfish.EngineOptions;
import org.petero.droidfish.engine.LocalPipe;
import org.petero.droidfish.engine.UCIEngineBase;
@ -74,8 +74,14 @@ public class CuckooChessEngine extends UCIEngineBase {
/** @inheritDoc */
@Override
public final void initOptions(EGTBOptions egtbOptions) {
super.initOptions(egtbOptions);
public final void initOptions(EngineOptions engineOptions) {
super.initOptions(engineOptions);
}
/** @inheritDoc */
@Override
public boolean optionsOk(EngineOptions engineOptions) {
return true;
}
/** @inheritDoc */

View File

@ -22,7 +22,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.petero.droidfish.EGTBOptions;
import org.petero.droidfish.EngineOptions;
import org.petero.droidfish.GUIInterface;
import org.petero.droidfish.GameMode;
import org.petero.droidfish.PGNOptions;
@ -42,7 +42,7 @@ public class DroidChessController {
private DroidComputerPlayer computerPlayer = null;
private PgnToken.PgnTokenReceiver gameTextListener = null;
private BookOptions bookOptions = new BookOptions();
private EGTBOptions egtbOptions = new EGTBOptions();
private EngineOptions engineOptions = new EngineOptions();
private Game game = null;
private Move ponderMove = null;
private GUIInterface gui;
@ -84,7 +84,7 @@ public class DroidChessController {
if (computerPlayer == null) {
computerPlayer = new DroidComputerPlayer(gui.getContext(), listener);
computerPlayer.setBookOptions(bookOptions);
computerPlayer.setEgtbOptions(egtbOptions);
computerPlayer.setEngineOptions(engineOptions);
}
computerPlayer.queueStartEngine(searchId, engine);
searchId++;
@ -152,11 +152,11 @@ public class DroidChessController {
}
}
public final synchronized void setEgtbOptions(EGTBOptions options) {
if (!egtbOptions.equals(options)) {
egtbOptions = options;
public final synchronized void setEngineOptions(EngineOptions options) {
if (!engineOptions.equals(options)) {
engineOptions = options;
if (computerPlayer != null)
computerPlayer.setEgtbOptions(egtbOptions);
computerPlayer.setEngineOptions(engineOptions);
}
}