DroidFish: Changed representation of the ECO database.

This makes it around 10% smaller.
This commit is contained in:
Peter Osterlund
2016-12-16 23:09:30 +01:00
parent 4408669833
commit 7dd20129ee
4 changed files with 129 additions and 80 deletions

View File

@@ -48,9 +48,32 @@ public class EcoDb {
}
return instance;
}
public static class Result {
public final String eco; // The ECO code
public final String opn; // The opening name, or null
public final String var; // The variation name, or null
public final int distToEcoTree;
Result(String eco, String opn, String var, int d) {
this.eco = eco;
this.opn = opn;
this.var = var;
distToEcoTree = d;
}
/** Return string formatted as "eco: opn, var". */
public String getName() {
String s = eco;
if (!opn.isEmpty()) {
s = s + ": " + opn;
if (!var.isEmpty())
s = s + ", " + var;
}
return s;
}
}
/** Get ECO classification for a given tree node. Also returns distance in plies to "ECO tree". */
public Pair<String,Integer> getEco(GameTree gt) {
public Result getEco(GameTree gt) {
ArrayList<Integer> treePath = new ArrayList<Integer>(); // Path to restore gt to original node
ArrayList<Pair<GameTree.Node,Boolean>> toCache = new ArrayList<Pair<GameTree.Node,Boolean>>();
@@ -74,7 +97,7 @@ public class EcoDb {
if (idx != null) {
Node ecoNode = readNode(idx);
if (ecoNode.nameIdx != -1) {
if (ecoNode.ecoIdx != -1) {
nodeIdx = idx;
break;
}
@@ -142,10 +165,18 @@ public class EcoDb {
if (nodeIdx != -1) {
Node n = readNode(nodeIdx);
if (n.nameIdx >= 0)
return new Pair<String, Integer>(ecoNames[n.nameIdx], distToEcoTree);
String eco = "", opn = "", var = "";
if (n.ecoIdx >= 0) {
eco = strPool[n.ecoIdx];
if (n.opnIdx >= 0) {
opn = strPool[n.opnIdx];
if (n.varIdx >= 0)
var = strPool[n.varIdx];
}
return new Result(eco, opn, var, distToEcoTree);
}
}
return new Pair<String, Integer>("", 0);
return new Result("", "", "", 0);
}
/** Get all moves in the ECO tree from a given position. */
@@ -182,13 +213,15 @@ public class EcoDb {
private static class Node {
int move; // Move (compressed) leading to the position corresponding to this node
int nameIdx; // Index in names array, or -1
int ecoIdx; // Index in string array, or -1
int opnIdx; // Index in string array, or -1
int varIdx; // Index in string array, or -1
int firstChild;
int nextSibling;
}
private byte[] nodesBuffer;
private String[] ecoNames;
private String[] strPool;
private HashMap<Long, Short> posHashToNodeIdx;
private HashMap<Long, ArrayList<Short>> posHashToNodeIdx2; // Handles collisions
private final long startPosHash; // Zobrist hash for standard starting position
@@ -239,11 +272,11 @@ public class EcoDb {
break;
nNodes++;
}
nodesBuffer = new byte[nNodes * 8];
System.arraycopy(buf, 0, nodesBuffer, 0, nNodes * 8);
nodesBuffer = new byte[nNodes * 12];
System.arraycopy(buf, 0, nodesBuffer, 0, nNodes * 12);
ArrayList<String> names = new ArrayList<String>();
int idx = (nNodes + 1) * 8;
int idx = (nNodes + 1) * 12;
int start = idx;
for (int i = idx; i < buf.length; i++) {
if (buf[i] == 0) {
@@ -251,7 +284,7 @@ public class EcoDb {
start = i + 1;
}
}
ecoNames = names.toArray(new String[names.size()]);
strPool = names.toArray(new String[names.size()]);
} catch (IOException ex) {
throw new RuntimeException("Can't read ECO database");
}
@@ -272,7 +305,7 @@ public class EcoDb {
long hash = pos.zobristHash();
if (posHashToNodeIdx.get(hash) == null) {
posHashToNodeIdx.put(hash, (short)nodeIdx);
} else if (node.nameIdx != -1) {
} else if (node.ecoIdx != -1) {
ArrayList<Short> lst = null;
if (posHashToNodeIdx2.get(hash) == null) {
lst = new ArrayList<Short>();
@@ -300,11 +333,13 @@ public class EcoDb {
private static Node readNode(int index, byte[] buf) {
Node n = new Node();
int o = index * 8;
int o = index * 12;
n.move = getU16(buf, o);
n.nameIdx = getS16(buf, o + 2);
n.firstChild = getS16(buf, o + 4);
n.nextSibling = getS16(buf, o + 6);
n.ecoIdx = getS16(buf, o + 2);
n.opnIdx = getS16(buf, o + 4);
n.varIdx = getS16(buf, o + 6);
n.firstChild = getS16(buf, o + 8);
n.nextSibling = getS16(buf, o + 10);
return n;
}

View File

@@ -41,23 +41,28 @@ public class EcoBuilder {
private static class Node {
int index; // Index in nodes array
Move move; // Move leading to the position corresponding to this node
int nameIdx; // Index in names array, or -1
int ecoIdx; // Index in string array, or -1
int opnIdx; // Index in string array, or -1
int varIdx; // Index in string array, or -1
ArrayList<Node> children = new ArrayList<Node>();
Node parent;
}
private ArrayList<Node> nodes;
private ArrayList<String> names;
private HashMap<String, Integer> nameToIndex;
private ArrayList<String> strs;
private HashMap<String, Integer> strToIndex;
/** Constructor. */
private EcoBuilder() {
nodes = new ArrayList<Node>();
names = new ArrayList<String>();
nameToIndex = new HashMap<String, Integer>();
strs = new ArrayList<String>();
strToIndex = new HashMap<String, Integer>();
Node rootNode = new Node();
rootNode.index = 0;
rootNode.move = new Move(0, 0, 0);
rootNode.nameIdx = -1;
rootNode.ecoIdx = -1;
rootNode.opnIdx = -1;
rootNode.varIdx = -1;
nodes.add(rootNode);
}
@@ -94,27 +99,18 @@ public class EcoBuilder {
HashMap<String,String> headers = new HashMap<String,String>();
GameTree tree = game.tree;
tree.getHeaders(headers);
String eco = headers.get("ECO");
String opening = headers.get("Opening");
String variation = headers.get("Variation");
String name = eco + ": " + opening;
if (variation != null)
name = name + ", " + variation;
// Add name to data structures
Integer nameIdx = nameToIndex.get(name);
if (nameIdx == null) {
nameIdx = nameToIndex.size();
nameToIndex.put(name, nameIdx);
names.add(name);
}
int ecoIdx = addData(headers, "ECO");
int opnIdx = addData(headers, "Opening");
int varIdx = addData(headers, "Variation");
// Add corresponding moves to data structures
Node parent = nodes.get(0);
while (true) {
ArrayList<Move> moves = tree.variations();
if (moves.isEmpty()) {
parent.nameIdx = nameIdx;
parent.ecoIdx = ecoIdx;
parent.opnIdx = opnIdx;
parent.varIdx = varIdx;
break;
}
Move m = moves.get(0);
@@ -130,7 +126,9 @@ public class EcoBuilder {
Node node = new Node();
node.index = nodes.size();
node.move = m;
node.nameIdx = -1;
node.ecoIdx = -1;
node.opnIdx = -1;
node.varIdx = -1;
node.parent = parent;
nodes.add(node);
parent.children.add(node);
@@ -141,24 +139,42 @@ public class EcoBuilder {
}
}
/** Add ECO, opening or variation data to string pool. */
private int addData(HashMap<String, String> headers, String hdrName) {
String s = headers.get(hdrName);
if (s == null)
return -1;
Integer idx = strToIndex.get(s);
if (idx == null) {
idx = strToIndex.size();
strToIndex.put(s, idx);
strs.add(s);
}
return idx;
}
/** Write the binary ECO code data file. */
private void writeDataFile(String ecoDatFile) throws Throwable {
FileOutputStream out = new FileOutputStream(ecoDatFile);
// Write nodes
byte[] buf = new byte[8];
byte[] buf = new byte[12];
for (int i = 0; i < nodes.size(); i++) {
Node n = nodes.get(i);
int cm = n.move == null ? 0 : n.move.getCompressedMove();
buf[0] = (byte)(cm >> 8); // Move, high byte
buf[1] = (byte)(cm & 255); // Move, low byte
buf[2] = (byte)(n.nameIdx >> 8); // Index, high byte
buf[3] = (byte)(n.nameIdx & 255); // Index, low byte
buf[2] = (byte)(n.ecoIdx >> 8); // Index, high byte
buf[3] = (byte)(n.ecoIdx & 255); // Index, low byte
buf[4] = (byte)(n.opnIdx >> 8); // Index, high byte
buf[5] = (byte)(n.opnIdx & 255); // Index, low byte
buf[6] = (byte)(n.varIdx >> 8); // Index, high byte
buf[7] = (byte)(n.varIdx & 255); // Index, low byte
int firstChild = -1;
if (n.children.size() > 0)
firstChild = n.children.get(0).index;
buf[4] = (byte)(firstChild >> 8);
buf[5] = (byte)(firstChild & 255);
buf[8] = (byte)(firstChild >> 8);
buf[9] = (byte)(firstChild & 255);
int nextSibling = -1;
if (n.parent != null) {
ArrayList<Node> siblings = n.parent.children;
@@ -169,17 +185,17 @@ public class EcoBuilder {
}
}
}
buf[6] = (byte)(nextSibling >> 8);
buf[7] = (byte)(nextSibling & 255);
buf[10] = (byte)(nextSibling >> 8);
buf[11] = (byte)(nextSibling & 255);
out.write(buf);
}
for (int i = 0; i < buf.length; i++)
buf[i] = -1;
out.write(buf);
// Write names
// Write strings
buf = new byte[]{0};
for (String name : names) {
for (String name : strs) {
out.write(name.getBytes("UTF-8"));
out.write(buf);
}

View File

@@ -933,10 +933,9 @@ public class DroidChessController {
private final void updateBookHints() {
if (game != null) {
Pair<String, ArrayList<Move>> bi = computerPlayer.getBookHints(game.currPos(), localPt());
Pair<String, Integer> ecoData =
EcoDb.getInstance().getEco(game.tree);
String eco = ecoData.first;
listener.notifyBookInfo(searchId, bi.first, bi.second, eco, ecoData.second);
EcoDb.Result ecoData = EcoDb.getInstance().getEco(game.tree);
String eco = ecoData.getName();
listener.notifyBookInfo(searchId, bi.first, bi.second, eco, ecoData.distToEcoTree);
}
}
@@ -976,10 +975,9 @@ public class DroidChessController {
computerPlayer.queueAnalyzeRequest(sr);
} else if (computersTurn || ponder) {
listener.clearSearchInfo(searchId);
Pair<String, Integer> ecoData =
EcoDb.getInstance().getEco(game.tree);
String eco = ecoData.first;
listener.notifyBookInfo(searchId, "", null, eco, ecoData.second);
EcoDb.Result ecoData = EcoDb.getInstance().getEco(game.tree);
String eco = ecoData.getName();
listener.notifyBookInfo(searchId, "", null, eco, ecoData.distToEcoTree);
final Pair<Position, ArrayList<Move>> ph = game.getUCIHistory();
Position currPos = new Position(game.currPos());
long now = System.currentTimeMillis();