Remove unneeded code from buildSrc

This commit is contained in:
Peter Osterlund 2019-08-11 11:40:31 +02:00
parent 2a01797dfa
commit 4230847224
13 changed files with 23 additions and 2750 deletions

View File

@ -20,99 +20,13 @@ package chess;
public class BitBoard {
/** Squares attacked by a king on a given square. */
public static final long[] kingAttacks;
public static final long[] knightAttacks;
public static final long[] wPawnAttacks, bPawnAttacks;
// Squares preventing a pawn from being a passed pawn, if occupied by enemy pawn
static final long[] wPawnBlockerMask, bPawnBlockerMask;
public static final long maskAToGFiles = 0x7F7F7F7F7F7F7F7FL;
public static final long maskBToHFiles = 0xFEFEFEFEFEFEFEFEL;
public static final long maskAToFFiles = 0x3F3F3F3F3F3F3F3FL;
public static final long maskCToHFiles = 0xFCFCFCFCFCFCFCFCL;
public static final long[] maskFile = {
0x0101010101010101L,
0x0202020202020202L,
0x0404040404040404L,
0x0808080808080808L,
0x1010101010101010L,
0x2020202020202020L,
0x4040404040404040L,
0x8080808080808080L
};
public static final long maskRow1 = 0x00000000000000FFL;
public static final long maskRow2 = 0x000000000000FF00L;
public static final long maskRow3 = 0x0000000000FF0000L;
public static final long maskRow4 = 0x00000000FF000000L;
public static final long maskRow5 = 0x000000FF00000000L;
public static final long maskRow6 = 0x0000FF0000000000L;
public static final long maskRow7 = 0x00FF000000000000L;
public static final long maskRow8 = 0xFF00000000000000L;
public static final long maskRow1Row8 = 0xFF000000000000FFL;
public static final long maskDarkSq = 0xAA55AA55AA55AA55L;
public static final long maskLightSq = 0x55AA55AA55AA55AAL;
public static final long maskCorners = 0x8100000000000081L;
static {
// Compute king attacks
kingAttacks = new long[64];
for (int sq = 0; sq < 64; sq++) {
long m = 1L << sq;
long mask = (((m >>> 1) | (m << 7) | (m >>> 9)) & maskAToGFiles) |
(((m << 1) | (m << 9) | (m >>> 7)) & maskBToHFiles) |
(m << 8) | (m >>> 8);
kingAttacks[sq] = mask;
}
// Compute knight attacks
knightAttacks = new long[64];
for (int sq = 0; sq < 64; sq++) {
long m = 1L << sq;
long mask = (((m << 6) | (m >>> 10)) & maskAToFFiles) |
(((m << 15) | (m >>> 17)) & maskAToGFiles) |
(((m << 17) | (m >>> 15)) & maskBToHFiles) |
(((m << 10) | (m >>> 6)) & maskCToHFiles);
knightAttacks[sq] = mask;
}
// Compute pawn attacks
wPawnAttacks = new long[64];
bPawnAttacks = new long[64];
wPawnBlockerMask = new long[64];
bPawnBlockerMask = new long[64];
for (int sq = 0; sq < 64; sq++) {
long m = 1L << sq;
long mask = ((m << 7) & maskAToGFiles) | ((m << 9) & maskBToHFiles);
wPawnAttacks[sq] = mask;
mask = ((m >>> 9) & maskAToGFiles) | ((m >>> 7) & maskBToHFiles);
bPawnAttacks[sq] = mask;
int x = Position.getX(sq);
int y = Position.getY(sq);
m = 0;
for (int y2 = y+1; y2 < 8; y2++) {
if (x > 0) m |= 1L << Position.getSquare(x-1, y2);
m |= 1L << Position.getSquare(x , y2);
if (x < 7) m |= 1L << Position.getSquare(x+1, y2);
}
wPawnBlockerMask[sq] = m;
m = 0;
for (int y2 = y-1; y2 >= 0; y2--) {
if (x > 0) m |= 1L << Position.getSquare(x-1, y2);
m |= 1L << Position.getSquare(x , y2);
if (x < 7) m |= 1L << Position.getSquare(x+1, y2);
}
bPawnBlockerMask[sq] = m;
}
}
private final static long[][] rTables;
private final static long[] rMasks;
private final static int[] rBits = { 12, 11, 11, 11, 11, 11, 11, 12,
@ -277,106 +191,4 @@ public class BitBoard {
public static long rookAttacks(int sq, long occupied) {
return rTables[sq][(int)(((occupied & rMasks[sq]) * rMagics[sq]) >>> (64 - rBits[sq]))];
}
static public final long[][] squaresBetween;
static {
squaresBetween = new long[64][];
for (int sq1 = 0; sq1 < 64; sq1++) {
squaresBetween[sq1] = new long[64];
for (int j = 0; j < 64; j++)
squaresBetween[sq1][j] = 0;
for (int dx = -1; dx <= 1; dx++) {
for (int dy = -1; dy <= 1; dy++) {
if ((dx == 0) && (dy == 0))
continue;
long m = 0;
int x = Position.getX(sq1);
int y = Position.getY(sq1);
while (true) {
x += dx; y += dy;
if ((x < 0) || (x > 7) || (y < 0) || (y > 7))
break;
int sq2 = Position.getSquare(x, y);
squaresBetween[sq1][sq2] = m;
m |= 1L << sq2;
}
}
}
}
}
private static final byte dirTable[] = {
-9, 0, 0, 0, 0, 0, 0, -8, 0, 0, 0, 0, 0, 0, -7,
0, 0, -9, 0, 0, 0, 0, 0, -8, 0, 0, 0, 0, 0, -7, 0,
0, 0, 0, -9, 0, 0, 0, 0, -8, 0, 0, 0, 0, -7, 0, 0,
0, 0, 0, 0, -9, 0, 0, 0, -8, 0, 0, 0, -7, 0, 0, 0,
0, 0, 0, 0, 0, -9, 0, 0, -8, 0, 0, -7, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, -9,-17, -8,-15, -7, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,-10, -9, -8, -7, -6, 0, 0, 0, 0, 0,
0, -1, -1, -1, -1, -1, -1, -1, 0, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0, 0, 0, 0, 6, 7, 8, 9, 10, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 7, 15, 8, 17, 9, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 7, 0, 0, 8, 0, 0, 9, 0, 0, 0, 0,
0, 0, 0, 0, 7, 0, 0, 0, 8, 0, 0, 0, 9, 0, 0, 0,
0, 0, 0, 7, 0, 0, 0, 0, 8, 0, 0, 0, 0, 9, 0, 0,
0, 0, 7, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 9, 0,
0, 7, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 9
};
static public final int getDirection(int from, int to) {
int offs = to + (to|7) - from - (from|7) + 0x77;
return dirTable[offs];
}
private static final byte distTable[] = {
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
0, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7,
0, 7, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 7,
0, 7, 6, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 6, 7,
0, 7, 6, 5, 4, 3, 3, 3, 3, 3, 3, 3, 4, 5, 6, 7,
0, 7, 6, 5, 4, 3, 2, 2, 2, 2, 2, 3, 4, 5, 6, 7,
0, 7, 6, 5, 4, 3, 2, 1, 1, 1, 2, 3, 4, 5, 6, 7,
0, 7, 6, 5, 4, 3, 2, 1, 0, 1, 2, 3, 4, 5, 6, 7,
0, 7, 6, 5, 4, 3, 2, 1, 1, 1, 2, 3, 4, 5, 6, 7,
0, 7, 6, 5, 4, 3, 2, 2, 2, 2, 2, 3, 4, 5, 6, 7,
0, 7, 6, 5, 4, 3, 3, 3, 3, 3, 3, 3, 4, 5, 6, 7,
0, 7, 6, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 6, 7,
0, 7, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 7,
0, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7,
0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
};
public static int getDistance(int from, int to) {
int offs = to + (to|7) - from - (from|7) + 0x77;
return distTable[offs];
}
public static long southFill(long mask) {
mask |= (mask >>> 8);
mask |= (mask >>> 16);
mask |= (mask >>> 32);
return mask;
}
public static long northFill(long mask) {
mask |= (mask << 8);
mask |= (mask << 16);
mask |= (mask << 32);
return mask;
}
private static final int trailingZ[] = {
63, 0, 58, 1, 59, 47, 53, 2,
60, 39, 48, 27, 54, 33, 42, 3,
61, 51, 37, 40, 49, 18, 28, 20,
55, 30, 34, 11, 43, 14, 22, 4,
62, 57, 46, 52, 38, 26, 32, 41,
50, 36, 17, 19, 29, 10, 13, 21,
56, 45, 25, 31, 35, 16, 9, 12,
44, 24, 15, 8, 23, 7, 6, 5
};
static public final int numberOfTrailingZeros(long mask) {
return trailingZ[(int)(((mask & -mask) * 0x07EDD5E59A4E28C2L) >>> 58)];
}
}

View File

@ -34,153 +34,6 @@ import java.util.Random;
/** Implements an opening book. */
public class Book {
public static class BookEntry {
Move move;
int count;
BookEntry(Move move) {
this.move = move;
count = 1;
}
}
private static Map<Long, List<BookEntry>> bookMap;
private static Random rndGen;
private static int numBookMoves = -1;
private boolean verbose;
public Book(boolean verbose) {
this.verbose = verbose;
}
private void initBook() {
if (numBookMoves >= 0)
return;
long t0 = System.currentTimeMillis();
bookMap = new HashMap<>();
rndGen = new SecureRandom();
rndGen.setSeed(System.currentTimeMillis());
numBookMoves = 0;
try (InputStream inStream = getClass().getResourceAsStream("/book.bin")) {
List<Byte> buf = new ArrayList<>(8192);
byte[] tmpBuf = new byte[1024];
while (true) {
int len = inStream.read(tmpBuf);
if (len <= 0) break;
for (int i = 0; i < len; i++)
buf.add(tmpBuf[i]);
}
Position startPos = TextIO.readFEN(TextIO.startPosFEN);
Position pos = new Position(startPos);
UndoInfo ui = new UndoInfo();
int len = buf.size();
for (int i = 0; i < len; i += 2) {
int b0 = buf.get(i); if (b0 < 0) b0 += 256;
int b1 = buf.get(i+1); if (b1 < 0) b1 += 256;
int move = (b0 << 8) + b1;
if (move == 0) {
pos = new Position(startPos);
} else {
boolean bad = ((move >> 15) & 1) != 0;
int prom = (move >> 12) & 7;
Move m = new Move(move & 63, (move >> 6) & 63,
promToPiece(prom, pos.whiteMove));
if (!bad)
addToBook(pos, m);
pos.makeMove(m, ui);
}
}
} catch (ChessParseError ex) {
throw new RuntimeException();
} catch (IOException ex) {
System.out.println("Can't read opening book resource");
throw new RuntimeException();
}
if (verbose) {
long t1 = System.currentTimeMillis();
System.out.printf("Book moves:%d (parse time:%.3f)%n", numBookMoves,
(t1 - t0) / 1000.0);
}
}
/** Add a move to a position in the opening book. */
private void addToBook(Position pos, Move moveToAdd) {
List<BookEntry> ent = bookMap.get(pos.zobristHash());
if (ent == null) {
ent = new ArrayList<>();
bookMap.put(pos.zobristHash(), ent);
}
for (int i = 0; i < ent.size(); i++) {
BookEntry be = ent.get(i);
if (be.move.equals(moveToAdd)) {
be.count++;
return;
}
}
BookEntry be = new BookEntry(moveToAdd);
ent.add(be);
numBookMoves++;
}
/** Return a random book move for a position, or null if out of book. */
public final Move getBookMove(Position pos) {
initBook();
List<BookEntry> bookMoves = bookMap.get(pos.zobristHash());
if (bookMoves == null) {
return null;
}
ArrayList<Move> legalMoves = MoveGen.instance.legalMoves(pos);
int sum = 0;
for (int i = 0; i < bookMoves.size(); i++) {
BookEntry be = bookMoves.get(i);
boolean contains = false;
for (Move m : legalMoves)
if (m.equals(be.move)) {
contains = true;
break;
}
if (!contains) {
// If an illegal move was found, it means there was a hash collision.
return null;
}
sum += getWeight(bookMoves.get(i).count);
}
if (sum <= 0) {
return null;
}
int rnd = rndGen.nextInt(sum);
sum = 0;
for (int i = 0; i < bookMoves.size(); i++) {
sum += getWeight(bookMoves.get(i).count);
if (rnd < sum) {
return bookMoves.get(i).move;
}
}
// Should never get here
throw new RuntimeException();
}
private int getWeight(int count) {
double tmp = Math.sqrt(count);
return (int)(tmp * Math.sqrt(tmp) * 100 + 1);
}
/** Return a string describing all book moves. */
public final String getAllBookMoves(Position pos) {
initBook();
StringBuilder ret = new StringBuilder();
List<BookEntry> bookMoves = bookMap.get(pos.zobristHash());
if (bookMoves != null) {
for (BookEntry be : bookMoves) {
String moveStr = TextIO.moveToString(pos, be.move, false);
ret.append(moveStr);
ret.append("(");
ret.append(be.count);
ret.append(") ");
}
}
return ret.toString();
}
/** Creates the book.bin file. */
public static void main(String[] args) throws IOException {
String inFile = args[0];
@ -265,14 +118,4 @@ public class Book {
return 0;
}
}
private static int promToPiece(int prom, boolean whiteMove) {
switch (prom) {
case 1: return whiteMove ? Piece.WQUEEN : Piece.BQUEEN;
case 2: return whiteMove ? Piece.WROOK : Piece.BROOK;
case 3: return whiteMove ? Piece.WBISHOP : Piece.BBISHOP;
case 4: return whiteMove ? Piece.WKNIGHT : Piece.BKNIGHT;
default: return Piece.EMPTY;
}
}
}

View File

@ -87,13 +87,11 @@ public class EcoBuilder {
private void readGame(String pgn) throws Throwable {
if (pgn.isEmpty())
return;
Game game = new Game(null, new TimeControlData());
PGNOptions options = new PGNOptions();
game.readPGN(pgn, options);
GameTree tree = new GameTree();
tree.readPGN(pgn);
// Determine name of opening
HashMap<String,String> headers = new HashMap<>();
GameTree tree = game.tree;
tree.getHeaders(headers);
int ecoIdx = addData(headers, "ECO");
int opnIdx = addData(headers, "Opening");

View File

@ -1,538 +0,0 @@
/*
DroidFish - An Android chess program.
Copyright (C) 2011 Peter Österlund, peterosterlund2@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package chess;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import chess.GameTree.Node;
public class Game {
boolean pendingDrawOffer;
public GameTree tree;
TimeControl timeController;
private boolean gamePaused;
/** If true, add new moves as mainline moves. */
private AddMoveBehavior addMoveBehavior;
private PgnToken.PgnTokenReceiver gameTextListener;
public Game(PgnToken.PgnTokenReceiver gameTextListener, TimeControlData tcData) {
this.gameTextListener = gameTextListener;
timeController = new TimeControl();
timeController.setTimeControl(tcData);
gamePaused = false;
newGame();
tree.setTimeControlData(tcData);
}
/** De-serialize from input stream. */
final void readFromStream(DataInputStream dis, int version) throws IOException, ChessParseError {
tree.readFromStream(dis, version);
if (version >= 3)
timeController.readFromStream(dis, version);
updateTimeControl(true);
}
/** Serialize to output stream. */
final synchronized void writeToStream(DataOutputStream dos) throws IOException {
tree.writeToStream(dos);
timeController.writeToStream(dos);
}
public final void setGamePaused(boolean gamePaused) {
if (gamePaused != this.gamePaused) {
this.gamePaused = gamePaused;
updateTimeControl(false);
}
}
/** Controls behavior when a new move is added to the game.*/
public static enum AddMoveBehavior {
/** Add the new move first in the list of variations. */
ADD_FIRST,
/** Add the new move last in the list of variations. */
ADD_LAST,
/** Remove all variations not matching the new move. */
REPLACE
}
/** Set whether new moves are entered as mainline moves or variations. */
public final void setAddFirst(AddMoveBehavior amb) {
addMoveBehavior = amb;
}
/** Sets start position and discards the whole game tree. */
final void setPos(Position pos) {
tree.setStartPos(new Position(pos));
updateTimeControl(false);
}
/** Set game state from a PGN string. */
final public boolean readPGN(String pgn, PGNOptions options) throws ChessParseError {
boolean ret = tree.readPGN(pgn, options);
if (ret) {
TimeControlData tcData = tree.getTimeControlData();
if (tcData != null)
timeController.setTimeControl(tcData);
updateTimeControl(tcData != null);
}
return ret;
}
final Position currPos() {
return tree.currentPos;
}
final Position prevPos() {
Move m = tree.currentNode.move;
if (m != null) {
tree.goBack();
Position ret = new Position(currPos());
tree.goForward(-1);
return ret;
} else {
return currPos();
}
}
public final Move getNextMove() {
if (canRedoMove()) {
tree.goForward(-1);
Move ret = tree.currentNode.move;
tree.goBack();
return ret;
} else {
return null;
}
}
/**
* Update the game state according to move/command string from a player.
* @param str The move or command to process.
* @return Pair where first item is true if str was understood, false otherwise.
* Second item is move played, or null if no move was played. */
public final Pair<Boolean, Move> processString(String str) {
if (getGameState() != GameState.ALIVE)
return new Pair<>(false, null);
if (str.startsWith("draw ")) {
String drawCmd = str.substring(str.indexOf(" ") + 1);
Move m = handleDrawCmd(drawCmd, true);
return new Pair<>(true, m);
} else if (str.equals("resign")) {
addToGameTree(new Move(0, 0, 0), "resign");
return new Pair<>(true, null);
}
Move m = TextIO.UCIstringToMove(str);
if (m != null)
if (!TextIO.isValid(currPos(), m))
m = null;
if (m == null) {
m = TextIO.stringToMove(currPos(), str);
if (!TextIO.isValid(currPos(), m))
m = null;
}
if (m == null)
return new Pair<>(false, null);
addToGameTree(m, pendingDrawOffer ? "draw offer" : "");
return new Pair<>(true, m);
}
/** Try claim a draw using a command string. Does not play the move involved
* in the draw claim if the draw claim is invalid. */
public final void tryClaimDraw(String str) {
if (str.startsWith("draw ")) {
String drawCmd = str.substring(str.indexOf(" ") + 1);
handleDrawCmd(drawCmd, false);
}
}
private void addToGameTree(Move m, String playerAction) {
if (m.equals(new Move(0, 0, 0))) { // Don't create more than one game-ending move at a node
List<Move> varMoves = tree.variations();
for (int i = varMoves.size() - 1; i >= 0; i--)
if (varMoves.get(i).equals(m))
tree.deleteVariation(i);
}
boolean movePresent = false;
int varNo;
{
ArrayList<Move> varMoves = tree.variations();
int nVars = varMoves.size();
if (addMoveBehavior == AddMoveBehavior.REPLACE) {
boolean modified = false;
for (int i = nVars-1; i >= 0; i--) {
if (!m.equals(varMoves.get(i))) {
tree.deleteVariation(i);
modified = true;
}
}
if (modified) {
varMoves = tree.variations();
nVars = varMoves.size();
}
}
Boolean gameEndingMove = null;
for (varNo = 0; varNo < nVars; varNo++) {
if (varMoves.get(varNo).equals(m)) {
boolean match = true;
if (playerAction.isEmpty()) {
if (gameEndingMove == null)
gameEndingMove = gameEndingMove(m);
if (!gameEndingMove) {
tree.goForward(varNo, false);
match = tree.getGameState() == GameState.ALIVE;
tree.goBack();
}
}
if (match) {
movePresent = true;
break;
}
}
}
}
if (!movePresent) {
String moveStr = TextIO.moveToUCIString(m);
varNo = tree.addMove(moveStr, playerAction, 0, "", "");
}
int newPos = 0;
if (addMoveBehavior == AddMoveBehavior.ADD_LAST)
newPos = varNo;
tree.reorderVariation(varNo, newPos);
tree.goForward(newPos);
int remaining = timeController.moveMade(System.currentTimeMillis(), !gamePaused);
tree.setRemainingTime(remaining);
updateTimeControl(true);
pendingDrawOffer = false;
}
/** Return true if move "m" in the current position ends the game (mate or stalemate). */
private boolean gameEndingMove(Move m) {
Position pos = currPos();
UndoInfo ui = new UndoInfo();
pos.makeMove(m, ui);
boolean gameEnd = MoveGen.instance.legalMoves(pos).isEmpty();
pos.unMakeMove(m, ui);
return gameEnd;
}
private void updateTimeControl(boolean discardElapsed) {
Position currPos = currPos();
int move = currPos.fullMoveCounter;
boolean wtm = currPos.whiteMove;
if (discardElapsed || (move != timeController.currentMove) || (wtm != timeController.whiteToMove)) {
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();
boolean stopTimer = gamePaused || (getGameState() != GameState.ALIVE);
if (!stopTimer) {
try {
if (TextIO.readFEN(TextIO.startPosFEN).equals(currPos))
stopTimer = true;
} catch (ChessParseError e) {
}
}
if (stopTimer) {
timeController.stopTimer(now);
} else {
timeController.startTimer(now);
}
}
/**
* Get the last played move, or null if no moves played yet.
*/
public final Move getLastMove() {
return tree.currentNode.move;
}
/** Return true if there is a move to redo. */
public final boolean canRedoMove() {
int nVar = tree.variations().size();
return nVar > 0;
}
/** Get number of variations in current game position. */
public final int numVariations() {
if (tree.currentNode == tree.rootNode)
return 1;
tree.goBack();
int nChildren = tree.variations().size();
tree.goForward(-1);
return nChildren;
}
/** Get current variation in current position. */
public final int currVariation() {
if (tree.currentNode == tree.rootNode)
return 0;
tree.goBack();
int defChild = tree.currentNode.defaultChild;
tree.goForward(-1);
return defChild;
}
/** Go to a new variation in the game tree. */
public final void changeVariation(int delta) {
if (tree.currentNode == tree.rootNode)
return;
tree.goBack();
int defChild = tree.currentNode.defaultChild;
int nChildren = tree.variations().size();
int newChild = defChild + delta;
newChild = Math.max(newChild, 0);
newChild = Math.min(newChild, nChildren - 1);
tree.goForward(newChild);
pendingDrawOffer = false;
updateTimeControl(true);
}
/** Move current variation up/down in the game tree. */
public final void moveVariation(int delta) {
int nBack = 0;
boolean found = false;
while (tree.currentNode != tree.rootNode) {
tree.goBack();
nBack++;
if (((delta < 0) && tree.currentNode.defaultChild > 0) ||
((delta > 0) && tree.currentNode.defaultChild < tree.variations().size() - 1)) {
found = true;
break;
}
}
if (found) {
int varNo = tree.currentNode.defaultChild;
int nChildren = tree.variations().size();
int newPos = varNo + delta;
newPos = Math.max(newPos, 0);
newPos = Math.min(newPos, nChildren - 1);
tree.reorderVariation(varNo, newPos);
tree.goForward(newPos);
nBack--;
}
while (nBack > 0) {
tree.goForward(-1);
nBack--;
}
pendingDrawOffer = false;
updateTimeControl(true);
}
/** Return true if the current variation can be moved up/down. */
public final boolean canMoveVariation(int delta) {
int nBack = 0;
boolean found = false;
while (tree.currentNode != tree.rootNode) {
tree.goBack();
nBack++;
if (((delta < 0) && tree.currentNode.defaultChild > 0) ||
((delta > 0) && tree.currentNode.defaultChild < tree.variations().size() - 1)) {
found = true;
break;
}
}
while (nBack > 0) {
tree.goForward(-1);
nBack--;
}
return found;
}
/** Delete whole game sub-tree rooted at current position. */
public final void removeSubTree() {
if (getLastMove() != null) {
tree.goBack();
int defChild = tree.currentNode.defaultChild;
tree.deleteVariation(defChild);
} else {
while (canRedoMove())
tree.deleteVariation(0);
}
pendingDrawOffer = false;
updateTimeControl(true);
}
public static enum GameState {
ALIVE,
WHITE_MATE, // White mates
BLACK_MATE, // Black mates
WHITE_STALEMATE, // White is stalemated
BLACK_STALEMATE, // Black is stalemated
DRAW_REP, // Draw by 3-fold repetition
DRAW_50, // Draw by 50 move rule
DRAW_NO_MATE, // Draw by impossibility of check mate
DRAW_AGREE, // Draw by agreement
RESIGN_WHITE, // White resigns
RESIGN_BLACK // Black resigns
}
/**
* Get the current state (draw, mate, ongoing, etc) of the game.
*/
public final GameState getGameState() {
return tree.getGameState();
}
/**
* Check if a draw offer is available.
* @return True if the current player has the option to accept a draw offer.
*/
public final boolean haveDrawOffer() {
return tree.currentNode.playerAction.equals("draw offer");
}
public final void undoMove() {
Move m = tree.currentNode.move;
if (m != null) {
tree.goBack();
pendingDrawOffer = false;
updateTimeControl(true);
}
}
public final void redoMove() {
if (canRedoMove()) {
tree.goForward(-1);
pendingDrawOffer = false;
updateTimeControl(true);
}
}
/** Go to given node in game tree.
* @return True if current node changed, false otherwise. */
public final boolean goNode(Node node) {
if (!tree.goNode(node))
return false;
pendingDrawOffer = false;
updateTimeControl(true);
return true;
}
public final void newGame() {
tree = new GameTree(gameTextListener);
timeController.reset();
pendingDrawOffer = false;
updateTimeControl(true);
}
/**
* Return the last zeroing position and a list of moves
* to go from that position to the current position.
*/
public final Pair<Position, ArrayList<Move>> getUCIHistory() {
Pair<List<Node>, Integer> ml = tree.getMoveList();
List<Node> moveList = ml.first;
Position pos = new Position(tree.startPos);
ArrayList<Move> mList = new ArrayList<>();
Position currPos = new Position(pos);
UndoInfo ui = new UndoInfo();
int nMoves = ml.second;
for (int i = 0; i < nMoves; i++) {
Node n = moveList.get(i);
mList.add(n.move);
currPos.makeMove(n.move, ui);
if (currPos.halfMoveClock == 0) {
pos = new Position(currPos);
mList.clear();
}
}
return new Pair<>(pos, mList);
}
private Move handleDrawCmd(String drawCmd, boolean playDrawMove) {
Move ret = null;
Position pos = tree.currentPos;
if (drawCmd.startsWith("rep") || drawCmd.startsWith("50")) {
boolean rep = drawCmd.startsWith("rep");
Move m = null;
String ms = null;
int firstSpace = drawCmd.indexOf(" ");
if (firstSpace >= 0) {
ms = drawCmd.substring(firstSpace + 1);
if (ms.length() > 0) {
m = TextIO.stringToMove(pos, ms);
}
}
boolean valid;
if (rep) {
valid = false;
UndoInfo ui = new UndoInfo();
int repetitions = 0;
Position posToCompare = new Position(tree.currentPos);
if (m != null) {
posToCompare.makeMove(m, ui);
repetitions = 1;
}
Pair<List<Node>, Integer> ml = tree.getMoveList();
List<Node> moveList = ml.first;
Position tmpPos = new Position(tree.startPos);
if (tmpPos.drawRuleEquals(posToCompare))
repetitions++;
int nMoves = ml.second;
for (int i = 0; i < nMoves; i++) {
Node n = moveList.get(i);
tmpPos.makeMove(n.move, ui);
TextIO.fixupEPSquare(tmpPos);
if (tmpPos.drawRuleEquals(posToCompare))
repetitions++;
}
if (repetitions >= 3)
valid = true;
} else {
Position tmpPos = new Position(pos);
if (m != null) {
UndoInfo ui = new UndoInfo();
tmpPos.makeMove(m, ui);
}
valid = tmpPos.halfMoveClock >= 100;
}
if (valid) {
String playerAction = rep ? "draw rep" : "draw 50";
if (m != null)
playerAction += " " + TextIO.moveToString(pos, m, false);
addToGameTree(new Move(0, 0, 0), playerAction);
} else {
pendingDrawOffer = true;
if (m != null && playDrawMove) {
ret = processString(ms).second;
}
}
} else if (drawCmd.startsWith("offer ")) {
pendingDrawOffer = true;
String ms = drawCmd.substring(drawCmd.indexOf(" ") + 1);
if (TextIO.stringToMove(pos, ms) != null) {
ret = processString(ms).second;
}
} else if (drawCmd.equals("accept")) {
if (haveDrawOffer())
addToGameTree(new Move(0, 0, 0), "draw accept");
}
return ret;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -30,58 +30,13 @@ public class Move {
/** Promotion piece. */
public int promoteTo;
public int score;
/** Create a move object. */
public Move(int from, int to, int promoteTo) {
this.from = from;
this.to = to;
this.promoteTo = promoteTo;
this.score = 0;
}
public Move(int from, int to, int promoteTo, int score) {
this.from = from;
this.to = to;
this.promoteTo = promoteTo;
this.score = score;
}
static public class SortByScore implements Comparator<Move> {
public int compare(Move sm1, Move sm2) {
return sm2.score - sm1.score;
}
}
public Move(Move m) {
this.from = m.from;
this.to = m.to;
this.promoteTo = m.promoteTo;
this.score = m.score;
}
public final void copyFrom(Move m) {
from = m.from;
to = m.to;
promoteTo = m.promoteTo;
// score = m.score;
}
public final void clear() {
from = 0;
to = 0;
promoteTo = 0;
score = 0;
}
public final void setMove(int from, int to, int promoteTo, int score) {
this.from = from;
this.to = to;
this.promoteTo = promoteTo;
this.score = score;
}
/** Note that score is not included in the comparison. */
@Override
public boolean equals(Object o) {
if ((o == null) || (o.getClass() != this.getClass()))

View File

@ -1,65 +0,0 @@
/*
DroidFish - An Android chess program.
Copyright (C) 2011 Peter Österlund, peterosterlund2@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package chess;
/** Settings controlling PGN import/export */
public class PGNOptions {
/** Pieces displayed as English letters. */
public static final int PT_ENGLISH = 0;
/** Pieces displayed as local language letters. */
public static final int PT_LOCAL = 1;
/** Piece displayed in figurine notation, by using UniCode characters
* and a special font. */
public static final int PT_FIGURINE = 2;
public static class Viewer {
public boolean variations;
public boolean comments;
public boolean nag;
public boolean headers;
public int pieceType;
}
public static class Import {
public boolean variations;
public boolean comments;
public boolean nag;
}
public static class Export {
public boolean variations;
public boolean comments;
public boolean nag;
public boolean playerAction;
public boolean clockInfo;
public boolean pgnPromotions;
public boolean moveNrAfterNag;
public int pieceType;
}
public Viewer view;
public Import imp;
public Export exp;
public PGNOptions() {
view = new Viewer();
imp = new Import();
exp = new Export();
exp.moveNrAfterNag = true;
exp.pieceType = PT_ENGLISH;
}
}

View File

@ -45,19 +45,4 @@ public class PgnToken {
this.type = type;
this.token = token;
}
/** PGN parser visitor interface. */
public interface PgnTokenReceiver {
/** If this method returns false, the object needs a full re-initialization, using clear() and processToken(). */
boolean isUpToDate();
/** Clear object state. */
void clear();
/** Update object state with one token from a PGN game. */
void processToken(GameTree.Node node, int type, String token);
/** Change current move number. */
void setCurrent(GameTree.Node node);
}
}

View File

@ -45,10 +45,4 @@ public class Piece {
public static boolean isWhite(int pType) {
return pType < BKING;
}
public static int makeWhite(int pType) {
return pType < BKING ? pType : pType - (BKING - WKING);
}
public static int makeBlack(int pType) {
return ((pType > EMPTY) && (pType < BKING)) ? pType + (BKING - WKING) : pType;
}
}

View File

@ -33,7 +33,6 @@ public class Position {
// Bitboards
public long[] pieceTypeBB;
public long whiteBB, blackBB;
public boolean whiteMove;
@ -66,7 +65,6 @@ public class Position {
for (int i = 0; i < Piece.nPieceTypes; i++) {
pieceTypeBB[i] = 0L;
}
whiteBB = blackBB = 0L;
whiteMove = true;
castleMask = 0;
epSquare = -1;
@ -84,8 +82,6 @@ public class Position {
for (int i = 0; i < Piece.nPieceTypes; i++) {
pieceTypeBB[i] = other.pieceTypeBB[i];
}
whiteBB = other.whiteBB;
blackBB = other.blackBB;
whiteMove = other.whiteMove;
castleMask = other.castleMask;
epSquare = other.epSquare;
@ -126,22 +122,7 @@ public class Position {
public final long zobristHash() {
return hashKey;
}
public final long pawnZobristHash() {
return pHashKey;
}
public final long kingZobristHash() {
return psHashKeys[Piece.WKING][wKingSq] ^
psHashKeys[Piece.BKING][bKingSq];
}
public final long historyHash() {
long ret = hashKey;
if (halfMoveClock >= 80) {
ret ^= moveCntKeys[Math.min(halfMoveClock, 100)];
}
return ret;
}
/**
* Decide if two positions are equal in the sense of the draw by repetition rule.
* @return True if positions are equal, false otherwise.
@ -204,13 +185,9 @@ public class Position {
pieceTypeBB[piece] &= ~sqMaskF;
pieceTypeBB[piece] |= sqMaskT;
if (Piece.isWhite(piece)) {
whiteBB &= ~sqMaskF;
whiteBB |= sqMaskT;
if (piece == Piece.WKING)
wKingSq = to;
} else {
blackBB &= ~sqMaskF;
blackBB |= sqMaskT;
if (piece == Piece.BKING)
bKingSq = to;
}
@ -232,12 +209,10 @@ public class Position {
if (removedPiece != Piece.EMPTY) {
if (Piece.isWhite(removedPiece)) {
whiteBB &= ~sqMask;
if (removedPiece == Piece.WPAWN) {
pHashKey ^= psHashKeys[Piece.WPAWN][square];
}
} else {
blackBB &= ~sqMask;
if (removedPiece == Piece.BPAWN) {
pHashKey ^= psHashKeys[Piece.BPAWN][square];
}
@ -246,14 +221,12 @@ public class Position {
if (piece != Piece.EMPTY) {
if (Piece.isWhite(piece)) {
whiteBB |= sqMask;
if (piece == Piece.WPAWN) {
pHashKey ^= psHashKeys[Piece.WPAWN][square];
}
if (piece == Piece.WKING)
wKingSq = square;
} else {
blackBB |= sqMask;
if (piece == Piece.BPAWN) {
pHashKey ^= psHashKeys[Piece.BPAWN][square];
}
@ -263,50 +236,6 @@ public class Position {
}
}
/**
* Set a square to a piece value.
* Special version that only updates enough of the state for the SEE function to be happy.
*/
public final void setSEEPiece(int square, int piece) {
int removedPiece = squares[square];
// Update board
squares[square] = piece;
// Update bitboards
long sqMask = 1L << square;
pieceTypeBB[removedPiece] &= ~sqMask;
pieceTypeBB[piece] |= sqMask;
if (removedPiece != Piece.EMPTY) {
if (Piece.isWhite(removedPiece))
whiteBB &= ~sqMask;
else
blackBB &= ~sqMask;
}
if (piece != Piece.EMPTY) {
if (Piece.isWhite(piece))
whiteBB |= sqMask;
else
blackBB |= sqMask;
}
}
/** Return true if white long castling right has not been lost. */
public final boolean a1Castle() {
return (castleMask & (1 << A1_CASTLE)) != 0;
}
/** Return true if white short castling right has not been lost. */
public final boolean h1Castle() {
return (castleMask & (1 << H1_CASTLE)) != 0;
}
/** Return true if black long castling right has not been lost. */
public final boolean a8Castle() {
return (castleMask & (1 << A8_CASTLE)) != 0;
}
/** Return true if black short castling right has not been lost. */
public final boolean h8Castle() {
return (castleMask & (1 << H8_CASTLE)) != 0;
}
/** Bitmask describing castling rights. */
public final int getCastleMask() {
return castleMask;
@ -334,15 +263,6 @@ public class Position {
return white ? wKingSq : bKingSq;
}
/** Count number of pieces of a certain type. */
public final int nPieces(int pType) {
int ret = 0;
for (int sq = 0; sq < 64; sq++)
if (squares[sq] == pType)
ret++;
return ret;
}
/** Apply a move to the current position. */
public final void makeMove(Move move, UndoInfo ui) {
ui.capturedPiece = squares[move.to];
@ -491,46 +411,6 @@ public class Position {
}
}
/**
* Apply a move to the current position.
* Special version that only updates enough of the state for the SEE function to be happy.
*/
public final void makeSEEMove(Move move, UndoInfo ui) {
ui.capturedPiece = squares[move.to];
int p = squares[move.from];
// Handle en passant
if (move.to == epSquare) {
if (p == Piece.WPAWN) {
setSEEPiece(move.to - 8, Piece.EMPTY);
} else if (p == Piece.BPAWN) {
setSEEPiece(move.to + 8, Piece.EMPTY);
}
}
// Perform move
setSEEPiece(move.from, Piece.EMPTY);
setSEEPiece(move.to, p);
whiteMove = !whiteMove;
}
public final void unMakeSEEMove(Move move, UndoInfo ui) {
whiteMove = !whiteMove;
int p = squares[move.to];
setSEEPiece(move.from, p);
setSEEPiece(move.to, ui.capturedPiece);
// Handle en passant
if (move.to == epSquare) {
if (p == Piece.WPAWN) {
setSEEPiece(move.to - 8, Piece.BPAWN);
} else if (p == Piece.BPAWN) {
setSEEPiece(move.to + 8, Piece.WPAWN);
}
}
}
private void removeCastleRights(int square) {
if (square == Position.getSquare(0, 0)) {
setCastleMask(castleMask & ~(1 << Position.A1_CASTLE));

View File

@ -105,7 +105,6 @@ public class TextIO {
}
}
pos.setCastleMask(castleMask);
removeBogusCastleFlags(pos);
if (words.length > 3) {
// En passant target square
@ -182,21 +181,6 @@ public class TextIO {
return pos;
}
public static void removeBogusCastleFlags(Position pos) {
int castleMask = pos.getCastleMask();
int validCastle = 0;
if (pos.getPiece(4) == Piece.WKING) {
if (pos.getPiece(0) == Piece.WROOK) validCastle |= (1 << Position.A1_CASTLE);
if (pos.getPiece(7) == Piece.WROOK) validCastle |= (1 << Position.H1_CASTLE);
}
if (pos.getPiece(60) == Piece.BKING) {
if (pos.getPiece(56) == Piece.BROOK) validCastle |= (1 << Position.A8_CASTLE);
if (pos.getPiece(63) == Piece.BROOK) validCastle |= (1 << Position.H8_CASTLE);
}
castleMask &= validCastle;
pos.setCastleMask(castleMask);
}
/** Remove pseudo-legal EP square if it is not legal, ie would leave king in check. */
public static void fixupEPSquare(Position pos) {
int epSquare = pos.getEpSquare();
@ -226,91 +210,6 @@ public class TextIO {
pos.setPiece(Position.getSquare(col, row), p);
}
/** Return a FEN string corresponding to a chess Position object. */
public static String toFEN(Position pos) {
StringBuilder ret = new StringBuilder();
// Piece placement
for (int r = 7; r >=0; r--) {
int numEmpty = 0;
for (int c = 0; c < 8; c++) {
int p = pos.getPiece(Position.getSquare(c, r));
if (p == Piece.EMPTY) {
numEmpty++;
} else {
if (numEmpty > 0) {
ret.append(numEmpty);
numEmpty = 0;
}
switch (p) {
case Piece.WKING: ret.append('K'); break;
case Piece.WQUEEN: ret.append('Q'); break;
case Piece.WROOK: ret.append('R'); break;
case Piece.WBISHOP: ret.append('B'); break;
case Piece.WKNIGHT: ret.append('N'); break;
case Piece.WPAWN: ret.append('P'); break;
case Piece.BKING: ret.append('k'); break;
case Piece.BQUEEN: ret.append('q'); break;
case Piece.BROOK: ret.append('r'); break;
case Piece.BBISHOP: ret.append('b'); break;
case Piece.BKNIGHT: ret.append('n'); break;
case Piece.BPAWN: ret.append('p'); break;
default: throw new RuntimeException();
}
}
}
if (numEmpty > 0) {
ret.append(numEmpty);
}
if (r > 0) {
ret.append('/');
}
}
ret.append(pos.whiteMove ? " w " : " b ");
// Castling rights
boolean anyCastle = false;
if (pos.h1Castle()) {
ret.append('K');
anyCastle = true;
}
if (pos.a1Castle()) {
ret.append('Q');
anyCastle = true;
}
if (pos.h8Castle()) {
ret.append('k');
anyCastle = true;
}
if (pos.a8Castle()) {
ret.append('q');
anyCastle = true;
}
if (!anyCastle) {
ret.append('-');
}
// En passant target square
{
ret.append(' ');
if (pos.getEpSquare() >= 0) {
int x = Position.getX(pos.getEpSquare());
int y = Position.getY(pos.getEpSquare());
ret.append((char)(x + 'a'));
ret.append((char)(y + '1'));
} else {
ret.append('-');
}
}
// Move counters
ret.append(' ');
ret.append(pos.halfMoveClock);
ret.append(' ');
ret.append(pos.fullMoveCounter);
return ret.toString();
}
/**
* Convert a chess move to human readable form.
* @param pos The chess position.
@ -425,22 +324,6 @@ public class TextIO {
}
}
/**
* Decide if move is valid in position pos.
* @param pos Position for which to test move.
* @param move The move to check for validity.
* @return True if move is valid in position pos, false otherwise.
*/
public static boolean isValid(Position pos, Move move) {
if (move == null)
return false;
ArrayList<Move> moves = new MoveGen().legalMoves(pos);
for (int i = 0; i < moves.size(); i++)
if (move.equals(moves.get(i)))
return true;
return false;
}
private final static class MoveInfo {
int piece; // -1 for unspecified
int fromX, fromY, toX, toY; // -1 for unspecified
@ -580,82 +463,6 @@ public class TextIO {
return move;
}
/** Convert a move object to UCI string format. */
public static String moveToUCIString(Move m) {
String ret = squareToString(m.from);
ret += squareToString(m.to);
switch (m.promoteTo) {
case Piece.WQUEEN:
case Piece.BQUEEN:
ret += "q";
break;
case Piece.WROOK:
case Piece.BROOK:
ret += "r";
break;
case Piece.WBISHOP:
case Piece.BBISHOP:
ret += "b";
break;
case Piece.WKNIGHT:
case Piece.BKNIGHT:
ret += "n";
break;
default:
break;
}
return ret;
}
/**
* Convert a string in UCI move format to a Move object.
* @return A move object, or null if move has invalid syntax
*/
public static Move UCIstringToMove(String move) {
Move m = null;
if ((move.length() < 4) || (move.length() > 5))
return m;
int fromSq = TextIO.getSquare(move.substring(0, 2));
int toSq = TextIO.getSquare(move.substring(2, 4));
if ((fromSq < 0) || (toSq < 0)) {
return m;
}
char prom = ' ';
boolean white = true;
if (move.length() == 5) {
prom = move.charAt(4);
if (Position.getY(toSq) == 7) {
white = true;
} else if (Position.getY(toSq) == 0) {
white = false;
} else {
return m;
}
}
int promoteTo;
switch (prom) {
case ' ':
promoteTo = Piece.EMPTY;
break;
case 'q':
promoteTo = white ? Piece.WQUEEN : Piece.BQUEEN;
break;
case 'r':
promoteTo = white ? Piece.WROOK : Piece.BROOK;
break;
case 'b':
promoteTo = white ? Piece.WBISHOP : Piece.BBISHOP;
break;
case 'n':
promoteTo = white ? Piece.WKNIGHT : Piece.BKNIGHT;
break;
default:
return m;
}
m = new Move(fromSq, toSq, promoteTo);
return m;
}
/**
* Convert a string, such as "e4" to a square number.
* @return The square number, or -1 if not a legal square.
@ -668,18 +475,6 @@ public class TextIO {
return Position.getSquare(x, y);
}
/**
* Convert a square number to a string, such as "e4".
*/
public static String squareToString(int square) {
StringBuilder ret = new StringBuilder();
int x = Position.getX(square);
int y = Position.getY(square);
ret.append((char) (x + 'a'));
ret.append((char) (y + '1'));
return ret.toString();
}
private static String pieceToChar(int p) {
switch (p) {
case Piece.WQUEEN: case Piece.BQUEEN: return "Q";
@ -702,18 +497,4 @@ public class TextIO {
}
return -1;
}
/** Add an = sign to a promotion move, as required by the PGN standard. */
public static String pgnPromotion(String str) {
int idx = str.length() - 1;
while (idx > 0) {
char c = str.charAt(idx);
if ((c != '#') && (c != '+'))
break;
idx--;
}
if ((idx > 0) && (charToPiece(true, str.charAt(idx)) != -1))
idx--;
return str.substring(0, idx + 1) + '=' + str.substring(idx + 1, str.length());
}
}

View File

@ -1,193 +0,0 @@
/*
DroidFish - An Android chess program.
Copyright (C) 2011 Peter Österlund, peterosterlund2@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package chess;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import chess.TimeControlData.TimeControlField;
/** Keep track of time control information for both players. */
public class TimeControl {
TimeControlData tcData;
private int whiteBaseTime; // Current remaining time, or remaining time when clock started
private int blackBaseTime; // Current remaining time, or remaining time when clock started
int currentMove;
boolean whiteToMove;
private int 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". */
public TimeControl() {
tcData = new TimeControlData();
reset();
}
public final void reset() {
currentMove = 1;
whiteToMove = true;
elapsed = 0;
timerT0 = 0;
}
/** Set time controls for white and black players. */
public final void setTimeControl(TimeControlData tcData) {
this.tcData = tcData;
}
public final void setCurrentMove(int move, boolean whiteToMove, int whiteBaseTime, int blackBaseTime) {
currentMove = move;
this.whiteToMove = whiteToMove;
this.whiteBaseTime = whiteBaseTime;
this.blackBaseTime = blackBaseTime;
timerT0 = 0;
elapsed = 0;
}
/** Move current move "delta" half-moves forward. */
public final void advanceMove(int delta) {
while (delta > 0) {
if (!whiteToMove)
currentMove++;
whiteToMove = !whiteToMove;
delta--;
}
while (delta < 0) {
whiteToMove = !whiteToMove;
if (!whiteToMove)
currentMove--;
delta++;
}
}
public final boolean clockRunning() {
return timerT0 != 0;
}
public final void startTimer(long now) {
if (!clockRunning()) {
timerT0 = now;
}
}
public final void stopTimer(long now) {
if (clockRunning()) {
int currElapsed = (int)(now - timerT0);
timerT0 = 0;
if (currElapsed > 0)
elapsed += currElapsed;
}
}
/** Compute new remaining time after a move is made. */
public final int moveMade(long now, boolean useIncrement) {
stopTimer(now);
ArrayList<TimeControlField> tc = tcData.getTC(whiteToMove);
Pair<Integer,Integer> tcInfo = getCurrentTC(whiteToMove);
int tcIdx = tcInfo.first;
int movesToTc = tcInfo.second;
int remaining = getRemainingTime(whiteToMove, now);
if (useIncrement) {
remaining += tc.get(tcIdx).increment;
if (movesToTc == 1) {
if (tcIdx+1 < tc.size())
tcIdx++;
remaining += tc.get(tcIdx).timeControl;
}
}
elapsed = 0;
return remaining;
}
/** Get remaining time */
public final int getRemainingTime(boolean whiteToMove, long now) {
int remaining = whiteToMove ? whiteBaseTime : blackBaseTime;
if (whiteToMove == this.whiteToMove) {
remaining -= elapsed;
if (timerT0 != 0)
remaining -= now - timerT0;
}
return remaining;
}
/** Get initial thinking time in milliseconds. */
public final int getInitialTime(boolean whiteMove) {
ArrayList<TimeControlField> tc = tcData.getTC(whiteMove);
return tc.get(0).timeControl;
}
/** Get time increment in milliseconds after playing next move. */
public final int getIncrement(boolean whiteMove) {
ArrayList<TimeControlField> tc = tcData.getTC(whiteMove);
int tcIdx = getCurrentTC(whiteMove).first;
return tc.get(tcIdx).increment;
}
/** 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 Array containing time control, moves per session and time increment. */
public int[] getTimeLimit(boolean whiteMove) {
ArrayList<TimeControlField> tc = tcData.getTC(whiteMove);
int tcIdx = getCurrentTC(whiteMove).first;
TimeControlField t = tc.get(tcIdx);
return new int[]{t.timeControl, t.movesPerSession, t.increment};
}
/** 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 = tcData.getTC(whiteMove);
int tcIdx = 0;
final int lastTcIdx = tc.size() - 1;
int nextTC = 1;
int currMove = currentMove;
if (!whiteToMove && whiteMove)
currMove++;
while (true) {
if (tc.get(tcIdx).movesPerSession <= 0)
return new Pair<>(tcIdx, 0);
nextTC += tc.get(tcIdx).movesPerSession;
if (nextTC > currMove)
break;
if (tcIdx < lastTcIdx)
tcIdx++;
}
return new Pair<>(tcIdx, nextTC - currMove);
}
/** De-serialize from input stream. */
public void readFromStream(DataInputStream dis, int version) throws IOException {
tcData.readFromStream(dis, version);
}
/** Serialize to output stream. */
public void writeToStream(DataOutputStream dos) throws IOException {
tcData.writeToStream(dos);
}
}

View File

@ -1,122 +0,0 @@
/*
DroidFish - An Android chess program.
Copyright (C) 2013,2016 Peter Österlund, peterosterlund2@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package chess;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
public final class TimeControlData {
public static final class TimeControlField {
int timeControl; // Time in milliseconds
int movesPerSession;
int increment; // Increment in milliseconds
public TimeControlField(int time, int moves, int inc) {
timeControl = time;
movesPerSession = moves;
increment = inc;
}
}
ArrayList<TimeControlField> tcW, tcB;
/** Constructor. Set a default time control. */
public TimeControlData() {
tcW = new ArrayList<>();
tcW.add(new TimeControlField(5*60*1000, 60, 0));
tcB = new ArrayList<>();
tcB.add(new TimeControlField(5*60*1000, 60, 0));
}
/** Set a single time control for both white and black. */
public final void setTimeControl(int time, int moves, int inc) {
tcW = new ArrayList<>();
tcW.add(new TimeControlField(time, moves, inc));
tcB = new ArrayList<>();
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;
}
/** Return true if white and black time controls are equal. */
public boolean isSymmetric() {
return arrayEquals(tcW, tcB);
}
@Override
public boolean equals(Object o) {
if (!(o instanceof TimeControlData))
return false;
TimeControlData tc2 = (TimeControlData)o;
return arrayEquals(tcW, tc2.tcW) && arrayEquals(tcB, tc2.tcB);
}
private static boolean arrayEquals(ArrayList<TimeControlField> a1,
ArrayList<TimeControlField> a2) {
if (a1.size() != a2.size())
return false;
for (int i = 0; i < a1.size(); i++) {
TimeControlField f1 = a1.get(i);
TimeControlField f2 = a2.get(i);
if ((f1.timeControl != f2.timeControl) ||
(f1.movesPerSession != f2.movesPerSession) ||
(f1.increment != f2.increment))
return false;
}
return true;
}
/** De-serialize from input stream. */
public void readFromStream(DataInputStream dis, int version) throws IOException {
for (int c = 0; c < 2; c++) {
ArrayList<TimeControlField> tc = new ArrayList<>();
if (c == 0)
tcW = tc;
else
tcB = tc;
int nw = dis.readInt();
for (int i = 0; i < nw; i++) {
int time = dis.readInt();
int moves = dis.readInt();
int inc = dis.readInt();
tc.add(new TimeControlField(time, moves, inc));
}
}
}
/** Serialize to output stream. */
public void writeToStream(DataOutputStream dos) throws IOException {
for (int c = 0; c < 2; c++) {
ArrayList<TimeControlField> tc = (c == 0) ? tcW : tcB;
int nw = tc.size();
dos.writeInt(nw);
for (int i = 0; i < nw; i++) {
TimeControlField tcf = tc.get(i);
dos.writeInt(tcf.timeControl);
dos.writeInt(tcf.movesPerSession);
dos.writeInt(tcf.increment);
}
}
}
}