diff --git a/DroidFish/.externalToolBuilders/copy_stockfish.launch b/DroidFish/.externalToolBuilders/copy_stockfish.launch new file mode 100644 index 0000000..ad4b768 --- /dev/null +++ b/DroidFish/.externalToolBuilders/copy_stockfish.launch @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/DroidFish/.project b/DroidFish/.project index 62325d0..bd20614 100644 --- a/DroidFish/.project +++ b/DroidFish/.project @@ -30,6 +30,16 @@ + + org.eclipse.ui.externaltools.ExternalToolBuilder + auto,full,incremental, + + + LaunchConfigHandle + <project>/.externalToolBuilders/copy_stockfish.launch + + + com.android.ide.eclipse.adt.ApkBuilder diff --git a/DroidFish/build_copy_exe.xml b/DroidFish/build_copy_exe.xml new file mode 100644 index 0000000..6ac5fe2 --- /dev/null +++ b/DroidFish/build_copy_exe.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/DroidFish/jni/Android.mk b/DroidFish/jni/Android.mk index dc1091a..62b2b0d 100644 --- a/DroidFish/jni/Android.mk +++ b/DroidFish/jni/Android.mk @@ -2,16 +2,14 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) -LOCAL_MODULE := stockfishjni -LOCAL_SRC_FILES := stockfishjni.cpp +LOCAL_MODULE := nativeutil +LOCAL_SRC_FILES := nativeutil.cpp LOCAL_CFLAGS := \ -mandroid \ -DTARGET_OS=android -D__ANDROID__ \ -isystem $(SYSROOT)/usr/include -LOCAL_STATIC_LIBRARIES := stockfish - include $(BUILD_SHARED_LIBRARY) include jni/stockfish/Android.mk diff --git a/DroidFish/jni/Application.mk b/DroidFish/jni/Application.mk index e5d3191..1dd0e71 100644 --- a/DroidFish/jni/Application.mk +++ b/DroidFish/jni/Application.mk @@ -1,2 +1,3 @@ -APP_ABI := all +APP_ABI := armeabi armeabi-v7a x86 APP_STL := stlport_static +APP_OPTIM := release diff --git a/DroidFish/jni/nativeutil.cpp b/DroidFish/jni/nativeutil.cpp new file mode 100644 index 0000000..facda95 --- /dev/null +++ b/DroidFish/jni/nativeutil.cpp @@ -0,0 +1,32 @@ +/* + DroidFish - An Android chess program. + Copyright (C) 2011-2012 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 . +*/ + +#include +#include +#include + +/* + * Class: org_petero_droidfish_engine_NativeUtil + * Method: getNPhysicalProcessors + * Signature: ()I + */ +extern "C" JNIEXPORT jint JNICALL Java_org_petero_droidfish_engine_NativeUtil_getNPhysicalProcessors + (JNIEnv *, jclass) +{ + return sysconf(_SC_NPROCESSORS_ONLN); +} diff --git a/DroidFish/jni/stockfish/Android.mk b/DroidFish/jni/stockfish/Android.mk index 474f5e0..4ff5c1b 100644 --- a/DroidFish/jni/stockfish/Android.mk +++ b/DroidFish/jni/stockfish/Android.mk @@ -19,4 +19,4 @@ LOCAL_CFLAGS := -I$(LOCAL_PATH)/../stlport/stlport \ LOCAL_STATIC_LIBRARIES := stlport -include $(BUILD_STATIC_LIBRARY) +include $(BUILD_EXECUTABLE) diff --git a/DroidFish/jni/stockfishjni.cpp b/DroidFish/jni/stockfishjni.cpp deleted file mode 100644 index 601da92..0000000 --- a/DroidFish/jni/stockfishjni.cpp +++ /dev/null @@ -1,180 +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 . -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -int main(int argc, char* argv[]); - -static int fdFromChild = -1; -static int fdToChild = -1; - -static int childpid = -1; - -/* - * Class: org_petero_droidfish_engine_StockFishJNI - * Method: startProcess - * Signature: ()V - */ -extern "C" JNIEXPORT void JNICALL Java_org_petero_droidfish_engine_StockFishJNI_startProcess - (JNIEnv* env, jobject obj) -{ - if (childpid != -1) - kill(childpid, SIGKILL); - - int fd1[2]; /* parent -> child */ - int fd2[2]; /* child -> parent */ - if (pipe(fd1) < 0) - exit(1); - if (pipe(fd2) < 0) - exit(1); - childpid = fork(); - if (childpid == -1) { - exit(1); - } - if (childpid == 0) { - close(fd1[1]); - close(fd2[0]); - close(0); dup(fd1[0]); close(fd1[0]); - close(1); dup(fd2[1]); close(fd2[1]); - close(2); dup(1); - static char* argv[] = {(char*)"stockfish", NULL}; - nice(10); - main(1, argv); - _exit(0); - } else { - close(fd1[0]); - close(fd2[1]); - fdFromChild = fd2[0]; - fdToChild = fd1[1]; - fcntl(fdFromChild, F_SETFL, O_NONBLOCK); - } -} - - -static std::deque inBuf; - -static bool getNextChar(int& c, int timeoutMillis) { - if (inBuf.empty()) { - fd_set readfds, exceptfds; - FD_ZERO(&readfds); - FD_SET(fdFromChild, &readfds); - FD_ZERO(&exceptfds); - FD_SET(fdFromChild, &exceptfds); - struct timeval tv; - tv.tv_sec = timeoutMillis / 1000; - tv.tv_usec = (timeoutMillis % 1000) * 1000; - int ret = select(fdFromChild + 1, &readfds, NULL, &exceptfds, &tv); - if ((ret < 0) || FD_ISSET(fdFromChild, &exceptfds)) - return false; - - if (FD_ISSET(fdFromChild, &readfds)) { - static char buf[4096]; - int len = read(fdFromChild, &buf[0], sizeof(buf)); - if (len == 0) - return false; // EOF - for (int i = 0; i < len; i++) - inBuf.push_back(buf[i]); - } - } - if (inBuf.empty()) { - c = -1; - return true; - } - c = inBuf.front(); - inBuf.pop_front(); - return true; -} - -static std::vector lineBuf; -/* - * Class: org_petero_droidfish_engine_StockFishJNI - * Method: readFromProcess - * Signature: (I)Ljava/lang/String; - */ -extern "C" JNIEXPORT jstring JNICALL Java_org_petero_droidfish_engine_StockFishJNI_readFromProcess - (JNIEnv* env, jobject obj, jint timeoutMillis) -{ - struct timeval tv0, tv1; - while (true) { - int c; - gettimeofday(&tv0, NULL); - if (!getNextChar(c, timeoutMillis)) - return 0; // Error - gettimeofday(&tv1, NULL); - int elapsedMillis = (tv1.tv_sec - tv0.tv_sec) * 1000 + (tv1.tv_usec - tv0.tv_usec) / 1000; - if (elapsedMillis > 0) { - timeoutMillis -= elapsedMillis; - if (timeoutMillis < 0) timeoutMillis = 0; - } - if (c == -1) { // Timeout - static char emptyString = 0; - return (*env).NewStringUTF(&emptyString); - } - if (c == '\n' || (c == '\r')) { - if (lineBuf.size() > 0) { - lineBuf.push_back(0); - jstring ret = (*env).NewStringUTF(&lineBuf[0]); - lineBuf.clear(); - return ret; - } - } else { - lineBuf.push_back((char)c); - } - } -} - -/* - * Class: org_petero_droidfish_engine_StockFishJNI - * Method: writeToProcess - * Signature: (Ljava/lang/String;)V - */ -extern "C" JNIEXPORT void JNICALL Java_org_petero_droidfish_engine_StockFishJNI_writeToProcess - (JNIEnv* env, jobject obj, jstring msg) -{ - const char* str = (*env).GetStringUTFChars(msg, NULL); - if (str) { - int len = strlen(str); - int written = 0; - while (written < len) { - int n = write(fdToChild, &str[written], len - written); - if (n <= 0) - break; - written += n; - } - (*env).ReleaseStringUTFChars(msg, str); - } -} - -/* - * Class: org_petero_droidfish_engine_StockFishJNI - * Method: getNPhysicalProcessors - * Signature: ()I - */ -extern "C" JNIEXPORT jint JNICALL Java_org_petero_droidfish_engine_StockFishJNI_getNPhysicalProcessors - (JNIEnv *, jclass) -{ - return sysconf(_SC_NPROCESSORS_ONLN); -} diff --git a/DroidFish/src/org/petero/droidfish/DroidFish.java b/DroidFish/src/org/petero/droidfish/DroidFish.java index 8a59ac4..bb41027 100644 --- a/DroidFish/src/org/petero/droidfish/DroidFish.java +++ b/DroidFish/src/org/petero/droidfish/DroidFish.java @@ -1,6 +1,6 @@ /* DroidFish - An Android chess program. - Copyright (C) 2011 Peter Österlund, peterosterlund2@gmail.com + Copyright (C) 2011-2012 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 @@ -178,7 +178,7 @@ public class DroidFish extends Activity implements GUIInterface { super.onCreate(savedInstanceState); String pgn = getPgnIntent(); - + createDirectories(); settings = PreferenceManager.getDefaultSharedPreferences(this); @@ -917,6 +917,11 @@ public class DroidFish extends Activity implements GUIInterface { return mEngineThreads; } + @Override + public Context getContext() { + return getApplicationContext(); + } + /** Report a move made that is a candidate for GUI animation. */ public void setAnimMove(Position sourcePos, Move move, boolean forward) { if (animateMoves && (move != null)) diff --git a/DroidFish/src/org/petero/droidfish/GUIInterface.java b/DroidFish/src/org/petero/droidfish/GUIInterface.java index 85e7d38..3126110 100644 --- a/DroidFish/src/org/petero/droidfish/GUIInterface.java +++ b/DroidFish/src/org/petero/droidfish/GUIInterface.java @@ -1,6 +1,6 @@ /* DroidFish - An Android chess program. - Copyright (C) 2011 Peter Österlund, peterosterlund2@gmail.com + Copyright (C) 2011-2012 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 @@ -25,6 +25,8 @@ import org.petero.droidfish.gamelogic.Game; import org.petero.droidfish.gamelogic.Move; import org.petero.droidfish.gamelogic.Position; +import android.content.Context; + /** Interface between the GUI and the ChessController. */ public interface GUIInterface { @@ -87,4 +89,7 @@ public interface GUIInterface { /** Return the number of engine threads to use. */ int engineThreads(); + + /** Return application context. */ + public Context getContext(); } diff --git a/DroidFish/src/org/petero/droidfish/engine/DroidComputerPlayer.java b/DroidFish/src/org/petero/droidfish/engine/DroidComputerPlayer.java index b1301ba..df0e1e1 100644 --- a/DroidFish/src/org/petero/droidfish/engine/DroidComputerPlayer.java +++ b/DroidFish/src/org/petero/droidfish/engine/DroidComputerPlayer.java @@ -1,6 +1,6 @@ /* DroidFish - An Android chess program. - Copyright (C) 2011 Peter Österlund, peterosterlund2@gmail.com + Copyright (C) 2011-2012 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 @@ -34,12 +34,15 @@ import org.petero.droidfish.gamelogic.TextIO; import org.petero.droidfish.gamelogic.UndoInfo; import org.petero.droidfish.gamelogic.SearchListener.PvInfo; +import android.content.Context; + /** * A computer algorithm player. * @author petero */ public class DroidComputerPlayer { private UCIEngine uciEngine = null; + private final Context context; private final SearchListener listener; private final DroidBook book; @@ -224,7 +227,8 @@ public class DroidComputerPlayer { private Thread engineMonitor; /** Constructor. Starts engine process if not already started. */ - public DroidComputerPlayer(SearchListener listener) { + public DroidComputerPlayer(Context context, SearchListener listener) { + this.context = context; this.listener = listener; book = DroidBook.getInstance(); engineState = new EngineState(); @@ -548,7 +552,7 @@ public class DroidComputerPlayer { myAssert(searchRequest != null); engineName = "Computer"; - uciEngine = UCIEngineBase.getEngine(searchRequest.engine, new UCIEngine.Report() { + uciEngine = UCIEngineBase.getEngine(context, searchRequest.engine, new UCIEngine.Report() { @Override public void reportError(String errMsg) { if (errMsg != null) { @@ -924,7 +928,7 @@ public class DroidComputerPlayer { nCPUsFromProc = nCPUs; } catch (IOException e) { } - int nCPUsFromOS = StockFishJNI.getNPhysicalProcessors(); + int nCPUsFromOS = NativeUtil.getNPhysicalProcessors(); return Math.max(nCPUsFromProc, nCPUsFromOS); } diff --git a/DroidFish/src/org/petero/droidfish/engine/ExternalEngine.java b/DroidFish/src/org/petero/droidfish/engine/ExternalEngine.java index 569162f..b7d79d0 100644 --- a/DroidFish/src/org/petero/droidfish/engine/ExternalEngine.java +++ b/DroidFish/src/org/petero/droidfish/engine/ExternalEngine.java @@ -1,3 +1,21 @@ +/* + DroidFish - An Android chess program. + Copyright (C) 2011-2012 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 . +*/ + package org.petero.droidfish.engine; import java.io.BufferedReader; @@ -11,8 +29,10 @@ import java.nio.channels.FileChannel; import java.util.LinkedList; import java.util.List; +/** Engine running as a process started from an external resource. */ public class ExternalEngine extends UCIEngineBase { private File engineFileName; + protected static final String intSfPath = "/data/data/org.petero.droidfish/internal_sf"; private static final String exePath = "/data/data/org.petero.droidfish/engine.exe"; private final Report report; private Process engineProc; @@ -170,7 +190,8 @@ public class ExternalEngine extends UCIEngineBase { stdErrThread.interrupt(); } - private final static void copyFile(File from, File to) throws IOException { + protected void copyFile(File from, File to) throws IOException { + new File(intSfPath).delete(); if (to.exists() && (from.length() == to.length()) && (from.lastModified() == to.lastModified())) return; if (to.exists()) diff --git a/DroidFish/src/org/petero/droidfish/engine/InternalStockFish.java b/DroidFish/src/org/petero/droidfish/engine/InternalStockFish.java new file mode 100644 index 0000000..f4c2115 --- /dev/null +++ b/DroidFish/src/org/petero/droidfish/engine/InternalStockFish.java @@ -0,0 +1,79 @@ +/* + DroidFish - An Android chess program. + Copyright (C) 2011-2012 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 . +*/ + +package org.petero.droidfish.engine; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import android.content.Context; +import android.os.Build; + +/** Stockfish engine running as process, started from assets resource. */ +public class InternalStockFish extends ExternalEngine { + private Context context; + + public InternalStockFish(Context context, Report report) { + super("", report); + this.context = context; + + } + + /** @inheritDoc */ + @Override + public final void initOptions() { + setOption("Hash", 16); + } + + /** @inheritDoc */ + @Override + public final void setStrength(int strength) { + setOption("Skill Level", strength/50); + } + + @Override + protected void copyFile(File from, File to) throws IOException { + if (new File(intSfPath).exists()) + return; + + if (to.exists()) + to.delete(); + to.createNewFile(); + + InputStream is = context.getAssets().open("stockfish-" + Build.CPU_ABI); + OutputStream os = new FileOutputStream(to); + + try { + byte[] buf = new byte[8192]; + while (true) { + int len = is.read(buf); + if (len <= 0) + break; + os.write(buf, 0, len); + } + } finally { + if (is != null) try { is.close(); } catch (IOException ex) {} + if (os != null) try { os.close(); } catch (IOException ex) {} + } + + new File(intSfPath).createNewFile(); + } +} diff --git a/DroidFish/src/org/petero/droidfish/engine/NativeUtil.java b/DroidFish/src/org/petero/droidfish/engine/NativeUtil.java new file mode 100644 index 0000000..fd23af2 --- /dev/null +++ b/DroidFish/src/org/petero/droidfish/engine/NativeUtil.java @@ -0,0 +1,28 @@ +/* + DroidFish - An Android chess program. + Copyright (C) 2011-2012 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 . +*/ + +package org.petero.droidfish.engine; + +public class NativeUtil { + static { + System.loadLibrary("nativeutil"); + } + + /** Return number of physical processors, i.e. hyper-threading ignored. */ + final static native int getNPhysicalProcessors(); +} diff --git a/DroidFish/src/org/petero/droidfish/engine/StockFishJNI.java b/DroidFish/src/org/petero/droidfish/engine/StockFishJNI.java deleted file mode 100644 index e5b7417..0000000 --- a/DroidFish/src/org/petero/droidfish/engine/StockFishJNI.java +++ /dev/null @@ -1,73 +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 . -*/ - -package org.petero.droidfish.engine; - -public class StockFishJNI extends UCIEngineBase { - static { - System.loadLibrary("stockfishjni"); - } - - /** @inheritDoc */ - @Override - public final void initOptions() { - setOption("Hash", 16); - } - - /** @inheritDoc */ - @Override - public final void setStrength(int strength) { - setOption("Skill Level", strength/50); - } - - /** @inheritDoc */ - @Override - public final String readLineFromEngine(int timeoutMillis) { - String ret = readFromProcess(timeoutMillis); - if (ret == null) - return null; - if (ret.length() > 0) { -// System.out.printf("Engine -> GUI: %s\n", ret); - } - return ret; - } - - /** @inheritDoc */ - @Override - public final synchronized void writeLineToEngine(String data) { -// System.out.printf("GUI -> Engine: %s\n", data); - writeToProcess(data + "\n"); - } - - /** @inheritDoc */ - @Override - protected final native void startProcess(); - - /** - * Read a line of data from the process. - * Return as soon as there is a full line of data to return, - * or when timeoutMillis milliseconds have passed. - */ - private final native String readFromProcess(int timeoutMillis); - - /** Write data to the process. */ - private final native void writeToProcess(String data); - - /** Return number of physical processors, i.e. hyper-threading ignored. */ - final static native int getNPhysicalProcessors(); -} diff --git a/DroidFish/src/org/petero/droidfish/engine/UCIEngineBase.java b/DroidFish/src/org/petero/droidfish/engine/UCIEngineBase.java index f96c927..15f946f 100644 --- a/DroidFish/src/org/petero/droidfish/engine/UCIEngineBase.java +++ b/DroidFish/src/org/petero/droidfish/engine/UCIEngineBase.java @@ -1,18 +1,38 @@ +/* + DroidFish - An Android chess program. + Copyright (C) 2011-2012 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 . +*/ + package org.petero.droidfish.engine; import java.util.HashMap; import org.petero.droidfish.engine.cuckoochess.CuckooChessEngine; +import android.content.Context; + public abstract class UCIEngineBase implements UCIEngine { private boolean processAlive; - public static UCIEngine getEngine(String engine, Report report) { + public static UCIEngine getEngine(Context context, String engine, Report report) { if ("cuckoochess".equals(engine)) return new CuckooChessEngine(report); else if ("stockfish".equals(engine)) - return new StockFishJNI(); + return new InternalStockFish(context, report); else return new ExternalEngine(engine, report); } diff --git a/DroidFish/src/org/petero/droidfish/gamelogic/DroidChessController.java b/DroidFish/src/org/petero/droidfish/gamelogic/DroidChessController.java index fd48921..7ac4cea 100644 --- a/DroidFish/src/org/petero/droidfish/gamelogic/DroidChessController.java +++ b/DroidFish/src/org/petero/droidfish/gamelogic/DroidChessController.java @@ -1,6 +1,6 @@ /* DroidFish - An Android chess program. - Copyright (C) 2011 Peter Österlund, peterosterlund2@gmail.com + Copyright (C) 2011-2012 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 @@ -79,7 +79,7 @@ public class DroidChessController { updateGUI(); this.gameMode = gameMode; if (computerPlayer == null) { - computerPlayer = new DroidComputerPlayer(listener); + computerPlayer = new DroidComputerPlayer(gui.getContext(), listener); computerPlayer.setBookOptions(bookOptions); } computerPlayer.queueStartEngine(searchId, engine);