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

View File

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

View File

@ -20,22 +20,11 @@ package org.petero.droidfish.gamelogic;
import java.util.ArrayList; import java.util.ArrayList;
import org.petero.droidfish.gamelogic.TimeControlData.TimeControlField;
/** Keep track of time control information for both players. */ /** Keep track of time control information for both players. */
public class TimeControl { public class TimeControl {
public static final class TimeControlField { private TimeControlData tcData;
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 whiteBaseTime; // Current remaining time, or remaining time when clock started
private long blackBaseTime; // 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". */ /** Constructor. Sets time control to "game in 5min". */
public TimeControl() { public TimeControl() {
setTimeControl(5 * 60 * 1000, 0, 0); tcData = new TimeControlData();
reset(); reset();
} }
@ -60,19 +49,9 @@ public class TimeControl {
timerT0 = 0; 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. */ /** Set time controls for white and black players. */
public final void setTimeControl(ArrayList<TimeControlField> whiteTC, public final void setTimeControl(TimeControlData tcData) {
ArrayList<TimeControlField> blackTC) { this.tcData = tcData;
tcW = whiteTC;
tcB = blackTC;
} }
public final void setCurrentMove(int move, boolean whiteToMove, long whiteBaseTime, long blackBaseTime) { 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) { public final int moveMade(long now, boolean useIncrement) {
stopTimer(now); stopTimer(now);
ArrayList<TimeControlField> tc = whiteToMove ? tcW : tcB; ArrayList<TimeControlField> tc = tcData.getTC(whiteToMove);
Pair<Integer,Integer> tcInfo = getCurrentTC(whiteToMove); Pair<Integer,Integer> tcInfo = getCurrentTC(whiteToMove);
int tcIdx = tcInfo.first; int tcIdx = tcInfo.first;
int movesToTc = tcInfo.second; int movesToTc = tcInfo.second;
@ -141,13 +120,13 @@ public class TimeControl {
/** Get initial thinking time in milliseconds. */ /** Get initial thinking time in milliseconds. */
public final int getInitialTime(boolean whiteMove) { public final int getInitialTime(boolean whiteMove) {
ArrayList<TimeControlField> tc = whiteMove ? tcW : tcB; ArrayList<TimeControlField> tc = tcData.getTC(whiteMove);
return (int)tc.get(0).timeControl; return (int)tc.get(0).timeControl;
} }
/** Get time increment in milliseconds after playing next move. */ /** Get time increment in milliseconds after playing next move. */
public final int getIncrement(boolean whiteMove) { public final int getIncrement(boolean whiteMove) {
ArrayList<TimeControlField> tc = whiteMove ? tcW : tcB; ArrayList<TimeControlField> tc = tcData.getTC(whiteMove);
int tcIdx = getCurrentTC(whiteMove).first; int tcIdx = getCurrentTC(whiteMove).first;
return (int)tc.get(tcIdx).increment; return (int)tc.get(tcIdx).increment;
} }
@ -159,7 +138,7 @@ public class TimeControl {
/** @return Array containing time control, moves per session and time increment. */ /** @return Array containing time control, moves per session and time increment. */
public int[] getTimeLimit(boolean whiteMove) { public int[] getTimeLimit(boolean whiteMove) {
ArrayList<TimeControlField> tc = whiteMove ? tcW : tcB; ArrayList<TimeControlField> tc = tcData.getTC(whiteMove);
int tcIdx = getCurrentTC(whiteMove).first; int tcIdx = getCurrentTC(whiteMove).first;
TimeControlField t = tc.get(tcIdx); TimeControlField t = tc.get(tcIdx);
return new int[]{(int)t.timeControl, t.movesPerSession, (int)t.increment}; 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. */ /** Return the current active time control index and number of moves to next time control. */
private Pair<Integer,Integer> getCurrentTC(boolean whiteMove) { private Pair<Integer,Integer> getCurrentTC(boolean whiteMove) {
ArrayList<TimeControlField> tc = whiteMove ? tcW : tcB; ArrayList<TimeControlField> tc = tcData.getTC(whiteMove);
int tcIdx = 0; int tcIdx = 0;
final int lastTcIdx = tc.size() - 1; final int lastTcIdx = tc.size() - 1;
int nextTC = 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. * Test of haveDrawOffer method, of class Game.
*/ */
public void testHaveDrawOffer() { public void testHaveDrawOffer() {
Game game = new Game(null, 0, 0, 0); Game game = new Game(null, new TimeControlData());
assertEquals(false, game.haveDrawOffer()); assertEquals(false, game.haveDrawOffer());
boolean res = game.processString("e4"); boolean res = game.processString("e4");
@ -124,7 +124,7 @@ public class GameTest extends TestCase {
* Test of draw by 50 move rule, of class Game. * Test of draw by 50 move rule, of class Game.
*/ */
public void testDraw50() throws ChessParseError { public void testDraw50() throws ChessParseError {
Game game = new Game(null, 0, 0, 0); Game game = new Game(null, new TimeControlData());
assertEquals(false, game.haveDrawOffer()); assertEquals(false, game.haveDrawOffer());
boolean res = game.processString("draw 50"); boolean res = game.processString("draw 50");
assertEquals(true, res); assertEquals(true, res);
@ -179,7 +179,7 @@ public class GameTest extends TestCase {
* Test of draw by repetition, of class Game. * Test of draw by repetition, of class Game.
*/ */
public void testDrawRep() throws ChessParseError { public void testDrawRep() throws ChessParseError {
Game game = new Game(null, 0, 0, 0); Game game = new Game(null, new TimeControlData());
assertEquals(false, game.haveDrawOffer()); assertEquals(false, game.haveDrawOffer());
game.processString("Nc3"); game.processString("Nc3");
game.processString("Nc6"); game.processString("Nc6");
@ -251,7 +251,7 @@ public class GameTest extends TestCase {
* Test of draw offer/accept/request command. * Test of draw offer/accept/request command.
*/ */
public void testDrawBug() throws ChessParseError { public void testDrawBug() throws ChessParseError {
Game game = new Game(null, 0, 0, 0); Game game = new Game(null, new TimeControlData());
assertEquals(false, game.haveDrawOffer()); assertEquals(false, game.haveDrawOffer());
game.processString("e4"); game.processString("e4");
game.processString("c5"); game.processString("c5");
@ -269,7 +269,7 @@ public class GameTest extends TestCase {
* Test of resign command, of class Game. * Test of resign command, of class Game.
*/ */
public void testResign() throws ChessParseError { 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()); assertEquals(Game.GameState.ALIVE, game.getGameState());
game.processString("f3"); game.processString("f3");
assertEquals(Game.GameState.ALIVE, game.getGameState()); assertEquals(Game.GameState.ALIVE, game.getGameState());
@ -299,7 +299,7 @@ public class GameTest extends TestCase {
* Test of processString method, of class Game. * Test of processString method, of class Game.
*/ */
public void testProcessString() throws ChessParseError { 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())); assertEquals(TextIO.startPosFEN, TextIO.toFEN(game.currPos()));
boolean res = game.processString("Nf3"); boolean res = game.processString("Nf3");
assertEquals(true, res); assertEquals(true, res);
@ -348,7 +348,7 @@ public class GameTest extends TestCase {
* Test of getGameState method, of class Game. * Test of getGameState method, of class Game.
*/ */
public void testGetGameState() throws ChessParseError { 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()); assertEquals(Game.GameState.ALIVE, game.getGameState());
game.processString("f3"); game.processString("f3");
game.processString("e5"); game.processString("e5");
@ -364,7 +364,7 @@ public class GameTest extends TestCase {
* Test of insufficientMaterial method, of class Game. * Test of insufficientMaterial method, of class Game.
*/ */
public void testInsufficientMaterial() throws ChessParseError { 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()); assertEquals(Game.GameState.ALIVE, game.getGameState());
game.setPos(TextIO.readFEN("4k3/8/8/8/8/8/8/4K3 w - - 0 1")); game.setPos(TextIO.readFEN("4k3/8/8/8/8/8/8/4K3 w - - 0 1"));
assertEquals(Game.GameState.DRAW_NO_MATE, game.getGameState()); 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. /** Test that UCI history is not longer than necessary.
* We can't expect engines to handle null moves, for example. */ * We can't expect engines to handle null moves, for example. */
public void testUCIHistory() throws ChessParseError { 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(); Pair<Position, ArrayList<Move>> hist = game.getUCIHistory();
assertEquals(0, hist.second.size()); assertEquals(0, hist.second.size());

View File

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