如何将Stockfish集成到Android应用程序中?

16

我正在尝试将Stockfish(或任何UCI兼容引擎)集成到我的Android应用程序中。

我从这里下载了Stockfish Android zip文件: 下载Stockfish Engine

在zip文件的Android目录下有两个文件:

  • stockfish-8-arm64-v8a
  • stockfish-8-armeabi-v7a

我有两个问题:

  1. 我是否只需要将这两个文件包含在我的应用程序中(如果是,我要把它们放在哪里)?我希望这些是预编译的二进制文件,因此不必担心自己进行编译。
  2. 我如何从我的Android Java代码调用这些文件?

谢谢!


2
这些文件实际上是以ELF ABI格式存储的(基本上是带有一些链接结构的机器代码)。根据您使用的IDE,您可能无法直接导入这些文件,因此您可能仍需要启用C/C++支持的源代码文件来进行项目开发。 - sfdcfox
这个做完了吗? - Shahbaz Sheikh
暂时还没有,抱歉。我现在把它放在一边了。 - yarrichar
很简单,只需要记住 Stockfish 是一个 C++ 项目,为了让 Android Studio 能够与 C++ 库通信,你需要使用 NDK https://developer.android.com/ndk/index.html。 - Carlos
不,我从来没有做过,抱歉 - 如果您这样做了,请告诉我! :) - yarrichar
显示剩余2条评论
2个回答

10

Stockfish是用C++编写的,如果要从使用Java编写的常规Android应用程序中调用它,则需要依靠JNI(Java Native Interface,参见jni-sample)。

  1. 在学习了如何使用JNI编译Stockfish后,您可以通过UCI协议与引擎进行交互:这是UCI规范

  2. 然后您可以调用特定的方法(例如评估位置或建议最佳移动)。一切都始于发送引擎 isready。如果得到答案,您正在正确的轨道上。

  3. 修改现有项目(如Droidfish)比从头开始编写要容易得多。


5

在经过多天的互联网搜索后,我找到了一个解决方案:

  • https://stockfishchess.org/download/下载源代码,不需要考虑平台。
  • 在Android Studio中创建一个本地的C++项目。
  • 你可以删除cpp文件夹中的native-lib.cpp文件(以及代码中的引用)。
  • 提取已下载文件的内容,进入src文件夹,将所有文件复制到Android项目的cpp文件夹中。
  • 在CMakeLists.txt(cpp文件夹)中添加:
   add_executable(
            stockfish
    
            benchmark.cpp   evaluate.h ...(and the rest of the copied files)
    )

在 build.gradle(app) 文件中, 在 externalNativeBuild -> cmake 中添加 targets "stockfish" , 如下所示:
externalNativeBuild {
            cmake {
                targets "stockfish"
                cppFlags ""
            }
        }

  • 构建APK
  • /app/.cxx/cmake/debug文件夹中已生成包含可执行文件的文件夹。
  • 创建一个不带有C++支持的新Android项目。
  • 在新项目中的libs文件夹中复制上述提到的文件夹(保留名称),并删除每个文件夹中的除stockfish文件以外的所有内容。
  • 将每个文件夹中的stockfish文件重命名为lib_stockfish.so,现在这些文件夹应该是这个样子:
...
-libs
     -arm64-v8a
               -lib_stockfish.so
     -armeabi-v7a
               -lib_stockfish.so
and so on...
...
  • 在build.gradle(app)文件中的android节点下添加:
sourceSets {
        main {

            jniLibs.srcDirs = ['libs']
        }
    }
  • 在build.gradle(app)中的dependencies中添加:
implementation fileTree(dir: "libs", include: ["*.jar", "*.so"])
  • 在应用程序标签的清单文件中添加以下内容:
android:extractNativeLibs="true"
  • 现在只是Java代码:

String path = getApplicationContext().getApplicationInfo().nativeLibraryDir+"/lib_stockfish.so";


File file = new File(path);

try {
    process = Runtime.getRuntime().exec(file.getPath());
} catch (IOException e) {
    e.printStackTrace();
}



Thread outThread =  new Thread(new Runnable() {
    @Override
    public void run() {

        Process processOut = process;
        if(processOut == null){
            return;
        }


           BufferedReader out = new BufferedReader(new InputStreamReader(processOut.getInputStream()));

            String data;
            try{


                   while( (data = out.readLine()) != null ){

                    //do something with data
                   }


                } catch(IOException e){
                 
               }

            }
        });

        outThread.start();


///to give commands

String command = "uci";//or other command

command += "\n";

try {
        Process ep = process;

        if (ep != null) {
            ep.getOutputStream().write(command.getBytes());
            ep.getOutputStream().flush();
        }
    } catch (IOException e) {
        
    }




嗨,感谢您的详细解释,我已经寻找了几天了。我按照您的说明进行操作,但不幸的是,当我运行代码时,出现了以下错误:“E/error: java.io.IOException: Cannot run program "/data/app/com.example.testc-hUWO86ZpvRLc1on2Z0uyig==/lib/x86/lib_stockfish.so": error=2, No such file or directory”。这个错误是由于“process = Runtime.getRuntime().exec(file.getPath());”这一行引起的。即使经过数小时的调试,我仍然找不到解决方案,请问您能帮我吗? - nikhil123
在 libs 文件夹中是否有一个名为 x86 的文件夹,其中包含 lib_stockfish.so? - Develocode 777
嗨,是的,我在libs / x86文件夹中有一个lib_stockfish.so文件,我从另一个项目中复制并根据您的说明重命名...它对您有用吗?我浪费了另一天的时间来寻找解决方案,但没有运气,最终我放弃了:( - nikhil123
对我来说,它是有效的。我正在开发一个国际象棋游戏。你在应用程序 gradle 中是否像这样添加了 jniLibs.srcDirs = ['libs']android{...sourceSets { main { jniLibs.srcDirs = ['libs'] }}} - Develocode 777
1
似乎我在原始答案中漏掉了一些内容,您需要在应用程序标签中添加android:extractNativeLibs="true",还需要在MainActivity中在给引擎下达任何指令之前调用outThread.start(); - Develocode 777
显示剩余8条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接