mirror of
https://github.com/peterosterlund2/droidfish.git
synced 2025-12-18 11:42:17 +01:00
DroidFish: Implemented DTZ/WDL tablebase hints in the GUI when only syzygy tablebases are available.
This commit is contained in:
@@ -26,6 +26,7 @@ import org.petero.droidfish.gamelogic.Move;
|
||||
import org.petero.droidfish.gamelogic.Piece;
|
||||
import org.petero.droidfish.gamelogic.Position;
|
||||
import org.petero.droidfish.gamelogic.UndoInfo;
|
||||
import org.petero.droidfish.gtb.ProbeResult;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
@@ -57,22 +58,17 @@ public abstract class ChessBoard extends View {
|
||||
|
||||
List<Move> moveHints;
|
||||
|
||||
/** Decoration for a square. Currently the only possible decoration is a number. */
|
||||
/** Decoration for a square. Currently the only possible decoration is a tablebase probe result. */
|
||||
public final static class SquareDecoration implements Comparable<SquareDecoration> {
|
||||
int sq;
|
||||
int number;
|
||||
public SquareDecoration(int sq, int number) {
|
||||
ProbeResult tbData;
|
||||
public SquareDecoration(int sq, ProbeResult tbData) {
|
||||
this.sq = sq;
|
||||
this.number = number;
|
||||
this.tbData = tbData;
|
||||
}
|
||||
@Override
|
||||
public int compareTo(SquareDecoration another) {
|
||||
int M0 = 100000;
|
||||
int n = number;
|
||||
int s1 = (n > 0) ? M0 - n : ((n == 0) ? 0 : -M0-n);
|
||||
n = another.number;
|
||||
int s2 = (n > 0) ? M0 - n : ((n == 0) ? 0 : -M0-n);
|
||||
return s2 - s1;
|
||||
return tbData.compareTo(another.tbData);
|
||||
}
|
||||
}
|
||||
private ArrayList<SquareDecoration> decorations;
|
||||
@@ -681,20 +677,42 @@ public abstract class ChessBoard extends View {
|
||||
int xCrd = getXCrd(Position.getX(sq));
|
||||
int yCrd = getYCrd(Position.getY(sq));
|
||||
|
||||
int num = sd.number;
|
||||
String s;
|
||||
if (num > 0)
|
||||
s = "+" + String.valueOf(num);
|
||||
else if (num < 0)
|
||||
s = String.valueOf(num);
|
||||
else
|
||||
s = "0";
|
||||
|
||||
Rect bounds = new Rect();
|
||||
decorationPaint.getTextBounds(s, 0, s.length(), bounds);
|
||||
xCrd += (sqSize - (bounds.left + bounds.right)) / 2;
|
||||
yCrd += (sqSize - (bounds.top + bounds.bottom)) / 2;
|
||||
canvas.drawText(s, xCrd, yCrd, decorationPaint);
|
||||
String s = null;
|
||||
int wdl = sd.tbData.wdl;
|
||||
int num = (sd.tbData.score + 1) / 2;
|
||||
switch (sd.tbData.type) {
|
||||
case DTM:
|
||||
if (wdl > 0)
|
||||
s = "+" + String.valueOf(num);
|
||||
else if (wdl < 0)
|
||||
s = "-" + String.valueOf(num);
|
||||
else
|
||||
s = "0";
|
||||
break;
|
||||
case DTZ:
|
||||
if (wdl > 0)
|
||||
s = "W" + String.valueOf(num);
|
||||
else if (wdl < 0)
|
||||
s = "L" + String.valueOf(num);
|
||||
else
|
||||
s = "0";
|
||||
break;
|
||||
case WDL:
|
||||
if (wdl > 0)
|
||||
s = "W";
|
||||
else if (wdl < 0)
|
||||
s = "L";
|
||||
else
|
||||
s = "0";
|
||||
break;
|
||||
}
|
||||
if (s != null) {
|
||||
Rect bounds = new Rect();
|
||||
decorationPaint.getTextBounds(s, 0, s.length(), bounds);
|
||||
xCrd += (sqSize - (bounds.left + bounds.right)) / 2;
|
||||
yCrd += (sqSize - (bounds.top + bounds.bottom)) / 2;
|
||||
canvas.drawText(s, xCrd, yCrd, decorationPaint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -58,6 +58,7 @@ import org.petero.droidfish.gamelogic.PgnToken;
|
||||
import org.petero.droidfish.gamelogic.GameTree.Node;
|
||||
import org.petero.droidfish.gamelogic.TimeControlData;
|
||||
import org.petero.droidfish.gtb.Probe;
|
||||
import org.petero.droidfish.gtb.ProbeResult;
|
||||
|
||||
import com.kalab.chess.enginesupport.ChessEngine;
|
||||
import com.kalab.chess.enginesupport.ChessEngineResolver;
|
||||
@@ -147,7 +148,6 @@ public class DroidFish extends Activity implements GUIInterface {
|
||||
// FIXME!!! Computer clock should stop if phone turned off (computer stops thinking if unplugged)
|
||||
// FIXME!!! Add support for "no time control" and "hour-glass time control" as defined by the PGN standard
|
||||
|
||||
// FIXME!!! Online play on FICS
|
||||
// FIXME!!! Add chess960 support
|
||||
// FIXME!!! Implement "hint" feature
|
||||
|
||||
@@ -1234,7 +1234,8 @@ public class DroidFish extends Activity implements GUIInterface {
|
||||
private final void setEngineOptions(boolean restart) {
|
||||
computeNetEngineID();
|
||||
ctrl.setEngineOptions(new EngineOptions(engineOptions), restart);
|
||||
Probe.getInstance().setPath(engineOptions.gtbPath, egtbForceReload);
|
||||
Probe.getInstance().setPath(engineOptions.gtbPath, engineOptions.rtbPath,
|
||||
egtbForceReload);
|
||||
egtbForceReload = false;
|
||||
}
|
||||
|
||||
@@ -1259,14 +1260,14 @@ public class DroidFish extends Activity implements GUIInterface {
|
||||
}
|
||||
|
||||
Probe gtbProbe = Probe.getInstance();
|
||||
ArrayList<Pair<Integer, Integer>> x = gtbProbe.movePieceProbe(cb.pos, sq);
|
||||
ArrayList<Pair<Integer,ProbeResult>> x = gtbProbe.movePieceProbe(cb.pos, sq);
|
||||
if (x == null) {
|
||||
cb.setSquareDecorations(null);
|
||||
return;
|
||||
}
|
||||
|
||||
ArrayList<SquareDecoration> sd = new ArrayList<SquareDecoration>();
|
||||
for (Pair<Integer,Integer> p : x)
|
||||
for (Pair<Integer,ProbeResult> p : x)
|
||||
sd.add(new SquareDecoration(p.first, p.second));
|
||||
cb.setSquareDecorations(sd);
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ import org.petero.droidfish.gamelogic.Piece;
|
||||
import org.petero.droidfish.gamelogic.Position;
|
||||
import org.petero.droidfish.gamelogic.TextIO;
|
||||
import org.petero.droidfish.gtb.Probe;
|
||||
import org.petero.droidfish.gtb.ProbeResult;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
@@ -256,14 +257,14 @@ public class EditBoard extends Activity {
|
||||
}
|
||||
|
||||
Probe gtbProbe = Probe.getInstance();
|
||||
ArrayList<Pair<Integer, Integer>> x = gtbProbe.relocatePieceProbe(cb.pos, sq);
|
||||
ArrayList<Pair<Integer,ProbeResult>> x = gtbProbe.relocatePieceProbe(cb.pos, sq);
|
||||
if (x == null) {
|
||||
cb.setSquareDecorations(null);
|
||||
return;
|
||||
}
|
||||
|
||||
ArrayList<SquareDecoration> sd = new ArrayList<SquareDecoration>();
|
||||
for (Pair<Integer,Integer> p : x)
|
||||
for (Pair<Integer,ProbeResult> p : x)
|
||||
sd.add(new SquareDecoration(p.first, p.second));
|
||||
cb.setSquareDecorations(sd);
|
||||
}
|
||||
|
||||
@@ -214,15 +214,21 @@ public class Position {
|
||||
return whiteMove ? wKingSq : bKingSq;
|
||||
}
|
||||
|
||||
/**
|
||||
* Count number of pieces of a certain type.
|
||||
*/
|
||||
/** Count number of pieces of a certain type. */
|
||||
public final int nPieces(int pType) {
|
||||
int ret = 0;
|
||||
for (int sq = 0; sq < 64; sq++) {
|
||||
for (int sq = 0; sq < 64; sq++)
|
||||
if (squares[sq] == pType)
|
||||
ret++;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Count total number of pieces. */
|
||||
public final int nPieces() {
|
||||
int ret = 0;
|
||||
for (int sq = 0; sq < 64; sq++)
|
||||
if (squares[sq] != Piece.EMPTY)
|
||||
ret++;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,53 +27,56 @@ import org.petero.droidfish.gamelogic.Piece;
|
||||
import org.petero.droidfish.gamelogic.Position;
|
||||
import org.petero.droidfish.gamelogic.UndoInfo;
|
||||
|
||||
/** Interface between Position class and GTB probing code. */
|
||||
/** Interface between Position class and GTB/RTB probing code. */
|
||||
public class Probe {
|
||||
private final GtbProbe gtb;
|
||||
private final RtbProbe rtb;
|
||||
private final int whiteSquares[];
|
||||
private final int blackSquares[];
|
||||
private final byte whitePieces[];
|
||||
private final byte blackPieces[];
|
||||
|
||||
private static final Probe INSTANCE = new Probe();
|
||||
private static final Probe instance = new Probe();
|
||||
|
||||
/** Get singleton instance. */
|
||||
public static Probe getInstance() {
|
||||
return INSTANCE;
|
||||
return instance;
|
||||
}
|
||||
|
||||
/** Constructor. */
|
||||
private Probe() {
|
||||
gtb = new GtbProbe();
|
||||
rtb = new RtbProbe();
|
||||
whiteSquares = new int[65];
|
||||
blackSquares = new int[65];
|
||||
whitePieces = new byte[65];
|
||||
blackPieces = new byte[65];
|
||||
}
|
||||
|
||||
public void setPath(String tbPath, boolean forceReload) {
|
||||
gtb.setPath(tbPath, forceReload);
|
||||
public void setPath(String gtbPath, String rtbPath, boolean forceReload) {
|
||||
gtb.setPath(gtbPath, forceReload);
|
||||
rtb.setPath(rtbPath, forceReload);
|
||||
}
|
||||
|
||||
public static final class ProbeResult {
|
||||
private static final class GtbProbeResult {
|
||||
public final static int DRAW = 0;
|
||||
public final static int WMATE = 1;
|
||||
public final static int BMATE = 2;
|
||||
public final static int UNKNOWN = 3;
|
||||
|
||||
public int result;
|
||||
public int movesToMate; // Full moves to mate, or 0 if DRAW or UNKNOWN.
|
||||
public int pliesToMate; // Plies to mate, or 0 if DRAW or UNKNOWN.
|
||||
}
|
||||
|
||||
/**
|
||||
* Probe table bases.
|
||||
* Probe GTB tablebases.
|
||||
* @param pos The position to probe.
|
||||
* @param result Two element array. Set to [tbinfo, plies].
|
||||
* @return True if success.
|
||||
*/
|
||||
public final ProbeResult probeHard(Position pos) {
|
||||
ProbeResult ret = probeHardRaw(pos);
|
||||
if (ret.result == ProbeResult.DRAW && pos.getEpSquare() != -1) {
|
||||
private final GtbProbeResult gtbProbe(Position pos) {
|
||||
GtbProbeResult ret = gtbProbeRaw(pos);
|
||||
if (ret.result == GtbProbeResult.DRAW && pos.getEpSquare() != -1) {
|
||||
ArrayList<Move> moveList = MoveGen.instance.legalMoves(pos);
|
||||
int pawn = pos.whiteMove ? Piece.WPAWN : Piece.BPAWN;
|
||||
int maxMate = -1;
|
||||
@@ -82,29 +85,29 @@ public class Probe {
|
||||
if ((move.to != pos.getEpSquare()) || (pos.getPiece(move.from) != pawn))
|
||||
return ret;
|
||||
pos.makeMove(move, ui);
|
||||
ProbeResult ret2 = probeHard(pos);
|
||||
GtbProbeResult ret2 = gtbProbe(pos);
|
||||
pos.unMakeMove(move, ui);
|
||||
switch (ret2.result) {
|
||||
case ProbeResult.DRAW:
|
||||
case GtbProbeResult.DRAW:
|
||||
break;
|
||||
case ProbeResult.WMATE:
|
||||
case ProbeResult.BMATE:
|
||||
maxMate = Math.max(maxMate, ret2.movesToMate);
|
||||
case GtbProbeResult.WMATE:
|
||||
case GtbProbeResult.BMATE:
|
||||
maxMate = Math.max(maxMate, ret2.pliesToMate);
|
||||
break;
|
||||
case ProbeResult.UNKNOWN:
|
||||
ret.result = ProbeResult.UNKNOWN;
|
||||
case GtbProbeResult.UNKNOWN:
|
||||
ret.result = GtbProbeResult.UNKNOWN;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
if (maxMate != -1) {
|
||||
ret.result = pos.whiteMove ? ProbeResult.BMATE : ProbeResult.WMATE;
|
||||
ret.movesToMate = maxMate;
|
||||
ret.result = pos.whiteMove ? GtbProbeResult.BMATE : GtbProbeResult.WMATE;
|
||||
ret.pliesToMate = maxMate;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private final ProbeResult probeHardRaw(Position pos) {
|
||||
private final GtbProbeResult gtbProbeRaw(Position pos) {
|
||||
int castleMask = 0;
|
||||
if (pos.a1Castle()) castleMask |= GtbProbe.A1_CASTLE;
|
||||
if (pos.h1Castle()) castleMask |= GtbProbe.H1_CASTLE;
|
||||
@@ -183,33 +186,81 @@ public class Probe {
|
||||
whiteSquares, blackSquares, whitePieces, blackPieces,
|
||||
result);
|
||||
}
|
||||
ProbeResult ret = new ProbeResult();
|
||||
GtbProbeResult ret = new GtbProbeResult();
|
||||
if (res) {
|
||||
switch (result[0]) {
|
||||
case GtbProbe.DRAW:
|
||||
ret.result = ProbeResult.DRAW;
|
||||
ret.movesToMate = 0;
|
||||
ret.result = GtbProbeResult.DRAW;
|
||||
ret.pliesToMate = 0;
|
||||
break;
|
||||
case GtbProbe.WMATE:
|
||||
ret.result = ProbeResult.WMATE;
|
||||
ret.movesToMate = (result[1] + 1) / 2;
|
||||
ret.result = GtbProbeResult.WMATE;
|
||||
ret.pliesToMate = result[1];
|
||||
break;
|
||||
case GtbProbe.BMATE:
|
||||
ret.result = ProbeResult.BMATE;
|
||||
ret.movesToMate = (result[1] + 1) / 2;
|
||||
ret.result = GtbProbeResult.BMATE;
|
||||
ret.pliesToMate = result[1];
|
||||
break;
|
||||
default:
|
||||
ret.result = ProbeResult.UNKNOWN;
|
||||
ret.movesToMate = 0;
|
||||
ret.result = GtbProbeResult.UNKNOWN;
|
||||
ret.pliesToMate = 0;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
ret.result = ProbeResult.UNKNOWN;
|
||||
ret.movesToMate = 0;
|
||||
ret.result = GtbProbeResult.UNKNOWN;
|
||||
ret.pliesToMate = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private final ProbeResult rtbProbe(Position pos) {
|
||||
if (pos.nPieces() > 6)
|
||||
return new ProbeResult(ProbeResult.Type.NONE, 0, 0);
|
||||
|
||||
rtb.initIfNeeded();
|
||||
|
||||
byte[] squares = new byte[64];
|
||||
for (int sq = 0; sq < 64; sq++)
|
||||
squares[sq] = (byte)pos.getPiece(sq);
|
||||
int[] result = new int[2];
|
||||
rtb.probe(squares, pos.whiteMove, pos.getEpSquare(), pos.getCastleMask(),
|
||||
pos.halfMoveClock, pos.fullMoveCounter, result);
|
||||
int wdl = 0;
|
||||
if (result[1] != RtbProbe.NOINFO) {
|
||||
int score = result[1];
|
||||
if (score > 0) {
|
||||
wdl = 1;
|
||||
} else if (score < 0) {
|
||||
wdl = -1;
|
||||
score = -score;
|
||||
}
|
||||
return new ProbeResult(ProbeResult.Type.DTZ, wdl, score);
|
||||
} else if (result[0] != RtbProbe.NOINFO) {
|
||||
return new ProbeResult(ProbeResult.Type.WDL, result[0], 0);
|
||||
} else {
|
||||
return new ProbeResult(ProbeResult.Type.NONE, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
final ProbeResult probe(Position pos) {
|
||||
GtbProbeResult gtbRes = gtbProbe(pos);
|
||||
if (gtbRes.result != GtbProbeResult.UNKNOWN) {
|
||||
int wdl = 0;
|
||||
int score = 0;
|
||||
if (gtbRes.result == GtbProbeResult.WMATE) {
|
||||
wdl = 1;
|
||||
score = gtbRes.pliesToMate;
|
||||
} else if (gtbRes.result == GtbProbeResult.BMATE) {
|
||||
wdl = -1;
|
||||
score = gtbRes.pliesToMate;
|
||||
}
|
||||
if (!pos.whiteMove)
|
||||
wdl = -wdl;
|
||||
return new ProbeResult(ProbeResult.Type.DTM, wdl, score);
|
||||
}
|
||||
return rtbProbe(pos);
|
||||
}
|
||||
|
||||
/** Return a list of all moves in moveList that are not known to be non-optimal.
|
||||
* Returns null if no legal move could be excluded. */
|
||||
public final ArrayList<Move> removeNonOptimal(Position pos, ArrayList<Move> moveList) {
|
||||
@@ -220,16 +271,16 @@ public class Probe {
|
||||
UndoInfo ui = new UndoInfo();
|
||||
for (Move m : moveList) {
|
||||
pos.makeMove(m, ui);
|
||||
ProbeResult res = probeHard(pos);
|
||||
GtbProbeResult res = gtbProbe(pos);
|
||||
pos.unMakeMove(m, ui);
|
||||
if (res.result == ProbeResult.UNKNOWN) {
|
||||
if (res.result == GtbProbeResult.UNKNOWN) {
|
||||
unknownMoves.add(m);
|
||||
} else {
|
||||
int wScore;
|
||||
if (res.result == ProbeResult.WMATE)
|
||||
wScore = MATE0 - res.movesToMate;
|
||||
else if (res.result == ProbeResult.BMATE)
|
||||
wScore = -(MATE0 - res.movesToMate);
|
||||
if (res.result == GtbProbeResult.WMATE)
|
||||
wScore = MATE0 - res.pliesToMate;
|
||||
else if (res.result == GtbProbeResult.BMATE)
|
||||
wScore = -(MATE0 - res.pliesToMate);
|
||||
else
|
||||
wScore = 0;
|
||||
int score = pos.whiteMove ? wScore : -wScore;
|
||||
@@ -251,11 +302,11 @@ public class Probe {
|
||||
|
||||
/** For a given position and from square, return EGTB information
|
||||
* about all legal destination squares. Return null if no information available. */
|
||||
public final ArrayList<Pair<Integer,Integer>> movePieceProbe(Position pos, int fromSq) {
|
||||
public final ArrayList<Pair<Integer,ProbeResult>> movePieceProbe(Position pos, int fromSq) {
|
||||
int p = pos.getPiece(fromSq);
|
||||
if ((p == Piece.EMPTY) || (pos.whiteMove != Piece.isWhite(p)))
|
||||
return null;
|
||||
ArrayList<Pair<Integer,Integer>> ret = new ArrayList<Pair<Integer,Integer>>();
|
||||
ArrayList<Pair<Integer,ProbeResult>> ret = new ArrayList<Pair<Integer,ProbeResult>>();
|
||||
|
||||
ArrayList<Move> moveList = new MoveGen().legalMoves(pos);
|
||||
UndoInfo ui = new UndoInfo();
|
||||
@@ -263,17 +314,18 @@ public class Probe {
|
||||
if (m.from != fromSq)
|
||||
continue;
|
||||
pos.makeMove(m, ui);
|
||||
ProbeResult res = probeHard(pos);
|
||||
boolean isZeroing = pos.halfMoveClock == 0;
|
||||
ProbeResult res = probe(pos);
|
||||
pos.unMakeMove(m, ui);
|
||||
if (res.result == ProbeResult.UNKNOWN)
|
||||
if (res.type == ProbeResult.Type.NONE)
|
||||
continue;
|
||||
int score = 0;
|
||||
if (res.result == ProbeResult.WMATE) {
|
||||
score = pos.whiteMove ? res.movesToMate + 1 : -res.movesToMate;
|
||||
} else if (res.result == ProbeResult.BMATE) {
|
||||
score = pos.whiteMove ? -res.movesToMate : res.movesToMate + 1;
|
||||
res.wdl = -res.wdl;
|
||||
if (isZeroing && (res.type == ProbeResult.Type.DTZ)) {
|
||||
res.score = 1;
|
||||
} else if (res.type != ProbeResult.Type.WDL) {
|
||||
res.score++;
|
||||
}
|
||||
ret.add(new Pair<Integer,Integer>(m.to, score));
|
||||
ret.add(new Pair<Integer,ProbeResult>(m.to, res));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -281,12 +333,12 @@ public class Probe {
|
||||
/** For a given position and from square, return EGTB information
|
||||
* about all legal alternative positions for the piece on from square.
|
||||
* Return null if no information is available. */
|
||||
public final ArrayList<Pair<Integer, Integer>> relocatePieceProbe(Position pos, int fromSq) {
|
||||
public final ArrayList<Pair<Integer,ProbeResult>> relocatePieceProbe(Position pos, int fromSq) {
|
||||
int p = pos.getPiece(fromSq);
|
||||
if (p == Piece.EMPTY)
|
||||
return null;
|
||||
boolean isPawn = (Piece.makeWhite(p) == Piece.WPAWN);
|
||||
ArrayList<Pair<Integer,Integer>> ret = new ArrayList<Pair<Integer,Integer>>();
|
||||
ArrayList<Pair<Integer,ProbeResult>> ret = new ArrayList<Pair<Integer,ProbeResult>>();
|
||||
for (int sq = 0; sq < 64; sq++) {
|
||||
if ((sq != fromSq) && (pos.getPiece(sq) != Piece.EMPTY))
|
||||
continue;
|
||||
@@ -294,18 +346,14 @@ public class Probe {
|
||||
continue;
|
||||
pos.setPiece(fromSq, Piece.EMPTY);
|
||||
pos.setPiece(sq, p);
|
||||
ProbeResult res = probeHard(pos);
|
||||
ProbeResult res = probe(pos);
|
||||
pos.setPiece(sq, Piece.EMPTY);
|
||||
pos.setPiece(fromSq, p);
|
||||
if (res.result == ProbeResult.UNKNOWN)
|
||||
if (res.type == ProbeResult.Type.NONE)
|
||||
continue;
|
||||
int score = 0;
|
||||
if (res.result == ProbeResult.WMATE) {
|
||||
score = res.movesToMate;
|
||||
} else if (res.result == ProbeResult.BMATE) {
|
||||
score = -res.movesToMate;
|
||||
}
|
||||
ret.add(new Pair<Integer,Integer>(sq, score));
|
||||
if (!pos.whiteMove)
|
||||
res.wdl = -res.wdl;
|
||||
ret.add(new Pair<Integer,ProbeResult>(sq, res));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
96
DroidFish/src/org/petero/droidfish/gtb/ProbeResult.java
Normal file
96
DroidFish/src/org/petero/droidfish/gtb/ProbeResult.java
Normal file
@@ -0,0 +1,96 @@
|
||||
package org.petero.droidfish.gtb;
|
||||
|
||||
/** Tablebase probe result. */
|
||||
public final class ProbeResult implements Comparable<ProbeResult> {
|
||||
public static enum Type {
|
||||
DTM, // score is distance (full moves) to mate, or 0
|
||||
DTZ, // score is distance (full moves) to zeroing move, or 0
|
||||
WDL, // score is +-1 or 0
|
||||
NONE, // No info available, score is 0
|
||||
}
|
||||
|
||||
public Type type;
|
||||
public int wdl; // +1 if if side to move wins, 0 for draw, -1 for loss
|
||||
public int score; // Distance to win in plies. Always >= 0.
|
||||
// Note! Zero if side to move is checkmated.
|
||||
|
||||
ProbeResult(Type type, int wdl, int score) {
|
||||
this.type = type;
|
||||
this.wdl = wdl;
|
||||
this.score = score;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return > 0 if other is "better" than this.
|
||||
* A win is better than a draw, which is better than a loss.
|
||||
* A DTM win is better than a DTZ win, which is better than a WDL win.
|
||||
* A WDL loss is better than a DTZ loss, which is better than a DTM loss.
|
||||
*/
|
||||
@Override
|
||||
public final int compareTo(ProbeResult other) {
|
||||
final Type type1 = this.type;
|
||||
final Type type2 = other.type;
|
||||
final boolean none1 = type1 == Type.NONE;
|
||||
final boolean none2 = type2 == Type.NONE;
|
||||
if (none1 != none2)
|
||||
return none2 ? -1 : 1;
|
||||
if (none1)
|
||||
return 0;
|
||||
final int wdl1 = this.wdl;
|
||||
final int wdl2 = other.wdl;
|
||||
final boolean win1 = wdl1 > 0;
|
||||
final boolean win2 = wdl2 > 0;
|
||||
if (win1 != win2)
|
||||
return win2 ? 1 : -1;
|
||||
final boolean draw1 = wdl1 == 0;
|
||||
final boolean draw2 = wdl2 == 0;
|
||||
if (draw1 != draw2)
|
||||
return draw2 ? 1 : -1;
|
||||
final int score1 = this.score;
|
||||
final int score2 = other.score;
|
||||
if (win1) {
|
||||
final boolean dtm1 = type1 == Type.DTM;
|
||||
final boolean dtm2 = type2 == Type.DTM;
|
||||
if (dtm1 != dtm2)
|
||||
return dtm2 ? 1 : -1;
|
||||
if (dtm1)
|
||||
return -compareScore(wdl1, score1, wdl2, score2);
|
||||
final boolean dtz1 = type1 == Type.DTZ;
|
||||
final boolean dtz2 = type2 == Type.DTZ;
|
||||
if (dtz1 != dtz2)
|
||||
return dtz2 ? 1 : -1;
|
||||
return -compareScore(wdl1, score1, wdl2, score2);
|
||||
} else if (draw1) {
|
||||
return 0;
|
||||
} else {
|
||||
final boolean wdlType1 = type1 == Type.WDL;
|
||||
final boolean wdlType2 = type2 == Type.WDL;
|
||||
if (wdlType1 != wdlType2)
|
||||
return wdlType2 ? 1 : -1;
|
||||
if (wdlType1)
|
||||
return -compareScore(wdl1, score1, wdl2, score2);
|
||||
final boolean dtzType1 = type1 == Type.DTZ;
|
||||
final boolean dtzType2 = type2 == Type.DTZ;
|
||||
if (dtzType1 != dtzType2)
|
||||
return dtzType2 ? 1 : -1;
|
||||
return -compareScore(wdl1, score1, wdl2, score2);
|
||||
}
|
||||
}
|
||||
|
||||
/** Return f((wdl1,score1)) - f((wdl2,score2)), where f(x) modifies
|
||||
* the score so that larger values are better. */
|
||||
final static int compareScore(int wdl1, int score1,
|
||||
int wdl2, int score2) {
|
||||
final int M = 1000;
|
||||
if (wdl1 > 0)
|
||||
score1 = M - score1;
|
||||
else if (wdl1 < 0)
|
||||
score1 = -M + score1;
|
||||
|
||||
if (wdl2 > 0)
|
||||
score2 = M - score2;
|
||||
else if (wdl2 < 0)
|
||||
score2 = -M + score2;
|
||||
return score1 - score2;
|
||||
}
|
||||
}
|
||||
95
DroidFish/src/org/petero/droidfish/gtb/RtbProbe.java
Normal file
95
DroidFish/src/org/petero/droidfish/gtb/RtbProbe.java
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
DroidFish - An Android chess program.
|
||||
Copyright (C) 2011-2014 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 org.petero.droidfish.gtb;
|
||||
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
import org.petero.droidfish.engine.EngineUtil;
|
||||
|
||||
/** */
|
||||
public class RtbProbe {
|
||||
static {
|
||||
System.loadLibrary("rtb");
|
||||
}
|
||||
|
||||
private String currTbPath = "";
|
||||
private ConcurrentLinkedQueue<String> tbPathQueue = new ConcurrentLinkedQueue<String>();
|
||||
|
||||
RtbProbe() {
|
||||
}
|
||||
|
||||
public final void setPath(String tbPath, boolean forceReload) {
|
||||
if (forceReload || !tbPathQueue.isEmpty() || !currTbPath.equals(tbPath)) {
|
||||
tbPathQueue.add(tbPath);
|
||||
Thread t = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// Sleep 0.4s to increase probability that engine
|
||||
// is initialized before TB.
|
||||
try { Thread.sleep(400); } catch (InterruptedException e) { }
|
||||
initIfNeeded();
|
||||
}
|
||||
});
|
||||
t.setPriority(Thread.MIN_PRIORITY);
|
||||
t.start();
|
||||
}
|
||||
}
|
||||
|
||||
public final synchronized void initIfNeeded() {
|
||||
String path = tbPathQueue.poll();
|
||||
while (!tbPathQueue.isEmpty())
|
||||
path = tbPathQueue.poll();
|
||||
if (path != null) {
|
||||
currTbPath = path;
|
||||
synchronized (EngineUtil.nativeLock) {
|
||||
init(currTbPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public final static int NOINFO = 1000;
|
||||
|
||||
/**
|
||||
* Probe table bases.
|
||||
* @param squares Array of length 64, see Position class.
|
||||
* @param wtm True if white to move.
|
||||
* @param epSq En passant square, see Position class.
|
||||
* @param castleMask Castle mask, see Position class.
|
||||
* @param halfMoveClock half move clock, see Position class.
|
||||
* @param fullMoveCounter Full move counter, see Position class.
|
||||
* @param result Two element array. Set to [wdlScore, dtzScore].
|
||||
* The wdl score is one of: 0: Draw
|
||||
* 1: win for side to move
|
||||
* -1: loss for side to move
|
||||
* NOINFO: No info available
|
||||
* The dtz score is one of: 0: Draw
|
||||
* x>0: Win in x plies
|
||||
* x<0: Loss in -x plies
|
||||
* NOINFO: No info available
|
||||
* @return True if success.
|
||||
*/
|
||||
public final native void probe(byte[] squares,
|
||||
boolean wtm,
|
||||
int epSq, int castleMask,
|
||||
int halfMoveClock,
|
||||
int fullMoveCounter,
|
||||
int[] result);
|
||||
|
||||
private final native static boolean init(String tbPath);
|
||||
}
|
||||
Reference in New Issue
Block a user