From c6cd60deef35584b779569b7078186792b23977f Mon Sep 17 00:00:00 2001 From: Andy2 Date: Mon, 11 Apr 2011 06:42:17 -0700 Subject: [PATCH] Save and restore per-player dicts; load games that have 'em correctly. Robots default to BasEnglish dict and humans to CollegeEng. Add new per-game default for robot dict. Still need to deal with language changes and non-English case in general. --- xwords4/android/XWords4/jni/Android.mk | 2 +- xwords4/android/XWords4/jni/anddict.c | 37 +++++++++++ xwords4/android/XWords4/jni/anddict.h | 5 ++ xwords4/android/XWords4/jni/xwjni.c | 24 ++++--- .../XWords4/res/values/common_rsrc.xml | 1 + .../android/XWords4/res/values/strings.xml | 4 +- xwords4/android/XWords4/res/xml/xwprefs.xml | 6 ++ .../eehouse/android/xw4/BoardActivity.java | 10 +-- .../org/eehouse/android/xw4/GameUtils.java | 64 ++++++++++++------- .../eehouse/android/xw4/jni/CommonPrefs.java | 11 +++- .../eehouse/android/xw4/jni/CurGameInfo.java | 27 +++++++- .../org/eehouse/android/xw4/jni/XwJNI.java | 18 +++--- 12 files changed, 156 insertions(+), 53 deletions(-) diff --git a/xwords4/android/XWords4/jni/Android.mk b/xwords4/android/XWords4/jni/Android.mk index 057f89440..25e123332 100644 --- a/xwords4/android/XWords4/jni/Android.mk +++ b/xwords4/android/XWords4/jni/Android.mk @@ -10,7 +10,7 @@ local_C_INCLUDES+= \ local_LDLIBS += -llog -# local_DEBUG = -DMEM_DEBUG -DDEBUG -DENABLE_LOGGING +local_DEBUG = -DMEM_DEBUG -DDEBUG -DENABLE_LOGGING local_DEFINES += \ $(local_DEBUG) \ -DXWFEATURE_RELAY \ diff --git a/xwords4/android/XWords4/jni/anddict.c b/xwords4/android/XWords4/jni/anddict.c index 0f6b67b30..b9c595ddb 100644 --- a/xwords4/android/XWords4/jni/anddict.c +++ b/xwords4/android/XWords4/jni/anddict.c @@ -422,6 +422,30 @@ and_dictionary_make_empty( MPFORMAL JNIEnv* env, JNIUtilCtxt* jniutil ) return (DictionaryCtxt*)anddict; } +void +makeDicts( MPFORMAL JNIEnv *env, JNIUtilCtxt* jniutil, PlayerDicts* dicts, + jobjectArray jdicts, jobjectArray jnames ) +{ + LOG_FUNC(); + int ii; + jsize len = (*env)->GetArrayLength( env, jdicts ); + XP_ASSERT( len == (*env)->GetArrayLength( env, jnames ) ); + + for ( ii = 0; ii < VSIZE(dicts->dicts); ++ii ) { + DictionaryCtxt* dict = NULL; + if ( ii < len ) { + jobject jdict = (*env)->GetObjectArrayElement( env, jdicts, ii ); + jstring jname = (*env)->GetObjectArrayElement( env, jnames, ii ); + dict = makeDict( MPPARM(mpool) env, jniutil, jdict, jname ); + XP_ASSERT( !!dict ); + (*env)->DeleteLocalRef( env, jdict ); + (*env)->DeleteLocalRef( env, jname ); + } + dicts->dicts[ii] = dict; + } + LOG_RETURN_VOID(); +} + DictionaryCtxt* makeDict( MPFORMAL JNIEnv *env, JNIUtilCtxt* jniutil, jbyteArray jbytes, jstring jname ) @@ -449,3 +473,16 @@ makeDict( MPFORMAL JNIEnv *env, JNIUtilCtxt* jniutil, jbyteArray jbytes, return (DictionaryCtxt*)anddict; } + +void +destroyDicts( PlayerDicts* dicts ) +{ + DictionaryCtxt** ctxts = dicts->dicts; + for ( ; ; ) { + if ( !*ctxts ) { + break; + } + dict_destroy( *ctxts ); + ++ctxts; + } +} diff --git a/xwords4/android/XWords4/jni/anddict.h b/xwords4/android/XWords4/jni/anddict.h index 1f6f4b41f..eed43c394 100644 --- a/xwords4/android/XWords4/jni/anddict.h +++ b/xwords4/android/XWords4/jni/anddict.h @@ -31,6 +31,11 @@ dict_splitFaces( DictionaryCtxt* dict, const XP_U8* bytes, DictionaryCtxt* makeDict( MPFORMAL JNIEnv *env, JNIUtilCtxt* jniutil, jbyteArray bytes, jstring jname ); +void makeDicts( MPFORMAL JNIEnv *env, JNIUtilCtxt* jniutil, PlayerDicts* dicts, + jobjectArray jdicts, jobjectArray jnames ); + +void destroyDicts( PlayerDicts* dicts ); + DictionaryCtxt* and_dictionary_make_empty( MPFORMAL JNIEnv *env, JNIUtilCtxt* jniutil ); diff --git a/xwords4/android/XWords4/jni/xwjni.c b/xwords4/android/XWords4/jni/xwjni.c index 26f4c4f2e..822686aa9 100644 --- a/xwords4/android/XWords4/jni/xwjni.c +++ b/xwords4/android/XWords4/jni/xwjni.c @@ -380,7 +380,7 @@ JNIEXPORT void JNICALL Java_org_eehouse_android_xw4_jni_XwJNI_game_1makeNewGame ( JNIEnv* env, jclass C, jint gamePtr, jobject j_gi, jobject j_util, jobject jniu, jobject j_draw, jobject j_cp, jobject j_procs, - jbyteArray jDictBytes, jstring jDictName ) + jobjectArray j_dicts, jobjectArray j_names ) { XWJNI_START_GLOBALS(); CurGameInfo* gi = makeGI( MPPARM(mpool) env, j_gi ); @@ -398,16 +398,15 @@ Java_org_eehouse_android_xw4_jni_XwJNI_game_1makeNewGame game_makeNewGame( MPPARM(mpool) &state->game, gi, globals->util, dctx, &cp, globals->xportProcs ); - DictionaryCtxt* dict = makeDict( MPPARM(mpool) env, globals->jniutil, - jDictBytes, jDictName ); + PlayerDicts dicts; + makeDicts( MPPARM(mpool) env, globals->jniutil, &dicts, j_dicts, j_names ); #ifdef STUBBED_DICT if ( !dict ) { XP_LOGF( "falling back to stubbed dict" ); dict = make_stubbed_dict( MPPARM_NOCOMMA(mpool) ); } #endif - XP_ASSERT( !!dict ); - model_setDictionary( state->game.model, dict ); + model_setPlayerDicts( state->game.model, &dicts ); XWJNI_END(); } /* makeNewGame */ @@ -439,19 +438,19 @@ JNIEXPORT void JNICALL Java_org_eehouse_android_xw4_jni_XwJNI_game_1dispose JNIEXPORT jboolean JNICALL Java_org_eehouse_android_xw4_jni_XwJNI_game_1makeFromStream -( JNIEnv* env, jclass C, jint gamePtr, jbyteArray jstream, - jobject /*out*/jgi, jbyteArray jdict, jstring jdictName, jobject jutil, - jobject jniu, jobject jdraw, jobject jcp, jobject jprocs ) +( JNIEnv* env, jclass C, jint gamePtr, jbyteArray jstream, jobject /*out*/jgi, + jobjectArray jdicts, jobjectArray jdictNames, jobject jutil, jobject jniu, + jobject jdraw, jobject jcp, jobject jprocs ) { jboolean result; + PlayerDicts dicts; XWJNI_START_GLOBALS(); globals->gi = (CurGameInfo*)XP_CALLOC( mpool, sizeof(*globals->gi) ); globals->util = makeUtil( MPPARM(mpool) &state->env, jutil, globals->gi, globals ); globals->jniutil = makeJNIUtil( MPPARM(mpool) &state->env, jniu ); - DictionaryCtxt* dict = makeDict( MPPARM(mpool) env, globals->jniutil, - jdict, jdictName ); + makeDicts( MPPARM(mpool) env, globals->jniutil, &dicts, jdicts, jdictNames ); globals->dctx = makeDraw( MPPARM(mpool) &state->env, jdraw ); globals->xportProcs = makeXportProcs( MPPARM(mpool) &state->env, jprocs ); @@ -461,7 +460,7 @@ Java_org_eehouse_android_xw4_jni_XwJNI_game_1makeFromStream CommonPrefs cp; loadCommonPrefs( env, &cp, jcp ); result = game_makeFromStream( MPPARM(mpool) stream, &state->game, - globals->gi, dict, NULL, + globals->gi, NULL, &dicts, globals->util, globals->dctx, &cp, globals->xportProcs ); stream_destroy( stream ); @@ -474,8 +473,7 @@ Java_org_eehouse_android_xw4_jni_XwJNI_game_1makeFromStream } else { destroyDraw( &globals->dctx ); destroyXportProcs( &globals->xportProcs ); - dict_destroy( dict ); - dict = NULL; + destroyDicts( &dicts ); destroyUtil( &globals->util ); destroyJNIUtil( &globals->jniutil ); destroyGI( MPPARM(mpool) &globals->gi ); diff --git a/xwords4/android/XWords4/res/values/common_rsrc.xml b/xwords4/android/XWords4/res/values/common_rsrc.xml index 7e99ccdfc..f6c463c59 100644 --- a/xwords4/android/XWords4/res/values/common_rsrc.xml +++ b/xwords4/android/XWords4/res/values/common_rsrc.xml @@ -37,6 +37,7 @@ key_board_size key_initial_player_minutes key_default_dict + key_default_robodict key_default_phonies2 key_default_timerenabled key_connect_frequency diff --git a/xwords4/android/XWords4/res/values/strings.xml b/xwords4/android/XWords4/res/values/strings.xml index 1385a2386..14b825500 100644 --- a/xwords4/android/XWords4/res/values/strings.xml +++ b/xwords4/android/XWords4/res/values/strings.xml @@ -269,7 +269,9 @@ Settings that apply to networked games - Game dictionary + Dictionary for humans + Dictionary for robots + Handle phonies How to handle \"phonies\" (words not in dictionary) diff --git a/xwords4/android/XWords4/res/xml/xwprefs.xml b/xwords4/android/XWords4/res/xml/xwprefs.xml index decbef929..e83348dac 100644 --- a/xwords4/android/XWords4/res/xml/xwprefs.xml +++ b/xwords4/android/XWords4/res/xml/xwprefs.xml @@ -13,6 +13,12 @@ android:defaultValue="CollegeEng_2to8" /> + + seen = new HashMap(); + for ( int ii = 0; ii < names.length; ++ii ) { + String name = names[ii]; + byte[] bytes = seen.get( name ); + if ( null == bytes ) { + bytes = openDict( context, name ); + seen.put( name, bytes ); + } + result[ii] = bytes; + } + return result; + } + public static boolean saveDict( Context context, String name, InputStream in ) { boolean success = false; @@ -618,23 +636,24 @@ public class GameUtils { public static void replaceDict( Context context, String path, String dict ) { - GameLock lock = new GameLock( path, true ).lock(); - byte[] stream = savedGame( context, lock ); - CurGameInfo gi = new CurGameInfo( context ); - byte[] dictBytes = GameUtils.openDict( context, dict ); + Assert.fail(); + // GameLock lock = new GameLock( path, true ).lock(); + // byte[] stream = savedGame( context, lock ); + // CurGameInfo gi = new CurGameInfo( context ); + // byte[] dictBytes = openDict( context, dict ); - int gamePtr = XwJNI.initJNI(); - XwJNI.game_makeFromStream( gamePtr, stream, - JNIUtilsImpl.get(), gi, - dictBytes, dict, - CommonPrefs.get( context ) ); - gi.dictName = dict; + // int gamePtr = XwJNI.initJNI(); + // XwJNI.game_makeFromStream( gamePtr, stream, + // JNIUtilsImpl.get(), gi, + // dictBytes, dict, + // CommonPrefs.get( context ) ); + // gi.dictName = dict; - saveGame( context, gamePtr, gi, lock, false ); + // saveGame( context, gamePtr, gi, lock, false ); - summarizeAndClose( context, lock, gamePtr, gi ); + // summarizeAndClose( context, lock, gamePtr, gi ); - lock.unlock(); + // lock.unlock(); } public static void applyChanges( Context context, CurGameInfo gi, @@ -645,7 +664,8 @@ public class GameUtils { // somesuch. But: do we have a way to save changes to a gi // that don't reset the game, e.g. player name for standalone // games? - byte[] dictBytes = GameUtils.openDict( context, gi.dictName ); + String[] dictNames = gi.dictNames(); + byte[][] dictBytes = openDicts( context, dictNames ); int gamePtr = XwJNI.initJNI(); boolean madeGame = false; CommonPrefs cp = CommonPrefs.get( context ); @@ -653,18 +673,18 @@ public class GameUtils { if ( forceNew ) { tellRelayDied( context, lock, true ); } else { - byte[] stream = GameUtils.savedGame( context, lock ); + byte[] stream = savedGame( context, lock ); // Will fail if there's nothing in the stream but a gi. madeGame = XwJNI.game_makeFromStream( gamePtr, stream, JNIUtilsImpl.get(), new CurGameInfo(context), - dictBytes, gi.dictName, cp ); + dictBytes, dictNames, cp ); } if ( forceNew || !madeGame ) { gi.setInProgress( false ); XwJNI.game_makeNewGame( gamePtr, gi, JNIUtilsImpl.get(), - cp, dictBytes, gi.dictName ); + cp, dictBytes, dictNames ); } if ( null != car ) { diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/CommonPrefs.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/CommonPrefs.java index 9daba8308..fb577aa78 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/CommonPrefs.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/CommonPrefs.java @@ -201,7 +201,7 @@ public class CommonPrefs { } } - public static String getDefaultDict( Context context ) + public static String getDefaultHumanDict( Context context ) { String value = getString( context, R.string.key_default_dict ); if ( value.equals("") || !GameUtils.dictExists( context, value ) ) { @@ -210,6 +210,15 @@ public class CommonPrefs { return value; } + public static String getDefaultRobotDict( Context context ) + { + String value = getString( context, R.string.key_default_robodict ); + if ( value.equals("") || !GameUtils.dictExists( context, value ) ) { + value = getDefaultHumanDict( context ); + } + return value; + } + public static CurGameInfo.XWPhoniesChoice getDefaultPhonies( Context context ) { diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/CurGameInfo.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/CurGameInfo.java index fc506c9c2..de367ee90 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/CurGameInfo.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/CurGameInfo.java @@ -74,7 +74,7 @@ public class CurGameInfo { players = new LocalPlayer[MAX_NUM_PLAYERS]; serverRole = isNetworked ? DeviceRole.SERVER_ISCLIENT : DeviceRole.SERVER_STANDALONE; - dictName = CommonPrefs.getDefaultDict( context ); + dictName = CommonPrefs.getDefaultHumanDict( context ); dictLang = DictLangCache.getDictLangCode( context, dictName ); hintsNotAllowed = !CommonPrefs.getDefaultHintsAllowed( context ); phoniesAction = CommonPrefs.getDefaultPhonies( context ); @@ -235,6 +235,17 @@ public class CurGameInfo { return names; } + public String[] dictNames() + { + assignDicts(); + + String[] result = new String[nPlayers]; + for ( int ii = 0; ii < nPlayers; ++ii ) { + result[ii] = players[ii].dictName; + } + return result; + } + public boolean addPlayer() { boolean added = nPlayers < MAX_NUM_PLAYERS; @@ -306,4 +317,18 @@ public class CurGameInfo { } return canJuggle; } + + private void assignDicts() + { + String humanDict = CommonPrefs.getDefaultHumanDict( m_context ); + int lang = DictLangCache.getDictLangCode( m_context, humanDict ); + Assert.assertTrue( lang == dictLang ); + String robotDict = CommonPrefs.getDefaultRobotDict( m_context ); + for ( int ii = 0; ii < nPlayers; ++ii ) { + LocalPlayer lp = players[ii]; + if ( null == lp.dictName ) { + lp.dictName = lp.isRobot() ? robotDict : humanDict; + } + } + } } diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/XwJNI.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/XwJNI.java index 461375566..b37878dc4 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/XwJNI.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/XwJNI.java @@ -59,13 +59,13 @@ public class XwJNI { JNIUtils jniu, DrawCtx draw, CommonPrefs cp, TransportProcs procs, - byte[] dict, String dictName ); + byte[][] dicts, String[] dictNames ); public static native boolean game_makeFromStream( int gamePtr, byte[] stream, CurGameInfo gi, - byte[] dict, - String dictName, + byte[][] dicts, + String[] dictNames, UtilCtxt util, JNIUtils jniu, DrawCtx draw, @@ -76,19 +76,19 @@ public class XwJNI { // played public static void game_makeNewGame( int gamePtr, CurGameInfo gi, JNIUtils jniu, CommonPrefs cp, - byte[] dict, String dictName ) { + byte[][] dicts, String[] dictNames ) { game_makeNewGame( gamePtr, gi, (UtilCtxt)null, jniu, (DrawCtx)null, cp, (TransportProcs)null, - dict, dictName ); + dicts, dictNames ); } public static boolean game_makeFromStream( int gamePtr, byte[] stream, JNIUtils jniu, CurGameInfo gi, - byte[] dict, String dictName, + byte[][] dicts, String[] dictNames, CommonPrefs cp ) { - return game_makeFromStream( gamePtr, stream, gi, dict, dictName, + return game_makeFromStream( gamePtr, stream, gi, dicts, dictNames, (UtilCtxt)null, jniu, (DrawCtx)null, cp, (TransportProcs)null ); } @@ -97,10 +97,10 @@ public class XwJNI { byte[] stream, JNIUtils jniu, CurGameInfo gi, - byte[] dict, String dictName, + byte[][] dicts, String[] dictNames, UtilCtxt util, CommonPrefs cp ) { - return game_makeFromStream( gamePtr, stream, gi, dict, dictName, + return game_makeFromStream( gamePtr, stream, gi, dicts, dictNames, util, jniu, (DrawCtx)null, cp, (TransportProcs)null ); }