diff --git a/DroidFishApp/src/main/java/org/petero/droidfish/DroidFish.java b/DroidFishApp/src/main/java/org/petero/droidfish/DroidFish.java index 8506bf6..ebcf892 100644 --- a/DroidFishApp/src/main/java/org/petero/droidfish/DroidFish.java +++ b/DroidFishApp/src/main/java/org/petero/droidfish/DroidFish.java @@ -48,6 +48,7 @@ import org.petero.droidfish.activities.util.PGNFile; import org.petero.droidfish.activities.util.PGNFile.GameInfo; import org.petero.droidfish.activities.Preferences; import org.petero.droidfish.book.BookOptions; +import org.petero.droidfish.engine.DroidComputerPlayer.EloData; import org.petero.droidfish.engine.EngineUtil; import org.petero.droidfish.engine.UCIOptions; import org.petero.droidfish.gamelogic.DroidChessController; @@ -136,6 +137,7 @@ import android.view.View.OnTouchListener; import android.view.WindowManager; import android.webkit.WebView; import android.widget.ArrayAdapter; +import android.widget.CheckBox; import android.widget.EditText; import android.widget.ImageButton; import android.widget.ImageView.ScaleType; @@ -1094,8 +1096,7 @@ public class DroidFish extends Activity mEcoHints = getIntSetting("ecoHints", ECO_HINTS_AUTO); String engine = settings.getString("engine", "stockfish"); - int strength = settings.getInt("strength", 1000); - setEngineStrength(engine, strength); + setEngine(engine); mPonderMode = settings.getBoolean("ponderMode", false); if (!mPonderMode) @@ -1308,16 +1309,16 @@ public class DroidFish extends Activity getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); } - private void setEngineStrength(String engine, int strength) { + private void setEngine(String engine) { if (!storageAvailable()) { if (!"stockfish".equals(engine) && !"cuckoochess".equals(engine)) engine = "stockfish"; } - ctrl.setEngineStrength(engine, strength); - setEngineTitle(engine, strength); + ctrl.setEngine(engine); + setEngineTitle(engine, ctrl.eloData().getEloToUse()); } - private void setEngineTitle(String engine, int strength) { + private void setEngineTitle(String engine, int elo) { String eName = ""; if (EngineUtil.isOpenExchangeEngine(engine)) { String engineFileName = new File(engine).getName(); @@ -1336,10 +1337,10 @@ public class DroidFish extends Activity eName = getString("cuckoochess".equals(engine) ? R.string.cuckoochess_engine : R.string.stockfish_engine); - boolean analysis = (ctrl != null) && ctrl.analysisMode(); - if ((strength < 1000) && !analysis) - eName = String.format(Locale.US, "%s: %d%%", eName, strength / 10); } + if (ctrl != null && !ctrl.analysisMode()) + if (elo != Integer.MAX_VALUE) + eName = String.format(Locale.US, "%s: %d", eName, elo); engineTitleText.setText(eName); } @@ -1363,10 +1364,9 @@ public class DroidFish extends Activity } @Override - public void updateEngineTitle() { + public void updateEngineTitle(int elo) { String engine = settings.getString("engine", "stockfish"); - int strength = settings.getInt("strength", 1000); - setEngineTitle(engine, strength); + setEngineTitle(engine, elo); } @Override @@ -1433,31 +1433,34 @@ public class DroidFish extends Activity } private class DrawerItem { - int id; - int itemId; // Item string resource id + DrawerItemId id; + private int resId; // Item string resource id - DrawerItem(int id, int itemId) { + DrawerItem(DrawerItemId id, int resId) { this.id = id; - this.itemId = itemId; + this.resId = resId; } @Override public String toString() { - return getString(itemId); + return getString(resId); } } - static private final int ITEM_NEW_GAME = 0; - static private final int ITEM_EDIT_BOARD = 1; - static private final int ITEM_SETTINGS = 2; - static private final int ITEM_FILE_MENU = 3; - static private final int ITEM_RESIGN = 4; - static private final int ITEM_FORCE_MOVE = 5; - static private final int ITEM_DRAW = 6; - static private final int ITEM_SELECT_BOOK = 7; - static private final int ITEM_MANAGE_ENGINES = 8; - static private final int ITEM_SET_COLOR_THEME = 9; - static private final int ITEM_ABOUT = 10; + private enum DrawerItemId { + NEW_GAME, + SET_STRENGTH, + EDIT_BOARD, + SETTINGS, + FILE_MENU, + RESIGN, + FORCE_MOVE, + DRAW, + SELECT_BOOK, + MANAGE_ENGINES, + SET_COLOR_THEME, + ABOUT, + } /** Initialize the drawer part of the user interface. */ private void initDrawers() { @@ -1466,14 +1469,15 @@ public class DroidFish extends Activity rightDrawer = findViewById(R.id.right_drawer); final DrawerItem[] leftItems = new DrawerItem[] { - new DrawerItem(ITEM_NEW_GAME, R.string.option_new_game), - new DrawerItem(ITEM_EDIT_BOARD, R.string.option_edit_board), - new DrawerItem(ITEM_FILE_MENU, R.string.option_file), - new DrawerItem(ITEM_SELECT_BOOK, R.string.option_select_book), - new DrawerItem(ITEM_MANAGE_ENGINES, R.string.option_manage_engines), - new DrawerItem(ITEM_SET_COLOR_THEME, R.string.option_color_theme), - new DrawerItem(ITEM_SETTINGS, R.string.option_settings), - new DrawerItem(ITEM_ABOUT, R.string.option_about) + new DrawerItem(DrawerItemId.NEW_GAME, R.string.option_new_game), + new DrawerItem(DrawerItemId.SET_STRENGTH, R.string.set_engine_strength), + new DrawerItem(DrawerItemId.EDIT_BOARD, R.string.option_edit_board), + new DrawerItem(DrawerItemId.FILE_MENU, R.string.option_file), + new DrawerItem(DrawerItemId.SELECT_BOOK, R.string.option_select_book), + new DrawerItem(DrawerItemId.MANAGE_ENGINES, R.string.option_manage_engines), + new DrawerItem(DrawerItemId.SET_COLOR_THEME, R.string.option_color_theme), + new DrawerItem(DrawerItemId.SETTINGS, R.string.option_settings), + new DrawerItem(DrawerItemId.ABOUT, R.string.option_about), }; leftDrawer.setAdapter(new ArrayAdapter<>(this, R.layout.drawer_list_item, @@ -1484,9 +1488,9 @@ public class DroidFish extends Activity }); final DrawerItem[] rightItems = new DrawerItem[] { - new DrawerItem(ITEM_RESIGN, R.string.option_resign_game), - new DrawerItem(ITEM_FORCE_MOVE, R.string.option_force_computer_move), - new DrawerItem(ITEM_DRAW, R.string.option_draw) + new DrawerItem(DrawerItemId.RESIGN, R.string.option_resign_game), + new DrawerItem(DrawerItemId.FORCE_MOVE, R.string.option_force_computer_move), + new DrawerItem(DrawerItemId.DRAW, R.string.option_draw), }; rightDrawer.setAdapter(new ArrayAdapter<>(this, R.layout.drawer_list_item, @@ -1504,7 +1508,7 @@ public class DroidFish extends Activity } /** React to a selection in the left/right drawers. */ - private void handleDrawerSelection(int itemId) { + private void handleDrawerSelection(DrawerItemId id) { drawerLayout.closeDrawer(Gravity.LEFT); drawerLayout.closeDrawer(Gravity.RIGHT); leftDrawer.clearChoices(); @@ -1512,30 +1516,33 @@ public class DroidFish extends Activity setAutoMode(AutoMode.OFF); - switch (itemId) { - case ITEM_NEW_GAME: + switch (id) { + case NEW_GAME: showDialog(NEW_GAME_DIALOG); break; - case ITEM_EDIT_BOARD: + case SET_STRENGTH: + reShowDialog(SET_STRENGTH_DIALOG); + break; + case EDIT_BOARD: startEditBoard(ctrl.getFEN()); break; - case ITEM_SETTINGS: { + case SETTINGS: { Intent i = new Intent(DroidFish.this, Preferences.class); startActivityForResult(i, RESULT_SETTINGS); break; } - case ITEM_FILE_MENU: + case FILE_MENU: if (storageAvailable()) reShowDialog(FILE_MENU_DIALOG); break; - case ITEM_RESIGN: + case RESIGN: if (ctrl.humansTurn()) ctrl.resignGame(); break; - case ITEM_FORCE_MOVE: + case FORCE_MOVE: ctrl.stopSearch(); break; - case ITEM_DRAW: + case DRAW: if (ctrl.humansTurn()) { if (ctrl.claimDrawIfPossible()) ctrl.stopPonder(); @@ -1543,20 +1550,20 @@ public class DroidFish extends Activity DroidFishApp.toast(R.string.offer_draw, Toast.LENGTH_SHORT); } break; - case ITEM_SELECT_BOOK: + case SELECT_BOOK: if (storageAvailable()) reShowDialog(SELECT_BOOK_DIALOG); break; - case ITEM_MANAGE_ENGINES: + case MANAGE_ENGINES: if (storageAvailable()) reShowDialog(MANAGE_ENGINES_DIALOG); else reShowDialog(SELECT_ENGINE_DIALOG_NOMANAGE); break; - case ITEM_SET_COLOR_THEME: + case SET_COLOR_THEME: showDialog(SET_COLOR_THEME_DIALOG); break; - case ITEM_ABOUT: + case ABOUT: showDialog(ABOUT_DIALOG); break; } @@ -2025,6 +2032,7 @@ public class DroidFish extends Activity static private final int DELETE_NETWORK_ENGINE_DIALOG = 25; static private final int CLIPBOARD_DIALOG = 26; static private final int SELECT_FEN_FILE_DIALOG = 27; + static private final int SET_STRENGTH_DIALOG = 28; /** Remove and show a dialog. */ void reShowDialog(int id) { @@ -2036,6 +2044,7 @@ public class DroidFish extends Activity protected Dialog onCreateDialog(int id) { switch (id) { case NEW_GAME_DIALOG: return newGameDialog(); + case SET_STRENGTH_DIALOG: return setStrengthDialog(); case PROMOTE_DIALOG: return promoteDialog(); case BOARD_MENU_DIALOG: return boardMenuDialog(); case FILE_MENU_DIALOG: return fileMenuDialog(); @@ -2076,6 +2085,106 @@ public class DroidFish extends Activity return builder.create(); } + private Dialog setStrengthDialog() { + EloStrengthSetter m = new EloStrengthSetter(); + return m.getDialog(); + } + + /** Handle user interface to set engine strength. */ + private class EloStrengthSetter { + private final EloData eloData = ctrl.eloData(); + + private CheckBox checkBox; + private TextView eloLabel; + private EditText editTxt; + private SeekBar seekBar; + + private int progressToElo(int p) { + return eloData.minElo + p; + } + + private int eloToProgress(int elo) { + return elo - eloData.minElo; + } + + private void updateText(int elo) { + String txt = Integer.valueOf(elo).toString(); + if (!txt.equals(editTxt.getText().toString())) { + editTxt.setText(txt); + editTxt.setSelection(txt.length()); + } + } + + private void updateEnabledState(boolean enabled) { + eloLabel.setEnabled(enabled); + editTxt.setEnabled(enabled); + seekBar.setEnabled(enabled); + } + + public Dialog getDialog() { + if (!eloData.canChangeStrength()) { + DroidFishApp.toast(R.string.engine_cannot_reduce_strength, Toast.LENGTH_LONG); + return null; + } + AlertDialog.Builder builder = new AlertDialog.Builder(DroidFish.this); + builder.setTitle(R.string.set_engine_strength); + View content = View.inflate(DroidFish.this, R.layout.set_strength, null); + builder.setView(content); + + checkBox = content.findViewById(R.id.strength_checkbox); + eloLabel = content.findViewById(R.id.strength_elolabel); + editTxt = content.findViewById(R.id.strength_edittext); + seekBar = content.findViewById(R.id.strength_seekbar); + + checkBox.setChecked(eloData.limitStrength); + seekBar.setMax(eloToProgress(eloData.maxElo)); + seekBar.setProgress(eloToProgress(eloData.elo)); + updateText(eloData.elo); + updateEnabledState(eloData.limitStrength); + + checkBox.setOnCheckedChangeListener((button, isChecked) -> { + updateEnabledState(isChecked); + }); + seekBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() { + @Override + public void onStopTrackingTouch(SeekBar seekBar) { } + @Override + public void onStartTrackingTouch(SeekBar seekBar) { } + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + updateText(progressToElo(progress)); + } + }); + editTxt.addTextChangedListener(new TextWatcher() { + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + String txt = editTxt.getText().toString(); + try { + int elo = Integer.parseInt(txt); + int p = eloToProgress(elo); + if (p != seekBar.getProgress()) + seekBar.setProgress(p); + updateText(progressToElo(p)); + } catch (NumberFormatException ignore) { + } + } + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { } + @Override + public void afterTextChanged(Editable s) { } + }); + + builder.setNegativeButton(R.string.cancel, null); + builder.setPositiveButton(android.R.string.ok, (dialog, which) -> { + boolean limitStrength = checkBox.isChecked(); + int elo = progressToElo(seekBar.getProgress()); + ctrl.setStrength(limitStrength, elo); + }); + + return builder.create(); + } + } + private void startNewGame(int type) { if (type != 2) { int gameModeType = (type == 0) ? GameMode.PLAYER_WHITE : GameMode.PLAYER_BLACK; @@ -2091,7 +2200,7 @@ public class DroidFish extends Activity ctrl.newGame(gameMode, tcData); ctrl.startGame(); setBoardFlip(true); - updateEngineTitle(); + updateEngineTitle(ctrl.eloData().getEloToUse()); // Game mode affects Elo setting } private Dialog promoteDialog() { @@ -2502,9 +2611,8 @@ public class DroidFish extends Activity editor.putString("engine", engine); editor.apply(); dialog.dismiss(); - int strength = settings.getInt("strength", 1000); setEngineOptions(false); - setEngineStrength(engine, strength); + setEngine(engine); }); builder.setOnCancelListener(dialog -> { if (!abortOnCancel) @@ -2845,8 +2953,7 @@ public class DroidFish extends Activity int numPV = this.numPV; final int maxPV = ctrl.maxPV(); if (gameMode.analysisMode()) { - numPV = Math.min(numPV, maxPV); - numPV = Math.max(numPV, 1); + numPV = Math.min(Math.max(numPV, 1), maxPV); if (maxPV > 1) { lst.add(getString(R.string.num_variations)); actions.add(MULTIPV_SET); } @@ -2988,11 +3095,9 @@ public class DroidFish extends Activity seekBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() { @Override - public void onStopTrackingTouch(SeekBar seekBar) { - } + public void onStopTrackingTouch(SeekBar seekBar) { } @Override - public void onStartTrackingTouch(SeekBar seekBar) { - } + public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { int nPV = progressToNumPV(progress, maxPV); @@ -3014,11 +3119,9 @@ public class DroidFish extends Activity } } @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - } + public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override - public void afterTextChanged(Editable s) { - } + public void afterTextChanged(Editable s) { } }); builder.setNegativeButton(R.string.cancel, null); @@ -3349,9 +3452,8 @@ public class DroidFish extends Activity editor.putString("engine", engine); editor.apply(); dialog.dismiss(); - int strength = settings.getInt("strength", 1000); setEngineOptions(false); - setEngineStrength(engine, strength); + setEngine(engine); } dialog.cancel(); reShowDialog(NETWORK_ENGINE_DIALOG); @@ -3553,22 +3655,22 @@ public class DroidFish extends Activity @Override public void reportInvalidMove(Move m) { String msg = String.format(Locale.US, "%s %s-%s", - getString(R.string.invalid_move), - TextIO.squareToString(m.from), TextIO.squareToString(m.to)); + getString(R.string.invalid_move), + TextIO.squareToString(m.from), TextIO.squareToString(m.to)); DroidFishApp.toast(msg, Toast.LENGTH_SHORT); } @Override public void reportEngineName(String engine) { String msg = String.format(Locale.US, "%s: %s", - getString(R.string.engine), engine); + getString(R.string.engine), engine); DroidFishApp.toast(msg, Toast.LENGTH_SHORT); } @Override public void reportEngineError(String errMsg) { String msg = String.format(Locale.US, "%s: %s", - getString(R.string.engine_error), errMsg); + getString(R.string.engine_error), errMsg); DroidFishApp.toast(msg, Toast.LENGTH_LONG); } diff --git a/DroidFishApp/src/main/java/org/petero/droidfish/GUIInterface.java b/DroidFishApp/src/main/java/org/petero/droidfish/GUIInterface.java index 4ccb089..5a96bfe 100644 --- a/DroidFishApp/src/main/java/org/petero/droidfish/GUIInterface.java +++ b/DroidFishApp/src/main/java/org/petero/droidfish/GUIInterface.java @@ -86,7 +86,7 @@ public interface GUIInterface { void setRemainingTime(int wTime, int bTime, int nextUpdate); /** Update engine title text. */ - void updateEngineTitle(); + void updateEngineTitle(int elo); /** Update title with the material difference. */ void updateMaterialDifferenceTitle(Util.MaterialDiff diff); diff --git a/DroidFishApp/src/main/java/org/petero/droidfish/activities/util/SeekBarPreference.java b/DroidFishApp/src/main/java/org/petero/droidfish/activities/util/SeekBarPreference.java index b33d64c..2808351 100644 --- a/DroidFishApp/src/main/java/org/petero/droidfish/activities/util/SeekBarPreference.java +++ b/DroidFishApp/src/main/java/org/petero/droidfish/activities/util/SeekBarPreference.java @@ -91,9 +91,7 @@ public class SeekBarPreference extends Preference implements OnSeekBarChangeList builder.setView(selectPercentageBinding.getRoot()); String title = ""; String key = getKey(); - if (key.equals("strength")) { - title = getContext().getString(R.string.edit_strength); - } else if (key.equals("bookRandom")) { + if (key.equals("bookRandom")) { title = getContext().getString(R.string.edit_randomization); } builder.setTitle(title); diff --git a/DroidFishApp/src/main/java/org/petero/droidfish/engine/DroidComputerPlayer.java b/DroidFishApp/src/main/java/org/petero/droidfish/engine/DroidComputerPlayer.java index f8efffc..08dce30 100644 --- a/DroidFishApp/src/main/java/org/petero/droidfish/engine/DroidComputerPlayer.java +++ b/DroidFishApp/src/main/java/org/petero/droidfish/engine/DroidComputerPlayer.java @@ -109,7 +109,7 @@ public class DroidComputerPlayer { int movesToGo; // Number of moves to next time control String engine; // Engine name (identifier) - int strength; // Engine strength setting (0 - 1000) + int elo; // Engine UCI_Elo setting, or Integer.MAX_VALUE for full strength int numPV; // Number of PV lines to compute boolean ponderEnabled; // True if pondering enabled, for engine time management @@ -145,14 +145,14 @@ public class DroidComputerPlayer { * @param ponderEnabled True if pondering is enabled in the GUI. Can affect time management. * @param ponderMove Move to ponder, or null for non-ponder search. * @param engine Chess engine to use for searching. - * @param strength Engine strength setting. + * @param elo Engine Elo strength setting. */ public static SearchRequest searchRequest(int id, long now, Position prevPos, ArrayList mList, Position currPos, boolean drawOffer, int wTime, int bTime, int wInc, int bInc, int movesToGo, boolean ponderEnabled, Move ponderMove, - String engine, int strength) { + String engine, int elo) { SearchRequest sr = new SearchRequest(); sr.searchId = id; sr.startTime = now; @@ -168,7 +168,7 @@ public class DroidComputerPlayer { sr.bInc = bInc; sr.movesToGo = movesToGo; sr.engine = engine; - sr.strength = strength; + sr.elo = elo; sr.numPV = 1; sr.ponderEnabled = ponderEnabled; sr.ponderMove = ponderMove; @@ -204,7 +204,7 @@ public class DroidComputerPlayer { sr.isAnalyze = true; sr.wTime = sr.bTime = sr.wInc = sr.bInc = sr.movesToGo = 0; sr.engine = engine; - sr.strength = 1000; + sr.elo = Integer.MAX_VALUE; sr.numPV = numPV; sr.ponderEnabled = false; sr.ponderMove = null; @@ -310,6 +310,56 @@ public class DroidComputerPlayer { } } + public static class EloData { + public boolean limitStrength = false; // True if engine strength reduction is enabled + public int elo = 0; // Current strength setting + public int minElo = 0; // Smallest possible Elo value + public int maxElo = 0; // Largest possible Elo value + + /** Return true if engine is able to change the playing strength. */ + public boolean canChangeStrength() { + return minElo < maxElo; + } + + /** Get current Elo setting. + * Return MAX_VALUE if reduced strength not enabled or not supported. */ + public int getEloToUse() { + if (canChangeStrength() && limitStrength) + return elo; + return Integer.MAX_VALUE; + } + } + + /** Return engine Elo strength data. */ + public synchronized EloData getEloData() { + EloData ret = new EloData(); + UCIEngine uci = uciEngine; + if (uci != null) { + UCIOptions opts = uci.getUCIOptions(); + UCIOptions.OptionBase lsOpt = opts.getOption("UCI_LimitStrength"); + UCIOptions.OptionBase eloOpt = opts.getOption("UCI_Elo"); + if (lsOpt instanceof UCIOptions.CheckOption && + eloOpt instanceof UCIOptions.SpinOption) { + ret.limitStrength = ((UCIOptions.CheckOption)lsOpt).value; + UCIOptions.SpinOption eloSpin = (UCIOptions.SpinOption)eloOpt; + ret.elo = eloSpin.value; + ret.minElo = eloSpin.minValue; + ret.maxElo = eloSpin.maxValue; + } + } + return ret; + } + + /** Set engine UCI strength parameters. */ + public void setStrength(int elo) { + Map opts = new TreeMap<>(); + boolean limitStrength = elo != Integer.MAX_VALUE; + opts.put("UCI_LimitStrength", limitStrength ? "true" : "false"); + if (limitStrength) + opts.put("UCI_Elo", String.valueOf(elo)); + setEngineUCIOptions(opts); + } + /** Return all book moves, both as a formatted string and as a list of moves. */ public final Pair> getBookHints(Position pos, boolean localized) { return book.getAllBookMoves(pos, localized); @@ -571,7 +621,7 @@ public class DroidComputerPlayer { // Set strength and MultiPV parameters clearInfo(); - uciEngine.setStrength(searchRequest.strength); + uciEngine.setEloStrength(searchRequest.elo); if (maxPV > 1) { int num = Math.min(maxPV, searchRequest.numPV); uciEngine.setOption("MultiPV", num); @@ -721,6 +771,7 @@ public class DroidComputerPlayer { uci.writeLineToEngine("ucinewgame"); uci.writeLineToEngine("isready"); engineState.setState(MainState.WAIT_READY); + listener.notifyEngineInitialized(); } break; } diff --git a/DroidFishApp/src/main/java/org/petero/droidfish/engine/ExternalEngine.java b/DroidFishApp/src/main/java/org/petero/droidfish/engine/ExternalEngine.java index d3b97ad..f58013f 100644 --- a/DroidFishApp/src/main/java/org/petero/droidfish/engine/ExternalEngine.java +++ b/DroidFishApp/src/main/java/org/petero/droidfish/engine/ExternalEngine.java @@ -236,10 +236,6 @@ public class ExternalEngine extends UCIEngineBase { return true; } - @Override - public void setStrength(int strength) { - } - @Override public String readLineFromEngine(int timeoutMillis) { String ret = inLines.readLine(timeoutMillis); diff --git a/DroidFishApp/src/main/java/org/petero/droidfish/engine/InternalStockFish.java b/DroidFishApp/src/main/java/org/petero/droidfish/engine/InternalStockFish.java index ce1c290..3ddf57c 100644 --- a/DroidFishApp/src/main/java/org/petero/droidfish/engine/InternalStockFish.java +++ b/DroidFishApp/src/main/java/org/petero/droidfish/engine/InternalStockFish.java @@ -46,9 +46,9 @@ public class InternalStockFish extends ExternalEngine { } @Override - protected boolean configurableOption(String name) { + protected boolean editableOption(String name) { name = name.toLowerCase(Locale.US); - if (!super.configurableOption(name)) + if (!super.editableOption(name)) return false; if (name.equals("skill level") || name.equals("write debug log") || name.equals("write search log")) @@ -56,11 +56,6 @@ public class InternalStockFish extends ExternalEngine { return true; } - @Override - public final void setStrength(int strength) { - setOption("Skill Level", strength/50); - } - private long readCheckSum(File f) { try (InputStream is = new FileInputStream(f); DataInputStream dis = new DataInputStream(is)) { diff --git a/DroidFishApp/src/main/java/org/petero/droidfish/engine/NetworkEngine.java b/DroidFishApp/src/main/java/org/petero/droidfish/engine/NetworkEngine.java index fc12b15..cc6c3ae 100644 --- a/DroidFishApp/src/main/java/org/petero/droidfish/engine/NetworkEngine.java +++ b/DroidFishApp/src/main/java/org/petero/droidfish/engine/NetworkEngine.java @@ -228,10 +228,6 @@ public class NetworkEngine extends UCIEngineBase { return true; } - @Override - public void setStrength(int strength) { - } - @Override public String readLineFromEngine(int timeoutMillis) { String ret = engineToGui.readLine(timeoutMillis); diff --git a/DroidFishApp/src/main/java/org/petero/droidfish/engine/UCIEngine.java b/DroidFishApp/src/main/java/org/petero/droidfish/engine/UCIEngine.java index 852e728..ecd3caa 100644 --- a/DroidFishApp/src/main/java/org/petero/droidfish/engine/UCIEngine.java +++ b/DroidFishApp/src/main/java/org/petero/droidfish/engine/UCIEngine.java @@ -67,8 +67,9 @@ public interface UCIEngine { /** Write a line to the engine. \n will be added automatically. */ void writeLineToEngine(String data); - /** Set the engine strength, allowed values 0 - 1000. */ - void setStrength(int strength); + /** Temporarily set the engine Elo strength to use for the next search. + * Integer.MAX_VALUE means full strength. */ + void setEloStrength(int elo); /** Set an engine integer option. */ void setOption(String name, int value); diff --git a/DroidFishApp/src/main/java/org/petero/droidfish/engine/UCIEngineBase.java b/DroidFishApp/src/main/java/org/petero/droidfish/engine/UCIEngineBase.java index b540e45..4350720 100644 --- a/DroidFishApp/src/main/java/org/petero/droidfish/engine/UCIEngineBase.java +++ b/DroidFishApp/src/main/java/org/petero/droidfish/engine/UCIEngineBase.java @@ -27,6 +27,7 @@ import java.util.Arrays; import java.util.Locale; import java.util.Map; import java.util.Properties; +import java.util.TreeMap; import org.petero.droidfish.EngineOptions; import org.petero.droidfish.engine.cuckoochess.CuckooChessEngine; @@ -80,14 +81,15 @@ public abstract class UCIEngineBase implements UCIEngine { iniOptions.load(is); } catch (IOException ignore) { } + Map opts = new TreeMap<>(); for (Map.Entry ent : iniOptions.entrySet()) { if (ent.getKey() instanceof String && ent.getValue() instanceof String) { String key = ((String)ent.getKey()).toLowerCase(Locale.US); String value = (String)ent.getValue(); - if (configurableOption(key)) - setOption(key, value); + opts.put(key, value); } } + setUCIOptions(opts); } @Override @@ -125,12 +127,11 @@ public abstract class UCIEngineBase implements UCIEngine { /** Get engine UCI options file. */ protected abstract File getOptionsFile(); - /** Return true if the UCI option can be changed by the user. */ - protected boolean configurableOption(String name) { + /** Return true if the UCI option can be edited in the "Engine Options" dialog. */ + protected boolean editableOption(String name) { name = name.toLowerCase(Locale.US); if (name.startsWith("uci_")) { - String[] allowed = { "uci_limitstrength", "uci_elo" }; - return Arrays.asList(allowed).contains(name); + return false; } else { String[] ignored = { "hash", "ponder", "multipv", "gaviotatbpath", "syzygypath" }; @@ -138,6 +139,17 @@ public abstract class UCIEngineBase implements UCIEngine { } } + /** Return true if the UCI option can be modified by the user, either directly + * from the "Engine Options" dialog or indirectly, for example from the + * "Set Engine Strength" dialog. */ + private boolean configurableOption(String name) { + if (editableOption(name)) + return true; + name = name.toLowerCase(Locale.US); + String[] configurable = { "uci_limitstrength", "uci_elo" }; + return Arrays.asList(configurable).contains(name); + } + @Override public void shutDown() { if (processAlive) { @@ -221,7 +233,7 @@ public abstract class UCIEngineBase implements UCIEngine { int maxV = Integer.parseInt(maxVal); if (minV <= defV && defV <= maxV) option = new UCIOptions.SpinOption(name, minV, maxV, defV); - } catch (NumberFormatException ex) { + } catch (NumberFormatException ignore) { } } } else if (type.equals("combo")) { @@ -241,8 +253,7 @@ public abstract class UCIEngineBase implements UCIEngine { } if (option != null) { - if (!configurableOption(name)) - option.visible = false; + option.visible = editableOption(name); options.addOption(option); } return option; @@ -253,6 +264,21 @@ public abstract class UCIEngineBase implements UCIEngine { return options.contains(optName); } + @Override + public final void setEloStrength(int elo) { + String lsName = "UCI_LimitStrength"; + boolean limit = elo != Integer.MAX_VALUE; + UCIOptions.OptionBase o = options.getOption(lsName); + if (o instanceof UCIOptions.CheckOption) { + // Don't use setOption() since this value reflects current search parameters, + // not user specified strength settings, so should not be saved in .ini file. + writeLineToEngine(String.format(Locale.US, "setoption name %s value %s", + lsName, limit ? "true" : "false")); + } + if (limit) + setOption("UCI_Elo", elo); + } + @Override public final void setOption(String name, int value) { setOption(name, String.format(Locale.US, "%d", value)); diff --git a/DroidFishApp/src/main/java/org/petero/droidfish/engine/UCIOptions.java b/DroidFishApp/src/main/java/org/petero/droidfish/engine/UCIOptions.java index f382823..697616f 100644 --- a/DroidFishApp/src/main/java/org/petero/droidfish/engine/UCIOptions.java +++ b/DroidFishApp/src/main/java/org/petero/droidfish/engine/UCIOptions.java @@ -41,7 +41,7 @@ public class UCIOptions implements Serializable, Cloneable { private static final long serialVersionUID = 1L; public String name; public Type type; - public boolean visible = true; + public boolean visible = true; // True if visible in "Engine Options" dialog @Override public OptionBase clone() throws CloneNotSupportedException { diff --git a/DroidFishApp/src/main/java/org/petero/droidfish/engine/cuckoochess/CuckooChessEngine.java b/DroidFishApp/src/main/java/org/petero/droidfish/engine/cuckoochess/CuckooChessEngine.java index 330d6a2..d6a485e 100644 --- a/DroidFishApp/src/main/java/org/petero/droidfish/engine/cuckoochess/CuckooChessEngine.java +++ b/DroidFishApp/src/main/java/org/petero/droidfish/engine/cuckoochess/CuckooChessEngine.java @@ -74,9 +74,9 @@ public class CuckooChessEngine extends UCIEngineBase { } @Override - protected boolean configurableOption(String name) { + protected boolean editableOption(String name) { name = name.toLowerCase(Locale.US); - if (!super.configurableOption(name)) + if (!super.editableOption(name)) return false; if (name.equals("strength")) return false; @@ -88,11 +88,6 @@ public class CuckooChessEngine extends UCIEngineBase { return true; } - @Override - public final void setStrength(int strength) { - setOption("strength", strength); - } - private void mainLoop(LocalPipe is, LocalPipe os) { String line; while ((line = is.readLine()) != null) { diff --git a/DroidFishApp/src/main/java/org/petero/droidfish/gamelogic/DroidChessController.java b/DroidFishApp/src/main/java/org/petero/droidfish/gamelogic/DroidChessController.java index ca9eb54..4824a46 100644 --- a/DroidFishApp/src/main/java/org/petero/droidfish/gamelogic/DroidChessController.java +++ b/DroidFishApp/src/main/java/org/petero/droidfish/gamelogic/DroidChessController.java @@ -41,6 +41,7 @@ import org.petero.droidfish.book.BookOptions; import org.petero.droidfish.book.EcoDb; import org.petero.droidfish.engine.DroidComputerPlayer; import org.petero.droidfish.engine.UCIOptions; +import org.petero.droidfish.engine.DroidComputerPlayer.EloData; import org.petero.droidfish.engine.DroidComputerPlayer.SearchRequest; import org.petero.droidfish.engine.DroidComputerPlayer.SearchType; import org.petero.droidfish.gamelogic.Game.CommentInfo; @@ -60,7 +61,6 @@ public class DroidChessController { private PGNOptions pgnOptions; private String engine = ""; - private int strength = 1000; private int numPV = 1; private SearchListener listener; @@ -146,13 +146,15 @@ public class DroidChessController { if (!gameMode.playerWhite() || !gameMode.playerBlack()) setPlayerNames(game); // If computer player involved, set player names updateGameMode(); - abortSearch(); - updateComputeThreads(); - gui.updateEngineTitle(); - updateGUI(); + gui.updateEngineTitle(getEloToUse()); // Game mode affects Elo setting + restartSearch(); } } + private int getEloToUse() { + return eloData().getEloToUse(); + } + public final GameMode getGameMode() { return gameMode; } @@ -179,30 +181,49 @@ public class DroidChessController { engineOptions = options; if (computerPlayer != null) computerPlayer.setEngineOptions(engineOptions); - if (restart && (game != null)) { - abortSearch(); - updateComputeThreads(); - updateGUI(); - } + if (restart) + restartSearch(); } } - /** Set engine and engine strength. Restart computer thinking if appropriate. - * @param engine Name of engine. - * @param strength Engine strength, 0 - 1000. */ - public final synchronized void setEngineStrength(String engine, int strength) { - boolean newEngine = !engine.equals(this.engine); - if (newEngine || (strength != this.strength)) { - this.engine = engine; - this.strength = strength; - if (game != null) { - abortSearch(); - updateComputeThreads(); - updateGUI(); - } + private void restartSearch() { + if (game != null) { + abortSearch(); + updateComputeThreads(); + updateGUI(); } } + /** Set engine. Restart computer thinking if appropriate. */ + public final synchronized void setEngine(String engine) { + if (!engine.equals(this.engine)) { + this.engine = engine; + restartSearch(); + } + } + + /** Set engine strength. Restart computer thinking if appropriate. */ + public final synchronized void setStrength(boolean limitStrength, int elo) { + EloData d = eloData(); + int oldElo = d.getEloToUse(); + d.limitStrength = limitStrength; + d.elo = elo; + int newElo = d.getEloToUse(); + if (oldElo != newElo) { + if (computerPlayer != null) + computerPlayer.setStrength(newElo); + restartSearch(); + gui.updateEngineTitle(newElo); + } + } + + /** Return engine Elo strength data. */ + public final synchronized EloData eloData() { + if (computerPlayer == null) + return new EloData(); + return computerPlayer.getEloData(); + } + /** Set engine UCI options. */ public final synchronized void setEngineUCIOptions(Map uciOptions) { if (computerPlayer != null) @@ -233,8 +254,7 @@ public class DroidChessController { DataInputStream dis = new DataInputStream(bais)) { game.readFromStream(dis, version); game.tree.translateMoves(); - } catch (IOException ignore) { - } catch (ChessParseError ignore) { + } catch (IOException|ChessParseError ignore) { } } @@ -383,9 +403,7 @@ public class DroidChessController { if (humansTurn()) { int varNo = game.tree.addMove("--", "", 0, "", ""); game.tree.goForward(varNo); - abortSearch(); - updateComputeThreads(); - updateGUI(); + restartSearch(); gui.setSelection(-1); } } @@ -596,11 +614,8 @@ public class DroidChessController { clampedNumPV = Math.max(clampedNumPV, 1); boolean modified = clampedNumPV != this.numPV; this.numPV = numPV; - if (modified) { - abortSearch(); - updateComputeThreads(); - updateGUI(); - } + if (modified) + restartSearch(); } /** Request computer player to make a move immediately. */ @@ -757,7 +772,7 @@ public class DroidChessController { } else if (currTime < 999950) { statStrTmp.append(String.format(Locale.US, " t:%.1f", currTime / 1000.0)); } else { - statStrTmp.append(String.format(Locale.US, " t:%d", (int)((currTime + 500) / 1000))); + statStrTmp.append(String.format(Locale.US, " t:%d", (currTime + 500) / 1000)); } statStrTmp.append(" n:"); appendWithPrefix(statStrTmp, currNodes); @@ -900,18 +915,25 @@ public class DroidChessController { } @Override - public void notifySearchResult(final int id, final String cmd, final Move ponder) { + public void notifySearchResult(int id, String cmd, Move ponder) { new Thread(() -> gui.runOnUIThread(() -> makeComputerMove(id, cmd, ponder))).start(); } @Override - public void notifyEngineName(final String engineName) { + public void notifyEngineName(String engineName) { gui.runOnUIThread(() -> { updatePlayerNames(engineName); gui.reportEngineName(engineName); }); } + @Override + public void notifyEngineInitialized() { + gui.runOnUIThread(() -> { + gui.updateEngineTitle(eloData().getEloToUse()); + }); + } + @Override public void reportEngineError(final String errMsg) { gui.runOnUIThread(() -> gui.reportEngineError(errMsg)); @@ -998,7 +1020,7 @@ public class DroidChessController { game.haveDrawOffer(), wTime, bTime, wInc, bInc, movesToGo, gui.ponderMode(), fPonderMove, - engine, strength); + engine, getEloToUse()); computerPlayer.queueSearchRequest(sr); } else { computerPlayer.queueStartEngine(searchId, engine); @@ -1033,8 +1055,9 @@ public class DroidChessController { String engine = "Computer"; if (computerPlayer != null) { engine = computerPlayer.getEngineName(); - if (strength < 1000) - engine += String.format(Locale.US, " (%.1f%%)", strength * 0.1); + int elo = getEloToUse(); + if (elo != Integer.MAX_VALUE) + engine += String.format(Locale.US, " (%d)", elo); } String player = gui.playerName(); String white = gameMode.playerWhite() ? player : engine; @@ -1045,8 +1068,9 @@ public class DroidChessController { private synchronized void updatePlayerNames(String engineName) { if (game != null) { - if (strength < 1000) - engineName += String.format(Locale.US, " (%.1f%%)", strength * 0.1); + int elo = getEloToUse(); + if (elo != Integer.MAX_VALUE) + engineName += String.format(Locale.US, " (%d)", elo); String white = gameMode.playerWhite() ? game.tree.white : engineName; String black = gameMode.playerBlack() ? game.tree.black : engineName; game.tree.setPlayerNames(white, black); diff --git a/DroidFishApp/src/main/java/org/petero/droidfish/gamelogic/SearchListener.java b/DroidFishApp/src/main/java/org/petero/droidfish/gamelogic/SearchListener.java index 8949e7e..951e998 100644 --- a/DroidFishApp/src/main/java/org/petero/droidfish/gamelogic/SearchListener.java +++ b/DroidFishApp/src/main/java/org/petero/droidfish/gamelogic/SearchListener.java @@ -84,4 +84,7 @@ public interface SearchListener { /** Report engine error. */ void reportEngineError(String errMsg); + + /** Report that engine has been initialized. */ + void notifyEngineInitialized(); } diff --git a/DroidFishApp/src/main/res/layout/set_strength.xml b/DroidFishApp/src/main/res/layout/set_strength.xml new file mode 100644 index 0000000..2d9f0e5 --- /dev/null +++ b/DroidFishApp/src/main/res/layout/set_strength.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + diff --git a/DroidFishApp/src/main/res/layout/title.xml b/DroidFishApp/src/main/res/layout/title.xml index 6a964c5..350f193 100644 --- a/DroidFishApp/src/main/res/layout/title.xml +++ b/DroidFishApp/src/main/res/layout/title.xml @@ -44,6 +44,7 @@ android:gravity="center" android:textSize="14sp" android:tag="title" + android:ellipsize="middle" android:text="@string/app_name" /> Прылады Загрузіць/Захаваць партыю Зрабіць ход - Змяніць ровень складанасці Змяніць рандамізацыю (выпадковасць) Няправільны фармат ліку Задаць кірунак ходу @@ -273,8 +272,6 @@ Паварочваць дошку: гулец Скарыстаць імя гульца для аўтаматычнага павароту дошкі Налады рухавічка - Сіла гульні - Падтрымваецца толькі ўнутранымі рухавічкамі. Рэжым аналізу заўсёды скарыстае поўную сілу. Разважанне Дазволіць рухавічку абдумванне падчас чакання ходу апанента. Падтрымваецца большасцю рухавічкоў. Хэш-табліца diff --git a/DroidFishApp/src/main/res/values-de/strings.xml b/DroidFishApp/src/main/res/values-de/strings.xml index b0f8abc..6e313ec 100644 --- a/DroidFishApp/src/main/res/values-de/strings.xml +++ b/DroidFishApp/src/main/res/values-de/strings.xml @@ -50,7 +50,6 @@ Um gegebenenfalls Strom zu sparen, ist es empfehlenswert, dass Sie diese Paramet Hilfsmittel Partie laden/speichern Gehe zu Zug - Spielstärke ändern Randomisierung ändern Ungültiges Zahlenformat Seite am Zug @@ -273,8 +272,6 @@ Um gegebenenfalls Strom zu sparen, ist es empfehlenswert, dass Sie diese Paramet Spielfeld nach Namen drehen Spielfeld in Abhängigkeit vom Spielernamen drehen Engine-Einstellungen - Spielstärke - Wird nur von internen Engines unterstützt. Im Analyse-Modus wird stets die volle Stärke verwendet. Vorausberechnung Vorausberechnung von Zügen durch die Engine, wenn der Spieler am Zug ist (von den meisten Engines unterstützt) Hash-Tabelle diff --git a/DroidFishApp/src/main/res/values-es/strings.xml b/DroidFishApp/src/main/res/values-es/strings.xml index 8f5d069..ca437a5 100644 --- a/DroidFishApp/src/main/res/values-es/strings.xml +++ b/DroidFishApp/src/main/res/values-es/strings.xml @@ -50,7 +50,6 @@ Si está usted utilizando la batería, se recomienda que cambie los ajustes para Herramientas Cargar/Guardar Partida Ir a la jugada - Editar Fuerza de juego Editar Aleatoriedad Formato de número no válido Turno de juego @@ -273,8 +272,6 @@ Si está usted utilizando la batería, se recomienda que cambie los ajustes para Invertir tablero : Jugador Utilizar el nombre del jugador para invertir el tablero automáticamente Ajustes del Motor/Programa - Fuerza/Nivel de Juego - Soportado únicamente por los motores internos. El modo análisis siempre utiliza fuerza máxima. Pensar siempre Dejar calcular al motor mientras espera la jugada del oponente. Lo incorporan la mayoría de los motores. Tablas Hash diff --git a/DroidFishApp/src/main/res/values-fr/strings.xml b/DroidFishApp/src/main/res/values-fr/strings.xml index 799ba2c..e1e3ff4 100644 --- a/DroidFishApp/src/main/res/values-fr/strings.xml +++ b/DroidFishApp/src/main/res/values-fr/strings.xml @@ -50,7 +50,6 @@ Lorsque que vous êtes sur batterie, il est recommandé de changer les paramètr Outils Charger/Sauvegarder une partie Aller au coup - Modifier le niveau Modifier la randomisation Format du nombre non valide Camp au trait @@ -273,8 +272,6 @@ Lorsque que vous êtes sur batterie, il est recommandé de changer les paramètr Disposition de l\'échiquier: Joueur Utiliser le nom du joueur pour disposer automatiquement l\'échiquier Paramètres du module - Niveau de jeu - Supporté uniquement par les modules internes. Le mode Analyse utilisera toujours le niveau maximal. Réflexion permanente Laisser le module actif lors du coup de l\'opposant. Supporté par la plupart des modules. Table de hachage diff --git a/DroidFishApp/src/main/res/values-it/strings.xml b/DroidFishApp/src/main/res/values-it/strings.xml index 65a11ae..246bdfc 100644 --- a/DroidFishApp/src/main/res/values-it/strings.xml +++ b/DroidFishApp/src/main/res/values-it/strings.xml @@ -50,7 +50,6 @@ Se l\'alimentazione è a batteria, è consigliabile modificare le impostazioni p Strumenti Apri/Salva partita Vai alla mossa - Imposta la Forza del motore Modifica la casualizzazione Formato del numero non valido Lato che muove @@ -273,8 +272,6 @@ Se l\'alimentazione è a batteria, è consigliabile modificare le impostazioni p Gira la scacchiera: Giocatore Usa il nome del giocatore per girare la scacchiera automaticamente Impostazioni del motore - Forza di gioco - Supportato solo dai motori interni. La modalità di analisi utilizza sempre la massima forza. Sto riflettendo Lascia che il motore rifletta nell\'attesa della mossa dell\'avversario. Supportato dalla maggior parte dei motori. Tabella hash diff --git a/DroidFishApp/src/main/res/values-ko/strings.xml b/DroidFishApp/src/main/res/values-ko/strings.xml index 2a6bc86..ba22c05 100644 --- a/DroidFishApp/src/main/res/values-ko/strings.xml +++ b/DroidFishApp/src/main/res/values-ko/strings.xml @@ -54,7 +54,6 @@ DroidFish는 백그라운드에 실행 중인 상태에서 다음과 같이 설 도구 게임 저장/불러오기 이동으로 가기 - 강도 조정 랜덤화 편집 잘못된 숫자 형식 이동할 사이드 @@ -277,8 +276,6 @@ DroidFish는 백그라운드에 실행 중인 상태에서 다음과 같이 설 플립 보드 : 플레이어 자동 플립 보드를 위해 플레이어 이름을 사용합니다 엔진 설정 - 플레이 강도 - 내장 엔진에서만 지원합니다. 분석 모드에서는 항상 최고 강도를 사용합니다. 숙고하기 상대방의 이동을 기다리는 동안 엔진이 생각하도록 합니다. 대부분의 엔진에 의해 지원됩니다. 해시 테이블 diff --git a/DroidFishApp/src/main/res/values-nl/strings.xml b/DroidFishApp/src/main/res/values-nl/strings.xml index b2f14dc..880f9d4 100644 --- a/DroidFishApp/src/main/res/values-nl/strings.xml +++ b/DroidFishApp/src/main/res/values-nl/strings.xml @@ -50,7 +50,6 @@ Als uw telefoon op batterij werkt is het aan te raden om deze instellingen te wi Tools Laad/Bewaar Partij Ga naar zet - Speelsterkte bewerken Willekeurigheid bewerken Ongeldig nummer formaat Speler aan zet @@ -273,8 +272,6 @@ Als uw telefoon op batterij werkt is het aan te raden om deze instellingen te wi Draai bord:Speler Draai bord automatisch op spelers naam Engine instellingen - Speel sterkte - Alleen ondersteund door interne engines. Analyse gebruikt altijd de hoogste denksterkte. Peinzen Laat de engine verder denken tijdens wachten op de zet van de tegenstander. Hashtabel diff --git a/DroidFishApp/src/main/res/values-pl/strings.xml b/DroidFishApp/src/main/res/values-pl/strings.xml index 17c852d..03d9860 100644 --- a/DroidFishApp/src/main/res/values-pl/strings.xml +++ b/DroidFishApp/src/main/res/values-pl/strings.xml @@ -50,7 +50,6 @@ Jeśli pracujesz na baterii, zalecana jest zmiana ustawień, w celu oszczędzani Narzędzia Załaduj/zapisz partię Idź do posunięcia - Edytuj siłę gry Zmień losowość Niepoprawny format liczby Strona na posunięciu @@ -273,8 +272,6 @@ Jeśli pracujesz na baterii, zalecana jest zmiana ustawień, w celu oszczędzani Obracanie szachownicy: gracz Używaj nazwy gracza, żeby obracać szachownicę automatycznie Ustawienia silnika - Siła gry - Wspierane wyłącznie przez lokalne silniki szachowe. Tryb analizy zawsze używa maksymalnej siły gry. Namysł Silnik szachowy będzie liczył pozycję czekając na posunięcie przeciwnika. Wspierane przez większość silników. Tablica haszująca diff --git a/DroidFishApp/src/main/res/values-pt/strings.xml b/DroidFishApp/src/main/res/values-pt/strings.xml index 37ac6fb..106c4ca 100644 --- a/DroidFishApp/src/main/res/values-pt/strings.xml +++ b/DroidFishApp/src/main/res/values-pt/strings.xml @@ -50,7 +50,6 @@ Se você está usando somente a bateria, recomenda-se que você mude as configur Ferramentas Carregar/Salvar partida Ir para o lance - Alterar nível Alterar aleatoriedade Formato de número inválido Lado a mover @@ -273,8 +272,6 @@ Se você está usando somente a bateria, recomenda-se que você mude as configur Inverter tabuleiro: jogador Usar o nome do jogador para virar o tabuleiro automaticamente Configurações do software de Xadrez - Nível de jogo - Somente suportado pelo software interno. Modo análise sempre usa força total. Análise constante Deixar o software analisando enquanto espera o lance do oponente. Suportado pela maioria dos softwares. Tabela hash diff --git a/DroidFishApp/src/main/res/values-ru/strings.xml b/DroidFishApp/src/main/res/values-ru/strings.xml index 86f7830..69f0465 100644 --- a/DroidFishApp/src/main/res/values-ru/strings.xml +++ b/DroidFishApp/src/main/res/values-ru/strings.xml @@ -50,7 +50,6 @@ Инструменты Загрузить/Сохранить партию Сделать ход - Изменить уровень сложности Изменить рандомизацию (случайность) Неправильный формат числа Задать направление хода @@ -273,8 +272,6 @@ Поворачивать доску: игрок Использовать имя игрока для автоматического поворота доски Настройки движка - Сила игры - Поддерживается только внутренними движками. Режим анализа всегда использует полную силу. Размышление Позволить движку обдумывание во время ожидания хода оппонента. Поддерживается большинством движков. Хэш-таблица diff --git a/DroidFishApp/src/main/res/values-tr/strings.xml b/DroidFishApp/src/main/res/values-tr/strings.xml index d991494..f9009ab 100644 --- a/DroidFishApp/src/main/res/values-tr/strings.xml +++ b/DroidFishApp/src/main/res/values-tr/strings.xml @@ -50,7 +50,6 @@ Pil gücüyle çalışıyorsanız, pil gücünden tasarruf etmek için ayarları Araçlar Oyun Yükle/Kaydet Harekete git - Gücü ayarla Rasgeleliği ayarla Geçersiz sayı formatı Hareket tarafı @@ -273,8 +272,6 @@ Pil gücüyle çalışıyorsanız, pil gücünden tasarruf etmek için ayarları Tahtayı Dödür: Oyuncu Tahtayı döndürmek için Oyuncu Adını kullan Motor Ayarları - Oynama zorluğu - Sadece dahili motorlar destekler. Analiz modu daima tam gücü kullanır. Düşünme Rakibini beklerken bilgisayarın düşünmesine izin ver. Çoğu motor destekler. Hash Tablosu diff --git a/DroidFishApp/src/main/res/values-uk/strings.xml b/DroidFishApp/src/main/res/values-uk/strings.xml index fe34cb8..2893a98 100644 --- a/DroidFishApp/src/main/res/values-uk/strings.xml +++ b/DroidFishApp/src/main/res/values-uk/strings.xml @@ -50,7 +50,6 @@ Інструменти Завантажити/Зберегти партію Зробити хід - Змінити рівень складності Змінити рандомізацію (випадковість) Неправильний формат числа Задати напрямок ходу @@ -273,8 +272,6 @@ Повертати дошку: гравець Використовувати ім\'я гравця для автоматичного повороту дошки Налаштування рушія - Сила ігри - Підтримується тільки внутрішніми рушіями. Режим аналізу завжди використовує повну силу. Розважання Дозволити рушію обдумування під час очікування ходу опонента. Підтримується більшістю рушіїв. Геш-таблиця diff --git a/DroidFishApp/src/main/res/values-zh-rCN/strings.xml b/DroidFishApp/src/main/res/values-zh-rCN/strings.xml index 87e6af6..abda69b 100644 --- a/DroidFishApp/src/main/res/values-zh-rCN/strings.xml +++ b/DroidFishApp/src/main/res/values-zh-rCN/strings.xml @@ -50,7 +50,6 @@ 工具 加载/保存对局 转到着法 - 编辑棋力 编辑随机性 编号格式无效 轮走棋方 @@ -273,8 +272,6 @@ 翻转棋盘: 棋手 以棋手名字自动翻转棋盘 引擎设置 - 对弈棋力 - 支持内置引擎。分析模式总是使用最强棋力 思考 引擎在等待对手走棋时思考。支持大多数引擎 哈希表 diff --git a/DroidFishApp/src/main/res/values/strings.xml b/DroidFishApp/src/main/res/values/strings.xml index a30aaad..219608f 100644 --- a/DroidFishApp/src/main/res/values/strings.xml +++ b/DroidFishApp/src/main/res/values/strings.xml @@ -50,7 +50,9 @@ If you are running on battery power, it is recommended that you change settings Tools Load/Save Game Goto move - Edit Strength + Limit Strength + Set Engine Strength + Engine cannot reduce playing strength Edit Randomization Invalid number format Side to Move @@ -273,8 +275,6 @@ If you are running on battery power, it is recommended that you change settings Flip Board: Player Use Player Name to flip board automatically Engine Settings - Playing Strength - Only supported by internal engines. Analysis mode always uses full strength. Pondering Let engine think while waiting for opponent\'s move. Supported by most engines. Hash Table diff --git a/DroidFishApp/src/main/res/xml/preferences.xml b/DroidFishApp/src/main/res/xml/preferences.xml index ac9d15f..1881ec8 100644 --- a/DroidFishApp/src/main/res/xml/preferences.xml +++ b/DroidFishApp/src/main/res/xml/preferences.xml @@ -30,12 +30,6 @@ - - *Settings* -> *Engine Settings* -> *Hash Table* to diff --git a/doc/droidfish_manual.pdf b/doc/droidfish_manual.pdf index 2ee356d..6171231 100644 Binary files a/doc/droidfish_manual.pdf and b/doc/droidfish_manual.pdf differ