DroidFish: Added support for multiple time controls in the DroidChessController class.

This commit is contained in:
Peter Osterlund 2013-04-14 08:56:17 +00:00
parent 8ef8fbe3cd
commit da625e085d
6 changed files with 94 additions and 69 deletions

View File

@ -34,6 +34,7 @@ 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.GameTree.Node;
import org.petero.droidfish.gamelogic.TimeControlData.TimeControlField;
/**
* The glue between the chess engine and the GUI.
@ -54,9 +55,7 @@ public class DroidChessController {
private int strength = 1000;
private int numPV = 1;
private int timeControl;
private int movesPerSession;
private int timeIncrement;
private TimeControlData tcData;
private SearchListener listener;
private boolean guiPaused = false;
@ -72,6 +71,7 @@ public class DroidChessController {
this.gameTextListener = gameTextListener;
gameMode = new GameMode(GameMode.TWO_PLAYERS);
pgnOptions = options;
tcData = new TimeControlData();
listener = new SearchListener();
searchId = 0;
}
@ -89,7 +89,7 @@ public class DroidChessController {
}
computerPlayer.queueStartEngine(searchId, engine);
searchId++;
game = new Game(gameTextListener, timeControl, movesPerSession, timeIncrement);
game = new Game(gameTextListener, tcData);
computerPlayer.clearTT();
setPlayerNames(game);
updateGameMode();
@ -105,11 +105,9 @@ public class DroidChessController {
/** Set time control parameters. */
public final synchronized void setTimeLimit(int time, int moves, int inc) {
timeControl = time;
movesPerSession = moves;
timeIncrement = inc;
tcData.setTimeControl(time, moves, inc);
if (game != null)
game.timeController.setTimeControl(timeControl, movesPerSession, timeIncrement);
game.timeController.setTimeControl(tcData);
}
/** @return Array containing time control, moves per session and time increment. */
@ -117,9 +115,10 @@ public class DroidChessController {
if (game != null)
return game.timeController.getTimeLimit(game.currPos().whiteMove);
int[] ret = new int[3];
ret[0] = timeControl;
ret[1] = movesPerSession;
ret[2] = timeIncrement;
TimeControlField tc = tcData.getTC(true).get(0);
ret[0] = (int)tc.timeControl;
ret[1] = tc.movesPerSession;
ret[2] = (int)tc.increment;
return ret;
}
@ -237,7 +236,7 @@ public class DroidChessController {
/** Parse a string as FEN or PGN data. */
public final synchronized void setFENOrPGN(String fenPgn) throws ChessParseError {
Game newGame = new Game(gameTextListener, timeControl, movesPerSession, timeIncrement);
Game newGame = new Game(gameTextListener, tcData);
try {
Position pos = TextIO.readFEN(fenPgn);
newGame.setPos(pos);

View File

@ -38,12 +38,11 @@ public class Game {
PgnToken.PgnTokenReceiver gameTextListener;
public Game(PgnToken.PgnTokenReceiver gameTextListener,
int timeControl, int movesPerSession, int timeIncrement) {
public Game(PgnToken.PgnTokenReceiver gameTextListener, TimeControlData tcData) {
this.gameTextListener = gameTextListener;
tree = new GameTree(gameTextListener);
timeController = new TimeControl();
timeController.setTimeControl(timeControl, movesPerSession, timeIncrement);
timeController.setTimeControl(tcData);
gamePaused = false;
newGame();
}

View File

@ -20,22 +20,11 @@ package org.petero.droidfish.gamelogic;
import java.util.ArrayList;
import org.petero.droidfish.gamelogic.TimeControlData.TimeControlField;
/** 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 TimeControlData tcData;
private long whiteBaseTime; // Current remaining time, or remaining time when clock started
private long blackBaseTime; // Current remaining time, or remaining time when clock started
@ -49,7 +38,7 @@ public class TimeControl {
/** Constructor. Sets time control to "game in 5min". */
public TimeControl() {
setTimeControl(5 * 60 * 1000, 0, 0);
tcData = new TimeControlData();
reset();
}
@ -60,19 +49,9 @@ public class TimeControl {
timerT0 = 0;
}
/** Set time control to "moves" moves in "time" milliseconds, + inc milliseconds per move. */
public final void setTimeControl(long time, int moves, long 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 setTimeControl(TimeControlData tcData) {
this.tcData = tcData;
}
public final void setCurrentMove(int move, boolean whiteToMove, long whiteBaseTime, long blackBaseTime) {
@ -109,7 +88,7 @@ public class TimeControl {
public final int moveMade(long now, boolean useIncrement) {
stopTimer(now);
ArrayList<TimeControlField> tc = whiteToMove ? tcW : tcB;
ArrayList<TimeControlField> tc = tcData.getTC(whiteToMove);
Pair<Integer,Integer> tcInfo = getCurrentTC(whiteToMove);
int tcIdx = tcInfo.first;
int movesToTc = tcInfo.second;
@ -141,13 +120,13 @@ public class TimeControl {
/** Get initial thinking time in milliseconds. */
public final int getInitialTime(boolean whiteMove) {
ArrayList<TimeControlField> tc = whiteMove ? tcW : tcB;
ArrayList<TimeControlField> tc = tcData.getTC(whiteMove);
return (int)tc.get(0).timeControl;
}
/** Get time increment in milliseconds after playing next move. */
public final int getIncrement(boolean whiteMove) {
ArrayList<TimeControlField> tc = whiteMove ? tcW : tcB;
ArrayList<TimeControlField> tc = tcData.getTC(whiteMove);
int tcIdx = getCurrentTC(whiteMove).first;
return (int)tc.get(tcIdx).increment;
}
@ -159,7 +138,7 @@ public class TimeControl {
/** @return Array containing time control, moves per session and time increment. */
public int[] getTimeLimit(boolean whiteMove) {
ArrayList<TimeControlField> tc = whiteMove ? tcW : tcB;
ArrayList<TimeControlField> tc = tcData.getTC(whiteMove);
int tcIdx = getCurrentTC(whiteMove).first;
TimeControlField t = tc.get(tcIdx);
return new int[]{(int)t.timeControl, t.movesPerSession, (int)t.increment};
@ -167,7 +146,7 @@ public class TimeControl {
/** 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;
ArrayList<TimeControlField> tc = tcData.getTC(whiteMove);
int tcIdx = 0;
final int lastTcIdx = tc.size() - 1;
int nextTC = 1;

View File

@ -0,0 +1,38 @@
package org.petero.droidfish.gamelogic;
import java.util.ArrayList;
public final class TimeControlData {
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;
}
}
ArrayList<TimeControlField> tcW, tcB;
TimeControlData() {
tcW = new ArrayList<TimeControlField>();
tcW.add(new TimeControlField(5*60*1000, 60, 0));
tcB = new ArrayList<TimeControlField>();
tcB.add(new TimeControlField(5*60*1000, 60, 0));
}
public final void setTimeControl(long time, int moves, long inc) {
tcW = new ArrayList<TimeControlField>();
tcW.add(new TimeControlField(time, moves, inc));
tcB = new ArrayList<TimeControlField>();
tcB.add(new TimeControlField(time, moves, inc));
}
/** Get time control data array for white or black player. */
public ArrayList<TimeControlField> getTC(boolean whiteMove) {
return whiteMove ? tcW : tcB;
}
}

View File

@ -36,7 +36,7 @@ public class GameTest extends TestCase {
* Test of haveDrawOffer method, of class Game.
*/
public void testHaveDrawOffer() {
Game game = new Game(null, 0, 0, 0);
Game game = new Game(null, new TimeControlData());
assertEquals(false, game.haveDrawOffer());
boolean res = game.processString("e4");
@ -124,7 +124,7 @@ public class GameTest extends TestCase {
* Test of draw by 50 move rule, of class Game.
*/
public void testDraw50() throws ChessParseError {
Game game = new Game(null, 0, 0, 0);
Game game = new Game(null, new TimeControlData());
assertEquals(false, game.haveDrawOffer());
boolean res = game.processString("draw 50");
assertEquals(true, res);
@ -179,7 +179,7 @@ public class GameTest extends TestCase {
* Test of draw by repetition, of class Game.
*/
public void testDrawRep() throws ChessParseError {
Game game = new Game(null, 0, 0, 0);
Game game = new Game(null, new TimeControlData());
assertEquals(false, game.haveDrawOffer());
game.processString("Nc3");
game.processString("Nc6");
@ -251,7 +251,7 @@ public class GameTest extends TestCase {
* Test of draw offer/accept/request command.
*/
public void testDrawBug() throws ChessParseError {
Game game = new Game(null, 0, 0, 0);
Game game = new Game(null, new TimeControlData());
assertEquals(false, game.haveDrawOffer());
game.processString("e4");
game.processString("c5");
@ -269,7 +269,7 @@ public class GameTest extends TestCase {
* Test of resign command, of class Game.
*/
public void testResign() throws ChessParseError {
Game game = new Game(null, 0, 0, 0);
Game game = new Game(null, new TimeControlData());
assertEquals(Game.GameState.ALIVE, game.getGameState());
game.processString("f3");
assertEquals(Game.GameState.ALIVE, game.getGameState());
@ -299,7 +299,7 @@ public class GameTest extends TestCase {
* Test of processString method, of class Game.
*/
public void testProcessString() throws ChessParseError {
Game game = new Game(null, 0, 0, 0);
Game game = new Game(null, new TimeControlData());
assertEquals(TextIO.startPosFEN, TextIO.toFEN(game.currPos()));
boolean res = game.processString("Nf3");
assertEquals(true, res);
@ -348,7 +348,7 @@ public class GameTest extends TestCase {
* Test of getGameState method, of class Game.
*/
public void testGetGameState() throws ChessParseError {
Game game = new Game(null, 0, 0, 0);
Game game = new Game(null, new TimeControlData());
assertEquals(Game.GameState.ALIVE, game.getGameState());
game.processString("f3");
game.processString("e5");
@ -364,7 +364,7 @@ public class GameTest extends TestCase {
* Test of insufficientMaterial method, of class Game.
*/
public void testInsufficientMaterial() throws ChessParseError {
Game game = new Game(null, 0, 0, 0);
Game game = new Game(null, new TimeControlData());
assertEquals(Game.GameState.ALIVE, game.getGameState());
game.setPos(TextIO.readFEN("4k3/8/8/8/8/8/8/4K3 w - - 0 1"));
assertEquals(Game.GameState.DRAW_NO_MATE, game.getGameState());
@ -407,7 +407,7 @@ public class GameTest extends TestCase {
/** Test that UCI history is not longer than necessary.
* We can't expect engines to handle null moves, for example. */
public void testUCIHistory() throws ChessParseError {
Game game = new Game(null, 0, 0, 0);
Game game = new Game(null, new TimeControlData());
Pair<Position, ArrayList<Move>> hist = game.getUCIHistory();
assertEquals(0, hist.second.size());

View File

@ -20,6 +20,8 @@ package org.petero.droidfish.gamelogic;
import java.util.ArrayList;
import org.petero.droidfish.gamelogic.TimeControlData.TimeControlField;
import junit.framework.TestCase;
@ -31,7 +33,9 @@ public class TimeControlTest extends TestCase {
TimeControl tc = new TimeControl();
long totTime = 5 * 60 * 1000;
long t0 = 1000;
tc.setTimeControl(totTime, 0, 0);
TimeControlData tcData = new TimeControlData();
tcData.setTimeControl(totTime, 0, 0);
tc.setTimeControl(tcData);
tc.setCurrentMove(1, true, totTime, totTime);
assertEquals(0, tc.getMovesToTC(true));
assertEquals(0, tc.getMovesToTC(false));
@ -70,7 +74,9 @@ public class TimeControlTest extends TestCase {
/** Test getMovesToTC */
public void testTimeControl() {
TimeControl tc = new TimeControl();
tc.setTimeControl(2 * 60 * 1000, 40, 0);
TimeControlData tcData = new TimeControlData();
tcData.setTimeControl(2 * 60 * 1000, 40, 0);
tc.setTimeControl(tcData);
tc.setCurrentMove(1, true, 0, 0);
assertEquals(40, tc.getMovesToTC(true));
assertEquals(40, tc.getMovesToTC(false));
@ -107,20 +113,21 @@ public class TimeControlTest extends TestCase {
assertEquals(40, tc.getMovesToTC(false));
}
private TimeControl.TimeControlField tcf(long time, int moves, long inc) {
return new TimeControl.TimeControlField(time, moves, inc);
private TimeControlField tcf(long time, int moves, long inc) {
return new 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);
TimeControlData tcData = new TimeControlData();
tcData.tcW = new ArrayList<TimeControlField>();
tcData.tcW.add(tcf(120*60*1000, 40, 0));
tcData.tcW.add(tcf(60*60*1000, 20, 0));
tcData.tcW.add(tcf(30*60*1000, 0, 15*1000));
tcData.tcB = new ArrayList<TimeControlField>();
tcData.tcB.add(tcf(5*60*1000, 60, 1000));
tc.setTimeControl(tcData);
assertEquals(40, tc.getMovesToTC(true));
assertEquals(60, tc.getMovesToTC(false));
@ -176,7 +183,9 @@ public class TimeControlTest extends TestCase {
int wBaseTime = (int)timeCont;
int bBaseTime = (int)timeCont;
final long inc = 700;
tc.setTimeControl(timeCont, 5, inc);
TimeControlData tcData = new TimeControlData();
tcData.setTimeControl(timeCont, 5, inc);
tc.setTimeControl(tcData);
tc.setCurrentMove(5, true, wBaseTime, bBaseTime);
long t0 = 1342134;
assertEquals(timeCont, tc.getRemainingTime(true, t0 + 4711));
@ -208,7 +217,8 @@ public class TimeControlTest extends TestCase {
assertEquals(timeCont - 4000 + timeCont + inc - 1000, tc.getRemainingTime(false, t0 + 4711));
// No extra time when passing time control in analysis mode
tc.setTimeControl(timeCont, 1, inc);
tcData.setTimeControl(timeCont, 1, inc);
tc.setTimeControl(tcData);
wBaseTime = bBaseTime = (int)timeCont;
tc.setCurrentMove(1, true, wBaseTime, bBaseTime);
tc.startTimer(t0 + 1000);