mirror of
https://github.com/peterosterlund2/droidfish.git
synced 2024-11-23 11:31:33 +01:00
Remove unneeded code from buildSrc
This commit is contained in:
parent
2a01797dfa
commit
4230847224
|
@ -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)];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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
|
@ -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()))
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user