DroidFish: Added support in TimeControl class for multiple time controls and for different time controls for white and black.

This commit is contained in:
Peter Osterlund 2013-04-13 21:25:25 +00:00
parent 671994e004
commit ba7d8f61eb
6 changed files with 191 additions and 58 deletions

View File

@ -109,7 +109,8 @@ public class DroidComputerPlayer {
boolean isAnalyze; // True if analysis search
int wTime; // White remaining time, milliseconds
int bTime; // Black remaining time, milliseconds
int inc; // Time increment per move, milliseconds
int wInc; // White time increment per move, milliseconds
int bInc; // Black time increment per move, milliseconds
int movesToGo; // Number of moves to next time control
String engine; // Engine name (identifier)
@ -157,7 +158,7 @@ public class DroidComputerPlayer {
public static SearchRequest searchRequest(int id, long now,
Position prevPos, ArrayList<Move> mList,
Position currPos, boolean drawOffer,
int wTime, int bTime, int inc, int movesToGo,
int wTime, int bTime, int wInc, int bInc, int movesToGo,
boolean ponderEnabled, Move ponderMove,
String engine, int engineThreads,
int strength) {
@ -172,7 +173,8 @@ public class DroidComputerPlayer {
sr.isAnalyze = false;
sr.wTime = wTime;
sr.bTime = bTime;
sr.inc = inc;
sr.wInc = wInc;
sr.bInc = bInc;
sr.movesToGo = movesToGo;
sr.engine = engine;
sr.engineThreads = engineThreads;
@ -212,7 +214,7 @@ public class DroidComputerPlayer {
sr.drawOffer = drawOffer;
sr.isSearch = false;
sr.isAnalyze = true;
sr.wTime = sr.bTime = sr.inc = sr.movesToGo = 0;
sr.wTime = sr.bTime = sr.wInc = sr.bInc = sr.movesToGo = 0;
sr.engine = engine;
sr.engineThreads = engineThreads;
sr.strength = 1000;
@ -554,8 +556,10 @@ public class DroidComputerPlayer {
if (sr.bTime < 1) sr.bTime = 1;
StringBuilder goStr = new StringBuilder(96);
goStr.append(String.format("go wtime %d btime %d", sr.wTime, sr.bTime));
if (sr.inc > 0)
goStr.append(String.format(" winc %d binc %d", sr.inc, sr.inc));
if (sr.wInc > 0)
goStr.append(String.format(" winc %d", sr.wInc));
if (sr.bInc > 0)
goStr.append(String.format(" binc %d", sr.bInc));
if (sr.movesToGo > 0)
goStr.append(String.format(" movestogo %d", sr.movesToGo));
if (sr.ponderMove != null)

View File

@ -873,18 +873,15 @@ public class DroidChessController {
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();
}
int wInc = game.timeController.getIncrement(true);
int bInc = game.timeController.getIncrement(false);
boolean wtm = currPos.whiteMove;
int movesToGo = game.timeController.getMovesToTC(wtm);
final Move fPonderMove = ponder ? ponderMove : null;
SearchRequest sr = DroidComputerPlayer.SearchRequest.searchRequest(
searchId, now, ph.first, ph.second, currPos,
game.haveDrawOffer(),
wTime, bTime, inc, movesToGo,
wTime, bTime, wInc, bInc, movesToGo,
gui.ponderMode(), fPonderMove,
engine, gui.engineThreads(),
strength);

View File

@ -201,9 +201,8 @@ public class Game {
int move = currPos.fullMoveCounter;
boolean wtm = currPos.whiteMove;
if (discardElapsed || (move != timeController.currentMove) || (wtm != timeController.whiteToMove)) {
int initialTime = timeController.getInitialTime();
int whiteBaseTime = tree.getRemainingTime(true, initialTime);
int blackBaseTime = tree.getRemainingTime(false, initialTime);
int whiteBaseTime = tree.getRemainingTime(true, timeController.getInitialTime(true));
int blackBaseTime = tree.getRemainingTime(false, timeController.getInitialTime(false));
timeController.setCurrentMove(move, wtm, whiteBaseTime, blackBaseTime);
}
long now = System.currentTimeMillis();

View File

@ -826,7 +826,7 @@ public class GameTree {
}
final int getRemainingTime(boolean whiteMove, int initialTime) {
int undef = Integer.MIN_VALUE;
final int undef = Integer.MIN_VALUE;
int remainingTime = undef;
Node node = currentNode;
boolean wtm = currentPos.whiteMove;

View File

@ -18,19 +18,33 @@
package org.petero.droidfish.gamelogic;
public class TimeControl {
private long timeControl;
private int movesPerSession;
private long increment;
import java.util.ArrayList;
private long whiteBaseTime;
private long blackBaseTime;
/** Keep track of time control information for both players. */
public class TimeControl {
public static final class TimeControlField {
long timeControl;
int movesPerSession;
long increment;
public TimeControlField(long time, int moves, long inc) {
timeControl = time;
movesPerSession = moves;
increment = inc;
}
}
private ArrayList<TimeControlField> tcW;
private ArrayList<TimeControlField> tcB;
private long whiteBaseTime; // Current remaining time, or remaining time when clock started
private long blackBaseTime; // Current remaining time, or remaining time when clock started
int currentMove;
boolean whiteToMove;
long elapsed; // Accumulated elapsed time for this move.
long timerT0; // Time when timer started. 0 if timer is stopped.
private long elapsed; // Accumulated elapsed time for this move.
private long timerT0; // Time when timer started. 0 if timer is stopped.
/** Constructor. Sets time control to "game in 5min". */
@ -48,9 +62,17 @@ public class TimeControl {
/** Set time control to "moves" moves in "time" milliseconds, + inc milliseconds per move. */
public final void setTimeControl(long time, int moves, long inc) {
timeControl = time;
movesPerSession = moves;
increment = inc;
tcW = new ArrayList<TimeControlField>();
tcW.add(new TimeControlField(time, moves, inc));
tcB = new ArrayList<TimeControlField>();
tcB.add(new TimeControlField(time, moves, inc));
}
/** Set time controls for white and black players. */
public final void setTimeControl(ArrayList<TimeControlField> whiteTC,
ArrayList<TimeControlField> blackTC) {
tcW = whiteTC;
tcB = blackTC;
}
public final void setCurrentMove(int move, boolean whiteToMove, long whiteBaseTime, long blackBaseTime) {
@ -86,11 +108,20 @@ public class TimeControl {
/** Compute new remaining time after a move is made. */
public final int moveMade(long now, boolean useIncrement) {
stopTimer(now);
ArrayList<TimeControlField> tc = whiteToMove ? tcW : tcB;
Pair<Integer,Integer> tcInfo = getCurrentTC(whiteToMove);
int tcIdx = tcInfo.first;
int movesToTc = tcInfo.second;
long remaining = getRemainingTime(whiteToMove, now);
if (useIncrement) {
remaining += increment;
if (getMovesToTC() == 1)
remaining += timeControl;
remaining += tc.get(tcIdx).increment;
if (movesToTc == 1) {
if (tcIdx+1 < tc.size())
tcIdx++;
remaining += tc.get(tcIdx).timeControl;
}
}
elapsed = 0;
return (int)remaining;
@ -108,24 +139,42 @@ public class TimeControl {
return (int)remaining;
}
public final int getInitialTime() {
return (int)timeControl;
/** Get initial thinking time in milliseconds. */
public final int getInitialTime(boolean whiteMove) {
ArrayList<TimeControlField> tc = whiteMove ? tcW : tcB;
return (int)tc.get(0).timeControl;
}
public final int getIncrement() {
return (int)increment;
/** Get time increment in milliseconds after playing next move. */
public final int getIncrement(boolean whiteMove) {
ArrayList<TimeControlField> tc = whiteMove ? tcW : tcB;
int tcIdx = getCurrentTC(whiteMove).first;
return (int)tc.get(tcIdx).increment;
}
public final int getMovesToTC() {
if (movesPerSession <= 0)
return 0;
/** Return number of moves to the next time control, or 0 if "sudden death". */
public final int getMovesToTC(boolean whiteMove) {
return getCurrentTC(whiteMove).second;
}
/** Return the current active time control index and number of moves to next time control. */
private Pair<Integer,Integer> getCurrentTC(boolean whiteMove) {
ArrayList<TimeControlField> tc = whiteMove ? tcW : tcB;
int tcIdx = 0;
final int lastTcIdx = tc.size() - 1;
int nextTC = 1;
while (nextTC <= currentMove)
nextTC += movesPerSession;
return nextTC - currentMove;
}
public final int getMovesPerSession() {
return movesPerSession;
int currMove = currentMove;
if (!whiteToMove && whiteMove)
currMove++;
while (true) {
if (tc.get(tcIdx).movesPerSession <= 0)
return new Pair<Integer,Integer>(tcIdx, 0);
nextTC += tc.get(tcIdx).movesPerSession;
if (nextTC > currMove)
break;
if (tcIdx < lastTcIdx)
tcIdx++;
}
return new Pair<Integer,Integer>(tcIdx, nextTC - currMove);
}
}

View File

@ -18,6 +18,8 @@
package org.petero.droidfish.gamelogic;
import java.util.ArrayList;
import junit.framework.TestCase;
@ -31,20 +33,24 @@ public class TimeControlTest extends TestCase {
long t0 = 1000;
tc.setTimeControl(totTime, 0, 0);
tc.setCurrentMove(1, true, totTime, totTime);
assertEquals(0, tc.getMovesToTC());
assertEquals(0, tc.getIncrement());
assertEquals(0, tc.getMovesToTC(true));
assertEquals(0, tc.getMovesToTC(false));
assertEquals(0, tc.getIncrement(true));
assertEquals(0, tc.getIncrement(false));
assertEquals(totTime, tc.getRemainingTime(true, 0));
tc.startTimer(t0);
int remain = tc.moveMade(t0 + 1000, true);
assertEquals(totTime - 1000, remain);
tc.setCurrentMove(2, true, totTime - 1000, totTime);
assertEquals(0, tc.getMovesToTC());
assertEquals(0, tc.getMovesToTC(true));
assertEquals(0, tc.getMovesToTC(false));
assertEquals(totTime - 1000, tc.getRemainingTime(true, t0 + 4711));
assertEquals(totTime, tc.getRemainingTime(false, t0 + 4711));
tc.setCurrentMove(1, false, totTime - 1000, totTime);
assertEquals(0, tc.getMovesToTC());
assertEquals(0, tc.getMovesToTC(true));
assertEquals(0, tc.getMovesToTC(false));
assertEquals(totTime - 1000, tc.getRemainingTime(true, t0 + 4711));
assertEquals(totTime, tc.getRemainingTime(false, t0 + 4711));
@ -66,24 +72,102 @@ public class TimeControlTest extends TestCase {
TimeControl tc = new TimeControl();
tc.setTimeControl(2 * 60 * 1000, 40, 0);
tc.setCurrentMove(1, true, 0, 0);
assertEquals(40, tc.getMovesToTC());
assertEquals(40, tc.getMovesToTC(true));
assertEquals(40, tc.getMovesToTC(false));
tc.setCurrentMove(1, false, 0, 0);
assertEquals(40, tc.getMovesToTC());
assertEquals(39, tc.getMovesToTC(true));
assertEquals(40, tc.getMovesToTC(false));
tc.setCurrentMove(2, true, 0, 0);
assertEquals(39, tc.getMovesToTC());
assertEquals(39, tc.getMovesToTC(true));
assertEquals(39, tc.getMovesToTC(false));
tc.setCurrentMove(40, true, 0, 0);
assertEquals(1, tc.getMovesToTC());
assertEquals(1, tc.getMovesToTC(true));
assertEquals(1, tc.getMovesToTC(false));
tc.setCurrentMove(40, false, 0, 0);
assertEquals(40, tc.getMovesToTC(true));
assertEquals(1, tc.getMovesToTC(false));
tc.setCurrentMove(41, true, 0, 0);
assertEquals(40, tc.getMovesToTC());
assertEquals(40, tc.getMovesToTC(true));
assertEquals(40, tc.getMovesToTC(false));
tc.setCurrentMove(80, true, 0, 0);
assertEquals(1, tc.getMovesToTC());
assertEquals(1, tc.getMovesToTC(true));
assertEquals(1, tc.getMovesToTC(false));
tc.setCurrentMove(80, false, 0, 0);
assertEquals(40, tc.getMovesToTC(true));
assertEquals(1, tc.getMovesToTC(false));
tc.setCurrentMove(81, true, 0, 0);
assertEquals(40, tc.getMovesToTC());
assertEquals(40, tc.getMovesToTC(true));
assertEquals(40, tc.getMovesToTC(false));
}
private TimeControl.TimeControlField tcf(long time, int moves, long inc) {
return new TimeControl.TimeControlField(time, moves, inc);
}
/** Test multiple time controls. */
public void testMultiTimeControl() {
TimeControl tc = new TimeControl();
ArrayList<TimeControl.TimeControlField> tcW = new ArrayList<TimeControl.TimeControlField>();
tcW.add(tcf(120*60*1000, 40, 0));
tcW.add(tcf(60*60*1000, 20, 0));
tcW.add(tcf(30*60*1000, 0, 15*1000));
ArrayList<TimeControl.TimeControlField> tcB = new ArrayList<TimeControl.TimeControlField>();
tcB.add(tcf(5*60*1000, 60, 1000));
tc.setTimeControl(tcW, tcB);
assertEquals(40, tc.getMovesToTC(true));
assertEquals(60, tc.getMovesToTC(false));
assertEquals(0, tc.getIncrement(true));
assertEquals(1000, tc.getIncrement(false));
tc.setCurrentMove(40, true, 0, 0);
assertEquals(1, tc.getMovesToTC(true));
assertEquals(21, tc.getMovesToTC(false));
assertEquals(0, tc.getIncrement(true));
assertEquals(1000, tc.getIncrement(false));
tc.setCurrentMove(40, false, 0, 0);
assertEquals(20, tc.getMovesToTC(true));
assertEquals(21, tc.getMovesToTC(false));
assertEquals(0, tc.getIncrement(true));
assertEquals(1000, tc.getIncrement(false));
tc.setCurrentMove(60, true, 0, 0);
assertEquals(1, tc.getMovesToTC(true));
assertEquals(1, tc.getMovesToTC(false));
assertEquals(0, tc.getIncrement(true));
assertEquals(1000, tc.getIncrement(false));
tc.setCurrentMove(61, true, 0, 0);
assertEquals(0, tc.getMovesToTC(true));
assertEquals(60, tc.getMovesToTC(false));
assertEquals(15000, tc.getIncrement(true));
assertEquals(1000, tc.getIncrement(false));
long wBaseTime = 60*1000;
long bBaseTime = 50*1000;
tc.setCurrentMove(30, true, wBaseTime, bBaseTime);
tc.startTimer(1500);
wBaseTime = tc.moveMade(1500 + 3000, true);
assertEquals(60*1000-3000, wBaseTime);
tc.setCurrentMove(30, false, wBaseTime, bBaseTime);
assertEquals(60*1000-3000, tc.getRemainingTime(true, 1500 + 3000));
assertEquals(50*1000, tc.getRemainingTime(false, 1500 + 3000));
tc.startTimer(5000);
bBaseTime = tc.moveMade(9000, true);
assertEquals(50000 - 4000 + 1000, bBaseTime);
tc.setCurrentMove(31, true, wBaseTime, bBaseTime);
assertEquals(60*1000-3000, tc.getRemainingTime(true, 9000));
assertEquals(50000 - 4000 + 1000, tc.getRemainingTime(false, 9000));
}
public void testExtraTime() {
@ -116,7 +200,7 @@ public class TimeControlTest extends TestCase {
assertEquals(timeCont - 1000 + timeCont + inc - 3000 + inc, tc.getRemainingTime(true, t0 + 4711));
assertEquals(timeCont - 4000 + timeCont + inc, tc.getRemainingTime(false, t0 + 4711));
// No increment when move made int paused mode, ie analysis mode
// No increment when move made in paused mode, ie analysis mode
tc.startTimer(t0 + 9000);
bBaseTime = tc.moveMade(t0 + 10000, false);
tc.setCurrentMove(7, true, wBaseTime, bBaseTime);