mirror of
https://github.com/peterosterlund2/droidfish.git
synced 2025-04-24 12:55:40 +02:00
DroidFish: Rewrote the engine communication so that the GUI never waits for the engine.
This commit is contained in:
parent
9d7d30b293
commit
c1ab57b4f9
DroidFish
jni
src/org/petero/droidfish
@ -73,21 +73,27 @@ static std::deque<char> inBuf;
|
|||||||
|
|
||||||
static bool getNextChar(int& c, int timeoutMillis) {
|
static bool getNextChar(int& c, int timeoutMillis) {
|
||||||
if (inBuf.empty()) {
|
if (inBuf.empty()) {
|
||||||
fd_set readfds, writefds;
|
fd_set readfds, exceptfds;
|
||||||
FD_ZERO(&readfds);
|
FD_ZERO(&readfds);
|
||||||
FD_SET(fdFromChild, &readfds);
|
FD_SET(fdFromChild, &readfds);
|
||||||
|
FD_ZERO(&exceptfds);
|
||||||
|
FD_SET(fdFromChild, &exceptfds);
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
tv.tv_sec = timeoutMillis / 1000;
|
tv.tv_sec = timeoutMillis / 1000;
|
||||||
tv.tv_usec = (timeoutMillis % 1000) * 1000;
|
tv.tv_usec = (timeoutMillis % 1000) * 1000;
|
||||||
int ret = select(fdFromChild + 1, &readfds, NULL, NULL, &tv);
|
int ret = select(fdFromChild + 1, &readfds, NULL, &exceptfds, &tv);
|
||||||
if (ret < 0)
|
if ((ret < 0) || FD_ISSET(fdFromChild, &exceptfds))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (FD_ISSET(fdFromChild, &readfds)) {
|
||||||
static char buf[4096];
|
static char buf[4096];
|
||||||
int len = read(fdFromChild, &buf[0], sizeof(buf));
|
int len = read(fdFromChild, &buf[0], sizeof(buf));
|
||||||
|
if (len == 0)
|
||||||
|
return false; // EOF
|
||||||
for (int i = 0; i < len; i++)
|
for (int i = 0; i < len; i++)
|
||||||
inBuf.push_back(buf[i]);
|
inBuf.push_back(buf[i]);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (inBuf.empty()) {
|
if (inBuf.empty()) {
|
||||||
c = -1;
|
c = -1;
|
||||||
return true;
|
return true;
|
||||||
|
@ -108,6 +108,7 @@ public class DroidFish extends Activity implements GUIInterface {
|
|||||||
// FIXME!!! Remove invalid playerActions in PGN import (should be done in verifyChildren)
|
// FIXME!!! Remove invalid playerActions in PGN import (should be done in verifyChildren)
|
||||||
// FIXME!!! Implement bookmark mechanism for positions in pgn files
|
// FIXME!!! Implement bookmark mechanism for positions in pgn files
|
||||||
// FIXME!!! Display chess notation in local language
|
// FIXME!!! Display chess notation in local language
|
||||||
|
// FIXME!!! Add support for "Chess Leipzig" font
|
||||||
|
|
||||||
// FIXME!!! Computer clock should stop if phone turned off (computer stops thinking if unplugged)
|
// FIXME!!! Computer clock should stop if phone turned off (computer stops thinking if unplugged)
|
||||||
// FIXME!!! Add support for all time controls defined by the PGN standard
|
// FIXME!!! Add support for all time controls defined by the PGN standard
|
||||||
@ -118,8 +119,6 @@ public class DroidFish extends Activity implements GUIInterface {
|
|||||||
// FIXME!!! Add chess960 support
|
// FIXME!!! Add chess960 support
|
||||||
// FIXME!!! Implement "hint" feature
|
// FIXME!!! Implement "hint" feature
|
||||||
|
|
||||||
// FIXME!!! Don't send "stop" command when engine is already stopped
|
|
||||||
|
|
||||||
// FIXME!!! Show extended book info. (Win percent, number of games, performance rating, etc.)
|
// FIXME!!! Show extended book info. (Win percent, number of games, performance rating, etc.)
|
||||||
// FIXME!!! Green color for "main move". Red color for "don't play in tournaments" moves.
|
// FIXME!!! Green color for "main move". Red color for "don't play in tournaments" moves.
|
||||||
|
|
||||||
@ -542,7 +541,7 @@ public class DroidFish extends Activity implements GUIInterface {
|
|||||||
|
|
||||||
mEngineThreads = getIntSetting("threads", 0);
|
mEngineThreads = getIntSetting("threads", 0);
|
||||||
|
|
||||||
String engine = settings.getString("engine", "");
|
String engine = settings.getString("engine", "stockfish");
|
||||||
int strength = settings.getInt("strength", 1000);
|
int strength = settings.getInt("strength", 1000);
|
||||||
setEngineStrength(engine, strength);
|
setEngineStrength(engine, strength);
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -35,6 +35,7 @@ public interface UCIEngine {
|
|||||||
*/
|
*/
|
||||||
public String readLineFromEngine(int timeoutMillis);
|
public String readLineFromEngine(int timeoutMillis);
|
||||||
|
|
||||||
|
// FIXME!! Writes should be handled by separate thread.
|
||||||
/** Write a line to the engine. \n will be added automatically. */
|
/** Write a line to the engine. \n will be added automatically. */
|
||||||
public void writeLineToEngine(String data);
|
public void writeLineToEngine(String data);
|
||||||
|
|
||||||
|
@ -49,6 +49,7 @@ public class CuckooChessEngine extends UCIEngineBase {
|
|||||||
private Pipe guiToEngine;
|
private Pipe guiToEngine;
|
||||||
private Pipe engineToGui;
|
private Pipe engineToGui;
|
||||||
private NioInputStream inFromEngine;
|
private NioInputStream inFromEngine;
|
||||||
|
private Thread engineThread;
|
||||||
|
|
||||||
public CuckooChessEngine() {
|
public CuckooChessEngine() {
|
||||||
try {
|
try {
|
||||||
@ -72,13 +73,14 @@ public class CuckooChessEngine extends UCIEngineBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected final void startProcess() {
|
protected final void startProcess() {
|
||||||
new Thread(new Runnable() {
|
engineThread = new Thread(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
NioInputStream in = new NioInputStream(guiToEngine);
|
NioInputStream in = new NioInputStream(guiToEngine);
|
||||||
NioPrintStream out = new NioPrintStream(engineToGui);
|
NioPrintStream out = new NioPrintStream(engineToGui);
|
||||||
mainLoop(in, out);
|
mainLoop(in, out);
|
||||||
}
|
}
|
||||||
}).start();
|
});
|
||||||
|
engineThread.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
private final void mainLoop(NioInputStream is, NioPrintStream os) {
|
private final void mainLoop(NioInputStream is, NioPrintStream os) {
|
||||||
@ -93,6 +95,8 @@ public class CuckooChessEngine extends UCIEngineBase {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final String readLineFromEngine(int timeoutMillis) {
|
public final String readLineFromEngine(int timeoutMillis) {
|
||||||
|
if ((engineThread != null) && !engineThread.isAlive())
|
||||||
|
return null;
|
||||||
String ret = inFromEngine.readLine(timeoutMillis);
|
String ret = inFromEngine.readLine(timeoutMillis);
|
||||||
if (ret == null)
|
if (ret == null)
|
||||||
return null;
|
return null;
|
||||||
|
@ -27,6 +27,8 @@ import org.petero.droidfish.GUIInterface;
|
|||||||
import org.petero.droidfish.GameMode;
|
import org.petero.droidfish.GameMode;
|
||||||
import org.petero.droidfish.PGNOptions;
|
import org.petero.droidfish.PGNOptions;
|
||||||
import org.petero.droidfish.engine.DroidComputerPlayer;
|
import org.petero.droidfish.engine.DroidComputerPlayer;
|
||||||
|
import org.petero.droidfish.engine.DroidComputerPlayer.SearchRequest;
|
||||||
|
import org.petero.droidfish.engine.DroidComputerPlayer.SearchType;
|
||||||
import org.petero.droidfish.gamelogic.Game.GameState;
|
import org.petero.droidfish.gamelogic.Game.GameState;
|
||||||
import org.petero.droidfish.gamelogic.GameTree.Node;
|
import org.petero.droidfish.gamelogic.GameTree.Node;
|
||||||
|
|
||||||
@ -43,8 +45,6 @@ public class DroidChessController {
|
|||||||
private GUIInterface gui;
|
private GUIInterface gui;
|
||||||
private GameMode gameMode;
|
private GameMode gameMode;
|
||||||
private PGNOptions pgnOptions;
|
private PGNOptions pgnOptions;
|
||||||
private Thread computerThread;
|
|
||||||
private Thread analysisThread;
|
|
||||||
|
|
||||||
private String engine = "";
|
private String engine = "";
|
||||||
private int strength = 1000;
|
private int strength = 1000;
|
||||||
@ -60,30 +60,30 @@ public class DroidChessController {
|
|||||||
/** Partial move that needs promotion choice to be completed. */
|
/** Partial move that needs promotion choice to be completed. */
|
||||||
private Move promoteMove;
|
private Move promoteMove;
|
||||||
|
|
||||||
private Object shutdownEngineLock = new Object();
|
private int searchId;
|
||||||
|
|
||||||
|
|
||||||
/** Constructor. */
|
/** Constructor. */
|
||||||
public DroidChessController(GUIInterface gui, PgnToken.PgnTokenReceiver gameTextListener, PGNOptions options) {
|
public DroidChessController(GUIInterface gui, PgnToken.PgnTokenReceiver gameTextListener, PGNOptions options) {
|
||||||
this.gui = gui;
|
this.gui = gui;
|
||||||
this.gameTextListener = gameTextListener;
|
this.gameTextListener = gameTextListener;
|
||||||
|
gameMode = new GameMode(GameMode.TWO_PLAYERS);
|
||||||
pgnOptions = options;
|
pgnOptions = options;
|
||||||
listener = new SearchListener();
|
listener = new SearchListener();
|
||||||
|
searchId = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Start a new game. */
|
/** Start a new game. */
|
||||||
public final synchronized void newGame(GameMode gameMode) {
|
public final synchronized void newGame(GameMode gameMode) {
|
||||||
ss.searchResultWanted = false;
|
boolean updateGui = abortSearch();
|
||||||
boolean updateGui = stopComputerThinking();
|
|
||||||
updateGui |= stopAnalysis();
|
|
||||||
if (updateGui)
|
if (updateGui)
|
||||||
updateGUI();
|
updateGUI();
|
||||||
this.gameMode = gameMode;
|
this.gameMode = gameMode;
|
||||||
ponderMove = null;
|
|
||||||
if (computerPlayer == null) {
|
if (computerPlayer == null) {
|
||||||
computerPlayer = new DroidComputerPlayer(engine, listener);
|
computerPlayer = new DroidComputerPlayer(listener);
|
||||||
computerPlayer.setBookOptions(bookOptions);
|
computerPlayer.setBookOptions(bookOptions);
|
||||||
}
|
}
|
||||||
|
computerPlayer.queueStartEngine(searchId, engine);
|
||||||
|
searchId++;
|
||||||
game = new Game(gameTextListener, timeControl, movesPerSession, timeIncrement);
|
game = new Game(gameTextListener, timeControl, movesPerSession, timeIncrement);
|
||||||
computerPlayer.clearTT();
|
computerPlayer.clearTT();
|
||||||
setPlayerNames(game);
|
setPlayerNames(game);
|
||||||
@ -92,7 +92,7 @@ public class DroidChessController {
|
|||||||
|
|
||||||
/** Start playing a new game. Should be called after newGame(). */
|
/** Start playing a new game. Should be called after newGame(). */
|
||||||
public final synchronized void startGame() {
|
public final synchronized void startGame() {
|
||||||
updateComputeThreads(true);
|
updateComputeThreads();
|
||||||
setSelection();
|
setSelection();
|
||||||
updateGUI();
|
updateGUI();
|
||||||
updateGameMode();
|
updateGameMode();
|
||||||
@ -117,15 +117,13 @@ public class DroidChessController {
|
|||||||
public final synchronized void setGameMode(GameMode newMode) {
|
public final synchronized void setGameMode(GameMode newMode) {
|
||||||
if (!gameMode.equals(newMode)) {
|
if (!gameMode.equals(newMode)) {
|
||||||
if (newMode.humansTurn(game.currPos().whiteMove))
|
if (newMode.humansTurn(game.currPos().whiteMove))
|
||||||
ss.searchResultWanted = false;
|
searchId++;
|
||||||
gameMode = newMode;
|
gameMode = newMode;
|
||||||
if (!gameMode.playerWhite() || !gameMode.playerBlack())
|
if (!gameMode.playerWhite() || !gameMode.playerBlack())
|
||||||
setPlayerNames(game); // If computer player involved, set player names
|
setPlayerNames(game); // If computer player involved, set player names
|
||||||
updateGameMode();
|
updateGameMode();
|
||||||
ponderMove = null;
|
abortSearch();
|
||||||
ss.searchResultWanted = false;
|
updateComputeThreads();
|
||||||
stopComputerThinking();
|
|
||||||
updateComputeThreads(true);
|
|
||||||
updateGUI();
|
updateGUI();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -136,12 +134,6 @@ public class DroidChessController {
|
|||||||
bookOptions = options;
|
bookOptions = options;
|
||||||
if (computerPlayer != null) {
|
if (computerPlayer != null) {
|
||||||
computerPlayer.setBookOptions(bookOptions);
|
computerPlayer.setBookOptions(bookOptions);
|
||||||
if (analysisThread != null) {
|
|
||||||
boolean updateGui = stopAnalysis();
|
|
||||||
updateGui |= startAnalysis();
|
|
||||||
if (updateGui)
|
|
||||||
updateGUI();
|
|
||||||
}
|
|
||||||
updateBookHints();
|
updateBookHints();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -157,9 +149,9 @@ public class DroidChessController {
|
|||||||
if (newEngine || (strength != this.strength)) {
|
if (newEngine || (strength != this.strength)) {
|
||||||
this.engine = engine;
|
this.engine = engine;
|
||||||
this.strength = strength;
|
this.strength = strength;
|
||||||
if (newEngine && ((analysisThread != null) || (computerThread != null))) {
|
if (game != null) {
|
||||||
stopAnalysis();
|
abortSearch();
|
||||||
updateComputeThreads(true);
|
updateComputeThreads();
|
||||||
updateGUI();
|
updateGUI();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -169,7 +161,7 @@ public class DroidChessController {
|
|||||||
public final synchronized void prefsChanged() {
|
public final synchronized void prefsChanged() {
|
||||||
updateBookHints();
|
updateBookHints();
|
||||||
updateMoveList();
|
updateMoveList();
|
||||||
listener.prefsChanged();
|
listener.prefsChanged(searchId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** De-serialize from byte array. */
|
/** De-serialize from byte array. */
|
||||||
@ -204,29 +196,27 @@ public class DroidChessController {
|
|||||||
if (!newGame.readPGN(fenPgn, pgnOptions))
|
if (!newGame.readPGN(fenPgn, pgnOptions))
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
ss.searchResultWanted = false;
|
searchId++;
|
||||||
game = newGame;
|
game = newGame;
|
||||||
if (computerPlayer != null)
|
|
||||||
computerPlayer.clearTT();
|
|
||||||
gameTextListener.clear();
|
gameTextListener.clear();
|
||||||
updateGameMode();
|
updateGameMode();
|
||||||
stopAnalysis();
|
abortSearch();
|
||||||
stopComputerThinking();
|
|
||||||
computerPlayer.clearTT();
|
computerPlayer.clearTT();
|
||||||
ponderMove = null;
|
updateComputeThreads();
|
||||||
updateComputeThreads(true);
|
|
||||||
gui.setSelection(-1);
|
gui.setSelection(-1);
|
||||||
updateGUI();
|
updateGUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** True if human's turn to make a move. (True in analysis mode.) */
|
/** True if human's turn to make a move. (True in analysis mode.) */
|
||||||
public final synchronized boolean humansTurn() {
|
public final synchronized boolean humansTurn() {
|
||||||
|
if (game == null)
|
||||||
|
return false;
|
||||||
return gameMode.humansTurn(game.currPos().whiteMove);
|
return gameMode.humansTurn(game.currPos().whiteMove);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Return true if computer player is using CPU power. */
|
/** Return true if computer player is using CPU power. */
|
||||||
public final synchronized boolean computerBusy() {
|
public final synchronized boolean computerBusy() {
|
||||||
return (computerThread != null) || (analysisThread != null);
|
return (computerPlayer != null) && computerPlayer.computerBusy();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Make a move for a human player. */
|
/** Make a move for a human player. */
|
||||||
@ -235,13 +225,12 @@ public class DroidChessController {
|
|||||||
Position oldPos = new Position(game.currPos());
|
Position oldPos = new Position(game.currPos());
|
||||||
if (doMove(m)) {
|
if (doMove(m)) {
|
||||||
if (m.equals(ponderMove) && !gameMode.analysisMode() &&
|
if (m.equals(ponderMove) && !gameMode.analysisMode() &&
|
||||||
(analysisThread == null) && (computerThread != null)) {
|
(computerPlayer.getSearchType() == SearchType.PONDER)) {
|
||||||
computerPlayer.ponderHit(oldPos, ponderMove);
|
computerPlayer.ponderHit(searchId);
|
||||||
|
ponderMove = null;
|
||||||
} else {
|
} else {
|
||||||
ss.searchResultWanted = false;
|
abortSearch();
|
||||||
stopAnalysis();
|
updateComputeThreads();
|
||||||
stopComputerThinking();
|
|
||||||
updateComputeThreads(true);
|
|
||||||
}
|
}
|
||||||
setAnimMove(oldPos, m, true);
|
setAnimMove(oldPos, m, true);
|
||||||
updateGUI();
|
updateGUI();
|
||||||
@ -283,11 +272,8 @@ public class DroidChessController {
|
|||||||
if (humansTurn()) {
|
if (humansTurn()) {
|
||||||
int varNo = game.tree.addMove("--", "", 0, "", "");
|
int varNo = game.tree.addMove("--", "", 0, "", "");
|
||||||
game.tree.goForward(varNo);
|
game.tree.goForward(varNo);
|
||||||
ss.searchResultWanted = false;
|
abortSearch();
|
||||||
stopAnalysis();
|
updateComputeThreads();
|
||||||
stopComputerThinking();
|
|
||||||
ponderMove = null;
|
|
||||||
updateComputeThreads(true);
|
|
||||||
updateGUI();
|
updateGUI();
|
||||||
gui.setSelection(-1);
|
gui.setSelection(-1);
|
||||||
}
|
}
|
||||||
@ -312,11 +298,9 @@ public class DroidChessController {
|
|||||||
/** Undo last move. Does not truncate game tree. */
|
/** Undo last move. Does not truncate game tree. */
|
||||||
public final synchronized void undoMove() {
|
public final synchronized void undoMove() {
|
||||||
if (game.getLastMove() != null) {
|
if (game.getLastMove() != null) {
|
||||||
ss.searchResultWanted = false;
|
abortSearch();
|
||||||
stopAnalysis();
|
|
||||||
stopComputerThinking();
|
|
||||||
boolean didUndo = undoMoveNoUpdate();
|
boolean didUndo = undoMoveNoUpdate();
|
||||||
updateComputeThreads(true);
|
updateComputeThreads();
|
||||||
setSelection();
|
setSelection();
|
||||||
if (didUndo)
|
if (didUndo)
|
||||||
setAnimMove(game.currPos(), game.getNextMove(), false);
|
setAnimMove(game.currPos(), game.getNextMove(), false);
|
||||||
@ -327,11 +311,9 @@ public class DroidChessController {
|
|||||||
/** Redo last move. Follows default variation. */
|
/** Redo last move. Follows default variation. */
|
||||||
public final synchronized void redoMove() {
|
public final synchronized void redoMove() {
|
||||||
if (game.canRedoMove()) {
|
if (game.canRedoMove()) {
|
||||||
ss.searchResultWanted = false;
|
abortSearch();
|
||||||
stopAnalysis();
|
|
||||||
stopComputerThinking();
|
|
||||||
redoMoveNoUpdate();
|
redoMoveNoUpdate();
|
||||||
updateComputeThreads(true);
|
updateComputeThreads();
|
||||||
setSelection();
|
setSelection();
|
||||||
setAnimMove(game.prevPos(), game.getLastMove(), true);
|
setAnimMove(game.prevPos(), game.getLastMove(), true);
|
||||||
updateGUI();
|
updateGUI();
|
||||||
@ -359,11 +341,8 @@ public class DroidChessController {
|
|||||||
needUpdate = true;
|
needUpdate = true;
|
||||||
}
|
}
|
||||||
if (needUpdate) {
|
if (needUpdate) {
|
||||||
ss.searchResultWanted = false;
|
abortSearch();
|
||||||
stopAnalysis();
|
updateComputeThreads();
|
||||||
stopComputerThinking();
|
|
||||||
ponderMove = null;
|
|
||||||
updateComputeThreads(true);
|
|
||||||
setSelection();
|
setSelection();
|
||||||
updateGUI();
|
updateGUI();
|
||||||
}
|
}
|
||||||
@ -380,11 +359,8 @@ public class DroidChessController {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (needUpdate) {
|
if (needUpdate) {
|
||||||
ss.searchResultWanted = false;
|
abortSearch();
|
||||||
stopAnalysis();
|
updateComputeThreads();
|
||||||
stopComputerThinking();
|
|
||||||
ponderMove = null;
|
|
||||||
updateComputeThreads(true);
|
|
||||||
setSelection();
|
setSelection();
|
||||||
updateGUI();
|
updateGUI();
|
||||||
}
|
}
|
||||||
@ -396,7 +372,6 @@ public class DroidChessController {
|
|||||||
return;
|
return;
|
||||||
if (!game.goNode(node))
|
if (!game.goNode(node))
|
||||||
return;
|
return;
|
||||||
ponderMove = null;
|
|
||||||
if (!humansTurn()) {
|
if (!humansTurn()) {
|
||||||
if (game.getLastMove() != null) {
|
if (game.getLastMove() != null) {
|
||||||
game.undoMove();
|
game.undoMove();
|
||||||
@ -404,11 +379,8 @@ public class DroidChessController {
|
|||||||
game.redoMove();
|
game.redoMove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ss.searchResultWanted = false;
|
abortSearch();
|
||||||
stopAnalysis();
|
updateComputeThreads();
|
||||||
stopComputerThinking();
|
|
||||||
ponderMove = null;
|
|
||||||
updateComputeThreads(true);
|
|
||||||
setSelection();
|
setSelection();
|
||||||
updateGUI();
|
updateGUI();
|
||||||
}
|
}
|
||||||
@ -426,12 +398,9 @@ public class DroidChessController {
|
|||||||
/** Go to a new variation in the game tree. */
|
/** Go to a new variation in the game tree. */
|
||||||
public final synchronized void changeVariation(int delta) {
|
public final synchronized void changeVariation(int delta) {
|
||||||
if (game.numVariations() > 1) {
|
if (game.numVariations() > 1) {
|
||||||
ss.searchResultWanted = false;
|
abortSearch();
|
||||||
stopAnalysis();
|
|
||||||
stopComputerThinking();
|
|
||||||
game.changeVariation(delta);
|
game.changeVariation(delta);
|
||||||
ponderMove = null;
|
updateComputeThreads();
|
||||||
updateComputeThreads(true);
|
|
||||||
setSelection();
|
setSelection();
|
||||||
updateGUI();
|
updateGUI();
|
||||||
}
|
}
|
||||||
@ -439,12 +408,9 @@ public class DroidChessController {
|
|||||||
|
|
||||||
/** Delete whole game sub-tree rooted at current position. */
|
/** Delete whole game sub-tree rooted at current position. */
|
||||||
public final synchronized void removeSubTree() {
|
public final synchronized void removeSubTree() {
|
||||||
ss.searchResultWanted = false;
|
abortSearch();
|
||||||
stopAnalysis();
|
|
||||||
stopComputerThinking();
|
|
||||||
game.removeSubTree();
|
game.removeSubTree();
|
||||||
ponderMove = null;
|
updateComputeThreads();
|
||||||
updateComputeThreads(true);
|
|
||||||
setSelection();
|
setSelection();
|
||||||
updateGUI();
|
updateGUI();
|
||||||
}
|
}
|
||||||
@ -508,44 +474,35 @@ public class DroidChessController {
|
|||||||
if (numPV > maxPV()) numPV = maxPV();
|
if (numPV > maxPV()) numPV = maxPV();
|
||||||
if (numPV != this.numPV) {
|
if (numPV != this.numPV) {
|
||||||
this.numPV = numPV;
|
this.numPV = numPV;
|
||||||
if (analysisThread != null) {
|
abortSearch();
|
||||||
stopAnalysis();
|
updateComputeThreads();
|
||||||
ponderMove = null;
|
|
||||||
updateComputeThreads(true);
|
|
||||||
updateGUI();
|
updateGUI();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/** Request computer player to make a move immediately. */
|
/** Request computer player to make a move immediately. */
|
||||||
public final synchronized void stopSearch() {
|
public final synchronized void stopSearch() {
|
||||||
if (computerThread != null) {
|
if (!humansTurn() && (computerPlayer != null))
|
||||||
computerPlayer.stopSearch();
|
computerPlayer.stopSearch();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/** Stop ponder search. */
|
/** Stop ponder search. */
|
||||||
public final synchronized void stopPonder() {
|
public final synchronized void stopPonder() {
|
||||||
if ((computerThread != null) && humansTurn()) {
|
if (humansTurn() && (computerPlayer != null)) {
|
||||||
boolean updateGui = stopComputerThinking();
|
if (computerPlayer.getSearchType() == SearchType.PONDER) {
|
||||||
|
boolean updateGui = abortSearch();
|
||||||
if (updateGui)
|
if (updateGui)
|
||||||
updateGUI();
|
updateGUI();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Shut down chess engine process. */
|
/** Shut down chess engine process. */
|
||||||
public final synchronized void shutdownEngine() {
|
public final synchronized void shutdownEngine() {
|
||||||
synchronized (shutdownEngineLock) {
|
|
||||||
gameMode = new GameMode(GameMode.TWO_PLAYERS);
|
gameMode = new GameMode(GameMode.TWO_PLAYERS);
|
||||||
ss.searchResultWanted = false;
|
abortSearch();
|
||||||
boolean updateGui = stopComputerThinking();
|
|
||||||
updateGui |= stopAnalysis();
|
|
||||||
if (updateGui)
|
|
||||||
updateGUI();
|
|
||||||
ponderMove = null;
|
|
||||||
computerPlayer.shutdownEngine();
|
computerPlayer.shutdownEngine();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/** Get PGN header tags and values. */
|
/** Get PGN header tags and values. */
|
||||||
public final synchronized void getHeaders(Map<String,String> headers) {
|
public final synchronized void getHeaders(Map<String,String> headers) {
|
||||||
@ -600,17 +557,19 @@ public class DroidChessController {
|
|||||||
private String bookInfo = "";
|
private String bookInfo = "";
|
||||||
private List<Move> bookMoves = null;
|
private List<Move> bookMoves = null;
|
||||||
|
|
||||||
|
private Move ponderMove = null;
|
||||||
private ArrayList<PvInfo> pvInfoV = new ArrayList<PvInfo>();
|
private ArrayList<PvInfo> pvInfoV = new ArrayList<PvInfo>();
|
||||||
|
|
||||||
public final void clearSearchInfo() {
|
public final void clearSearchInfo(int id) {
|
||||||
|
ponderMove = null;
|
||||||
pvInfoV.clear();
|
pvInfoV.clear();
|
||||||
currDepth = 0;
|
currDepth = 0;
|
||||||
bookInfo = "";
|
bookInfo = "";
|
||||||
bookMoves = null;
|
bookMoves = null;
|
||||||
setSearchInfo();
|
setSearchInfo(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final void setSearchInfo() {
|
private final void setSearchInfo(final int id) {
|
||||||
StringBuilder buf = new StringBuilder();
|
StringBuilder buf = new StringBuilder();
|
||||||
for (int i = 0; i < pvInfoV.size(); i++) {
|
for (int i = 0; i < pvInfoV.size(); i++) {
|
||||||
PvInfo pvi = pvInfoV.get(i);
|
PvInfo pvi = pvInfoV.get(i);
|
||||||
@ -639,35 +598,42 @@ public class DroidChessController {
|
|||||||
: "";
|
: "";
|
||||||
final String newPV = buf.toString();
|
final String newPV = buf.toString();
|
||||||
final String newBookInfo = bookInfo;
|
final String newBookInfo = bookInfo;
|
||||||
final SearchStatus localSS = ss;
|
final ArrayList<ArrayList<Move>> pvMoves = new ArrayList<ArrayList<Move>>();
|
||||||
|
for (int i = 0; i < pvInfoV.size(); i++) {
|
||||||
|
if (ponderMove != null) {
|
||||||
|
ArrayList<Move> tmp = new ArrayList<Move>();
|
||||||
|
tmp.add(ponderMove);
|
||||||
|
for (Move m : pvInfoV.get(i).pv)
|
||||||
|
tmp.add(m);
|
||||||
|
pvMoves.add(tmp);
|
||||||
|
} else {
|
||||||
|
pvMoves.add(pvInfoV.get(i).pv);
|
||||||
|
}
|
||||||
|
}
|
||||||
gui.runOnUIThread(new Runnable() {
|
gui.runOnUIThread(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
if (!localSS.searchResultWanted && (bookMoves != null))
|
setThinkingInfo(id, pvMoves, newPV, statStr, newBookInfo, bookMoves);
|
||||||
return;
|
|
||||||
ArrayList<ArrayList<Move>> pvMoves = new ArrayList<ArrayList<Move>>();
|
|
||||||
for (int i = 0; i < pvInfoV.size(); i++)
|
|
||||||
pvMoves.add(pvInfoV.get(i).pv);
|
|
||||||
gui.setThinkingInfo(newPV, statStr, newBookInfo, pvMoves, bookMoves);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void notifyDepth(int depth) {
|
public void notifyDepth(int id, int depth) {
|
||||||
currDepth = depth;
|
currDepth = depth;
|
||||||
setSearchInfo();
|
setSearchInfo(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void notifyCurrMove(Position pos, Move m, int moveNr) {
|
public void notifyCurrMove(int id, Position pos, Move m, int moveNr) {
|
||||||
currMove = TextIO.moveToString(pos, m, false);
|
currMove = TextIO.moveToString(pos, m, false);
|
||||||
currMoveNr = moveNr;
|
currMoveNr = moveNr;
|
||||||
setSearchInfo();
|
setSearchInfo(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
public void notifyPV(Position pos, ArrayList<PvInfo> pvInfo, boolean isPonder) {
|
public void notifyPV(int id, Position pos, ArrayList<PvInfo> pvInfo, Move ponderMove) {
|
||||||
|
this.ponderMove = ponderMove;
|
||||||
pvInfoV = (ArrayList<PvInfo>) pvInfo.clone();
|
pvInfoV = (ArrayList<PvInfo>) pvInfo.clone();
|
||||||
for (PvInfo pv : pvInfo) {
|
for (PvInfo pv : pvInfo) {
|
||||||
currTime = pv.time;
|
currTime = pv.time;
|
||||||
@ -677,64 +643,84 @@ public class DroidChessController {
|
|||||||
StringBuilder buf = new StringBuilder();
|
StringBuilder buf = new StringBuilder();
|
||||||
Position tmpPos = new Position(pos);
|
Position tmpPos = new Position(pos);
|
||||||
UndoInfo ui = new UndoInfo();
|
UndoInfo ui = new UndoInfo();
|
||||||
boolean first = true;
|
if (ponderMove != null) {
|
||||||
|
String moveStr = TextIO.moveToString(tmpPos, ponderMove, false);
|
||||||
|
buf.append(String.format(" [%s]", moveStr));
|
||||||
|
tmpPos.makeMove(ponderMove, ui);
|
||||||
|
}
|
||||||
for (Move m : pv.pv) {
|
for (Move m : pv.pv) {
|
||||||
String moveStr = TextIO.moveToString(tmpPos, m, false);
|
String moveStr = TextIO.moveToString(tmpPos, m, false);
|
||||||
if (first && isPonder) {
|
|
||||||
buf.append(String.format(" [%s]", moveStr));
|
|
||||||
first = false;
|
|
||||||
} else {
|
|
||||||
buf.append(String.format(" %s", moveStr));
|
buf.append(String.format(" %s", moveStr));
|
||||||
}
|
|
||||||
tmpPos.makeMove(m, ui);
|
tmpPos.makeMove(m, ui);
|
||||||
}
|
}
|
||||||
pv.pvStr = buf.toString();
|
pv.pvStr = buf.toString();
|
||||||
}
|
}
|
||||||
whiteMove = pos.whiteMove ^ isPonder;
|
whiteMove = pos.whiteMove ^ (ponderMove != null);
|
||||||
|
|
||||||
setSearchInfo();
|
setSearchInfo(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void notifyStats(int nodes, int nps, int time) {
|
public void notifyStats(int id, int nodes, int nps, int time) {
|
||||||
currNodes = nodes;
|
currNodes = nodes;
|
||||||
currNps = nps;
|
currNps = nps;
|
||||||
currTime = time;
|
currTime = time;
|
||||||
setSearchInfo();
|
setSearchInfo(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void notifyBookInfo(String bookInfo, List<Move> moveList) {
|
public void notifyBookInfo(int id, String bookInfo, List<Move> moveList) {
|
||||||
this.bookInfo = bookInfo;
|
this.bookInfo = bookInfo;
|
||||||
bookMoves = moveList;
|
bookMoves = moveList;
|
||||||
setSearchInfo();
|
setSearchInfo(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void prefsChanged() {
|
public void prefsChanged(int id) {
|
||||||
setSearchInfo();
|
setSearchInfo(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void notifySearchResult(Game g, String cmd, Move ponder) {
|
public void notifySearchResult(final int id, final String cmd, final Move ponder) {
|
||||||
makeComputerMove(g, cmd, ponder);
|
new Thread(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
gui.runOnUIThread(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
makeComputerMove(id, cmd, ponder);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void notifyEngineName(final String engineName) {
|
||||||
|
gui.runOnUIThread(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
updatePlayerNames(engineName);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Discard current search. Return true if GUI update needed. */
|
||||||
|
private final boolean abortSearch() {
|
||||||
|
ponderMove = null;
|
||||||
|
searchId++;
|
||||||
|
if (computerPlayer == null)
|
||||||
|
return false;
|
||||||
|
if (computerPlayer.stopSearch()) {
|
||||||
|
listener.clearSearchInfo(searchId);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private final void updateBookHints() {
|
private final void updateBookHints() {
|
||||||
if (gameMode != null) {
|
if (humansTurn()) {
|
||||||
boolean analysis = gameMode.analysisMode();
|
|
||||||
if (!analysis && humansTurn()) {
|
|
||||||
ss = new SearchStatus();
|
|
||||||
Pair<String, ArrayList<Move>> bi = computerPlayer.getBookHints(game.currPos());
|
Pair<String, ArrayList<Move>> bi = computerPlayer.getBookHints(game.currPos());
|
||||||
listener.notifyBookInfo(bi.first, bi.second);
|
listener.notifyBookInfo(searchId, bi.first, bi.second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private final static class SearchStatus {
|
|
||||||
boolean searchResultWanted = true;
|
|
||||||
}
|
|
||||||
private SearchStatus ss = new SearchStatus();
|
|
||||||
|
|
||||||
private final void updateGameMode() {
|
private final void updateGameMode() {
|
||||||
if (game != null) {
|
if (game != null) {
|
||||||
@ -747,40 +733,98 @@ public class DroidChessController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Start/stop computer thinking/analysis as appropriate. */
|
/** Start/stop computer thinking/analysis as appropriate. */
|
||||||
private final void updateComputeThreads(boolean clearPV) {
|
private final void updateComputeThreads() {
|
||||||
boolean analysis = gameMode.analysisMode();
|
boolean alive = game.tree.getGameState() == GameState.ALIVE;
|
||||||
boolean computersTurn = !humansTurn();
|
boolean analysis = gameMode.analysisMode() && alive;
|
||||||
boolean ponder = gui.ponderMode() && !analysis && !computersTurn && (ponderMove != null);
|
boolean computersTurn = !humansTurn() && alive;
|
||||||
if (!analysis)
|
boolean ponder = gui.ponderMode() && !analysis && !computersTurn && (ponderMove != null) && alive;
|
||||||
stopAnalysis();
|
if (!analysis && !(computersTurn || ponder))
|
||||||
if (!(computersTurn || ponder))
|
computerPlayer.stopSearch();
|
||||||
stopComputerThinking();
|
listener.clearSearchInfo(searchId);
|
||||||
if (clearPV) {
|
|
||||||
listener.clearSearchInfo();
|
|
||||||
updateBookHints();
|
updateBookHints();
|
||||||
|
if (!computerPlayer.sameSearchId(searchId)) {
|
||||||
|
if (analysis) {
|
||||||
|
Pair<Position, ArrayList<Move>> ph = game.getUCIHistory();
|
||||||
|
SearchRequest sr = DroidComputerPlayer.SearchRequest.analyzeRequest(
|
||||||
|
searchId, ph.first, ph.second,
|
||||||
|
new Position(game.currPos()),
|
||||||
|
game.haveDrawOffer(), engine,
|
||||||
|
gui.engineThreads(), numPV);
|
||||||
|
computerPlayer.queueAnalyzeRequest(sr);
|
||||||
|
} else if (computersTurn || ponder) {
|
||||||
|
listener.clearSearchInfo(searchId);
|
||||||
|
listener.notifyBookInfo(searchId, "", null);
|
||||||
|
final Pair<Position, ArrayList<Move>> ph = game.getUCIHistory();
|
||||||
|
Position currPos = new Position(game.currPos());
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
int wTime = game.timeController.getRemainingTime(true, now);
|
||||||
|
int bTime = game.timeController.getRemainingTime(false, now);
|
||||||
|
int inc = game.timeController.getIncrement();
|
||||||
|
int movesToGo = game.timeController.getMovesToTC();
|
||||||
|
if (ponder && !currPos.whiteMove && (movesToGo > 0)) {
|
||||||
|
movesToGo--;
|
||||||
|
if (movesToGo <= 0)
|
||||||
|
movesToGo += game.timeController.getMovesPerSession();
|
||||||
}
|
}
|
||||||
if (analysis)
|
final Move fPonderMove = ponder ? ponderMove : null;
|
||||||
startAnalysis();
|
SearchRequest sr = DroidComputerPlayer.SearchRequest.searchRequest(
|
||||||
if (computersTurn || ponder)
|
searchId, now, ph.first, ph.second, currPos,
|
||||||
startComputerThinking(ponder);
|
game.haveDrawOffer(),
|
||||||
|
wTime, bTime, inc, movesToGo,
|
||||||
|
gui.ponderMode(), fPonderMove,
|
||||||
|
engine, gui.engineThreads(),
|
||||||
|
strength);
|
||||||
|
computerPlayer.queueSearchRequest(sr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final synchronized void makeComputerMove(int id, final String cmd, final Move ponder) {
|
||||||
|
if (searchId != id)
|
||||||
|
return;
|
||||||
|
searchId++;
|
||||||
|
Position oldPos = new Position(game.currPos());
|
||||||
|
game.processString(cmd);
|
||||||
|
ponderMove = ponder;
|
||||||
|
updateGameMode();
|
||||||
|
gui.computerMoveMade();
|
||||||
|
listener.clearSearchInfo(searchId);
|
||||||
|
updateComputeThreads();
|
||||||
|
setSelection();
|
||||||
|
setAnimMove(oldPos, game.getLastMove(), true);
|
||||||
|
updateGUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
private final void setPlayerNames(Game game) {
|
private final void setPlayerNames(Game game) {
|
||||||
if (game != null) {
|
if (game != null) {
|
||||||
String engine = (computerPlayer != null) ? computerPlayer.getEngineName() :
|
String engine = "Computer";
|
||||||
"Computer";
|
if (computerPlayer != null) {
|
||||||
|
engine = computerPlayer.getEngineName();
|
||||||
|
if (strength < 1000)
|
||||||
|
engine += String.format(" (%.1f%%)", strength * 0.1);
|
||||||
|
}
|
||||||
String white = gameMode.playerWhite() ? "Player" : engine;
|
String white = gameMode.playerWhite() ? "Player" : engine;
|
||||||
String black = gameMode.playerBlack() ? "Player" : engine;
|
String black = gameMode.playerBlack() ? "Player" : engine;
|
||||||
game.tree.setPlayerNames(white, black);
|
game.tree.setPlayerNames(white, black);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final synchronized void updatePlayerNames(String engineName) {
|
||||||
|
if (game != null) {
|
||||||
|
if (strength < 1000)
|
||||||
|
engineName += String.format(" (%.1f%%)", strength * 0.1);
|
||||||
|
String white = gameMode.playerWhite() ? game.tree.white : engineName;
|
||||||
|
String black = gameMode.playerBlack() ? game.tree.black : engineName;
|
||||||
|
game.tree.setPlayerNames(white, black);
|
||||||
|
updateMoveList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private final boolean undoMoveNoUpdate() {
|
private final boolean undoMoveNoUpdate() {
|
||||||
if (game.getLastMove() == null)
|
if (game.getLastMove() == null)
|
||||||
return false;
|
return false;
|
||||||
ss.searchResultWanted = false;
|
searchId++;
|
||||||
game.undoMove();
|
game.undoMove();
|
||||||
ponderMove = null;
|
|
||||||
if (!humansTurn()) {
|
if (!humansTurn()) {
|
||||||
if (game.getLastMove() != null) {
|
if (game.getLastMove() != null) {
|
||||||
game.undoMove();
|
game.undoMove();
|
||||||
@ -802,9 +846,8 @@ public class DroidChessController {
|
|||||||
|
|
||||||
private final void redoMoveNoUpdate() {
|
private final void redoMoveNoUpdate() {
|
||||||
if (game.canRedoMove()) {
|
if (game.canRedoMove()) {
|
||||||
ss.searchResultWanted = false;
|
searchId++;
|
||||||
game.redoMove();
|
game.redoMove();
|
||||||
ponderMove = null;
|
|
||||||
if (!humansTurn() && game.canRedoMove()) {
|
if (!humansTurn() && game.canRedoMove()) {
|
||||||
game.redoMove();
|
game.redoMove();
|
||||||
if (!humansTurn())
|
if (!humansTurn())
|
||||||
@ -846,13 +889,14 @@ public class DroidChessController {
|
|||||||
if (s.state == Game.GameState.ALIVE) {
|
if (s.state == Game.GameState.ALIVE) {
|
||||||
s.moveNr = game.currPos().fullMoveCounter;
|
s.moveNr = game.currPos().fullMoveCounter;
|
||||||
s.white = game.currPos().whiteMove;
|
s.white = game.currPos().whiteMove;
|
||||||
if (computerThread != null)
|
DroidComputerPlayer.SearchType st = SearchType.NONE;
|
||||||
if (humansTurn())
|
if (computerPlayer != null)
|
||||||
s.ponder = true;
|
st = computerPlayer.getSearchType();
|
||||||
else
|
switch (st) {
|
||||||
s.thinking = true;
|
case SEARCH: s.thinking = true; break;
|
||||||
if (analysisThread != null)
|
case PONDER: s.ponder = true; break;
|
||||||
s.analyzing = true;
|
case ANALYZE: s.analyzing = true; break;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if ((s.state == GameState.DRAW_REP) || (s.state == GameState.DRAW_50))
|
if ((s.state == GameState.DRAW_REP) || (s.state == GameState.DRAW_50))
|
||||||
s.drawInfo = game.getDrawInfo();
|
s.drawInfo = game.getDrawInfo();
|
||||||
@ -880,6 +924,12 @@ public class DroidChessController {
|
|||||||
updateRemainingTime();
|
updateRemainingTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final synchronized void setThinkingInfo(int id, ArrayList<ArrayList<Move>> pvMoves, String pvStr,
|
||||||
|
String statStr, String bookInfo, List<Move> bookMoves) {
|
||||||
|
if (id == searchId)
|
||||||
|
gui.setThinkingInfo(pvStr, statStr, bookInfo, pvMoves, bookMoves);
|
||||||
|
}
|
||||||
|
|
||||||
private final void updateMoveList() {
|
private final void updateMoveList() {
|
||||||
if (game == null)
|
if (game == null)
|
||||||
return;
|
return;
|
||||||
@ -909,120 +959,6 @@ public class DroidChessController {
|
|||||||
gui.setAnimMove(sourcePos, move, forward);
|
gui.setAnimMove(sourcePos, move, forward);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final synchronized void startComputerThinking(boolean ponder) {
|
|
||||||
if (analysisThread != null) return;
|
|
||||||
if (game.getGameState() != GameState.ALIVE) return;
|
|
||||||
if (computerThread == null) {
|
|
||||||
ss = new SearchStatus();
|
|
||||||
final Pair<Position, ArrayList<Move>> ph = game.getUCIHistory();
|
|
||||||
final Game g = game;
|
|
||||||
final boolean haveDrawOffer = g.haveDrawOffer();
|
|
||||||
final Position currPos = new Position(g.currPos());
|
|
||||||
long now = System.currentTimeMillis();
|
|
||||||
final int wTime = game.timeController.getRemainingTime(true, now);
|
|
||||||
final int bTime = game.timeController.getRemainingTime(false, now);
|
|
||||||
final int inc = game.timeController.getIncrement();
|
|
||||||
int movesToGo = game.timeController.getMovesToTC();
|
|
||||||
if (ponder && !currPos.whiteMove && (movesToGo > 0)) {
|
|
||||||
movesToGo--;
|
|
||||||
if (movesToGo <= 0)
|
|
||||||
movesToGo += game.timeController.getMovesPerSession();
|
|
||||||
}
|
|
||||||
final int fMovesToGo = movesToGo;
|
|
||||||
final Move fPonderMove = ponder ? ponderMove : null;
|
|
||||||
computerThread = new Thread(new Runnable() {
|
|
||||||
public void run() {
|
|
||||||
computerPlayer.doSearch(ph.first, ph.second, currPos, haveDrawOffer,
|
|
||||||
wTime, bTime, inc, fMovesToGo,
|
|
||||||
gui.ponderMode(), fPonderMove,
|
|
||||||
gui.engineThreads(),
|
|
||||||
engine, strength, g);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
listener.clearSearchInfo();
|
|
||||||
computerPlayer.shouldStop = false;
|
|
||||||
computerThread.start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private final void makeComputerMove(final Game g, final String cmd, final Move ponder) {
|
|
||||||
final SearchStatus localSS = ss;
|
|
||||||
gui.runOnUIThread(new Runnable() {
|
|
||||||
public void run() {
|
|
||||||
synchronized (shutdownEngineLock) {
|
|
||||||
if (!localSS.searchResultWanted)
|
|
||||||
return;
|
|
||||||
Position oldPos = new Position(g.currPos());
|
|
||||||
g.processString(cmd);
|
|
||||||
ponderMove = ponder;
|
|
||||||
updateGameMode();
|
|
||||||
gui.computerMoveMade();
|
|
||||||
listener.clearSearchInfo();
|
|
||||||
stopComputerThinking();
|
|
||||||
stopAnalysis(); // To force analysis to restart for new position
|
|
||||||
updateComputeThreads(true);
|
|
||||||
setSelection();
|
|
||||||
setAnimMove(oldPos, g.getLastMove(), true);
|
|
||||||
updateGUI();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private final synchronized boolean stopComputerThinking() {
|
|
||||||
if (computerThread != null) {
|
|
||||||
computerPlayer.stopSearch();
|
|
||||||
try {
|
|
||||||
computerThread.join();
|
|
||||||
} catch (InterruptedException ex) {
|
|
||||||
System.out.printf("Could not stop computer thread%n");
|
|
||||||
}
|
|
||||||
computerThread = null;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private final synchronized boolean startAnalysis() {
|
|
||||||
if (gameMode.analysisMode()) {
|
|
||||||
if (computerThread != null) return false;
|
|
||||||
if (analysisThread == null) {
|
|
||||||
ss = new SearchStatus();
|
|
||||||
final Pair<Position, ArrayList<Move>> ph = game.getUCIHistory();
|
|
||||||
final boolean haveDrawOffer = game.haveDrawOffer();
|
|
||||||
final Position currPos = new Position(game.currPos());
|
|
||||||
final boolean alive = game.tree.getGameState() == GameState.ALIVE;
|
|
||||||
analysisThread = new Thread(new Runnable() {
|
|
||||||
public void run() {
|
|
||||||
if (alive)
|
|
||||||
computerPlayer.analyze(ph.first, ph.second, currPos, haveDrawOffer,
|
|
||||||
gui.engineThreads(), engine, numPV);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
listener.clearSearchInfo();
|
|
||||||
computerPlayer.shouldStop = false;
|
|
||||||
analysisThread.start();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private final synchronized boolean stopAnalysis() {
|
|
||||||
if (analysisThread != null) {
|
|
||||||
computerPlayer.stopSearch();
|
|
||||||
try {
|
|
||||||
analysisThread.join();
|
|
||||||
} catch (InterruptedException ex) {
|
|
||||||
System.out.printf("Could not stop analysis thread%n");
|
|
||||||
}
|
|
||||||
analysisThread = null;
|
|
||||||
listener.clearSearchInfo();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private final boolean findValidDrawClaim() {
|
private final boolean findValidDrawClaim() {
|
||||||
if (game.getGameState() != GameState.ALIVE) return true;
|
if (game.getGameState() != GameState.ALIVE) return true;
|
||||||
game.processString("draw accept");
|
game.processString("draw accept");
|
||||||
|
@ -65,18 +65,29 @@ public interface SearchListener {
|
|||||||
this.lowerBound = lowerBound;
|
this.lowerBound = lowerBound;
|
||||||
this.pv = pv;
|
this.pv = pv;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void removeFirstMove() {
|
|
||||||
if (!pv.isEmpty())
|
|
||||||
pv.remove(0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void notifyDepth(int depth);
|
/** Report current engine search depth. */
|
||||||
public void notifyCurrMove(Position pos, Move m, int moveNr);
|
public void notifyDepth(int id, int depth);
|
||||||
public void notifyPV(Position pos, ArrayList<PvInfo> pvInfo, boolean isPonder);
|
|
||||||
public void notifyStats(int nodes, int nps, int time);
|
|
||||||
public void notifyBookInfo(String bookInfo, List<Move> moveList);
|
|
||||||
|
|
||||||
public void notifySearchResult(Game g, String cmd, Move ponder);
|
/** Report the move, valid in position pos, that the engine is currently searching. */
|
||||||
|
public void notifyCurrMove(int id, Position pos, Move m, int moveNr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Report PV information. If ponderMove is non-null, ponderMove is the first move
|
||||||
|
* to play from position pos.
|
||||||
|
*/
|
||||||
|
public void notifyPV(int id, Position pos, ArrayList<PvInfo> pvInfo, Move ponderMove);
|
||||||
|
|
||||||
|
/** Report search statistics. */
|
||||||
|
public void notifyStats(int id, int nodes, int nps, int time);
|
||||||
|
|
||||||
|
/** Report opening book information. */
|
||||||
|
public void notifyBookInfo(int id, String bookInfo, List<Move> moveList);
|
||||||
|
|
||||||
|
/** Report move (or command, such as "resign") played by the engine. */
|
||||||
|
public void notifySearchResult(int id, String cmd, Move ponder);
|
||||||
|
|
||||||
|
/** Report engine name. */
|
||||||
|
public void notifyEngineName(String engineName);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user