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

2022-09-03 14:45:01

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

我已经从这里下载了stockfish Android zip:下载Stockfish引擎

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

  • 鳕鱼-8-arm64-v8a
  • 鳕鱼-8-阿米亚比-v7a

我有两个问题:

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

谢谢!


答案 1

Stockfish是用C++编写的,要从用Java编写的常规Android应用程序中调用它,您需要

  1. 依靠 JNI(Java Native Interface,参见 jni-sample)来做到这一点。
  2. 在学习如何使用JNI编译Stockfish之后,您可以通过UCI协议与引擎进行交互:以下是UCI规范

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

修改像Droidfish这样的现有项目要容易得多,而不是从头开始。


答案 2

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

  • https://stockfishchess.org/download/ 下载源代码,平台无关紧要
  • 在安卓工作室中创建原生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)
    )
  • 在 externalNativeBuild->cmake 中的 build.gradle(app) 中,添加如下内容: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...
...
  • 在 android 的 build.gradle(app) 中添加:
sourceSets {
        main {

            jniLibs.srcDirs = ['libs']
        }
    }
  • 在 build.gradle(app) 中的依赖项中添加:
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) {
        
    }




推荐