mirror of
https://github.com/peterosterlund2/droidfish.git
synced 2025-12-18 11:42:17 +01:00
Merge branch 'eco-code'.
Re-implemented functionality to be more CPU efficient.
This commit is contained in:
11
DroidFish/.externalToolBuilders/ECO_Builder.launch
Normal file
11
DroidFish/.externalToolBuilders/ECO_Builder.launch
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramBuilderLaunchConfigurationType">
|
||||||
|
<stringAttribute key="org.eclipse.debug.core.ATTR_REFRESH_SCOPE" value="${working_set:<?xml version="1.0" encoding="UTF-8"?> <resources> <item path="/DroidFish/assets/eco.dat" type="1"/> </resources>}"/>
|
||||||
|
<booleanAttribute key="org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND" value="false"/>
|
||||||
|
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_BUILD_SCOPE" value="${working_set:<?xml version="1.0" encoding="UTF-8"?> <resources> <item path="/DroidFish/src/org/petero/droidfish" type="2"/> </resources>}"/>
|
||||||
|
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="/usr/bin/java"/>
|
||||||
|
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_RUN_BUILD_KINDS" value="full,incremental,auto,"/>
|
||||||
|
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="org.petero.droidfish/buildtools/EcoBuilder ${workspace_loc:/DroidFish/src/org/petero/droidfish/buildtools/eco.pgn} ${workspace_loc:/DroidFish/assets/eco.dat}"/>
|
||||||
|
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED" value="true"/>
|
||||||
|
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/DroidFish/bin/classes}"/>
|
||||||
|
</launchConfiguration>
|
||||||
@@ -40,6 +40,16 @@
|
|||||||
</dictionary>
|
</dictionary>
|
||||||
</arguments>
|
</arguments>
|
||||||
</buildCommand>
|
</buildCommand>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
|
||||||
|
<triggers>auto,full,incremental,</triggers>
|
||||||
|
<arguments>
|
||||||
|
<dictionary>
|
||||||
|
<key>LaunchConfigHandle</key>
|
||||||
|
<value><project>/.externalToolBuilders/ECO_Builder.launch</value>
|
||||||
|
</dictionary>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
<buildCommand>
|
<buildCommand>
|
||||||
<name>org.eclipse.andmore.ApkBuilder</name>
|
<name>org.eclipse.andmore.ApkBuilder</name>
|
||||||
<arguments>
|
<arguments>
|
||||||
|
|||||||
1
DroidFish/assets/.gitignore
vendored
1
DroidFish/assets/.gitignore
vendored
@@ -9,3 +9,4 @@
|
|||||||
/stockfish-x86
|
/stockfish-x86
|
||||||
/stockfish-x86_64
|
/stockfish-x86_64
|
||||||
/stockfish-x86-nopie
|
/stockfish-x86-nopie
|
||||||
|
/eco.dat
|
||||||
|
|||||||
@@ -162,7 +162,6 @@ public class DroidFish extends Activity
|
|||||||
|
|
||||||
// FIXME!!! Show extended book info. (Win percent, number of games, performance rating, etc.)
|
// FIXME!!! Show extended book info. (Win percent, number of games, performance rating, etc.)
|
||||||
// FIXME!!! Green color for "main move". Red color for "don't play in tournaments" moves.
|
// FIXME!!! Green color for "main move". Red color for "don't play in tournaments" moves.
|
||||||
// FIXME!!! ECO opening codes
|
|
||||||
|
|
||||||
// FIXME!!! Option to display coordinates in border outside chess board.
|
// FIXME!!! Option to display coordinates in border outside chess board.
|
||||||
|
|
||||||
@@ -1450,7 +1449,7 @@ public class DroidFish extends Activity
|
|||||||
try {
|
try {
|
||||||
String engine = settings.getString("engine", "stockfish");
|
String engine = settings.getString("engine", "stockfish");
|
||||||
if (EngineUtil.isNetEngine(engine)) {
|
if (EngineUtil.isNetEngine(engine)) {
|
||||||
String[] lines = Util.readFile(engine);
|
String[] lines = FileUtil.readFile(engine);
|
||||||
if (lines.length >= 3)
|
if (lines.length >= 3)
|
||||||
id = lines[1] + ":" + lines[2];
|
id = lines[1] + ":" + lines[2];
|
||||||
}
|
}
|
||||||
@@ -1948,6 +1947,7 @@ public class DroidFish extends Activity
|
|||||||
private String thinkingStr1 = "";
|
private String thinkingStr1 = "";
|
||||||
private String thinkingStr2 = "";
|
private String thinkingStr2 = "";
|
||||||
private String bookInfoStr = "";
|
private String bookInfoStr = "";
|
||||||
|
private String ecoInfoStr = "";
|
||||||
private String variantStr = "";
|
private String variantStr = "";
|
||||||
private ArrayList<ArrayList<Move>> pvMoves = new ArrayList<ArrayList<Move>>();
|
private ArrayList<ArrayList<Move>> pvMoves = new ArrayList<ArrayList<Move>>();
|
||||||
private ArrayList<Move> bookMoves = null;
|
private ArrayList<Move> bookMoves = null;
|
||||||
@@ -1958,8 +1958,9 @@ public class DroidFish extends Activity
|
|||||||
thinkingStr1 = ti.pvStr;
|
thinkingStr1 = ti.pvStr;
|
||||||
thinkingStr2 = ti.statStr;
|
thinkingStr2 = ti.statStr;
|
||||||
bookInfoStr = ti.bookInfo;
|
bookInfoStr = ti.bookInfo;
|
||||||
this.pvMoves = ti.pvMoves;
|
ecoInfoStr = ti.eco;
|
||||||
this.bookMoves = ti.bookMoves;
|
pvMoves = ti.pvMoves;
|
||||||
|
bookMoves = ti.bookMoves;
|
||||||
updateThinkingInfo();
|
updateThinkingInfo();
|
||||||
|
|
||||||
if (ctrl.computerBusy()) {
|
if (ctrl.computerBusy()) {
|
||||||
@@ -1986,18 +1987,20 @@ public class DroidFish extends Activity
|
|||||||
}
|
}
|
||||||
thinking.setText(s, TextView.BufferType.SPANNABLE);
|
thinking.setText(s, TextView.BufferType.SPANNABLE);
|
||||||
}
|
}
|
||||||
if (mShowBookHints && (bookInfoStr.length() > 0)) {
|
if (mShowBookHints && !ecoInfoStr.isEmpty()) {
|
||||||
String s = "";
|
String s = thinkingEmpty ? "" : "<br>";
|
||||||
if (!thinkingEmpty)
|
s += ecoInfoStr;
|
||||||
s += "<br>";
|
thinking.append(Html.fromHtml(s));
|
||||||
|
thinkingEmpty = false;
|
||||||
|
}
|
||||||
|
if (mShowBookHints && !bookInfoStr.isEmpty()) {
|
||||||
|
String s = thinkingEmpty ? "" : "<br>";
|
||||||
s += Util.boldStart + getString(R.string.book) + Util.boldStop + bookInfoStr;
|
s += Util.boldStart + getString(R.string.book) + Util.boldStop + bookInfoStr;
|
||||||
thinking.append(Html.fromHtml(s));
|
thinking.append(Html.fromHtml(s));
|
||||||
thinkingEmpty = false;
|
thinkingEmpty = false;
|
||||||
}
|
}
|
||||||
if (showVariationLine && (variantStr.indexOf(' ') >= 0)) {
|
if (showVariationLine && (variantStr.indexOf(' ') >= 0)) {
|
||||||
String s = "";
|
String s = thinkingEmpty ? "" : "<br>";
|
||||||
if (!thinkingEmpty)
|
|
||||||
s += "<br>";
|
|
||||||
s += Util.boldStart + getString(R.string.variation) + Util.boldStop + variantStr;
|
s += Util.boldStart + getString(R.string.variation) + Util.boldStop + variantStr;
|
||||||
thinking.append(Html.fromHtml(s));
|
thinking.append(Html.fromHtml(s));
|
||||||
thinkingEmpty = false;
|
thinkingEmpty = false;
|
||||||
@@ -2340,7 +2343,7 @@ public class DroidFish extends Activity
|
|||||||
WebView wv = new WebView(this);
|
WebView wv = new WebView(this);
|
||||||
builder.setView(wv);
|
builder.setView(wv);
|
||||||
InputStream is = getResources().openRawResource(R.raw.about);
|
InputStream is = getResources().openRawResource(R.raw.about);
|
||||||
String data = Util.readFromStream(is);
|
String data = FileUtil.readFromStream(is);
|
||||||
if (data == null)
|
if (data == null)
|
||||||
data = "";
|
data = "";
|
||||||
try { is.close(); } catch (IOException e1) {}
|
try { is.close(); } catch (IOException e1) {}
|
||||||
@@ -3251,7 +3254,7 @@ public class DroidFish extends Activity
|
|||||||
String port = "0";
|
String port = "0";
|
||||||
try {
|
try {
|
||||||
if (EngineUtil.isNetEngine(networkEngineToConfig)) {
|
if (EngineUtil.isNetEngine(networkEngineToConfig)) {
|
||||||
String[] lines = Util.readFile(networkEngineToConfig);
|
String[] lines = FileUtil.readFile(networkEngineToConfig);
|
||||||
if (lines.length > 1)
|
if (lines.length > 1)
|
||||||
hostName = lines[1];
|
hostName = lines[1];
|
||||||
if (lines.length > 2)
|
if (lines.length > 2)
|
||||||
@@ -3754,6 +3757,7 @@ public class DroidFish extends Activity
|
|||||||
return currPos;
|
return currPos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean isUpToDate() {
|
public boolean isUpToDate() {
|
||||||
return upToDate;
|
return upToDate;
|
||||||
}
|
}
|
||||||
@@ -3818,6 +3822,7 @@ public class DroidFish extends Activity
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void processToken(Node node, int type, String token) {
|
public void processToken(Node node, int type, String token) {
|
||||||
if ( (prevType == PgnToken.RIGHT_BRACKET) &&
|
if ( (prevType == PgnToken.RIGHT_BRACKET) &&
|
||||||
(type != PgnToken.LEFT_BRACKET)) {
|
(type != PgnToken.LEFT_BRACKET)) {
|
||||||
|
|||||||
45
DroidFish/src/org/petero/droidfish/FileUtil.java
Normal file
45
DroidFish/src/org/petero/droidfish/FileUtil.java
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
package org.petero.droidfish;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class FileUtil {
|
||||||
|
/** Read a text file. Return string array with one string per line. */
|
||||||
|
public static String[] readFile(String filename) throws IOException {
|
||||||
|
ArrayList<String> ret = new ArrayList<String>();
|
||||||
|
InputStream inStream = new FileInputStream(filename);
|
||||||
|
InputStreamReader inFile = new InputStreamReader(inStream);
|
||||||
|
BufferedReader inBuf = new BufferedReader(inFile);
|
||||||
|
String line;
|
||||||
|
while ((line = inBuf.readLine()) != null)
|
||||||
|
ret.add(line);
|
||||||
|
inBuf.close();
|
||||||
|
return ret.toArray(new String[ret.size()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Read all data from an input stream. Return null if IO error. */
|
||||||
|
public static String readFromStream(InputStream is) {
|
||||||
|
InputStreamReader isr;
|
||||||
|
try {
|
||||||
|
isr = new InputStreamReader(is, "UTF-8");
|
||||||
|
BufferedReader br = new BufferedReader(isr);
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
String line;
|
||||||
|
while ((line = br.readLine()) != null) {
|
||||||
|
sb.append(line);
|
||||||
|
sb.append('\n');
|
||||||
|
}
|
||||||
|
br.close();
|
||||||
|
return sb.toString();
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
return null;
|
||||||
|
} catch (IOException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -59,6 +59,7 @@ public interface GUIInterface {
|
|||||||
public String bookInfo;
|
public String bookInfo;
|
||||||
public ArrayList<ArrayList<Move>> pvMoves;
|
public ArrayList<ArrayList<Move>> pvMoves;
|
||||||
public ArrayList<Move> bookMoves;
|
public ArrayList<Move> bookMoves;
|
||||||
|
public String eco;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Update the computer thinking information. */
|
/** Update the computer thinking information. */
|
||||||
|
|||||||
@@ -1,13 +1,5 @@
|
|||||||
package org.petero.droidfish;
|
package org.petero.droidfish;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
import org.petero.droidfish.gamelogic.Piece;
|
import org.petero.droidfish.gamelogic.Piece;
|
||||||
import org.petero.droidfish.gamelogic.Position;
|
import org.petero.droidfish.gamelogic.Position;
|
||||||
|
|
||||||
@@ -41,40 +33,6 @@ public final class Util {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Read a text file. Return string array with one string per line. */
|
|
||||||
public static String[] readFile(String networkEngineToConfig) throws IOException {
|
|
||||||
ArrayList<String> ret = new ArrayList<String>();
|
|
||||||
InputStream inStream = new FileInputStream(networkEngineToConfig);
|
|
||||||
InputStreamReader inFile = new InputStreamReader(inStream);
|
|
||||||
BufferedReader inBuf = new BufferedReader(inFile);
|
|
||||||
String line;
|
|
||||||
while ((line = inBuf.readLine()) != null)
|
|
||||||
ret.add(line);
|
|
||||||
inBuf.close();
|
|
||||||
return ret.toArray(new String[ret.size()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Read all data from an input stream. Return null if IO error. */
|
|
||||||
public static String readFromStream(InputStream is) {
|
|
||||||
InputStreamReader isr;
|
|
||||||
try {
|
|
||||||
isr = new InputStreamReader(is, "UTF-8");
|
|
||||||
BufferedReader br = new BufferedReader(isr);
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
String line;
|
|
||||||
while ((line = br.readLine()) != null) {
|
|
||||||
sb.append(line);
|
|
||||||
sb.append('\n');
|
|
||||||
}
|
|
||||||
br.close();
|
|
||||||
return sb.toString();
|
|
||||||
} catch (UnsupportedEncodingException e) {
|
|
||||||
return null;
|
|
||||||
} catch (IOException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Represent material difference as two unicode strings. */
|
/** Represent material difference as two unicode strings. */
|
||||||
public final static class MaterialDiff {
|
public final static class MaterialDiff {
|
||||||
public CharSequence white;
|
public CharSequence white;
|
||||||
|
|||||||
265
DroidFish/src/org/petero/droidfish/book/EcoDb.java
Normal file
265
DroidFish/src/org/petero/droidfish/book/EcoDb.java
Normal file
@@ -0,0 +1,265 @@
|
|||||||
|
/*
|
||||||
|
DroidFish - An Android chess program.
|
||||||
|
Copyright (C) 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 org.petero.droidfish.book;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.WeakHashMap;
|
||||||
|
|
||||||
|
import org.petero.droidfish.gamelogic.ChessParseError;
|
||||||
|
import org.petero.droidfish.gamelogic.GameTree;
|
||||||
|
import org.petero.droidfish.gamelogic.Move;
|
||||||
|
import org.petero.droidfish.gamelogic.Position;
|
||||||
|
import org.petero.droidfish.gamelogic.TextIO;
|
||||||
|
import org.petero.droidfish.gamelogic.UndoInfo;
|
||||||
|
|
||||||
|
/** ECO code database. */
|
||||||
|
@SuppressLint("UseSparseArrays")
|
||||||
|
public class EcoDb {
|
||||||
|
private static EcoDb instance;
|
||||||
|
|
||||||
|
/** Get singleton instance. */
|
||||||
|
public static EcoDb getInstance(Context context) {
|
||||||
|
if (instance == null) {
|
||||||
|
instance = new EcoDb(context);
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get ECO classification for a given tree node. */
|
||||||
|
public String getEco(GameTree gt, GameTree.Node node) {
|
||||||
|
ArrayList<GameTree.Node> gtNodePath = new ArrayList<GameTree.Node>();
|
||||||
|
int nodeIdx = -1;
|
||||||
|
while (node != null) {
|
||||||
|
nodeIdx = findNode(node);
|
||||||
|
if (nodeIdx != -1)
|
||||||
|
break;
|
||||||
|
if (node == gt.rootNode) {
|
||||||
|
Short idx = posHashToNodeIdx.get(gt.startPos.zobristHash());
|
||||||
|
if (idx != null) {
|
||||||
|
nodeIdx = idx;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gtNodePath.add(node);
|
||||||
|
node = node.getParent();
|
||||||
|
}
|
||||||
|
if (nodeIdx != -1) {
|
||||||
|
Node ecoNode = readNode(nodeIdx);
|
||||||
|
boolean childFound = true;
|
||||||
|
for (int i = gtNodePath.size() - 1; i >= 0; i--) {
|
||||||
|
GameTree.Node gtNode = gtNodePath.get(i);
|
||||||
|
int m = gtNode.move.getCompressedMove();
|
||||||
|
int child = childFound ? ecoNode.firstChild : -1;
|
||||||
|
while (child != -1) {
|
||||||
|
Node cNode = readNode(child);
|
||||||
|
if (cNode.move == m)
|
||||||
|
break;
|
||||||
|
child = cNode.nextSibling;
|
||||||
|
}
|
||||||
|
if (child != -1) {
|
||||||
|
nodeIdx = child;
|
||||||
|
ecoNode = readNode(nodeIdx);
|
||||||
|
} else
|
||||||
|
childFound = false;
|
||||||
|
cacheNode(gtNode, nodeIdx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nodeIdx != -1) {
|
||||||
|
Node n = readNode(nodeIdx);
|
||||||
|
if (n.nameIdx >= 0)
|
||||||
|
return ecoNames[n.nameIdx];
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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 firstChild;
|
||||||
|
int nextSibling;
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] nodesBuffer;
|
||||||
|
private String[] ecoNames;
|
||||||
|
private HashMap<Long, Short> posHashToNodeIdx;
|
||||||
|
private WeakLRUCache<GameTree.Node, Integer> gtNodeToIdx;
|
||||||
|
|
||||||
|
/** Return cached Node index corresponding to a GameTree.Node, or -1 if not found. */
|
||||||
|
private int findNode(GameTree.Node node) {
|
||||||
|
Integer idx = gtNodeToIdx.get(node);
|
||||||
|
return idx == null ? -1 : idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Store GameTree.Node to Node index in cache. */
|
||||||
|
private void cacheNode(GameTree.Node node, int nodeIdx) {
|
||||||
|
gtNodeToIdx.put(node, nodeIdx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Constructor. */
|
||||||
|
private EcoDb(Context context) {
|
||||||
|
posHashToNodeIdx = new HashMap<Long, Short>();
|
||||||
|
gtNodeToIdx = new WeakLRUCache<GameTree.Node, Integer>(50);
|
||||||
|
try {
|
||||||
|
ByteArrayOutputStream bufStream = new ByteArrayOutputStream();
|
||||||
|
InputStream inStream = context.getAssets().open("eco.dat");
|
||||||
|
if (inStream == null)
|
||||||
|
throw new IOException("Can't read ECO database");
|
||||||
|
byte[] buf = new byte[1024];
|
||||||
|
while (true) {
|
||||||
|
int len = inStream.read(buf);
|
||||||
|
if (len <= 0) break;
|
||||||
|
bufStream.write(buf, 0, len);
|
||||||
|
}
|
||||||
|
inStream.close();
|
||||||
|
bufStream.flush();
|
||||||
|
buf = bufStream.toByteArray();
|
||||||
|
int nNodes = 0;
|
||||||
|
while (true) {
|
||||||
|
Node n = readNode(nNodes, buf);
|
||||||
|
if (n.move == 0xffff)
|
||||||
|
break;
|
||||||
|
nNodes++;
|
||||||
|
}
|
||||||
|
nodesBuffer = new byte[nNodes * 8];
|
||||||
|
System.arraycopy(buf, 0, nodesBuffer, 0, nNodes * 8);
|
||||||
|
|
||||||
|
ArrayList<String> names = new ArrayList<String>();
|
||||||
|
int idx = (nNodes + 1) * 8;
|
||||||
|
int start = idx;
|
||||||
|
for (int i = idx; i < buf.length; i++) {
|
||||||
|
if (buf[i] == 0) {
|
||||||
|
names.add(new String(buf, start, i - start, "UTF-8"));
|
||||||
|
start = i + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ecoNames = names.toArray(new String[names.size()]);
|
||||||
|
} catch (IOException ex) {
|
||||||
|
throw new RuntimeException("Can't read ECO database");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (nodesBuffer.length > 0) {
|
||||||
|
Position pos = TextIO.readFEN(TextIO.startPosFEN);
|
||||||
|
populateCache(pos, 0);
|
||||||
|
}
|
||||||
|
} catch (ChessParseError e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Initialize popHashToNodeIdx. */
|
||||||
|
private void populateCache(Position pos, int nodeIdx) {
|
||||||
|
if (posHashToNodeIdx.get(pos.zobristHash()) == null)
|
||||||
|
posHashToNodeIdx.put(pos.zobristHash(), (short)nodeIdx);
|
||||||
|
Node node = readNode(nodeIdx);
|
||||||
|
int child = node.firstChild;
|
||||||
|
UndoInfo ui = new UndoInfo();
|
||||||
|
while (child != -1) {
|
||||||
|
node = readNode(child);
|
||||||
|
Move m = Move.fromCompressed(node.move);
|
||||||
|
pos.makeMove(m, ui);
|
||||||
|
populateCache(pos, child);
|
||||||
|
pos.unMakeMove(m, ui);
|
||||||
|
child = node.nextSibling;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Node readNode(int index) {
|
||||||
|
return readNode(index, nodesBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Node readNode(int index, byte[] buf) {
|
||||||
|
Node n = new Node();
|
||||||
|
int o = index * 8;
|
||||||
|
n.move = getU16(buf, o);
|
||||||
|
n.nameIdx = getS16(buf, o + 2);
|
||||||
|
n.firstChild = getS16(buf, o + 4);
|
||||||
|
n.nextSibling = getS16(buf, o + 6);
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getU16(byte[] buf, int offs) {
|
||||||
|
int b0 = buf[offs] & 255;
|
||||||
|
int b1 = buf[offs + 1] & 255;
|
||||||
|
return (b0 << 8) + b1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getS16(byte[] buf, int offs) {
|
||||||
|
int ret = getU16(buf, offs);
|
||||||
|
if (ret >= 0x8000)
|
||||||
|
ret -= 0x10000;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A Cache where the keys are weak references and the cache automatically
|
||||||
|
* shrinks when it becomes too large, using approximate LRU ordering.
|
||||||
|
* This cache is not designed to store null values. */
|
||||||
|
private static class WeakLRUCache<K, V> {
|
||||||
|
private WeakHashMap<K, V> mapNew; // Most recently used entries
|
||||||
|
private WeakHashMap<K, V> mapOld; // Older entries
|
||||||
|
private int maxSize;
|
||||||
|
|
||||||
|
public WeakLRUCache(int maxSize) {
|
||||||
|
mapNew = new WeakHashMap<K, V>();
|
||||||
|
mapOld = new WeakHashMap<K, V>();
|
||||||
|
this.maxSize = maxSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Insert a value in the map, replacing any old value with the same key. */
|
||||||
|
public void put(K key, V val) {
|
||||||
|
if (mapNew.containsKey(key)) {
|
||||||
|
mapNew.put(key, val);
|
||||||
|
} else {
|
||||||
|
if (mapOld.containsKey(key))
|
||||||
|
mapOld.remove(key);
|
||||||
|
insertNew(key, val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the value corresponding to key, or null if not found. */
|
||||||
|
public V get(K key) {
|
||||||
|
V val = mapNew.get(key);
|
||||||
|
if (val != null)
|
||||||
|
return val;
|
||||||
|
val = mapOld.get(key);
|
||||||
|
if (val != null) {
|
||||||
|
mapOld.remove(key);
|
||||||
|
insertNew(key, val);
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void insertNew(K key, V val) {
|
||||||
|
if (mapNew.size() >= maxSize) {
|
||||||
|
WeakHashMap<K, V> tmp = mapNew;
|
||||||
|
mapNew = mapOld;
|
||||||
|
mapOld = tmp;
|
||||||
|
mapNew.clear();
|
||||||
|
}
|
||||||
|
mapNew.put(key, val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -87,7 +87,7 @@ final class InternalBook implements IOpeningBook {
|
|||||||
try {
|
try {
|
||||||
InputStream inStream = getClass().getResourceAsStream("/book.bin");
|
InputStream inStream = getClass().getResourceAsStream("/book.bin");
|
||||||
if (inStream == null)
|
if (inStream == null)
|
||||||
throw new IOException();
|
throw new IOException("Can't read internal opening book");
|
||||||
List<Byte> buf = new ArrayList<Byte>(8192);
|
List<Byte> buf = new ArrayList<Byte>(8192);
|
||||||
byte[] tmpBuf = new byte[1024];
|
byte[] tmpBuf = new byte[1024];
|
||||||
while (true) {
|
while (true) {
|
||||||
@@ -120,8 +120,7 @@ final class InternalBook implements IOpeningBook {
|
|||||||
} catch (ChessParseError ex) {
|
} catch (ChessParseError ex) {
|
||||||
throw new RuntimeException();
|
throw new RuntimeException();
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
System.out.println("Can't read opening book resource");
|
throw new RuntimeException("Can't read internal opening book");
|
||||||
throw new RuntimeException();
|
|
||||||
}
|
}
|
||||||
/* {
|
/* {
|
||||||
long t1 = System.currentTimeMillis();
|
long t1 = System.currentTimeMillis();
|
||||||
|
|||||||
204
DroidFish/src/org/petero/droidfish/buildtools/EcoBuilder.java
Normal file
204
DroidFish/src/org/petero/droidfish/buildtools/EcoBuilder.java
Normal file
@@ -0,0 +1,204 @@
|
|||||||
|
/*
|
||||||
|
DroidFish - An Android chess program.
|
||||||
|
Copyright (C) 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 org.petero.droidfish.buildtools;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
import org.petero.droidfish.FileUtil;
|
||||||
|
import org.petero.droidfish.PGNOptions;
|
||||||
|
import org.petero.droidfish.gamelogic.Game;
|
||||||
|
import org.petero.droidfish.gamelogic.GameTree;
|
||||||
|
import org.petero.droidfish.gamelogic.Move;
|
||||||
|
import org.petero.droidfish.gamelogic.TimeControlData;
|
||||||
|
|
||||||
|
/** Build the ECO data file from eco.pgn. */
|
||||||
|
public class EcoBuilder {
|
||||||
|
public static void main(String[] args) throws Throwable {
|
||||||
|
String ecoPgnFile = args[0];
|
||||||
|
String ecoDatFile = args[1];
|
||||||
|
(new EcoBuilder()).createECOFile(ecoPgnFile, ecoDatFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
ArrayList<Node> children = new ArrayList<Node>();
|
||||||
|
Node parent;
|
||||||
|
int lineLength; // Length in plies of line this node came from
|
||||||
|
}
|
||||||
|
private ArrayList<Node> nodes;
|
||||||
|
private ArrayList<String> names;
|
||||||
|
private HashMap<String, Integer> nameToIndex;
|
||||||
|
|
||||||
|
/** Constructor. */
|
||||||
|
private EcoBuilder() {
|
||||||
|
nodes = new ArrayList<Node>();
|
||||||
|
names = new ArrayList<String>();
|
||||||
|
nameToIndex = new HashMap<String, Integer>();
|
||||||
|
Node rootNode = new Node();
|
||||||
|
rootNode.index = 0;
|
||||||
|
rootNode.move = new Move(0, 0, 0);
|
||||||
|
rootNode.nameIdx = -1;
|
||||||
|
rootNode.lineLength = 0;
|
||||||
|
nodes.add(rootNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Read pgn text file, write binary file. */
|
||||||
|
private void createECOFile(String ecoPgnFile, String ecoDatFile) throws Throwable {
|
||||||
|
String[] ecoPgn = FileUtil.readFile(ecoPgnFile);
|
||||||
|
StringBuilder pgn = new StringBuilder();
|
||||||
|
boolean gotMoves = false;
|
||||||
|
for (String line : ecoPgn) {
|
||||||
|
boolean isHeader = line.startsWith("[");
|
||||||
|
if (gotMoves && isHeader) {
|
||||||
|
readGame(pgn.toString());
|
||||||
|
pgn = new StringBuilder();
|
||||||
|
gotMoves = false;
|
||||||
|
}
|
||||||
|
pgn.append(line);
|
||||||
|
pgn.append('\n');
|
||||||
|
gotMoves |= !isHeader;
|
||||||
|
}
|
||||||
|
readGame(pgn.toString());
|
||||||
|
|
||||||
|
writeDataFile(ecoDatFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Read and process one game. */
|
||||||
|
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);
|
||||||
|
|
||||||
|
// Determine name of opening
|
||||||
|
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 lineLength = 0;
|
||||||
|
while (true) {
|
||||||
|
if (tree.variations().isEmpty())
|
||||||
|
break;
|
||||||
|
lineLength++;
|
||||||
|
tree.goForward(0);
|
||||||
|
}
|
||||||
|
while (tree.currentNode.getParent() != null)
|
||||||
|
tree.goBack();
|
||||||
|
|
||||||
|
// Add corresponding moves to data structures
|
||||||
|
Node parent = nodes.get(0);
|
||||||
|
while (true) {
|
||||||
|
ArrayList<Move> moves = tree.variations();
|
||||||
|
if (moves.isEmpty())
|
||||||
|
break;
|
||||||
|
Move m = moves.get(0);
|
||||||
|
tree.goForward(0);
|
||||||
|
int oldIdx = -1;
|
||||||
|
for (int i = 0; i < parent.children.size(); i++) {
|
||||||
|
if (parent.children.get(i).move.equals(m)) {
|
||||||
|
oldIdx = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (oldIdx == -1) {
|
||||||
|
Node node = new Node();
|
||||||
|
node.index = nodes.size();
|
||||||
|
node.move = m;
|
||||||
|
node.nameIdx = nameIdx;
|
||||||
|
node.parent = parent;
|
||||||
|
node.lineLength = lineLength;
|
||||||
|
nodes.add(node);
|
||||||
|
parent.children.add(node);
|
||||||
|
parent = node;
|
||||||
|
} else {
|
||||||
|
parent = parent.children.get(oldIdx);
|
||||||
|
if (parent.lineLength > lineLength) {
|
||||||
|
parent.lineLength = lineLength;
|
||||||
|
parent.nameIdx = nameIdx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 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];
|
||||||
|
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
|
||||||
|
int firstChild = -1;
|
||||||
|
if (n.children.size() > 0)
|
||||||
|
firstChild = n.children.get(0).index;
|
||||||
|
buf[4] = (byte)(firstChild >> 8);
|
||||||
|
buf[5] = (byte)(firstChild & 255);
|
||||||
|
int nextSibling = -1;
|
||||||
|
if (n.parent != null) {
|
||||||
|
ArrayList<Node> siblings = n.parent.children;
|
||||||
|
for (int j = 0; j < siblings.size()-1; j++) {
|
||||||
|
if (siblings.get(j).move.equals(n.move)) {
|
||||||
|
nextSibling = siblings.get(j+1).index;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buf[6] = (byte)(nextSibling >> 8);
|
||||||
|
buf[7] = (byte)(nextSibling & 255);
|
||||||
|
out.write(buf);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < buf.length; i++)
|
||||||
|
buf[i] = -1;
|
||||||
|
out.write(buf);
|
||||||
|
|
||||||
|
// Write names
|
||||||
|
buf = new byte[]{0};
|
||||||
|
for (String name : names) {
|
||||||
|
out.write(name.getBytes("UTF-8"));
|
||||||
|
out.write(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
out.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
11716
DroidFish/src/org/petero/droidfish/buildtools/eco.pgn
Normal file
11716
DroidFish/src/org/petero/droidfish/buildtools/eco.pgn
Normal file
File diff suppressed because it is too large
Load Diff
@@ -27,8 +27,8 @@ import java.net.Socket;
|
|||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
|
|
||||||
import org.petero.droidfish.EngineOptions;
|
import org.petero.droidfish.EngineOptions;
|
||||||
|
import org.petero.droidfish.FileUtil;
|
||||||
import org.petero.droidfish.R;
|
import org.petero.droidfish.R;
|
||||||
import org.petero.droidfish.Util;
|
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
@@ -71,7 +71,7 @@ public class NetworkEngine extends UCIEngineBase {
|
|||||||
boolean ok = false;
|
boolean ok = false;
|
||||||
if (EngineUtil.isNetEngine(fileName)) {
|
if (EngineUtil.isNetEngine(fileName)) {
|
||||||
try {
|
try {
|
||||||
String[] lines = Util.readFile(fileName);
|
String[] lines = FileUtil.readFile(fileName);
|
||||||
if (lines.length >= 3) {
|
if (lines.length >= 3) {
|
||||||
host = lines[1];
|
host = lines[1];
|
||||||
port = lines[2];
|
port = lines[2];
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import org.petero.droidfish.GameMode;
|
|||||||
import org.petero.droidfish.PGNOptions;
|
import org.petero.droidfish.PGNOptions;
|
||||||
import org.petero.droidfish.Util;
|
import org.petero.droidfish.Util;
|
||||||
import org.petero.droidfish.book.BookOptions;
|
import org.petero.droidfish.book.BookOptions;
|
||||||
|
import org.petero.droidfish.book.EcoDb;
|
||||||
import org.petero.droidfish.engine.DroidComputerPlayer;
|
import org.petero.droidfish.engine.DroidComputerPlayer;
|
||||||
import org.petero.droidfish.engine.UCIOptions;
|
import org.petero.droidfish.engine.UCIOptions;
|
||||||
import org.petero.droidfish.engine.DroidComputerPlayer.SearchRequest;
|
import org.petero.droidfish.engine.DroidComputerPlayer.SearchRequest;
|
||||||
@@ -682,6 +683,7 @@ public class DroidChessController {
|
|||||||
private boolean whiteMove = true;
|
private boolean whiteMove = true;
|
||||||
private String bookInfo = "";
|
private String bookInfo = "";
|
||||||
private ArrayList<Move> bookMoves = null;
|
private ArrayList<Move> bookMoves = null;
|
||||||
|
private String eco = ""; // ECO classification
|
||||||
|
|
||||||
private Move ponderMove = null;
|
private Move ponderMove = null;
|
||||||
private ArrayList<PvInfo> pvInfoV = new ArrayList<PvInfo>();
|
private ArrayList<PvInfo> pvInfoV = new ArrayList<PvInfo>();
|
||||||
@@ -694,6 +696,7 @@ public class DroidChessController {
|
|||||||
currDepth = 0;
|
currDepth = 0;
|
||||||
bookInfo = "";
|
bookInfo = "";
|
||||||
bookMoves = null;
|
bookMoves = null;
|
||||||
|
eco = "";
|
||||||
setSearchInfo(id);
|
setSearchInfo(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -766,7 +769,6 @@ public class DroidChessController {
|
|||||||
}
|
}
|
||||||
final String statStr = statStrTmp.toString();
|
final String statStr = statStrTmp.toString();
|
||||||
final String newPV = buf.toString();
|
final String newPV = buf.toString();
|
||||||
final String newBookInfo = bookInfo;
|
|
||||||
final ArrayList<ArrayList<Move>> pvMoves = new ArrayList<ArrayList<Move>>();
|
final ArrayList<ArrayList<Move>> pvMoves = new ArrayList<ArrayList<Move>>();
|
||||||
for (int i = 0; i < pvInfoV.size(); i++) {
|
for (int i = 0; i < pvInfoV.size(); i++) {
|
||||||
if (ponderMove != null) {
|
if (ponderMove != null) {
|
||||||
@@ -783,7 +785,8 @@ public class DroidChessController {
|
|||||||
ti.id = id;
|
ti.id = id;
|
||||||
ti.pvStr = newPV;
|
ti.pvStr = newPV;
|
||||||
ti.statStr = statStr;
|
ti.statStr = statStr;
|
||||||
ti.bookInfo = newBookInfo;
|
ti.bookInfo = bookInfo;
|
||||||
|
ti.eco = eco;
|
||||||
ti.pvMoves = pvMoves;
|
ti.pvMoves = pvMoves;
|
||||||
ti.bookMoves = bookMoves;
|
ti.bookMoves = bookMoves;
|
||||||
latestThinkingInfo = ti;
|
latestThinkingInfo = ti;
|
||||||
@@ -856,9 +859,11 @@ public class DroidChessController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void notifyBookInfo(int id, String bookInfo, ArrayList<Move> moveList) {
|
public void notifyBookInfo(int id, String bookInfo, ArrayList<Move> moveList,
|
||||||
|
String eco) {
|
||||||
this.bookInfo = bookInfo;
|
this.bookInfo = bookInfo;
|
||||||
bookMoves = moveList;
|
bookMoves = moveList;
|
||||||
|
this.eco = eco;
|
||||||
setSearchInfo(id);
|
setSearchInfo(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -922,7 +927,8 @@ public class DroidChessController {
|
|||||||
private final void updateBookHints() {
|
private final void updateBookHints() {
|
||||||
if (humansTurn()) {
|
if (humansTurn()) {
|
||||||
Pair<String, ArrayList<Move>> bi = computerPlayer.getBookHints(game.currPos(), localPt());
|
Pair<String, ArrayList<Move>> bi = computerPlayer.getBookHints(game.currPos(), localPt());
|
||||||
listener.notifyBookInfo(searchId, bi.first, bi.second);
|
String eco = EcoDb.getInstance(gui.getContext()).getEco(game.tree, game.tree.currentNode);
|
||||||
|
listener.notifyBookInfo(searchId, bi.first, bi.second, eco);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -962,7 +968,7 @@ public class DroidChessController {
|
|||||||
computerPlayer.queueAnalyzeRequest(sr);
|
computerPlayer.queueAnalyzeRequest(sr);
|
||||||
} else if (computersTurn || ponder) {
|
} else if (computersTurn || ponder) {
|
||||||
listener.clearSearchInfo(searchId);
|
listener.clearSearchInfo(searchId);
|
||||||
listener.notifyBookInfo(searchId, "", null);
|
listener.notifyBookInfo(searchId, "", null, "");
|
||||||
final Pair<Position, ArrayList<Move>> ph = game.getUCIHistory();
|
final Pair<Position, ArrayList<Move>> ph = game.getUCIHistory();
|
||||||
Position currPos = new Position(game.currPos());
|
Position currPos = new Position(game.currPos());
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ import org.petero.droidfish.gamelogic.GameTree.Node;
|
|||||||
*/
|
*/
|
||||||
public class Game {
|
public class Game {
|
||||||
boolean pendingDrawOffer;
|
boolean pendingDrawOffer;
|
||||||
GameTree tree;
|
public GameTree tree;
|
||||||
TimeControl timeController;
|
TimeControl timeController;
|
||||||
private boolean gamePaused;
|
private boolean gamePaused;
|
||||||
/** If true, add new moves as mainline moves. */
|
/** If true, add new moves as mainline moves. */
|
||||||
@@ -92,7 +92,7 @@ public class Game {
|
|||||||
updateTimeControl(false);
|
updateTimeControl(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
final boolean readPGN(String pgn, PGNOptions options) throws ChessParseError {
|
final public boolean readPGN(String pgn, PGNOptions options) throws ChessParseError {
|
||||||
boolean ret = tree.readPGN(pgn, options);
|
boolean ret = tree.readPGN(pgn, options);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
TimeControlData tcData = tree.getTimeControlData();
|
TimeControlData tcData = tree.getTimeControlData();
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ public class GameTree {
|
|||||||
String event, site, date, round, white, black;
|
String event, site, date, round, white, black;
|
||||||
// Result is the last tag pair in the STR, but it is computed on demand from the game tree.
|
// Result is the last tag pair in the STR, but it is computed on demand from the game tree.
|
||||||
|
|
||||||
Position startPos;
|
public Position startPos;
|
||||||
private String timeControl, whiteTimeControl, blackTimeControl;
|
private String timeControl, whiteTimeControl, blackTimeControl;
|
||||||
|
|
||||||
// Non-standard tags
|
// Non-standard tags
|
||||||
@@ -49,8 +49,8 @@ public class GameTree {
|
|||||||
}
|
}
|
||||||
private List<TagPair> tagPairs;
|
private List<TagPair> tagPairs;
|
||||||
|
|
||||||
Node rootNode;
|
public Node rootNode;
|
||||||
Node currentNode;
|
public Node currentNode;
|
||||||
Position currentPos; // Cached value. Computable from "currentNode".
|
Position currentPos; // Cached value. Computable from "currentNode".
|
||||||
|
|
||||||
private final PgnToken.PgnTokenReceiver gameStateListener;
|
private final PgnToken.PgnTokenReceiver gameStateListener;
|
||||||
@@ -1001,7 +1001,7 @@ public class GameTree {
|
|||||||
public static class Node {
|
public static class Node {
|
||||||
String moveStr; // String representation of move leading to this node. Empty string in root node.
|
String moveStr; // String representation of move leading to this node. Empty string in root node.
|
||||||
String moveStrLocal; // Localized version of moveStr
|
String moveStrLocal; // Localized version of moveStr
|
||||||
Move move; // Computed on demand for better PGN parsing performance.
|
public Move move; // Computed on demand for better PGN parsing performance.
|
||||||
// Subtrees of invalid moves will be dropped when detected.
|
// Subtrees of invalid moves will be dropped when detected.
|
||||||
// Always valid for current node.
|
// Always valid for current node.
|
||||||
private UndoInfo ui; // Computed when move is computed
|
private UndoInfo ui; // Computed when move is computed
|
||||||
@@ -1014,7 +1014,7 @@ public class GameTree {
|
|||||||
|
|
||||||
private Node parent; // Null if root node
|
private Node parent; // Null if root node
|
||||||
int defaultChild;
|
int defaultChild;
|
||||||
private List<Node> children;
|
private ArrayList<Node> children;
|
||||||
|
|
||||||
public Node() {
|
public Node() {
|
||||||
this.moveStr = "";
|
this.moveStr = "";
|
||||||
@@ -1073,7 +1073,7 @@ public class GameTree {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (anyToRemove) {
|
if (anyToRemove) {
|
||||||
List<Node> validChildren = new ArrayList<Node>();
|
ArrayList<Node> validChildren = new ArrayList<Node>();
|
||||||
for (Node child : children)
|
for (Node child : children)
|
||||||
if (child.move != null)
|
if (child.move != null)
|
||||||
validChildren.add(child);
|
validChildren.add(child);
|
||||||
@@ -1510,7 +1510,7 @@ public class GameTree {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Get PGN header tags and values. */
|
/** Get PGN header tags and values. */
|
||||||
void getHeaders(Map<String,String> headers) {
|
public void getHeaders(Map<String,String> headers) {
|
||||||
headers.put("Event", event);
|
headers.put("Event", event);
|
||||||
headers.put("Site", site);
|
headers.put("Site", site);
|
||||||
headers.put("Date", date);
|
headers.put("Date", date);
|
||||||
|
|||||||
@@ -45,6 +45,11 @@ public class Move {
|
|||||||
this.promoteTo = m.promoteTo;
|
this.promoteTo = m.promoteTo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Create object from compressed representation. */
|
||||||
|
public static Move fromCompressed(int cm) {
|
||||||
|
return new Move((cm >> 10) & 63, (cm >> 4) & 63, cm & 15);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if ((o == null) || (o.getClass() != this.getClass()))
|
if ((o == null) || (o.getClass() != this.getClass()))
|
||||||
@@ -60,6 +65,11 @@ public class Move {
|
|||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
|
return getCompressedMove();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get move as a 16-bit value. */
|
||||||
|
public int getCompressedMove() {
|
||||||
return (from * 64 + to) * 16 + promoteTo;
|
return (from * 64 + to) * 16 + promoteTo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ public interface SearchListener {
|
|||||||
public void notifyStats(int id, long nodes, int nps, long tbHits, int hash, int time);
|
public void notifyStats(int id, long nodes, int nps, long tbHits, int hash, int time);
|
||||||
|
|
||||||
/** Report opening book information. */
|
/** Report opening book information. */
|
||||||
public void notifyBookInfo(int id, String bookInfo, ArrayList<Move> moveList);
|
public void notifyBookInfo(int id, String bookInfo, ArrayList<Move> moveList, String eco);
|
||||||
|
|
||||||
/** Report move (or command, such as "resign") played by the engine. */
|
/** Report move (or command, such as "resign") played by the engine. */
|
||||||
public void notifySearchResult(int id, String cmd, Move ponder);
|
public void notifySearchResult(int id, String cmd, Move ponder);
|
||||||
|
|||||||
Reference in New Issue
Block a user