mirror of
https://github.com/peterosterlund2/droidfish.git
synced 2025-12-08 07:11:32 +01:00
DroidFish: Rewrote the cuckoochess communication so that internet permission is no longer needed.
This commit is contained in:
@@ -6,6 +6,8 @@
|
||||
android:installLocation="auto">
|
||||
<supports-screens android:largeScreens="true"
|
||||
android:anyDensity="true" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<application android:icon="@drawable/icon"
|
||||
android:label="@string/app_name"
|
||||
android:debuggable="false">
|
||||
@@ -45,9 +47,6 @@
|
||||
android:label="@string/cpu_warning_title">
|
||||
</activity>
|
||||
</application>
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-sdk android:minSdkVersion="3"
|
||||
android:targetSdkVersion="10"/>
|
||||
</manifest>
|
||||
|
||||
@@ -803,7 +803,7 @@ public class DroidComputerPlayer {
|
||||
|
||||
private final synchronized int getReadTimeout() {
|
||||
boolean needGuiUpdate = depthModified || currMoveModified || pvModified || statsModified;
|
||||
int timeout = 1000;
|
||||
int timeout = 2000000000;
|
||||
if (needGuiUpdate) {
|
||||
long now = System.currentTimeMillis();
|
||||
timeout = (int)(lastGUIUpdate + guiUpdateInterval - now + 1);
|
||||
|
||||
@@ -26,8 +26,6 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.petero.droidfish.R;
|
||||
import android.content.Context;
|
||||
@@ -45,7 +43,7 @@ public class ExternalEngine extends UCIEngineBase {
|
||||
private Thread exitThread;
|
||||
private Thread stdInThread;
|
||||
private Thread stdErrThread;
|
||||
private List<String> inLines;
|
||||
private LocalPipe inLines;
|
||||
private boolean startedOk;
|
||||
private boolean isRunning;
|
||||
|
||||
@@ -58,7 +56,7 @@ public class ExternalEngine extends UCIEngineBase {
|
||||
exitThread = null;
|
||||
stdInThread = null;
|
||||
stdErrThread = null;
|
||||
inLines = new LinkedList<String>();
|
||||
inLines = new LocalPipe();
|
||||
startedOk = false;
|
||||
isRunning = false;
|
||||
}
|
||||
@@ -120,8 +118,7 @@ public class ExternalEngine extends UCIEngineBase {
|
||||
if ((ep == null) || Thread.currentThread().isInterrupted())
|
||||
return;
|
||||
synchronized (inLines) {
|
||||
inLines.add(line);
|
||||
inLines.notify();
|
||||
inLines.addLine(line);
|
||||
if (first) {
|
||||
startedOk = true;
|
||||
isRunning = true;
|
||||
@@ -130,8 +127,8 @@ public class ExternalEngine extends UCIEngineBase {
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
return;
|
||||
}
|
||||
inLines.close();
|
||||
}
|
||||
});
|
||||
stdInThread.start();
|
||||
@@ -176,26 +173,13 @@ public class ExternalEngine extends UCIEngineBase {
|
||||
/** @inheritDoc */
|
||||
@Override
|
||||
public String readLineFromEngine(int timeoutMillis) {
|
||||
try {
|
||||
synchronized (inLines) {
|
||||
if (inLines.size() == 0) {
|
||||
Thread inThread = stdInThread;
|
||||
if ((inThread == null) || !inThread.isAlive())
|
||||
return null;
|
||||
inLines.wait(timeoutMillis);
|
||||
}
|
||||
}
|
||||
synchronized (inLines) {
|
||||
if (inLines.size() > 0) {
|
||||
String ret = inLines.get(0);
|
||||
inLines.remove(0);
|
||||
// System.out.printf("Engine -> GUI: %s\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
String ret = inLines.readLine(timeoutMillis);
|
||||
if (ret == null)
|
||||
return null;
|
||||
if (ret.length() > 0) {
|
||||
// System.out.printf("Engine -> GUI: %s\n", ret);
|
||||
}
|
||||
return "";
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
|
||||
63
DroidFish/src/org/petero/droidfish/engine/LocalPipe.java
Normal file
63
DroidFish/src/org/petero/droidfish/engine/LocalPipe.java
Normal file
@@ -0,0 +1,63 @@
|
||||
package org.petero.droidfish.engine;
|
||||
|
||||
import java.util.LinkedList;
|
||||
|
||||
/** Implements line-based text communication between threads. */
|
||||
public class LocalPipe {
|
||||
private LinkedList<String> lines = new LinkedList<String>();
|
||||
private boolean closed = false;
|
||||
|
||||
/** Write a line to the pipe. */
|
||||
public final synchronized void printLine(String format) {
|
||||
String s = String.format(format, new Object[]{});
|
||||
addLine(s);
|
||||
}
|
||||
|
||||
/** Write a line to the pipe. */
|
||||
public final synchronized void printLine(String format, Object ... args) {
|
||||
String s = String.format(format, args);
|
||||
addLine(s);
|
||||
}
|
||||
|
||||
public final synchronized void addLine(String line) {
|
||||
lines.add(line);
|
||||
notify();
|
||||
}
|
||||
|
||||
/** Read a line from the pipe. Returns null on failure. */
|
||||
public final synchronized String readLine() {
|
||||
return readLine(-1);
|
||||
}
|
||||
|
||||
/** Read a line from the pipe. Returns null on failure. Returns empty string on timeout. */
|
||||
public final synchronized String readLine(int timeoutMillis) {
|
||||
if (closed)
|
||||
return null;
|
||||
try {
|
||||
if (lines.isEmpty()) {
|
||||
if (timeoutMillis > 0)
|
||||
wait(timeoutMillis);
|
||||
else
|
||||
wait();
|
||||
}
|
||||
if (lines.isEmpty())
|
||||
return closed ? null : "";
|
||||
String ret = lines.get(0);
|
||||
lines.remove(0);
|
||||
return ret;
|
||||
} catch (InterruptedException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/** Close pipe. Makes readLine() return null. */
|
||||
public final synchronized void close() {
|
||||
closed = true;
|
||||
notify();
|
||||
}
|
||||
|
||||
/** Return true if writer side has closed the pipe. */
|
||||
public final synchronized boolean isClosed() {
|
||||
return closed;
|
||||
}
|
||||
}
|
||||
@@ -23,11 +23,9 @@ import chess.ComputerPlayer;
|
||||
import chess.Move;
|
||||
import chess.Position;
|
||||
import chess.TextIO;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.Pipe;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.petero.droidfish.engine.LocalPipe;
|
||||
import org.petero.droidfish.engine.UCIEngineBase;
|
||||
|
||||
/**
|
||||
@@ -46,22 +44,16 @@ public class CuckooChessEngine extends UCIEngineBase {
|
||||
// Set to true to break out of main loop
|
||||
private boolean quit;
|
||||
|
||||
private Pipe guiToEngine;
|
||||
private Pipe engineToGui;
|
||||
private NioInputStream inFromEngine;
|
||||
private LocalPipe guiToEngine;
|
||||
private LocalPipe engineToGui;
|
||||
private Thread engineThread;
|
||||
|
||||
public CuckooChessEngine(Report report) {
|
||||
pos = null;
|
||||
moves = new ArrayList<Move>();
|
||||
quit = false;
|
||||
try {
|
||||
guiToEngine = Pipe.open();
|
||||
engineToGui = Pipe.open();
|
||||
inFromEngine = new NioInputStream(engineToGui);
|
||||
} catch (IOException e) {
|
||||
report.reportError(e.getMessage());
|
||||
}
|
||||
guiToEngine = new LocalPipe();
|
||||
engineToGui = new LocalPipe();
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
@@ -69,9 +61,7 @@ public class CuckooChessEngine extends UCIEngineBase {
|
||||
protected final void startProcess() {
|
||||
engineThread = new Thread(new Runnable() {
|
||||
public void run() {
|
||||
NioInputStream in = new NioInputStream(guiToEngine);
|
||||
NioPrintStream out = new NioPrintStream(engineToGui);
|
||||
mainLoop(in, out);
|
||||
mainLoop(guiToEngine, engineToGui);
|
||||
}
|
||||
});
|
||||
int pMin = Thread.MIN_PRIORITY;
|
||||
@@ -93,7 +83,7 @@ public class CuckooChessEngine extends UCIEngineBase {
|
||||
setOption("strength", strength);
|
||||
}
|
||||
|
||||
private final void mainLoop(NioInputStream is, NioPrintStream os) {
|
||||
private final void mainLoop(LocalPipe is, LocalPipe os) {
|
||||
String line;
|
||||
while ((line = is.readLine()) != null) {
|
||||
handleCommand(line, os);
|
||||
@@ -103,12 +93,18 @@ public class CuckooChessEngine extends UCIEngineBase {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutDown() {
|
||||
super.shutDown();
|
||||
guiToEngine.close();
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
@Override
|
||||
public final String readLineFromEngine(int timeoutMillis) {
|
||||
if ((engineThread != null) && !engineThread.isAlive())
|
||||
return null;
|
||||
String ret = inFromEngine.readLine(timeoutMillis);
|
||||
String ret = engineToGui.readLine(timeoutMillis);
|
||||
if (ret == null)
|
||||
return null;
|
||||
if (ret.length() > 0) {
|
||||
@@ -121,25 +117,21 @@ public class CuckooChessEngine extends UCIEngineBase {
|
||||
@Override
|
||||
public final synchronized void writeLineToEngine(String data) {
|
||||
// System.out.printf("GUI -> Engine: %s\n", data);
|
||||
try {
|
||||
String s = data + "\n";
|
||||
guiToEngine.sink().write(ByteBuffer.wrap(s.getBytes()));
|
||||
} catch (IOException e) {
|
||||
}
|
||||
guiToEngine.addLine(data);
|
||||
}
|
||||
|
||||
private final void handleCommand(String cmdLine, NioPrintStream os) {
|
||||
private final void handleCommand(String cmdLine, LocalPipe os) {
|
||||
String[] tokens = tokenize(cmdLine);
|
||||
try {
|
||||
String cmd = tokens[0];
|
||||
if (cmd.equals("uci")) {
|
||||
os.printf("id name %s%n", ComputerPlayer.engineName);
|
||||
os.printf("id author Peter Osterlund%n");
|
||||
os.printLine("id name %s", ComputerPlayer.engineName);
|
||||
os.printLine("id author Peter Osterlund");
|
||||
DroidEngineControl.printOptions(os);
|
||||
os.printf("uciok%n");
|
||||
os.printLine("uciok");
|
||||
} else if (cmd.equals("isready")) {
|
||||
initEngine(os);
|
||||
os.printf("readyok%n");
|
||||
os.printLine("readyok");
|
||||
} else if (cmd.equals("setoption")) {
|
||||
initEngine(os);
|
||||
StringBuilder optionName = new StringBuilder();
|
||||
@@ -260,7 +252,7 @@ public class CuckooChessEngine extends UCIEngineBase {
|
||||
}
|
||||
}
|
||||
|
||||
private final void initEngine(NioPrintStream os) {
|
||||
private final void initEngine(LocalPipe os) {
|
||||
if (engine == null) {
|
||||
engine = new DroidEngineControl(os);
|
||||
}
|
||||
|
||||
@@ -35,12 +35,14 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import org.petero.droidfish.engine.LocalPipe;
|
||||
|
||||
/**
|
||||
* Control the search thread.
|
||||
* @author petero
|
||||
*/
|
||||
public class DroidEngineControl {
|
||||
NioPrintStream os;
|
||||
LocalPipe os;
|
||||
|
||||
Thread engineThread;
|
||||
private final Object threadMutex;
|
||||
@@ -76,18 +78,18 @@ public class DroidEngineControl {
|
||||
* This class is responsible for sending "info" strings during search.
|
||||
*/
|
||||
static class SearchListener implements Search.Listener {
|
||||
NioPrintStream os;
|
||||
LocalPipe os;
|
||||
|
||||
SearchListener(NioPrintStream os) {
|
||||
SearchListener(LocalPipe os) {
|
||||
this.os = os;
|
||||
}
|
||||
|
||||
public void notifyDepth(int depth) {
|
||||
os.printf("info depth %d%n", depth);
|
||||
os.printLine("info depth %d", depth);
|
||||
}
|
||||
|
||||
public void notifyCurrMove(Move m, int moveNr) {
|
||||
os.printf("info currmove %s currmovenumber %d%n", moveToString(m), moveNr);
|
||||
os.printLine("info currmove %s currmovenumber %d", moveToString(m), moveNr);
|
||||
}
|
||||
|
||||
public void notifyPV(int depth, int score, int time, long nodes, int nps, boolean isMate,
|
||||
@@ -103,16 +105,16 @@ public class DroidEngineControl {
|
||||
} else if (lowerBound) {
|
||||
bound = " lowerbound";
|
||||
}
|
||||
os.printf("info depth %d score %s %d%s time %d nodes %d nps %d pv%s%n",
|
||||
os.printLine("info depth %d score %s %d%s time %d nodes %d nps %d pv%s",
|
||||
depth, isMate ? "mate" : "cp", score, bound, time, nodes, nps, pvBuf.toString());
|
||||
}
|
||||
|
||||
public void notifyStats(long nodes, int nps, int time) {
|
||||
os.printf("info nodes %d nps %d time %d%n", nodes, nps, time);
|
||||
os.printLine("info nodes %d nps %d time %d", nodes, nps, time);
|
||||
}
|
||||
}
|
||||
|
||||
public DroidEngineControl(NioPrintStream os) {
|
||||
public DroidEngineControl(LocalPipe os) {
|
||||
this.os = os;
|
||||
threadMutex = new Object();
|
||||
setupTT();
|
||||
@@ -260,9 +262,9 @@ public class DroidEngineControl {
|
||||
Move ponderMove = getPonderMove(pos, m);
|
||||
synchronized (threadMutex) {
|
||||
if (ponderMove != null) {
|
||||
os.printf("bestmove %s ponder %s%n", moveToString(m), moveToString(ponderMove));
|
||||
os.printLine("bestmove %s ponder %s", moveToString(m), moveToString(ponderMove));
|
||||
} else {
|
||||
os.printf("bestmove %s%n", moveToString(m));
|
||||
os.printLine("bestmove %s", moveToString(m));
|
||||
}
|
||||
engineThread = null;
|
||||
sc = null;
|
||||
@@ -362,14 +364,14 @@ public class DroidEngineControl {
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void printOptions(NioPrintStream os) {
|
||||
os.printf("option name Hash type spin default 2 min 1 max 2048%n");
|
||||
os.printf("option name OwnBook type check default false%n");
|
||||
os.printf("option name Ponder type check default true%n");
|
||||
os.printf("option name UCI_AnalyseMode type check default false%n");
|
||||
os.printf("option name UCI_EngineAbout type string default %s by Peter Osterlund, see http://web.comhem.se/petero2home/javachess/index.html%n",
|
||||
static void printOptions(LocalPipe os) {
|
||||
os.printLine("option name Hash type spin default 2 min 1 max 2048");
|
||||
os.printLine("option name OwnBook type check default false");
|
||||
os.printLine("option name Ponder type check default true");
|
||||
os.printLine("option name UCI_AnalyseMode type check default false");
|
||||
os.printLine("option name UCI_EngineAbout type string default %s by Peter Osterlund, see http://web.comhem.se/petero2home/javachess/index.html",
|
||||
ComputerPlayer.engineName);
|
||||
os.printf("option name Strength type spin default 1000 min 0 max 1000\n");
|
||||
os.printLine("option name Strength type spin default 1000 min 0 max 1000");
|
||||
}
|
||||
|
||||
final void setOption(String optionName, String optionValue) {
|
||||
|
||||
@@ -1,109 +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 org.petero.droidfish.engine.cuckoochess;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.Pipe;
|
||||
import java.nio.channels.SelectionKey;
|
||||
import java.nio.channels.Selector;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/** Simple InputStream look-alike on top of nio. */
|
||||
class NioInputStream {
|
||||
Pipe.SourceChannel in;
|
||||
ByteBuffer buffer;
|
||||
Selector selector;
|
||||
|
||||
ArrayList<Character> inBuf;
|
||||
StringBuilder lineBuf;
|
||||
|
||||
public NioInputStream(Pipe pipe) {
|
||||
in = pipe.source();
|
||||
try {
|
||||
in.configureBlocking(false);
|
||||
selector = Selector.open();
|
||||
in.register(selector, SelectionKey.OP_READ);
|
||||
|
||||
buffer = ByteBuffer.allocate(1024);
|
||||
inBuf = new ArrayList<Character>();
|
||||
lineBuf = new StringBuilder(128);
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
|
||||
public String readLine() {
|
||||
while (true) {
|
||||
String s = readLine(1000);
|
||||
if (s != null)
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
public String readLine(int timeoutMillis) {
|
||||
try {
|
||||
boolean haveNewLine = false;
|
||||
for (int i = 0; i < inBuf.size(); i++) {
|
||||
if (inBuf.get(i) == '\n') {
|
||||
haveNewLine = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!haveNewLine) {
|
||||
// Refill inBuf
|
||||
if (timeoutMillis < 1)
|
||||
timeoutMillis = 1;
|
||||
selector.select(timeoutMillis);
|
||||
buffer.clear();
|
||||
for (SelectionKey sk : selector.selectedKeys())
|
||||
if (sk.isValid() && sk.isReadable())
|
||||
in.read(buffer);
|
||||
buffer.flip();
|
||||
while (buffer.position() < buffer.limit()) {
|
||||
byte b = buffer.get();
|
||||
inBuf.add((char)b);
|
||||
}
|
||||
}
|
||||
|
||||
// Extract line
|
||||
String ret = "";
|
||||
int i;
|
||||
for (i = 0; i < inBuf.size(); i++) {
|
||||
char c = inBuf.get(i);
|
||||
if (c == '\n') {
|
||||
int newSize = inBuf.size() - i - 1;
|
||||
for (int j = 0; j < newSize; j++)
|
||||
inBuf.set(j, inBuf.get(j+i+1));
|
||||
while (inBuf.size() > newSize)
|
||||
inBuf.remove(inBuf.size() - 1);
|
||||
ret = lineBuf.toString();
|
||||
lineBuf = new StringBuilder(128);
|
||||
break;
|
||||
} else {
|
||||
lineBuf.append(c);
|
||||
}
|
||||
}
|
||||
if (i == inBuf.size())
|
||||
inBuf.clear();
|
||||
return ret;
|
||||
} catch (IOException e) {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,48 +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 org.petero.droidfish.engine.cuckoochess;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.Pipe;
|
||||
|
||||
/** Simple PrintStream look-alike on top of nio. */
|
||||
class NioPrintStream {
|
||||
Pipe.SinkChannel out;
|
||||
|
||||
public NioPrintStream(Pipe pipe) {
|
||||
out = pipe.sink();
|
||||
}
|
||||
|
||||
public void printf(String format) {
|
||||
try {
|
||||
String s = String.format(format, new Object[]{});
|
||||
out.write(ByteBuffer.wrap(s.getBytes()));
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
|
||||
public void printf(String format, Object ... args) {
|
||||
try {
|
||||
String s = String.format(format, args);
|
||||
out.write(ByteBuffer.wrap(s.getBytes()));
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user