Implement maxNPS UCI option for CuckooChess

This is an alternative way to limit the engine strength. It also has
the advantage of reducing heat and battery drain.
This commit is contained in:
Peter Osterlund 2020-04-11 01:58:26 +02:00
parent 29d605af99
commit 67e03495dc
3 changed files with 39 additions and 6 deletions

View File

@ -73,6 +73,7 @@ public class EngineControl {
// Reduced strength variables // Reduced strength variables
private int strength = 1000; private int strength = 1000;
private int maxNPS = 0;
private long randomSeed = 0; private long randomSeed = 0;
/** /**
@ -226,7 +227,7 @@ public class EngineControl {
sc = new Search(pos, posHashList, posHashListSize, tt, ht); sc = new Search(pos, posHashList, posHashListSize, tt, ht);
sc.timeLimit(minTimeLimit, maxTimeLimit); sc.timeLimit(minTimeLimit, maxTimeLimit);
sc.setListener(new SearchListener(os)); sc.setListener(new SearchListener(os));
sc.setStrength(strength, randomSeed); sc.setStrength(strength, randomSeed, maxNPS);
MoveGen.MoveList moves = moveGen.pseudoLegalMoves(pos); MoveGen.MoveList moves = moveGen.pseudoLegalMoves(pos);
MoveGen.removeIllegal(pos, moves); MoveGen.removeIllegal(pos, moves);
if ((searchMoves != null) && (searchMoves.size() > 0)) if ((searchMoves != null) && (searchMoves.size() > 0))
@ -374,6 +375,7 @@ public class EngineControl {
os.printf("option name UCI_EngineAbout type string default %s by Peter Osterlund, see %s%n", os.printf("option name UCI_EngineAbout type string default %s by Peter Osterlund, see %s%n",
ComputerPlayer.engineName, "http://hem.bredband.net/petero2b/javachess/index.html"); ComputerPlayer.engineName, "http://hem.bredband.net/petero2b/javachess/index.html");
os.print("option name Strength type spin default 1000 min 0 max 1000\n"); os.print("option name Strength type spin default 1000 min 0 max 1000\n");
os.print("option name maxNPS type spin default 0 min 0 max 10000000\n");
for (String pName : Parameters.instance().getParamNames()) { for (String pName : Parameters.instance().getParamNames()) {
ParamBase p = Parameters.instance().getParam(pName); ParamBase p = Parameters.instance().getParam(pName);
@ -424,6 +426,8 @@ public class EngineControl {
analyseMode = Boolean.parseBoolean(optionValue); analyseMode = Boolean.parseBoolean(optionValue);
} else if (optionName.equals("strength")) { } else if (optionName.equals("strength")) {
strength = Integer.parseInt(optionValue); strength = Integer.parseInt(optionValue);
} else if (optionName.equals("maxnps")) {
maxNPS = Integer.parseInt(optionValue);
} else { } else {
Parameters.instance().set(optionName, optionValue); Parameters.instance().set(optionName, optionValue);
} }

View File

@ -66,6 +66,7 @@ public class Search {
// Reduced strength variables // Reduced strength variables
private int strength = 1000; // Strength (0-1000) private int strength = 1000; // Strength (0-1000)
private int maxNPS = 0; // If > 0, reduce strength by limiting NPS
private boolean weak = false; // Set to strength < 1000 private boolean weak = false; // Set to strength < 1000
private long randomSeed = 0; private long randomSeed = 0;
@ -170,12 +171,16 @@ public class Search {
maxTimeMillis = maxTimeLimit; maxTimeMillis = maxTimeLimit;
} }
final public void setStrength(int strength, long randomSeed) { final public void setStrength(int strength, long randomSeed, int maxNPS) {
if (strength < 0) strength = 0; if (strength < 0) strength = 0;
if (strength > 1000) strength = 1000; if (strength > 1000) strength = 1000;
this.strength = strength; this.strength = strength;
weak = strength < 1000; weak = strength < 1000;
this.randomSeed = randomSeed; this.randomSeed = randomSeed;
this.maxNPS = maxNPS;
nodesBetweenTimeCheck = 5000;
if (maxNPS > 0)
nodesBetweenTimeCheck = Math.min(Math.max(maxNPS / 100, 1), nodesBetweenTimeCheck);
} }
final public Move iterativeDeepening(MoveGen.MoveList scMovesIn, final public Move iterativeDeepening(MoveGen.MoveList scMovesIn,
@ -264,6 +269,9 @@ public class Search {
mi, "-", alpha, beta, "-", "-"); mi, "-", alpha, beta, "-", "-");
System.out.printf("%-6s...\n", TextIO.moveToUCIString(m)); */ System.out.printf("%-6s...\n", TextIO.moveToUCIString(m)); */
pos.makeMove(m, ui); pos.makeMove(m, ui);
nodes++;
totalNodes++;
nodesToGo--;
SearchTreeInfo sti = searchTreeInfo[0]; SearchTreeInfo sti = searchTreeInfo[0];
sti.currentMove = m; sti.currentMove = m;
sti.lmr = lmrS; sti.lmr = lmrS;
@ -301,6 +309,9 @@ public class Search {
nodes = qNodes = 0; nodes = qNodes = 0;
posHashList[posHashListSize++] = pos.zobristHash(); posHashList[posHashListSize++] = pos.zobristHash();
pos.makeMove(m, ui); pos.makeMove(m, ui);
nodes++;
totalNodes++;
nodesToGo--;
int score2 = -negaScout(-beta, -score, 1, depthS - plyScale, -1, givesCheck); int score2 = -negaScout(-beta, -score, 1, depthS - plyScale, -1, givesCheck);
score = Math.max(score, score2); score = Math.max(score, score2);
nodesThisMove += nodes + qNodes; nodesThisMove += nodes + qNodes;
@ -320,6 +331,9 @@ public class Search {
nodes = qNodes = 0; nodes = qNodes = 0;
posHashList[posHashListSize++] = pos.zobristHash(); posHashList[posHashListSize++] = pos.zobristHash();
pos.makeMove(m, ui); pos.makeMove(m, ui);
nodes++;
totalNodes++;
nodesToGo--;
score = -negaScout(-score, -alpha, 1, depthS - plyScale, -1, givesCheck); score = -negaScout(-score, -alpha, 1, depthS - plyScale, -1, givesCheck);
nodesThisMove += nodes + qNodes; nodesThisMove += nodes + qNodes;
posHashListSize--; posHashListSize--;
@ -459,7 +473,7 @@ public class Search {
long idx = log.logNodeStart(sti.nodeIdx, sti.currentMove, alpha, beta, ply, depth/plyScale); long idx = log.logNodeStart(sti.nodeIdx, sti.currentMove, alpha, beta, ply, depth/plyScale);
searchTreeInfo[ply].nodeIdx = idx; searchTreeInfo[ply].nodeIdx = idx;
} }
if (--nodesToGo <= 0) { if (nodesToGo <= 0) {
nodesToGo = nodesBetweenTimeCheck; nodesToGo = nodesBetweenTimeCheck;
long tNow = System.currentTimeMillis(); long tNow = System.currentTimeMillis();
long timeLimit = searchNeedMoreTime ? maxTimeMillis : minTimeMillis; long timeLimit = searchNeedMoreTime ? maxTimeMillis : minTimeMillis;
@ -467,6 +481,15 @@ public class Search {
((maxNodes >= 0) && (totalNodes >= maxNodes))) { ((maxNodes >= 0) && (totalNodes >= maxNodes))) {
throw new StopSearch(); throw new StopSearch();
} }
if (maxNPS > 0) {
long time = tNow - tStart;
if (totalNodes * 1000.0 > maxNPS * Math.max(1, time)) {
long wantedTime = totalNodes * 1000 / maxNPS;
long sleepTime = wantedTime - time;
if (sleepTime > 0)
try { Thread.sleep(sleepTime); } catch (InterruptedException ignore) {}
}
}
if (tNow - tLastStats >= 1000) { if (tNow - tLastStats >= 1000) {
notifyStats(); notifyStats();
} }
@ -797,6 +820,7 @@ public class Search {
pos.makeMove(m, ui); pos.makeMove(m, ui);
nodes++; nodes++;
totalNodes++; totalNodes++;
nodesToGo--;
sti.currentMove = m; sti.currentMove = m;
/* long nodes0 = nodes; /* long nodes0 = nodes;
long qNodes0 = qNodes; long qNodes0 = qNodes;
@ -1021,6 +1045,7 @@ public class Search {
pos.makeMove(m, ui); pos.makeMove(m, ui);
qNodes++; qNodes++;
totalNodes++; totalNodes++;
nodesToGo--;
score = -quiesce(-beta, -alpha, ply + 1, depth - 1, nextInCheck); score = -quiesce(-beta, -alpha, ply + 1, depth - 1, nextInCheck);
pos.unMakeMove(m, ui); pos.unMakeMove(m, ui);
if (score > bestScore) { if (score > bestScore) {

View File

@ -70,6 +70,7 @@ public class DroidEngineControl {
// Reduced strength variables // Reduced strength variables
private int strength = 1000; private int strength = 1000;
private int maxNPS = 0;
private long randomSeed = 0; private long randomSeed = 0;
private Random rndGen = new Random(); private Random rndGen = new Random();
@ -224,8 +225,8 @@ public class DroidEngineControl {
sc = new Search(pos, posHashList, posHashListSize, tt, ht); sc = new Search(pos, posHashList, posHashListSize, tt, ht);
sc.timeLimit(minTimeLimit, maxTimeLimit); sc.timeLimit(minTimeLimit, maxTimeLimit);
sc.setListener(new SearchListener(os)); sc.setListener(new SearchListener(os));
sc.setStrength(strength, randomSeed); sc.setStrength(strength, randomSeed, maxNPS);
sc.nodesBetweenTimeCheck = 500; sc.nodesBetweenTimeCheck = Math.min(500, sc.nodesBetweenTimeCheck);
MoveGen.MoveList moves = moveGen.pseudoLegalMoves(pos); MoveGen.MoveList moves = moveGen.pseudoLegalMoves(pos);
MoveGen.removeIllegal(pos, moves); MoveGen.removeIllegal(pos, moves);
if ((searchMoves != null) && (searchMoves.size() > 0)) if ((searchMoves != null) && (searchMoves.size() > 0))
@ -367,9 +368,10 @@ public class DroidEngineControl {
os.printLine("option name OwnBook type check default false"); os.printLine("option name OwnBook type check default false");
os.printLine("option name Ponder type check default true"); os.printLine("option name Ponder type check default true");
os.printLine("option name UCI_AnalyseMode type check default false"); os.printLine("option name UCI_AnalyseMode type check default false");
os.printLine("option name UCI_EngineAbout type string default %s by Peter Osterlund, see http://web.comhem.se/petero2home/javachess/index.html", os.printLine("option name UCI_EngineAbout type string default %s by Peter Osterlund, see http://hem.bredband.net/petero2b/javachess/index.html",
ComputerPlayer.engineName); ComputerPlayer.engineName);
os.printLine("option name Strength type spin default 1000 min 0 max 1000"); os.printLine("option name Strength type spin default 1000 min 0 max 1000");
os.printLine("option name maxNPS type spin default 0 min 0 max 10000000");
} }
final void setOption(String optionName, String optionValue) { final void setOption(String optionName, String optionValue) {
@ -385,6 +387,8 @@ public class DroidEngineControl {
analyseMode = Boolean.parseBoolean(optionValue); analyseMode = Boolean.parseBoolean(optionValue);
} else if (optionName.equals("strength")) { } else if (optionName.equals("strength")) {
strength = Integer.parseInt(optionValue); strength = Integer.parseInt(optionValue);
} else if (optionName.equals("maxnps")) {
maxNPS = Integer.parseInt(optionValue);
} }
} catch (NumberFormatException ignore) { } catch (NumberFormatException ignore) {
} }