diff --git a/DroidFish/src/org/petero/droidfish/engine/DroidComputerPlayer.java b/DroidFish/src/org/petero/droidfish/engine/DroidComputerPlayer.java index f225fa2..238f405 100644 --- a/DroidFish/src/org/petero/droidfish/engine/DroidComputerPlayer.java +++ b/DroidFish/src/org/petero/droidfish/engine/DroidComputerPlayer.java @@ -25,6 +25,7 @@ import java.util.ArrayList; import org.petero.droidfish.BookOptions; import org.petero.droidfish.engine.cuckoochess.CuckooChessEngine; +import org.petero.droidfish.gamelogic.Game; import org.petero.droidfish.gamelogic.Move; import org.petero.droidfish.gamelogic.MoveGen; import org.petero.droidfish.gamelogic.Pair; @@ -63,33 +64,11 @@ public class DroidComputerPlayer { book = DroidBook.getInstance(); } - /** Set engine and engine strength. - * @param engine Name of engine. - * @param strength Engine strength, 0 - 1000. */ - public final synchronized void setEngineStrength(String engine, int strength) { - if (!engine.equals(this.engine)) { - shutdownEngine(); - this.engine = engine; - startEngine(); - } - this.strength = strength; - if (uciEngine != null) - uciEngine.setStrength(strength); - } - /** Return maximum number of PVs supported by engine. */ public final synchronized int getMaxPV() { return maxPV; } - /** Set engine multi-PV mode. */ - public final synchronized void setNumPV(int numPV) { - if ((uciEngine != null) && (maxPV > 1)) { - int num = Math.min(maxPV, numPV); - uciEngine.setOption("MultiPV", num); - } - } - /** Set opening book options. */ public final void setBookOptions(BookOptions options) { book.setOptions(options); @@ -141,15 +120,18 @@ 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 engineThreads Number of engine threads to use, if supported by engine. - * @return The computer player command, and the next ponder move. + * @param engine Chess engine to use for searching. + * @param strength Engine strength setting. */ - public final Pair doSearch(Position prevPos, ArrayList mList, - Position currPos, boolean drawOffer, - int wTime, int bTime, int inc, int movesToGo, - boolean ponderEnabled, Move ponderMove, - int engineThreads) { - if (listener != null) - listener.notifyBookInfo("", null); + public final void doSearch(Position prevPos, ArrayList mList, + Position currPos, boolean drawOffer, + int wTime, int bTime, int inc, int movesToGo, + boolean ponderEnabled, Move ponderMove, + int engineThreads, + String engine, int strength, Game g) { + setEngineStrength(engine, strength); + setNumPV(1); + listener.notifyBookInfo("", null); if (ponderMove != null) mList.add(ponderMove); @@ -171,7 +153,8 @@ public class DroidComputerPlayer { Move bookMove = book.getBookMove(currPos); if (bookMove != null) { if (canClaimDraw(currPos, posHashList, posHashListSize, bookMove) == "") { - return new Pair(TextIO.moveToString(currPos, bookMove, false), null); + listener.notifySearchResult(g, TextIO.moveToString(currPos, bookMove, false), null); + return; } } @@ -179,12 +162,14 @@ public class DroidComputerPlayer { ArrayList moves = new MoveGen().pseudoLegalMoves(currPos); moves = MoveGen.removeIllegal(currPos, moves); if (moves.size() == 0) { - return new Pair("", null); // User set up a position where computer has no valid moves. + listener.notifySearchResult(g, "", null); // User set up a position where computer has no valid moves. + return; } if (moves.size() == 1) { Move bestMove = moves.get(0); if (canClaimDraw(currPos, posHashList, posHashListSize, bestMove) == "") { - return new Pair(TextIO.moveToUCIString(bestMove), null); + listener.notifySearchResult(g, TextIO.moveToUCIString(bestMove), null); + return; } } } @@ -231,7 +216,7 @@ public class DroidComputerPlayer { if (drawOffer && !statIsMate && (statScore <= -300)) { bestMove = "draw accept"; } - return new Pair(bestMove, nextPonderMove); + listener.notifySearchResult(g, bestMove, nextPonderMove); } public boolean shouldStop = false; @@ -250,16 +235,21 @@ public class DroidComputerPlayer { * @param currPos Position to analyze. * @param drawOffer True if other side have offered draw. * @param engineThreads Number of threads to use, or 0 for default value. + * @param engine Chess engine to use for searching + * @param numPV Multi-PV mode. */ public final void analyze(Position prevPos, ArrayList mList, Position currPos, - boolean drawOffer, int engineThreads) { + boolean drawOffer, int engineThreads, + String engine, int numPV) { + setEngineStrength(engine, 1000); + setNumPV(numPV); if (shouldStop) return; - if (listener != null) { + { Pair> bi = getBookHints(currPos); listener.notifyBookInfo(bi.first, bi.second); } - + // If no legal moves, there is nothing to analyze ArrayList moves = new MoveGen().pseudoLegalMoves(currPos); moves = MoveGen.removeIllegal(currPos, moves); @@ -287,6 +277,28 @@ public class DroidComputerPlayer { monitorEngine(currPos, null); } + /** Set engine and engine strength. + * @param engine Name of engine. + * @param strength Engine strength, 0 - 1000. */ + private final synchronized void setEngineStrength(String engine, int strength) { + if (!engine.equals(this.engine)) { + shutdownEngine(); + this.engine = engine; + startEngine(); + } + this.strength = strength; + if (uciEngine != null) + uciEngine.setStrength(strength); + } + + /** Set engine multi-PV mode. */ + private final synchronized void setNumPV(int numPV) { + if ((uciEngine != null) && (maxPV > 1)) { + int num = Math.min(maxPV, numPV); + uciEngine.setOption("MultiPV", num); + } + } + private final synchronized void startEngine() { boolean useCuckoo = engine.equals("cuckoochess"); if (uciEngine == null) { @@ -572,8 +584,6 @@ public class DroidComputerPlayer { /** Notify GUI about search statistics. */ private final synchronized void notifyGUI(Position pos, Move ponderMove) { - if (listener == null) - return; if (depthModified) { listener.notifyDepth(statCurrDepth); depthModified = false; diff --git a/DroidFish/src/org/petero/droidfish/gamelogic/DroidChessController.java b/DroidFish/src/org/petero/droidfish/gamelogic/DroidChessController.java index 54f62b7..b25b2e4 100644 --- a/DroidFish/src/org/petero/droidfish/gamelogic/DroidChessController.java +++ b/DroidFish/src/org/petero/droidfish/gamelogic/DroidChessController.java @@ -713,6 +713,11 @@ public class DroidChessController { public void prefsChanged() { setSearchInfo(); } + + @Override + public void notifySearchResult(Game g, String cmd, Move ponder) { + makeComputerMove(g, cmd, ponder); + } } private final void updateBookHints() { @@ -927,36 +932,11 @@ public class DroidChessController { final Move fPonderMove = ponder ? ponderMove : null; computerThread = new Thread(new Runnable() { public void run() { - computerPlayer.setEngineStrength(engine, strength); - computerPlayer.setNumPV(1); - final Pair pair = - computerPlayer.doSearch(ph.first, ph.second, currPos, haveDrawOffer, - wTime, bTime, inc, fMovesToGo, - gui.ponderMode(), fPonderMove, - gui.engineThreads()); - final String cmd = pair.first; - final Move ponder = pair.second; - 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(); - } - } - }); + computerPlayer.doSearch(ph.first, ph.second, currPos, haveDrawOffer, + wTime, bTime, inc, fMovesToGo, + gui.ponderMode(), fPonderMove, + gui.engineThreads(), + engine, strength, g); } }); listener.clearSearchInfo(); @@ -965,6 +945,30 @@ public class DroidChessController { } } + 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(); @@ -990,12 +994,9 @@ public class DroidChessController { final boolean alive = game.tree.getGameState() == GameState.ALIVE; analysisThread = new Thread(new Runnable() { public void run() { - if (alive) { - computerPlayer.setEngineStrength(engine, 1000); - computerPlayer.setNumPV(numPV); + if (alive) computerPlayer.analyze(ph.first, ph.second, currPos, haveDrawOffer, - gui.engineThreads()); - } + gui.engineThreads(), engine, numPV); } }); listener.clearSearchInfo(); diff --git a/DroidFish/src/org/petero/droidfish/gamelogic/SearchListener.java b/DroidFish/src/org/petero/droidfish/gamelogic/SearchListener.java index 5a99814..7ee14bd 100644 --- a/DroidFish/src/org/petero/droidfish/gamelogic/SearchListener.java +++ b/DroidFish/src/org/petero/droidfish/gamelogic/SearchListener.java @@ -77,4 +77,6 @@ public interface SearchListener { public void notifyPV(Position pos, ArrayList pvInfo, boolean isPonder); public void notifyStats(int nodes, int nps, int time); public void notifyBookInfo(String bookInfo, List moveList); + + public void notifySearchResult(Game g, String cmd, Move ponder); }