From 734ba8544a7523150617985c2182a8500f8bd901 Mon Sep 17 00:00:00 2001 From: Chukwuemeka Nwagu Date: Wed, 28 Jul 2021 18:50:48 +0100 Subject: [PATCH] refactor shared engine modules --- .../UserInterfaceState.xcuserstate | Bin 169403 -> 169403 bytes jwtc/CMakeLists.txt | 2 +- jwtc/build.gradle.kts | 9 +- jwtc/src/androidMain/cpp/chess-jni.cpp | 318 ++++++++++++++++++ jwtc/src/androidMain/cpp/chess-jni.hpp | 76 +++++ jwtc/src/iosMain/cpp/GameWrapper.h | 5 + jwtc/src/iosMain/cpp/GameWrapper.mm | 9 + jwtc/src/iosMain/cpp/jwtc.def | 2 + .../iosMain/kotlin/jwtc/chess/GGWrapper.kt | 8 + stockfish/CMakeLists.txt | 2 +- .../src/androidMain/cpp/stockfish-lib.cpp | 269 +++++++++++++++ 11 files changed, 697 insertions(+), 3 deletions(-) create mode 100644 jwtc/src/androidMain/cpp/chess-jni.cpp create mode 100644 jwtc/src/androidMain/cpp/chess-jni.hpp create mode 100644 jwtc/src/iosMain/cpp/GameWrapper.h create mode 100644 jwtc/src/iosMain/cpp/GameWrapper.mm create mode 100644 jwtc/src/iosMain/cpp/jwtc.def create mode 100644 jwtc/src/iosMain/kotlin/jwtc/chess/GGWrapper.kt create mode 100644 stockfish/src/androidMain/cpp/stockfish-lib.cpp diff --git a/iosApp/iosApp.xcworkspace/xcuserdata/cnwagu.xcuserdatad/UserInterfaceState.xcuserstate b/iosApp/iosApp.xcworkspace/xcuserdata/cnwagu.xcuserdatad/UserInterfaceState.xcuserstate index 62972e85517b6d8b3016a7bda69c5e170796febe..d047efdf44ba31ae186032271422988a718d9364 100644 GIT binary patch delta 174 zcmdnJnrruJt__>?SYIf+O}o2!yIvU|yDC$4!;uEt%_g>D7R;6g29teDr9kxNtkOyA z1)1$cOdEbTvhG+UV$QL$k#*-}heDCb`L3+f)l?Z3*$`sW4YU|Jwr8p`9!_O6pRU`@ zXu@eO-wo8z$nkYLV<)5J_U3LzJ|>{tq+UidM)U0_dl|n<0=fH_Ga5rE#qA<17}@49 MGHsW3VOkIf0L?QxfdBvi delta 175 zcmdnJnrruJt__>?SRVyAubaJjyIvU|y9QHr!;uDw%_g>D7R(mrrjvb3r9kxNtkOyA z1w~Al?HXBkH2hw~u~NjMk*RRHK{unw1wKsifk4fD;rsNPIf31nQoxP$gw?B zmGN*Yqs4UHZblPM3;AxKWFyDd>5QF>lG~fR8Tpuia+7))%@{4VpX_D)DhcH7U(RR@ Vp%k}^tYBoD!^pf{+J$LBAOOP?Iy(RW diff --git a/jwtc/CMakeLists.txt b/jwtc/CMakeLists.txt index 07585fe..4bb25e8 100644 --- a/jwtc/CMakeLists.txt +++ b/jwtc/CMakeLists.txt @@ -5,7 +5,7 @@ add_library( # Specifies the name of the library. # Sets the library as a shared library. SHARED # Provides a relative path to your source file(s). - src/commonMain/cpp/chess-jni.cpp + src/androidMain/cpp/chess-jni.cpp src/commonMain/cpp/Pos.cpp src/commonMain/cpp/Move.cpp src/commonMain/cpp/ChessBoard.cpp diff --git a/jwtc/build.gradle.kts b/jwtc/build.gradle.kts index 0f386c1..95140f0 100644 --- a/jwtc/build.gradle.kts +++ b/jwtc/build.gradle.kts @@ -17,7 +17,14 @@ kotlin { else ::iosX64 - iosTarget("ios") {} + iosTarget("ios") { +// compilations.getByName("main") { +// val jwtc by cinterops.creating { +// defFile(project.file("src/iosMain/cpp/jwtc.def")) +// packageName("com.cinterop.jwtc") +// } +// } + } cocoapods { summary = "Some description for the Shared Module" diff --git a/jwtc/src/androidMain/cpp/chess-jni.cpp b/jwtc/src/androidMain/cpp/chess-jni.cpp new file mode 100644 index 0000000..439908a --- /dev/null +++ b/jwtc/src/androidMain/cpp/chess-jni.cpp @@ -0,0 +1,318 @@ +#include "chess-jni.hpp" + +//////////////////////////////////////////////////////////////////////////////// +// TODO functions depend on the existing objext in stGame, +// build a check for NULL +//////////////////////////////////////////////////////////////////////////////// + + + +static Game *stGame = NULL; +static JavaVM *jvm; +static jint stArrMoves[ChessBoard::MAX_MOVES]; + + +static void *search_thread(void *arg) { + JNIEnv* env; +/* + JavaVMAttachArgs args; + args.version= JNI_VERSION_1_2; + args.name="user"; + args.group=NULL; +*/ + + //DEBUG_PRINT("Attaching to thread in search_thread\n", 0); + if (jvm->AttachCurrentThread(&env, NULL) != JNI_OK) { + + //DEBUG_PRINT("Could not attach to current thread\n", 0); + return NULL; + } + + //DEBUG_PRINT("Calling native search method\n", 0); + stGame->search(); + //DEBUG_PRINT("Detaching from current thread\n", 0); + + if (jvm->DetachCurrentThread() != JNI_OK) { + //DEBUG_PRINT("Could not deattach from current thread\n", 0); + } + return NULL; +} + + +JNIEXPORT void JNICALL Java_jwtc_chess_JNI_destroy( JNIEnv* env, jobject thiz) { + // TODO + /* + if(stGame != NULL){ + delete stGame; + stGame = NULL; + } + */ + +} + +JNIEXPORT int JNICALL Java_jwtc_chess_JNI_isInited( JNIEnv* env, jobject thiz) { + return stGame != NULL; +} + +JNIEXPORT int JNICALL Java_jwtc_chess_JNI_requestMove( JNIEnv* env, jobject thiz, jint from, jint to) { + return (int)stGame->requestMove(from, to); +} +JNIEXPORT int JNICALL Java_jwtc_chess_JNI_move( JNIEnv* env, jobject thiz, jint move) { + return (int)stGame->move(move); +} +JNIEXPORT void JNICALL Java_jwtc_chess_JNI_undo( JNIEnv* env, jobject thiz) { + stGame->undo(); +} + +JNIEXPORT void JNICALL Java_jwtc_chess_JNI_reset( JNIEnv* env, jobject thiz) { + stGame->reset(); + //DEBUG_PRINT("Reset\n", 0); +} + +JNIEXPORT void JNICALL Java_jwtc_chess_JNI_putPiece( JNIEnv* env, jobject thiz, jint pos, jint piece, jint turn) { + ChessBoard *board = stGame->getBoard(); + board->put(pos, piece, turn); + + //DEBUG_PRINT("Put [%d, %d, %d]\n", pos, piece, turn); +} + +JNIEXPORT void JNICALL Java_jwtc_chess_JNI_searchMove( JNIEnv* env, jobject thiz, jint secs) { + pthread_t tid; + + stGame->setSearchTime(secs); + + //DEBUG_PRINT("Creating search thread\n", 0); + + pthread_create(&tid, NULL, search_thread, NULL); + + //DEBUG_PRINT("Done creating search thread\n", 0); + +} +JNIEXPORT void JNICALL Java_jwtc_chess_JNI_searchDepth( JNIEnv* env, jobject thiz, jint depth) { + stGame->searchLimited(depth); +} +JNIEXPORT int JNICALL Java_jwtc_chess_JNI_getMove( JNIEnv* env, jobject thiz) { + return stGame->getBestMove(); +} +JNIEXPORT int JNICALL Java_jwtc_chess_JNI_getBoardValue( JNIEnv* env, jobject thiz) { + return stGame->getBoard()->boardValueExtension(); +} +JNIEXPORT int JNICALL Java_jwtc_chess_JNI_peekSearchDone( JNIEnv* env, jobject thiz) { + return stGame->m_bSearching ? 0 : 1; +} +JNIEXPORT int JNICALL Java_jwtc_chess_JNI_peekSearchBestMove( JNIEnv* env, jobject thiz, jint ply) { + return stGame->getBestMoveAt(ply); +} +JNIEXPORT int JNICALL Java_jwtc_chess_JNI_peekSearchBestValue( JNIEnv* env, jobject thiz) { + return stGame->m_bestValue; +} +JNIEXPORT int JNICALL Java_jwtc_chess_JNI_peekSearchDepth( JNIEnv* env, jobject thiz) { + return stGame->m_searchDepth; +} +JNIEXPORT int JNICALL Java_jwtc_chess_JNI_getEvalCount( JNIEnv* env, jobject thiz) { + return stGame->m_evalCount; +} +JNIEXPORT void JNICALL Java_jwtc_chess_JNI_setPromo( JNIEnv* env, jobject thiz, jint piece) { + stGame->setPromo(piece); +} + +JNIEXPORT int JNICALL Java_jwtc_chess_JNI_getState( JNIEnv* env, jobject thiz) { + return stGame->getBoard()->getState(); +} + +JNIEXPORT int JNICALL Java_jwtc_chess_JNI_isEnded( JNIEnv* env, jobject thiz) { + return stGame->getBoard()->isEnded(); +} + +JNIEXPORT void JNICALL Java_jwtc_chess_JNI_setCastlingsEPAnd50( JNIEnv* env, jobject thiz, jint wccl, jint wccs, jint bccl, jint bccs, jint ep, jint r50) { + stGame->getBoard()->setCastlingsEPAnd50(wccl, wccs, bccl, bccs, ep, r50); +} +JNIEXPORT int JNICALL Java_jwtc_chess_JNI_getNumBoard( JNIEnv* env, jobject thiz) { + return stGame->getBoard()->getNumBoard(); +} +JNIEXPORT void JNICALL Java_jwtc_chess_JNI_commitBoard( JNIEnv* env, jobject thiz) { + stGame->commitBoard(); +} +JNIEXPORT void JNICALL Java_jwtc_chess_JNI_setTurn( JNIEnv* env, jobject thiz, jint turn) { + stGame->getBoard()->setTurn(turn); +} + +JNIEXPORT int JNICALL Java_jwtc_chess_JNI_getMoveArraySize( JNIEnv* env, jobject thiz) { + ChessBoard *board = stGame->getBoard(); + board->getMoves(); + //DEBUG_PRINT("W hasOO %d, hasOOO %d B hasOO %d, hasOOO %d | COL %d, %d", board->hasOO(1), board->hasOOO(1), board->hasOO(0), board->hasOOO(0), ChessBoard::COL_AROOK, ChessBoard::COL_HROOK); + int i = 0; + while(board->hasMoreMoves()) + { + stArrMoves[i++] = board->getNextMove(); + } + return board->getNumMoves(); +} +JNIEXPORT int JNICALL Java_jwtc_chess_JNI_getMoveArrayAt( JNIEnv* env, jobject thiz, jint i) { + return stArrMoves[i]; +} + +JNIEXPORT int JNICALL Java_jwtc_chess_JNI_getTurn( JNIEnv* env, jobject thiz) { + return stGame->getBoard()->getTurn(); +} + +JNIEXPORT int JNICALL Java_jwtc_chess_JNI_pieceAt( JNIEnv* env, jobject thiz, jint turn, jint pos) { + return stGame->getBoard()->pieceAt(turn, pos); +} +JNIEXPORT jstring JNICALL Java_jwtc_chess_JNI_getMyMoveToString( JNIEnv* env, jobject thiz) { + char buf[20]; + stGame->getBoard()->myMoveToString(buf); + return env->NewStringUTF(buf); +} +JNIEXPORT int JNICALL Java_jwtc_chess_JNI_getMyMove( JNIEnv* env, jobject thiz) { + return stGame->getBoard()->getMyMove(); +} +JNIEXPORT int JNICALL Java_jwtc_chess_JNI_isLegalPosition( JNIEnv* env, jobject thiz) { + return stGame->getBoard()->isLegalPosition(); +} + +JNIEXPORT int JNICALL Java_jwtc_chess_JNI_isAmbiguousCastle( JNIEnv* env, jobject thiz, jint from, jint to) { + return stGame->getBoard()->isAmbiguousCastle(from, to); +} + +JNIEXPORT void JNICALL Java_jwtc_chess_JNI_doCastleMove( JNIEnv* env, jobject thiz, jint from, jint to) { + int move = stGame->getBoard()->getCastleMove(from, to); + stGame->move(move); +} + +JNIEXPORT jstring JNICALL Java_jwtc_chess_JNI_toFEN( JNIEnv* env, jobject thiz) { + char buf[255]; + stGame->getBoard()->toFEN(buf); + return env->NewStringUTF(buf); +} + +JNIEXPORT void JNICALL Java_jwtc_chess_JNI_removePiece( JNIEnv* env, jobject thiz, jint turn, jint pos) { + stGame->getBoard()->remove(turn, pos); +} +JNIEXPORT BITBOARD JNICALL Java_jwtc_chess_JNI_getHashKey( JNIEnv* env, jobject thiz) { + return stGame->getBoard()->getHashKey(); +} +JNIEXPORT void JNICALL Java_jwtc_chess_JNI_loadDB( JNIEnv* env, jobject thiz, jstring sFile, jint depth) { + const char *nativeString = env->GetStringUTFChars(sFile, 0); + stGame->loadDB(nativeString, depth); + env->ReleaseStringUTFChars(sFile, nativeString); + //"db-5.bin" +} +JNIEXPORT void JNICALL Java_jwtc_chess_JNI_interrupt( JNIEnv* env, jobject thiz) { + stGame->m_bInterrupted = true; + +} +JNIEXPORT int JNICALL Java_jwtc_chess_JNI_getNumCaptured( JNIEnv* env, jobject thiz, jint turn, jint piece) { + return stGame->getBoard()->getNumCaptured(turn, piece); +} + +// Evaluation settings stuff +JNIEXPORT int JNICALL Java_jwtc_chess_JNI_getEvalPropertyCount( JNIEnv* env, jobject thiz) { + return 0; +} + +JNIEXPORT jstring JNICALL Java_jwtc_chess_JNI_getEvalPropertyName( JNIEnv* env, jobject thiz, jint iProp) { + char buf[20]; + + return env->NewStringUTF(buf); +} + +JNIEXPORT int JNICALL Java_jwtc_chess_JNI_getEvalPropertyValue( JNIEnv* env, jobject thiz, jint iProp) { + return 0; +} + +JNIEXPORT void JNICALL Java_jwtc_chess_JNI_setEvalPropertyValue( JNIEnv* env, jobject thiz, jint iProp, jint value) { + +} + + +static JNINativeMethod sMethods[] = { + {"destroy", "()V", (void*)Java_jwtc_chess_JNI_destroy}, + {"isInited", "()I", (void*)Java_jwtc_chess_JNI_isInited}, + {"requestMove", "(II)I", (void*)Java_jwtc_chess_JNI_requestMove}, + {"move", "(I)I", (void*)Java_jwtc_chess_JNI_move}, + {"undo", "()V", (void*)Java_jwtc_chess_JNI_undo}, + {"reset", "()V", (void*)Java_jwtc_chess_JNI_reset}, + {"putPiece", "(III)V", (void*)Java_jwtc_chess_JNI_putPiece}, + {"searchMove", "(I)V", (void*)Java_jwtc_chess_JNI_searchMove}, + {"searchDepth", "(I)V", (void*)Java_jwtc_chess_JNI_searchDepth}, + {"getMove", "()I", (void*)Java_jwtc_chess_JNI_getMove}, + {"getBoardValue", "()I", (void*)Java_jwtc_chess_JNI_getBoardValue}, + {"peekSearchDone", "()I", (void*)Java_jwtc_chess_JNI_peekSearchDone}, + {"peekSearchBestMove", "(I)I", (void*)Java_jwtc_chess_JNI_peekSearchBestMove}, + {"peekSearchBestValue", "()I", (void*)Java_jwtc_chess_JNI_peekSearchBestValue}, + {"peekSearchDepth", "()I", (void*)Java_jwtc_chess_JNI_peekSearchDepth}, + {"getEvalCount", "()I", (void*)Java_jwtc_chess_JNI_getEvalCount}, + {"setPromo", "(I)V", (void*)Java_jwtc_chess_JNI_setPromo}, + {"getState", "()I", (void*)Java_jwtc_chess_JNI_getState}, + {"isEnded", "()I", (void*)Java_jwtc_chess_JNI_isEnded}, + {"setCastlingsEPAnd50", "(IIIIII)V", (void*)Java_jwtc_chess_JNI_setCastlingsEPAnd50}, + {"getNumBoard", "()I", (void*)Java_jwtc_chess_JNI_getNumBoard}, + {"getTurn", "()I", (void*)Java_jwtc_chess_JNI_getTurn}, + {"commitBoard", "()V", (void*)Java_jwtc_chess_JNI_commitBoard}, + {"setTurn", "(I)V", (void*)Java_jwtc_chess_JNI_setTurn}, + {"getMoveArraySize", "()I", (void*)Java_jwtc_chess_JNI_getMoveArraySize}, + {"getMoveArrayAt", "(I)I", (void*)Java_jwtc_chess_JNI_getMoveArrayAt}, + {"pieceAt", "(II)I", (void*)Java_jwtc_chess_JNI_pieceAt}, + {"getMyMoveToString", "()Ljava/lang/String;", (void*)Java_jwtc_chess_JNI_getMyMoveToString}, + {"getMyMove", "()I", (void*)Java_jwtc_chess_JNI_getMyMove}, + {"isLegalPosition", "()I", (void*)Java_jwtc_chess_JNI_isLegalPosition}, + {"isAmbiguousCastle", "(II)I", (void*)Java_jwtc_chess_JNI_isAmbiguousCastle}, + {"doCastleMove", "(II)I", (void*)Java_jwtc_chess_JNI_doCastleMove}, + {"toFEN", "()Ljava/lang/String;", (void*)Java_jwtc_chess_JNI_toFEN}, + {"removePiece", "(II)V", (void*)Java_jwtc_chess_JNI_removePiece}, + {"getHashKey", "()J", (void*)Java_jwtc_chess_JNI_getHashKey}, + {"loadDB", "(Ljava/lang/String;I)V", (void*)Java_jwtc_chess_JNI_loadDB}, + {"interrupt", "()V", (void*)Java_jwtc_chess_JNI_interrupt}, + {"getNumCaptured", "(II)I", (void*)Java_jwtc_chess_JNI_getNumCaptured}, + {"getEvalPropertyName", "(I)Ljava/lang/String;", (void*)Java_jwtc_chess_JNI_getEvalPropertyName}, + {"getEvalPropertyCount", "()I", (void*)Java_jwtc_chess_JNI_getEvalPropertyCount}, + {"getEvalPropertyValue", "(I)I", (void*)Java_jwtc_chess_JNI_getEvalPropertyValue}, + {"setEvalPropertyValue", "(II)V", (void*)Java_jwtc_chess_JNI_setEvalPropertyValue} +}; + +extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved) { + JNIEnv* env = NULL; + jint result = -1; + + //DEBUG_PRINT("JNI_OnLoad called\n", 0); + + if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { + DEBUG_PRINT("vm->GetEnv failed\n", 0); + return result; + } + + jniRegisterNativeMethods(env, "jwtc/chess/JNI", sMethods, 1); + + //DEBUG_PRINT("Getting pointer to JavaVM...\n", 0); + if (env->GetJavaVM(&jvm) < 0) { + //DEBUG_PRINT("Could not get pointer to JavaVM\n", 0); + } + + + ChessBoard::initStatics(); + stGame = new Game(); + + //DEBUG_PRINT("JNI_OnLoad is DONE!\n", 0); + + return JNI_VERSION_1_4; +} + +int jniRegisterNativeMethods(JNIEnv* env, const char* className, + const JNINativeMethod* gMethods, int numMethods) { + jclass clazz; + + //DEBUG_PRINT("Registering %s natives\n", className); + clazz = env->FindClass(className); + if (clazz == NULL) { + //DEBUG_PRINT("Native registration unable to find class '%s'\n", className); + return -1; + } + + if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) { + //DEBUG_PRINT("RegisterNatives failed for '%s'\n", className); + return -1; + } + + return 0; +} \ No newline at end of file diff --git a/jwtc/src/androidMain/cpp/chess-jni.hpp b/jwtc/src/androidMain/cpp/chess-jni.hpp new file mode 100644 index 0000000..9d4080f --- /dev/null +++ b/jwtc/src/androidMain/cpp/chess-jni.hpp @@ -0,0 +1,76 @@ +#include + +//#include +//#include +#include + +#ifndef _Included_chessJNI +#define _Included_chessJNI + +#include "common.h" + + +#include "ChessBoard.h" +#include "Game.h" + +//static void search_thread(void* arg); + +int jniRegisterNativeMethods(JNIEnv* env, const char* className, + const JNINativeMethod* gMethods, int numMethods); + +extern "C" { + + +JNIEXPORT void JNICALL Java_jwtc_chess_JNI_destroy( JNIEnv* env, jobject thiz); +JNIEXPORT int JNICALL Java_jwtc_chess_JNI_isInited( JNIEnv* env, jobject thiz); +JNIEXPORT int JNICALL Java_jwtc_chess_JNI_requestMove( JNIEnv* env, jobject thiz, jint from, jint to); +JNIEXPORT int JNICALL Java_jwtc_chess_JNI_move( JNIEnv* env, jobject thiz, jint move); +JNIEXPORT void JNICALL Java_jwtc_chess_JNI_undo( JNIEnv* env, jobject thiz); +JNIEXPORT void JNICALL Java_jwtc_chess_JNI_reset( JNIEnv* env, jobject thiz); +JNIEXPORT void JNICALL Java_jwtc_chess_JNI_putPiece( JNIEnv* env, jobject thiz, jint pos, jint piece, jint turn); +JNIEXPORT void JNICALL Java_jwtc_chess_JNI_searchMove( JNIEnv* env, jobject thiz, jint secs); +JNIEXPORT void JNICALL Java_jwtc_chess_JNI_searchDepth( JNIEnv* env, jobject thiz, jint depth); +JNIEXPORT int JNICALL Java_jwtc_chess_JNI_getMove( JNIEnv* env, jobject thiz); +JNIEXPORT int JNICALL Java_jwtc_chess_JNI_getBoardValue( JNIEnv* env, jobject thiz); +JNIEXPORT int JNICALL Java_jwtc_chess_JNI_peekSearchDone( JNIEnv* env, jobject thiz); +JNIEXPORT int JNICALL Java_jwtc_chess_JNI_peekSearchBestMove( JNIEnv* env, jobject thiz, jint ply); +JNIEXPORT int JNICALL Java_jwtc_chess_JNI_peekSearchBestValue( JNIEnv* env, jobject thiz); +JNIEXPORT int JNICALL Java_jwtc_chess_JNI_peekSearchDepth( JNIEnv* env, jobject thiz); +JNIEXPORT int JNICALL Java_jwtc_chess_JNI_getEvalCount( JNIEnv* env, jobject thiz); +JNIEXPORT void JNICALL Java_jwtc_chess_JNI_setPromo( JNIEnv* env, jobject thiz, jint piece); +JNIEXPORT int JNICALL Java_jwtc_chess_JNI_getState( JNIEnv* env, jobject thiz); +JNIEXPORT int JNICALL Java_jwtc_chess_JNI_isEnded( JNIEnv* env, jobject thiz); +JNIEXPORT void JNICALL Java_jwtc_chess_JNI_setCastlingsEPAnd50( JNIEnv* env, jobject thiz, jint wccl, jint wccs, jint bccl, jint bccs, jint ep, jint r50); +JNIEXPORT int JNICALL Java_jwtc_chess_JNI_getNumBoard( JNIEnv* env, jobject thiz); +JNIEXPORT void JNICALL Java_jwtc_chess_JNI_commitBoard( JNIEnv* env, jobject thiz); +JNIEXPORT void JNICALL Java_jwtc_chess_JNI_setTurn( JNIEnv* env, jobject thiz, jint turn); +//JNIEXPORT jintArray JNICALL Java_jwtc_chess_JNI_getMoveArray(JNIEnv *env, jobject thiz); +JNIEXPORT int JNICALL Java_jwtc_chess_JNI_getMoveArraySize( JNIEnv* env, jobject thiz); +JNIEXPORT int JNICALL Java_jwtc_chess_JNI_getMoveArrayAt( JNIEnv* env, jobject thiz, jint i); +JNIEXPORT int JNICALL Java_jwtc_chess_JNI_getTurn( JNIEnv* env, jobject thiz); +JNIEXPORT int JNICALL Java_jwtc_chess_JNI_pieceAt( JNIEnv* env, jobject thiz, jint turn, jint pos); +JNIEXPORT jstring JNICALL Java_jwtc_chess_JNI_getMyMoveToString( JNIEnv* env, jobject thiz); +JNIEXPORT int JNICALL Java_jwtc_chess_JNI_getMyMove( JNIEnv* env, jobject thiz); +JNIEXPORT int JNICALL Java_jwtc_chess_JNI_isLegalPosition( JNIEnv* env, jobject thiz); +JNIEXPORT int JNICALL Java_jwtc_chess_JNI_isAmbiguousCastle( JNIEnv* env, jobject thiz, jint from, jint to); +JNIEXPORT void JNICALL Java_jwtc_chess_JNI_doCastleMove( JNIEnv* env, jobject thiz, jint from, jint to); +JNIEXPORT jstring JNICALL Java_jwtc_chess_JNI_toFEN( JNIEnv* env, jobject thiz); +JNIEXPORT void JNICALL Java_jwtc_chess_JNI_removePiece( JNIEnv* env, jobject thiz, jint turn, jint pos); +JNIEXPORT BITBOARD JNICALL Java_jwtc_chess_JNI_getHashKey( JNIEnv* env, jobject thiz); +JNIEXPORT void JNICALL Java_jwtc_chess_JNI_loadDB( JNIEnv* env, jobject thiz, jstring sFile, jint depth); +JNIEXPORT void JNICALL Java_jwtc_chess_JNI_interrupt( JNIEnv* env, jobject thiz); +JNIEXPORT int JNICALL Java_jwtc_chess_JNI_getNumCaptured( JNIEnv* env, jobject thiz, jint turn, jint piece); +JNIEXPORT void JNICALL Java_jwtc_chess_JNI_resetHouse( JNIEnv* env, jobject thiz); +JNIEXPORT void JNICALL Java_jwtc_chess_JNI_putPieceHouse( JNIEnv* env, jobject thiz, jint pos, jint piece); +JNIEXPORT int JNICALL Java_jwtc_chess_JNI_getNumHouse( JNIEnv* env, jobject thiz, jint turn, jint piece); +JNIEXPORT void JNICALL Java_jwtc_chess_JNI_setNumHouse( JNIEnv* env, jobject thiz, jint turn, jint piece, jint num); +JNIEXPORT int JNICALL Java_jwtc_chess_JNI_searchMoveHouse( JNIEnv* env, jobject thiz, jint secs); + +JNIEXPORT int JNICALL Java_jwtc_chess_JNI_getEvalPropertyCount( JNIEnv* env, jobject thiz); +JNIEXPORT jstring JNICALL Java_jwtc_chess_JNI_getEvalPropertyName( JNIEnv* env, jobject thiz, jint iProp); +JNIEXPORT int JNICALL Java_jwtc_chess_JNI_getEvalPropertyValue( JNIEnv* env, jobject thiz, jint iProp); +JNIEXPORT void JNICALL Java_jwtc_chess_JNI_setEvalPropertyValue( JNIEnv* env, jobject thiz, jint iProp, jint value); + +} + +#endif diff --git a/jwtc/src/iosMain/cpp/GameWrapper.h b/jwtc/src/iosMain/cpp/GameWrapper.h new file mode 100644 index 0000000..e7f1dde --- /dev/null +++ b/jwtc/src/iosMain/cpp/GameWrapper.h @@ -0,0 +1,5 @@ +#import + +@interface GameWrapper +- (void) getBestMove; +@end diff --git a/jwtc/src/iosMain/cpp/GameWrapper.mm b/jwtc/src/iosMain/cpp/GameWrapper.mm new file mode 100644 index 0000000..fc4595a --- /dev/null +++ b/jwtc/src/iosMain/cpp/GameWrapper.mm @@ -0,0 +1,9 @@ +#include "GameWrapper.h" +#include "Game.h" + +@implementation GameWrapper +- (void) getBestMove { + Game game; + game.getBestMove(); +} +@end \ No newline at end of file diff --git a/jwtc/src/iosMain/cpp/jwtc.def b/jwtc/src/iosMain/cpp/jwtc.def new file mode 100644 index 0000000..09cbeb8 --- /dev/null +++ b/jwtc/src/iosMain/cpp/jwtc.def @@ -0,0 +1,2 @@ +headers = GameWrapper.h +headerFilter = GameWrapper.h \ No newline at end of file diff --git a/jwtc/src/iosMain/kotlin/jwtc/chess/GGWrapper.kt b/jwtc/src/iosMain/kotlin/jwtc/chess/GGWrapper.kt new file mode 100644 index 0000000..934e653 --- /dev/null +++ b/jwtc/src/iosMain/kotlin/jwtc/chess/GGWrapper.kt @@ -0,0 +1,8 @@ +package jwtc.chess + +class GGWrapper { + + fun init() { + // GameWrapper() + } +} \ No newline at end of file diff --git a/stockfish/CMakeLists.txt b/stockfish/CMakeLists.txt index c2a70a8..2024705 100644 --- a/stockfish/CMakeLists.txt +++ b/stockfish/CMakeLists.txt @@ -10,12 +10,12 @@ add_library( # Specifies the name of the library. # Sets the library as a shared library. SHARED # Provides a relative path to your source file(s). + src/androidMain/cpp/stockfish-lib.cpp src/commonMain/cpp/benchmark.cpp src/commonMain/cpp/bitbase.cpp src/commonMain/cpp/bitboard.cpp src/commonMain/cpp/endgame.cpp src/commonMain/cpp/evaluate.cpp - src/commonMain/cpp/stockfish-lib.cpp src/commonMain/cpp/material.cpp src/commonMain/cpp/misc.cpp src/commonMain/cpp/movegen.cpp diff --git a/stockfish/src/androidMain/cpp/stockfish-lib.cpp b/stockfish/src/androidMain/cpp/stockfish-lib.cpp new file mode 100644 index 0000000..af4ce9b --- /dev/null +++ b/stockfish/src/androidMain/cpp/stockfish-lib.cpp @@ -0,0 +1,269 @@ +#include +#include + +#define LOG_TAG "StockfishServiceJNI" + +#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG,__VA_ARGS__) +#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG , LOG_TAG,__VA_ARGS__) +#define LOGI(...) __android_log_print(ANDROID_LOG_INFO , LOG_TAG,__VA_ARGS__) +#define LOGW(...) __android_log_print(ANDROID_LOG_WARN , LOG_TAG,__VA_ARGS__) +#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR , LOG_TAG,__VA_ARGS__) + +#include +#include +#include +#include +#include +#include + + +// Stockfish +#include "bitboard.h" +#include "evaluate.h" +#include "position.h" +#include "search.h" +#include "thread.h" +#include "tt.h" +#include "uci.h" +#include "syzygy/tbprobe.h" + +namespace stockfishservice { + +class engine_wrapper { + engine_wrapper() { } + + ~engine_wrapper() { + if (engine_thread.joinable()) { + engine_thread.join(); + } + if (service_object) { + JNIEnv *jenv; + vm->AttachCurrentThread(&jenv, NULL); + jenv->DeleteGlobalRef(service_object); + vm->DetachCurrentThread(); + } + } + + void thread_loop(); + +public: + static engine_wrapper &sharedEngine() { + static engine_wrapper engineWrapper; + return engineWrapper; + } + + void startEngine(); + + // delete copy and move constructors and assign operators + engine_wrapper(engine_wrapper const &) = delete; // Copy construct + engine_wrapper(engine_wrapper &&) = delete; // Move construct + engine_wrapper &operator=(engine_wrapper const &) = delete; // Copy assign + engine_wrapper &operator=(engine_wrapper &&) = delete; // Move assign + + // ALL PUBLIC + bool engine_is_running = false; + std::mutex startup_mutex; + std::condition_variable startup_cv; + // output handling + std::string output_line; + jmethodID output_method = nullptr; + jobject service_object = nullptr; + JavaVM *vm = nullptr; + // input handling + std::deque input_lines; + std::thread engine_thread; + std::mutex mutex; + std::condition_variable condition_variable; +}; + +void engine_wrapper::startEngine() { + engine_thread = std::thread(&engine_wrapper::thread_loop, this); +} + +void engine_wrapper::thread_loop() { + LOGV("Initializing stockfish"); + UCI::init(Options); + PSQT::init(); + Bitboards::init(); + Position::init(); + Bitbases::init(); + Search::init(); + Eval::init(); + Pawns::init(); + Threads.init(); + Tablebases::init(Options["SyzygyPath"]); + TT.resize(Options["Hash"]); + + LOGV("Going into UCI::loop"); + + char *argv = "stockfish_engine"; + UCI::loop(1, &argv); + + Threads.exit(); + { + std::lock_guard lk(startup_mutex); + LOGE("engine is stopped"); + engine_is_running = false; + } +} + +class jni_sink : public std::streambuf { +protected: + virtual int_type overflow(int_type c) { + if (c == EOF) { + return c; + } + engine_wrapper &engine = engine_wrapper::sharedEngine(); + if (isprint(c)) { + engine.output_line += c; + return c; + } + if (c != '\n') { + return EOF; + } + if (engine.output_line.length() == 0) { + return c; + } + engine.output_line += c; + LOGV("sending line : %s to Java", engine.output_line.c_str()); + JNIEnv *jenv; + jint result = engine.vm->AttachCurrentThread(&jenv, NULL); + if (result != 0) { + LOGE("attaching to JVM failed"); + engine.output_line = ""; + return c; + } + jstring args = jenv->NewStringUTF(engine.output_line.c_str()); + jenv->CallVoidMethod(engine.service_object, engine.output_method, args); + jenv->DeleteLocalRef(args); + result = engine.vm->DetachCurrentThread(); + if (result != 0) { + LOGE("detaching from JVM failed"); + return EOF; + } + engine.output_line = ""; + return c; + } +}; + +class jni_source : public std::streambuf { + char buffer[1001]; // 1 char putback area +public: + jni_source() { + setg(buffer + 1, buffer + 1, buffer + 1); + } + +protected: + virtual int_type underflow() { + if (gptr() < egptr()) { + return traits_type::to_int_type(*gptr()); + } + + int numPutBack = std::min(traits_type::to_int_type(gptr() - eback()), 1); + + std::memmove(buffer + (1 - numPutBack), gptr() - numPutBack, numPutBack); + + engine_wrapper &engine = engine_wrapper::sharedEngine(); + LOGV("Locking input mutex in jni_source"); + std::unique_lock lk(engine.mutex); + if (!engine.engine_is_running) { + { + LOGV("Engine was not running."); + std::lock_guard lk(engine.startup_mutex); + engine.engine_is_running = true; + } + engine.startup_cv.notify_all(); + LOGV("Notifying engine startup waiters."); + } + LOGV("Start waiting for input..."); + engine.condition_variable.wait(lk, [&] { return (engine.input_lines.size() > 0); }); + LOGV("Input arrived to jni_source."); + int len = std::min((int)engine.input_lines.front().length(), 1000); + LOGD("Input: %s", engine.input_lines.front().c_str()); + std::copy(engine.input_lines.front().begin(), engine.input_lines.front().begin() + len, buffer + 1); + if (len == engine.input_lines.front().length()) { + engine.input_lines.pop_front(); + } else { + engine.input_lines.front() = engine.input_lines.front().substr(len); + } + + setg(buffer + (1 - numPutBack), buffer + 1, buffer + 1 + len); + return traits_type::to_int_type(*gptr()); + } +}; + +} // namespace + +// JNI +// ================== +// ================== + +extern "C" { + +stockfishservice::jni_sink sink_buf; +stockfishservice::jni_source source_buf; + +JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { + JNIEnv *jenv; + if (vm->GetEnv(reinterpret_cast(&jenv), JNI_VERSION_1_6) != JNI_OK) { + return -1; + } + + jclass clazz = jenv->FindClass("com/nwagu/stockfish/StockfishService"); + if (clazz == 0) { + LOGE("class com/nwagu/stockfish/StockfishService not found"); + } + + jmethodID engineToClient = jenv->GetMethodID(clazz, "engineToClient", "(Ljava/lang/String;)V"); + if (engineToClient == 0) { + LOGE("method engineToClient not found"); + } + LOGV("Creating sharedEngine()"); + stockfishservice::engine_wrapper &engine = stockfishservice::engine_wrapper::sharedEngine(); + engine.output_method = engineToClient; + engine.vm = vm; + + jenv->DeleteLocalRef(clazz); + LOGV("redirecting cout and cin"); + + std::cin.rdbuf(&source_buf); + std::cout.rdbuf(&sink_buf); + + return JNI_VERSION_1_6; +} + + +JNIEXPORT void JNICALL Java_com_nwagu_stockfish_StockfishService_clientToEngine(JNIEnv *env, + jobject thiz, + jstring line) { + LOGV("At clientToEngine."); + stockfishservice::engine_wrapper &engine = stockfishservice::engine_wrapper::sharedEngine(); + if (!engine.service_object) { + LOGV("Setting Java Service object."); + engine.service_object = env->NewGlobalRef(thiz); + } + if (!engine.engine_is_running) { + LOGV("Calling startEngine()."); + engine.startEngine(); + { + std::unique_lock ul(engine.startup_mutex); + LOGV("Waiting for engine startup."); + engine.startup_cv.wait(ul, [&] {return engine.engine_is_running;}); + LOGV("Engine startup wait is over."); + } + } + { + jboolean is_copy; + const char *line_str = env->GetStringUTFChars(line, &is_copy); + std::lock_guard lk(engine.mutex); + engine.input_lines.emplace_back(line_str); + env->ReleaseStringUTFChars(line, line_str); + } + LOGV("Waking up reader thread."); + engine.condition_variable.notify_one(); +} + +} // extern "C" + + +