mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2025-01-28 07:58:08 +01:00
Merge branch 'android_branch' into send_in_background
Conflicts: xwords4/linux/cursesmain.c
This commit is contained in:
commit
2492e7cfc5
67 changed files with 2705 additions and 742 deletions
|
@ -22,7 +22,7 @@
|
||||||
to come from a domain that you own or have control over. -->
|
to come from a domain that you own or have control over. -->
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="org.eehouse.android.xw4"
|
package="org.eehouse.android.xw4"
|
||||||
android:versionCode="29"
|
android:versionCode="30"
|
||||||
android:versionName="@string/app_version"
|
android:versionName="@string/app_version"
|
||||||
>
|
>
|
||||||
|
|
||||||
|
@ -118,8 +118,11 @@
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity android:name="RelayGameActivity"/>
|
<activity android:name="RelayGameActivity"/>
|
||||||
|
<activity android:name="DictBrowseActivity"
|
||||||
|
android:configChanges="keyboardHidden|orientation"
|
||||||
|
/>
|
||||||
<activity android:name="ChatActivity"
|
<activity android:name="ChatActivity"
|
||||||
|
android:configChanges="keyboardHidden|orientation"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<service android:name="RelayService"/>
|
<service android:name="RelayService"/>
|
||||||
|
|
|
@ -25,6 +25,9 @@ local_DEFINES += \
|
||||||
-DDISABLE_EMPTYTRAY_UNDO \
|
-DDISABLE_EMPTYTRAY_UNDO \
|
||||||
-DDISABLE_TILE_SEL \
|
-DDISABLE_TILE_SEL \
|
||||||
-DXWFEATURE_BOARDWORDS \
|
-DXWFEATURE_BOARDWORDS \
|
||||||
|
-DXWFEATURE_WALKDICT \
|
||||||
|
-DXWFEATURE_DICTSANITY \
|
||||||
|
-DFEATURE_TRAY_EDIT \
|
||||||
-DNODE_CAN_4 \
|
-DNODE_CAN_4 \
|
||||||
-DRELAY_ROOM_DEFAULT=\"\"\
|
-DRELAY_ROOM_DEFAULT=\"\"\
|
||||||
-D__LITTLE_ENDIAN \
|
-D__LITTLE_ENDIAN \
|
||||||
|
@ -47,6 +50,7 @@ common_SRC_FILES += \
|
||||||
$(COMMON_PATH)/pool.c \
|
$(COMMON_PATH)/pool.c \
|
||||||
$(COMMON_PATH)/tray.c \
|
$(COMMON_PATH)/tray.c \
|
||||||
$(COMMON_PATH)/dictnry.c \
|
$(COMMON_PATH)/dictnry.c \
|
||||||
|
$(COMMON_PATH)/dictiter.c \
|
||||||
$(COMMON_PATH)/mscore.c \
|
$(COMMON_PATH)/mscore.c \
|
||||||
$(COMMON_PATH)/vtabmgr.c \
|
$(COMMON_PATH)/vtabmgr.c \
|
||||||
$(COMMON_PATH)/strutils.c \
|
$(COMMON_PATH)/strutils.c \
|
||||||
|
|
|
@ -44,6 +44,12 @@ typedef struct _AndDictionaryCtxt {
|
||||||
jbyteArray byteArray;
|
jbyteArray byteArray;
|
||||||
} AndDictionaryCtxt;
|
} AndDictionaryCtxt;
|
||||||
|
|
||||||
|
#define CHECK_PTR(p,c,e) \
|
||||||
|
if ( ((p)+(c)) >= (e) ) { \
|
||||||
|
XP_LOGF( "%s (line %d); out of bytes", __func__, __LINE__ ); \
|
||||||
|
goto error; \
|
||||||
|
}
|
||||||
|
|
||||||
static void splitFaces_via_java( JNIEnv* env, AndDictionaryCtxt* ctxt,
|
static void splitFaces_via_java( JNIEnv* env, AndDictionaryCtxt* ctxt,
|
||||||
const XP_U8* ptr,
|
const XP_U8* ptr,
|
||||||
int nFaceBytes, int nFaces, XP_Bool isUTF8 );
|
int nFaceBytes, int nFaces, XP_Bool isUTF8 );
|
||||||
|
@ -94,15 +100,19 @@ andCountSpecials( AndDictionaryCtxt* ctxt )
|
||||||
return result;
|
return result;
|
||||||
} /* andCountSpecials */
|
} /* andCountSpecials */
|
||||||
|
|
||||||
static XP_Bitmap
|
static XP_Bool
|
||||||
andMakeBitmap( AndDictionaryCtxt* ctxt, XP_U8 const** ptrp )
|
andMakeBitmap( AndDictionaryCtxt* ctxt, XP_U8 const** ptrp,
|
||||||
|
const XP_U8 const* end, XP_Bitmap* result )
|
||||||
{
|
{
|
||||||
|
XP_Bool success = XP_TRUE;
|
||||||
XP_U8 const* ptr = *ptrp;
|
XP_U8 const* ptr = *ptrp;
|
||||||
|
CHECK_PTR( ptr, 1, end );
|
||||||
XP_U8 nCols = *ptr++;
|
XP_U8 nCols = *ptr++;
|
||||||
jobject bitmap = NULL;
|
jobject bitmap = NULL;
|
||||||
|
|
||||||
if ( nCols > 0 ) {
|
if ( nCols > 0 ) {
|
||||||
|
CHECK_PTR( ptr, 1, end );
|
||||||
XP_U8 nRows = *ptr++;
|
XP_U8 nRows = *ptr++;
|
||||||
|
CHECK_PTR( ptr, ((nRows*nCols)+7) / 8, end );
|
||||||
#ifdef DROP_BITMAPS
|
#ifdef DROP_BITMAPS
|
||||||
ptr += ((nRows*nCols)+7) / 8;
|
ptr += ((nRows*nCols)+7) / 8;
|
||||||
#else
|
#else
|
||||||
|
@ -135,14 +145,20 @@ andMakeBitmap( AndDictionaryCtxt* ctxt, XP_U8 const** ptrp )
|
||||||
XP_FREE( ctxt->super.mpool, colors );
|
XP_FREE( ctxt->super.mpool, colors );
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
goto done;
|
||||||
|
error:
|
||||||
|
success = XP_FALSE;
|
||||||
|
done:
|
||||||
*ptrp = ptr;
|
*ptrp = ptr;
|
||||||
return (XP_Bitmap)bitmap;
|
*result = bitmap;
|
||||||
|
return success;
|
||||||
} /* andMakeBitmap */
|
} /* andMakeBitmap */
|
||||||
|
|
||||||
static void
|
static XP_Bool
|
||||||
andLoadSpecialData( AndDictionaryCtxt* ctxt, XP_U8 const** ptrp )
|
andLoadSpecialData( AndDictionaryCtxt* ctxt, XP_U8 const** ptrp,
|
||||||
|
const XP_U8 const* end )
|
||||||
{
|
{
|
||||||
|
XP_Bool success = XP_TRUE;
|
||||||
XP_U16 nSpecials = andCountSpecials( ctxt );
|
XP_U16 nSpecials = andCountSpecials( ctxt );
|
||||||
XP_U8 const* ptr = *ptrp;
|
XP_U8 const* ptr = *ptrp;
|
||||||
Tile ii;
|
Tile ii;
|
||||||
|
@ -159,23 +175,36 @@ andLoadSpecialData( AndDictionaryCtxt* ctxt, XP_U8 const** ptrp )
|
||||||
const XP_UCHAR* facep = ctxt->super.facePtrs[(short)ii];
|
const XP_UCHAR* facep = ctxt->super.facePtrs[(short)ii];
|
||||||
if ( IS_SPECIAL(*facep) ) {
|
if ( IS_SPECIAL(*facep) ) {
|
||||||
/* get the string */
|
/* get the string */
|
||||||
|
CHECK_PTR( ptr, 1, end );
|
||||||
XP_U8 txtlen = *ptr++;
|
XP_U8 txtlen = *ptr++;
|
||||||
|
CHECK_PTR( ptr, txtlen, end );
|
||||||
XP_UCHAR* text = (XP_UCHAR*)XP_MALLOC(ctxt->super.mpool, txtlen+1);
|
XP_UCHAR* text = (XP_UCHAR*)XP_MALLOC(ctxt->super.mpool, txtlen+1);
|
||||||
|
texts[(int)*facep] = text;
|
||||||
XP_MEMCPY( text, ptr, txtlen );
|
XP_MEMCPY( text, ptr, txtlen );
|
||||||
ptr += txtlen;
|
ptr += txtlen;
|
||||||
text[txtlen] = '\0';
|
text[txtlen] = '\0';
|
||||||
XP_ASSERT( *facep < nSpecials ); /* firing */
|
XP_ASSERT( *facep < nSpecials ); /* firing */
|
||||||
texts[(int)*facep] = text;
|
|
||||||
|
|
||||||
bitmaps[(int)*facep].largeBM = andMakeBitmap( ctxt, &ptr );
|
if ( !andMakeBitmap( ctxt, &ptr, end,
|
||||||
bitmaps[(int)*facep].smallBM = andMakeBitmap( ctxt, &ptr );
|
&bitmaps[(int)*facep].largeBM ) ) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
if ( !andMakeBitmap( ctxt, &ptr, end,
|
||||||
|
&bitmaps[(int)*facep].smallBM ) ) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
goto done;
|
||||||
|
error:
|
||||||
|
success = XP_FALSE;
|
||||||
|
done:
|
||||||
ctxt->super.chars = texts;
|
ctxt->super.chars = texts;
|
||||||
ctxt->super.bitmaps = bitmaps;
|
ctxt->super.bitmaps = bitmaps;
|
||||||
|
|
||||||
*ptrp = ptr;
|
*ptrp = ptr;
|
||||||
|
return success;
|
||||||
} /* andLoadSpecialData */
|
} /* andLoadSpecialData */
|
||||||
|
|
||||||
/** Android doesn't include iconv for C code to use, so we'll have java do it.
|
/** Android doesn't include iconv for C code to use, so we'll have java do it.
|
||||||
|
@ -236,132 +265,151 @@ splitFaces_via_java( JNIEnv* env, AndDictionaryCtxt* ctxt, const XP_U8* ptr,
|
||||||
ctxt->super.facePtrs = ptrs;
|
ctxt->super.facePtrs = ptrs;
|
||||||
} /* splitFaces_via_java */
|
} /* splitFaces_via_java */
|
||||||
|
|
||||||
static void
|
static XP_Bool
|
||||||
parseDict( AndDictionaryCtxt* ctxt, XP_U8 const* ptr, XP_U32 dictLength )
|
parseDict( AndDictionaryCtxt* ctxt, XP_U8 const* ptr, XP_U32 dictLength,
|
||||||
|
XP_U32* numEdges )
|
||||||
{
|
{
|
||||||
while( !!ptr ) { /* lets us break.... */
|
XP_Bool success = XP_TRUE;
|
||||||
XP_U32 offset;
|
XP_ASSERT( !!ptr );
|
||||||
XP_U16 nFaces, numFaceBytes = 0;
|
const XP_U8 const* end = ptr + dictLength;
|
||||||
XP_U16 i;
|
XP_U32 offset;
|
||||||
XP_U16 flags;
|
XP_U16 nFaces, numFaceBytes = 0;
|
||||||
void* mappedBase = (void*)ptr;
|
XP_U16 i;
|
||||||
XP_U8 nodeSize;
|
XP_U16 flags;
|
||||||
XP_Bool isUTF8 = XP_FALSE;
|
void* mappedBase = (void*)ptr;
|
||||||
|
XP_U8 nodeSize;
|
||||||
|
XP_Bool isUTF8 = XP_FALSE;
|
||||||
|
|
||||||
flags = n_ptr_tohs( &ptr );
|
CHECK_PTR( ptr, sizeof(flags), end );
|
||||||
if ( 0 != (DICT_HEADER_MASK & flags) ) {
|
flags = n_ptr_tohs( &ptr );
|
||||||
flags &= ~DICT_HEADER_MASK;
|
if ( 0 != (DICT_HEADER_MASK & flags) ) {
|
||||||
XP_U16 headerLen = n_ptr_tohs( &ptr );
|
XP_U16 headerLen;
|
||||||
if ( 4 <= headerLen ) { /* have word count? */
|
flags &= ~DICT_HEADER_MASK;
|
||||||
ctxt->super.nWords = n_ptr_tohl( &ptr );
|
CHECK_PTR( ptr, sizeof(headerLen), end );
|
||||||
headerLen -= 4; /* don't skip it */
|
headerLen = n_ptr_tohs( &ptr );
|
||||||
}
|
if ( 4 <= headerLen ) { /* have word count? */
|
||||||
ptr += headerLen;
|
CHECK_PTR( ptr, sizeof(ctxt->super.nWords), end );
|
||||||
|
ctxt->super.nWords = n_ptr_tohl( &ptr );
|
||||||
|
headerLen -= 4; /* don't skip it */
|
||||||
}
|
}
|
||||||
|
CHECK_PTR( ptr, headerLen, end );
|
||||||
if ( flags == 0x0002 ) {
|
ptr += headerLen;
|
||||||
nodeSize = 3;
|
|
||||||
} else if ( flags == 0x0003 ) {
|
|
||||||
nodeSize = 4;
|
|
||||||
} else if ( flags == 0x0004 ) {
|
|
||||||
isUTF8 = XP_TRUE;
|
|
||||||
nodeSize = 3;
|
|
||||||
} else if ( flags == 0x0005 ) {
|
|
||||||
isUTF8 = XP_TRUE;
|
|
||||||
nodeSize = 4;
|
|
||||||
} else {
|
|
||||||
break; /* we want to return NULL */
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( isUTF8 ) {
|
|
||||||
numFaceBytes = (XP_U16)(*ptr++);
|
|
||||||
}
|
|
||||||
nFaces = (XP_U16)(*ptr++);
|
|
||||||
if ( nFaces > 64 ) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ctxt->super.nodeSize = nodeSize;
|
|
||||||
|
|
||||||
if ( !isUTF8 ) {
|
|
||||||
numFaceBytes = nFaces * 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
ctxt->super.nFaces = (XP_U8)nFaces;
|
|
||||||
ctxt->super.isUTF8 = isUTF8;
|
|
||||||
|
|
||||||
if ( isUTF8 ) {
|
|
||||||
splitFaces_via_java( ctxt->env, ctxt, ptr, numFaceBytes, nFaces,
|
|
||||||
XP_TRUE );
|
|
||||||
ptr += numFaceBytes;
|
|
||||||
} else {
|
|
||||||
XP_U8 tmp[nFaces*4]; /* should be enough... */
|
|
||||||
XP_U16 nBytes = 0;
|
|
||||||
XP_U16 ii;
|
|
||||||
/* Need to translate from iso-8859-n to utf8 */
|
|
||||||
for ( ii = 0; ii < nFaces; ++ii ) {
|
|
||||||
XP_UCHAR ch = ptr[1];
|
|
||||||
|
|
||||||
ptr += 2;
|
|
||||||
|
|
||||||
tmp[nBytes] = ch;
|
|
||||||
nBytes += 1;
|
|
||||||
}
|
|
||||||
XP_ASSERT( nFaces == nBytes );
|
|
||||||
splitFaces_via_java( ctxt->env, ctxt, tmp, nBytes, nFaces,
|
|
||||||
XP_FALSE );
|
|
||||||
}
|
|
||||||
|
|
||||||
ctxt->super.is_4_byte = (ctxt->super.nodeSize == 4);
|
|
||||||
|
|
||||||
ctxt->super.countsAndValues =
|
|
||||||
(XP_U8*)XP_MALLOC(ctxt->super.mpool, nFaces*2);
|
|
||||||
|
|
||||||
ctxt->super.langCode = ptr[0] & 0x7F;
|
|
||||||
ptr += 2; /* skip xloc header */
|
|
||||||
for ( i = 0; i < nFaces*2; i += 2 ) {
|
|
||||||
ctxt->super.countsAndValues[i] = *ptr++;
|
|
||||||
ctxt->super.countsAndValues[i+1] = *ptr++;
|
|
||||||
}
|
|
||||||
|
|
||||||
andLoadSpecialData( ctxt, &ptr );
|
|
||||||
|
|
||||||
dictLength -= ptr - (XP_U8*)mappedBase;
|
|
||||||
if ( dictLength >= sizeof(offset) ) {
|
|
||||||
offset = n_ptr_tohl( &ptr );
|
|
||||||
dictLength -= sizeof(offset);
|
|
||||||
#ifdef NODE_CAN_4
|
|
||||||
XP_ASSERT( dictLength % ctxt->super.nodeSize == 0 );
|
|
||||||
# ifdef DEBUG
|
|
||||||
ctxt->super.numEdges = dictLength / ctxt->super.nodeSize;
|
|
||||||
# endif
|
|
||||||
#else
|
|
||||||
XP_ASSERT( dictLength % 3 == 0 );
|
|
||||||
# ifdef DEBUG
|
|
||||||
ctxt->super.numEdges = dictLength / 3;
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
offset = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( dictLength > 0 ) {
|
|
||||||
ctxt->super.base = (array_edge*)ptr;
|
|
||||||
#ifdef NODE_CAN_4
|
|
||||||
ctxt->super.topEdge = ctxt->super.base
|
|
||||||
+ (offset * ctxt->super.nodeSize);
|
|
||||||
#else
|
|
||||||
ctxt->super.topEdge = ctxt->super.base + (offset * 3);
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
ctxt->super.topEdge = (array_edge*)NULL;
|
|
||||||
ctxt->super.base = (array_edge*)NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
setBlankTile( &ctxt->super );
|
|
||||||
|
|
||||||
break; /* exit phony while loop */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( flags == 0x0002 ) {
|
||||||
|
nodeSize = 3;
|
||||||
|
} else if ( flags == 0x0003 ) {
|
||||||
|
nodeSize = 4;
|
||||||
|
} else if ( flags == 0x0004 ) {
|
||||||
|
isUTF8 = XP_TRUE;
|
||||||
|
nodeSize = 3;
|
||||||
|
} else if ( flags == 0x0005 ) {
|
||||||
|
isUTF8 = XP_TRUE;
|
||||||
|
nodeSize = 4;
|
||||||
|
} else {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( isUTF8 ) {
|
||||||
|
CHECK_PTR( ptr, 1, end );
|
||||||
|
numFaceBytes = (XP_U16)(*ptr++);
|
||||||
|
}
|
||||||
|
CHECK_PTR( ptr, 1, end );
|
||||||
|
nFaces = (XP_U16)(*ptr++);
|
||||||
|
if ( nFaces > 64 ) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctxt->super.nodeSize = nodeSize;
|
||||||
|
|
||||||
|
if ( !isUTF8 ) {
|
||||||
|
numFaceBytes = nFaces * 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctxt->super.nFaces = (XP_U8)nFaces;
|
||||||
|
ctxt->super.isUTF8 = isUTF8;
|
||||||
|
|
||||||
|
if ( isUTF8 ) {
|
||||||
|
CHECK_PTR( ptr, numFaceBytes, end );
|
||||||
|
splitFaces_via_java( ctxt->env, ctxt, ptr, numFaceBytes, nFaces,
|
||||||
|
XP_TRUE );
|
||||||
|
ptr += numFaceBytes;
|
||||||
|
} else {
|
||||||
|
XP_U8 tmp[nFaces*4]; /* should be enough... */
|
||||||
|
XP_U16 nBytes = 0;
|
||||||
|
XP_U16 ii;
|
||||||
|
/* Need to translate from iso-8859-n to utf8 */
|
||||||
|
CHECK_PTR( ptr, 2 * nFaces, end );
|
||||||
|
for ( ii = 0; ii < nFaces; ++ii ) {
|
||||||
|
XP_UCHAR ch = ptr[1];
|
||||||
|
|
||||||
|
ptr += 2;
|
||||||
|
|
||||||
|
tmp[nBytes] = ch;
|
||||||
|
nBytes += 1;
|
||||||
|
}
|
||||||
|
XP_ASSERT( nFaces == nBytes );
|
||||||
|
splitFaces_via_java( ctxt->env, ctxt, tmp, nBytes, nFaces,
|
||||||
|
XP_FALSE );
|
||||||
|
}
|
||||||
|
|
||||||
|
ctxt->super.is_4_byte = (ctxt->super.nodeSize == 4);
|
||||||
|
|
||||||
|
ctxt->super.countsAndValues =
|
||||||
|
(XP_U8*)XP_MALLOC(ctxt->super.mpool, nFaces*2);
|
||||||
|
|
||||||
|
CHECK_PTR( ptr, 2, end );
|
||||||
|
ctxt->super.langCode = ptr[0] & 0x7F;
|
||||||
|
ptr += 2; /* skip xloc header */
|
||||||
|
CHECK_PTR( ptr, 2 * nFaces, end );
|
||||||
|
for ( i = 0; i < nFaces*2; i += 2 ) {
|
||||||
|
ctxt->super.countsAndValues[i] = *ptr++;
|
||||||
|
ctxt->super.countsAndValues[i+1] = *ptr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !andLoadSpecialData( ctxt, &ptr, end ) ) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
dictLength -= ptr - (XP_U8*)mappedBase;
|
||||||
|
if ( dictLength >= sizeof(offset) ) {
|
||||||
|
CHECK_PTR( ptr, sizeof(offset), end );
|
||||||
|
offset = n_ptr_tohl( &ptr );
|
||||||
|
dictLength -= sizeof(offset);
|
||||||
|
#ifdef NODE_CAN_4
|
||||||
|
XP_ASSERT( dictLength % ctxt->super.nodeSize == 0 );
|
||||||
|
*numEdges = dictLength / ctxt->super.nodeSize;
|
||||||
|
#else
|
||||||
|
XP_ASSERT( dictLength % 3 == 0 );
|
||||||
|
*numEdges = dictLength / 3;
|
||||||
|
#endif
|
||||||
|
#ifdef DEBUG
|
||||||
|
ctxt->super.numEdges = *numEdges;
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( dictLength > 0 ) {
|
||||||
|
ctxt->super.base = (array_edge*)ptr;
|
||||||
|
#ifdef NODE_CAN_4
|
||||||
|
ctxt->super.topEdge = ctxt->super.base
|
||||||
|
+ (offset * ctxt->super.nodeSize);
|
||||||
|
#else
|
||||||
|
ctxt->super.topEdge = ctxt->super.base + (offset * 3);
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
ctxt->super.topEdge = (array_edge*)NULL;
|
||||||
|
ctxt->super.base = (array_edge*)NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
setBlankTile( &ctxt->super );
|
||||||
|
|
||||||
|
goto done;
|
||||||
|
error:
|
||||||
|
success = XP_FALSE;
|
||||||
|
done:
|
||||||
|
return success;
|
||||||
} /* parseDict */
|
} /* parseDict */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -391,9 +439,9 @@ and_dictionary_destroy( DictionaryCtxt* dict )
|
||||||
XP_FREE( ctxt->super.mpool, ctxt->super.bitmaps );
|
XP_FREE( ctxt->super.mpool, ctxt->super.bitmaps );
|
||||||
}
|
}
|
||||||
|
|
||||||
XP_FREE( ctxt->super.mpool, ctxt->super.faces );
|
XP_FREEP( ctxt->super.mpool, &ctxt->super.faces );
|
||||||
XP_FREE( ctxt->super.mpool, ctxt->super.facePtrs );
|
XP_FREEP( ctxt->super.mpool, &ctxt->super.facePtrs );
|
||||||
XP_FREE( ctxt->super.mpool, ctxt->super.countsAndValues );
|
XP_FREEP( ctxt->super.mpool, &ctxt->super.countsAndValues );
|
||||||
XP_FREEP( ctxt->super.mpool, &ctxt->super.name );
|
XP_FREEP( ctxt->super.mpool, &ctxt->super.name );
|
||||||
XP_FREEP( ctxt->super.mpool, &ctxt->super.langName );
|
XP_FREEP( ctxt->super.mpool, &ctxt->super.langName );
|
||||||
|
|
||||||
|
@ -408,7 +456,7 @@ and_dictionary_destroy( DictionaryCtxt* dict )
|
||||||
(*env)->DeleteGlobalRef( env, ctxt->byteArray );
|
(*env)->DeleteGlobalRef( env, ctxt->byteArray );
|
||||||
}
|
}
|
||||||
XP_FREE( ctxt->super.mpool, ctxt );
|
XP_FREE( ctxt->super.mpool, ctxt );
|
||||||
}
|
} /* and_dictionary_destroy */
|
||||||
|
|
||||||
jobject
|
jobject
|
||||||
and_dictionary_getChars( JNIEnv* env, DictionaryCtxt* dict )
|
and_dictionary_getChars( JNIEnv* env, DictionaryCtxt* dict )
|
||||||
|
@ -454,7 +502,7 @@ makeDicts( MPFORMAL JNIEnv *env, JNIUtilCtxt* jniutil,
|
||||||
if ( NULL != jdict || NULL != jpath ) {
|
if ( NULL != jdict || NULL != jpath ) {
|
||||||
jstring jname = (*env)->GetObjectArrayElement( env, jnames, ii );
|
jstring jname = (*env)->GetObjectArrayElement( env, jnames, ii );
|
||||||
dict = makeDict( MPPARM(mpool) env, jniutil, jname, jdict,
|
dict = makeDict( MPPARM(mpool) env, jniutil, jname, jdict,
|
||||||
jpath, jlang );
|
jpath, jlang, false );
|
||||||
XP_ASSERT( !!dict );
|
XP_ASSERT( !!dict );
|
||||||
(*env)->DeleteLocalRef( env, jdict );
|
(*env)->DeleteLocalRef( env, jdict );
|
||||||
(*env)->DeleteLocalRef( env, jname );
|
(*env)->DeleteLocalRef( env, jname );
|
||||||
|
@ -474,46 +522,57 @@ makeDicts( MPFORMAL JNIEnv *env, JNIUtilCtxt* jniutil,
|
||||||
|
|
||||||
DictionaryCtxt*
|
DictionaryCtxt*
|
||||||
makeDict( MPFORMAL JNIEnv *env, JNIUtilCtxt* jniutil, jstring jname,
|
makeDict( MPFORMAL JNIEnv *env, JNIUtilCtxt* jniutil, jstring jname,
|
||||||
jbyteArray jbytes, jstring jpath, jstring jlangname )
|
jbyteArray jbytes, jstring jpath, jstring jlangname, jboolean check )
|
||||||
{
|
{
|
||||||
AndDictionaryCtxt* anddict = (AndDictionaryCtxt*)
|
jbyte* bytes = NULL;
|
||||||
and_dictionary_make_empty( MPPARM(mpool) env, jniutil );
|
jbyteArray byteArray = NULL;
|
||||||
|
off_t bytesSize = 0;
|
||||||
jsize len = 0;
|
|
||||||
|
|
||||||
if ( NULL == jpath ) {
|
if ( NULL == jpath ) {
|
||||||
len = (*env)->GetArrayLength( env, jbytes );
|
bytesSize = (*env)->GetArrayLength( env, jbytes );
|
||||||
anddict->byteArray = (*env)->NewGlobalRef( env, jbytes );
|
byteArray = (*env)->NewGlobalRef( env, jbytes );
|
||||||
anddict->bytes =
|
bytes = (*env)->GetByteArrayElements( env, byteArray, NULL );
|
||||||
(*env)->GetByteArrayElements( env, anddict->byteArray, NULL );
|
|
||||||
} else {
|
} else {
|
||||||
XP_ASSERT( NULL == anddict->byteArray );
|
|
||||||
const char* path = (*env)->GetStringUTFChars( env, jpath, NULL );
|
const char* path = (*env)->GetStringUTFChars( env, jpath, NULL );
|
||||||
|
|
||||||
struct stat statbuf;
|
struct stat statbuf;
|
||||||
if ( 0 == stat( path, &statbuf ) ) {
|
if ( 0 == stat( path, &statbuf ) && 0 < statbuf.st_size ) {
|
||||||
int fd = open( path, O_RDONLY );
|
int fd = open( path, O_RDONLY );
|
||||||
if ( fd >= 0 ) {
|
if ( fd >= 0 ) {
|
||||||
anddict->bytes = mmap( NULL, statbuf.st_size,
|
void* ptr = mmap( NULL, statbuf.st_size, PROT_READ,
|
||||||
PROT_READ, MAP_PRIVATE,
|
MAP_PRIVATE, fd, 0 );
|
||||||
fd, 0 );
|
|
||||||
close( fd );
|
close( fd );
|
||||||
|
if ( MAP_FAILED != ptr ) {
|
||||||
anddict->bytesSize = statbuf.st_size;
|
bytes = ptr;
|
||||||
len = statbuf.st_size;
|
bytesSize = statbuf.st_size;
|
||||||
XP_ASSERT( MAP_FAILED != anddict->bytes );
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(*env)->ReleaseStringUTFChars( env, jpath, path );
|
(*env)->ReleaseStringUTFChars( env, jpath, path );
|
||||||
}
|
}
|
||||||
|
|
||||||
anddict->super.destructor = and_dictionary_destroy;
|
AndDictionaryCtxt* anddict = NULL;
|
||||||
|
if ( NULL != bytes ) {
|
||||||
|
anddict = (AndDictionaryCtxt*)
|
||||||
|
and_dictionary_make_empty( MPPARM(mpool) env, jniutil );
|
||||||
|
anddict->bytes = bytes;
|
||||||
|
anddict->byteArray = byteArray;
|
||||||
|
anddict->bytesSize = bytesSize;
|
||||||
|
|
||||||
parseDict( anddict, (XP_U8*)anddict->bytes, len );
|
anddict->super.destructor = and_dictionary_destroy;
|
||||||
|
|
||||||
/* copy the name */
|
/* copy the name */
|
||||||
anddict->super.name = getStringCopy( MPPARM(mpool) env, jname );
|
anddict->super.name = getStringCopy( MPPARM(mpool) env, jname );
|
||||||
anddict->super.langName = getStringCopy( MPPARM(mpool) env, jlangname );
|
anddict->super.langName = getStringCopy( MPPARM(mpool) env, jlangname );
|
||||||
|
|
||||||
|
XP_U32 numEdges;
|
||||||
|
XP_Bool parses = parseDict( anddict, (XP_U8*)anddict->bytes,
|
||||||
|
bytesSize, &numEdges );
|
||||||
|
if ( !parses || (check && !checkSanity( &anddict->super, numEdges ) ) ) {
|
||||||
|
and_dictionary_destroy( (DictionaryCtxt*)anddict );
|
||||||
|
anddict = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (DictionaryCtxt*)anddict;
|
return (DictionaryCtxt*)anddict;
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ dict_splitFaces( DictionaryCtxt* dict, const XP_U8* bytes,
|
||||||
|
|
||||||
DictionaryCtxt* makeDict( MPFORMAL JNIEnv *env, JNIUtilCtxt* jniutil,
|
DictionaryCtxt* makeDict( MPFORMAL JNIEnv *env, JNIUtilCtxt* jniutil,
|
||||||
jstring jname, jbyteArray bytes, jstring path,
|
jstring jname, jbyteArray bytes, jstring path,
|
||||||
jstring jlang );
|
jstring jlang, jboolean check );
|
||||||
|
|
||||||
void makeDicts( MPFORMAL JNIEnv *env, JNIUtilCtxt* jniutil,
|
void makeDicts( MPFORMAL JNIEnv *env, JNIUtilCtxt* jniutil,
|
||||||
DictionaryCtxt** dict, PlayerDicts* dicts, jobjectArray jnames,
|
DictionaryCtxt** dict, PlayerDicts* dicts, jobjectArray jnames,
|
||||||
|
|
|
@ -280,7 +280,7 @@ makeStringArray( JNIEnv *env, int siz, const XP_UCHAR** vals )
|
||||||
(*env)->DeleteLocalRef( env, empty );
|
(*env)->DeleteLocalRef( env, empty );
|
||||||
|
|
||||||
int ii;
|
int ii;
|
||||||
for ( ii = 0; ii < siz; ++ii ) {
|
for ( ii = 0; !!vals && ii < siz; ++ii ) {
|
||||||
jstring jstr = (*env)->NewStringUTF( env, vals[ii] );
|
jstring jstr = (*env)->NewStringUTF( env, vals[ii] );
|
||||||
(*env)->SetObjectArrayElement( env, jarray, ii, jstr );
|
(*env)->SetObjectArrayElement( env, jarray, ii, jstr );
|
||||||
(*env)->DeleteLocalRef( env, jstr );
|
(*env)->DeleteLocalRef( env, jstr );
|
||||||
|
|
|
@ -132,18 +132,26 @@ and_util_userQuery( XW_UtilCtxt* uc, UtilQueryID id, XWStreamCtxt* stream )
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static XP_Bool
|
||||||
|
and_util_confirmTrade( XW_UtilCtxt* uc, const XP_UCHAR** tiles, XP_U16 nTiles )
|
||||||
|
{
|
||||||
|
XP_Bool result = XP_FALSE;
|
||||||
|
UTIL_CBK_HEADER("confirmTrade", "([Ljava/lang/String;)Z" );
|
||||||
|
jobjectArray jtiles = makeStringArray( env, nTiles, tiles );
|
||||||
|
result = (*env)->CallBooleanMethod( env, util->jutil, mid, jtiles );
|
||||||
|
(*env)->DeleteLocalRef( env, jtiles );
|
||||||
|
UTIL_CBK_TAIL();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
static XP_S16
|
static XP_S16
|
||||||
and_util_userPickTile( XW_UtilCtxt* uc, const PickInfo* pi,
|
and_util_userPickTileBlank( XW_UtilCtxt* uc, XP_U16 playerNum,
|
||||||
XP_U16 playerNum, const XP_UCHAR** texts, XP_U16 nTiles )
|
const XP_UCHAR** tileFaces, XP_U16 nTiles )
|
||||||
{
|
{
|
||||||
XP_S16 result = -1;
|
XP_S16 result = -1;
|
||||||
UTIL_CBK_HEADER("userPickTile", "(I[Ljava/lang/String;)I" );
|
UTIL_CBK_HEADER("userPickTileBlank", "(I[Ljava/lang/String;)I" );
|
||||||
|
|
||||||
#ifdef FEATURE_TRAY_EDIT
|
jobject jtexts = makeStringArray( env, nTiles, tileFaces );
|
||||||
++error; /* need to pass pi if this is on */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
jobject jtexts = makeStringArray( env, nTiles, texts );
|
|
||||||
|
|
||||||
result = (*env)->CallIntMethod( env, util->jutil, mid,
|
result = (*env)->CallIntMethod( env, util->jutil, mid,
|
||||||
playerNum, jtexts );
|
playerNum, jtexts );
|
||||||
|
@ -151,8 +159,27 @@ and_util_userPickTile( XW_UtilCtxt* uc, const PickInfo* pi,
|
||||||
(*env)->DeleteLocalRef( env, jtexts );
|
(*env)->DeleteLocalRef( env, jtexts );
|
||||||
UTIL_CBK_TAIL();
|
UTIL_CBK_TAIL();
|
||||||
return result;
|
return result;
|
||||||
} /* and_util_userPickTile */
|
}
|
||||||
|
|
||||||
|
static XP_S16
|
||||||
|
and_util_userPickTileTray( XW_UtilCtxt* uc, const PickInfo* pi,
|
||||||
|
XP_U16 playerNum, const XP_UCHAR** tileFaces,
|
||||||
|
XP_U16 nTiles )
|
||||||
|
{
|
||||||
|
XP_S16 result = -1;
|
||||||
|
UTIL_CBK_HEADER("userPickTileTray",
|
||||||
|
"(I[Ljava/lang/String;[Ljava/lang/String;I)I" );
|
||||||
|
jobject jtexts = makeStringArray( env, nTiles, tileFaces );
|
||||||
|
jobject jcurtiles = makeStringArray( env, pi->nCurTiles, pi->curTiles );
|
||||||
|
result = (*env)->CallIntMethod( env, util->jutil, mid,
|
||||||
|
playerNum, jtexts, jcurtiles,
|
||||||
|
pi->thisPick );
|
||||||
|
(*env)->DeleteLocalRef( env, jtexts );
|
||||||
|
(*env)->DeleteLocalRef( env, jcurtiles );
|
||||||
|
|
||||||
|
UTIL_CBK_TAIL();
|
||||||
|
return result;
|
||||||
|
} /* and_util_userPickTile */
|
||||||
|
|
||||||
static XP_Bool
|
static XP_Bool
|
||||||
and_util_askPassword( XW_UtilCtxt* uc, const XP_UCHAR* name,
|
and_util_askPassword( XW_UtilCtxt* uc, const XP_UCHAR* name,
|
||||||
|
@ -260,11 +287,17 @@ and_util_engineProgressCallback( XW_UtilCtxt* uc )
|
||||||
bool
|
bool
|
||||||
utilTimerFired( XW_UtilCtxt* uc, XWTimerReason why, int handle )
|
utilTimerFired( XW_UtilCtxt* uc, XWTimerReason why, int handle )
|
||||||
{
|
{
|
||||||
|
bool handled;
|
||||||
AndUtil* util = (AndUtil*)uc;
|
AndUtil* util = (AndUtil*)uc;
|
||||||
TimerStorage* timerStorage = &util->timerStorage[why];
|
TimerStorage* timerStorage = &util->timerStorage[why];
|
||||||
XP_ASSERT( handle == (int)timerStorage );
|
if ( handle == (int)timerStorage ) {
|
||||||
return (handle == (int)timerStorage)
|
handled = (*timerStorage->proc)( timerStorage->closure, why );
|
||||||
&& (*timerStorage->proc)( timerStorage->closure, why );
|
} else {
|
||||||
|
XP_LOGF( "%s: mismatch: handle=%d; timerStorage=%d", __func__,
|
||||||
|
handle, (int)timerStorage );
|
||||||
|
handled = false;
|
||||||
|
}
|
||||||
|
return handled;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -498,7 +531,9 @@ makeUtil( MPFORMAL JNIEnv** envp, jobject jutil, CurGameInfo* gi,
|
||||||
SET_PROC(getSquareBonus);
|
SET_PROC(getSquareBonus);
|
||||||
SET_PROC(userError);
|
SET_PROC(userError);
|
||||||
SET_PROC(userQuery);
|
SET_PROC(userQuery);
|
||||||
SET_PROC(userPickTile);
|
SET_PROC(confirmTrade);
|
||||||
|
SET_PROC(userPickTileBlank);
|
||||||
|
SET_PROC(userPickTileTray);
|
||||||
SET_PROC(askPassword);
|
SET_PROC(askPassword);
|
||||||
SET_PROC(trayHiddenChange);
|
SET_PROC(trayHiddenChange);
|
||||||
SET_PROC(yOffsetChange);
|
SET_PROC(yOffsetChange);
|
||||||
|
|
|
@ -76,6 +76,7 @@ void and_freep( void** ptrp );
|
||||||
|
|
||||||
#define XP_MIN(a,b) ((a)<(b)?(a):(b))
|
#define XP_MIN(a,b) ((a)<(b)?(a):(b))
|
||||||
#define XP_MAX(a,b) ((a)>(b)?(a):(b))
|
#define XP_MAX(a,b) ((a)>(b)?(a):(b))
|
||||||
|
#define XP_ABS(a) ((a)>=0?(a):-(a))
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
void and_assert( const char* test, int line, const char* file, const char* func );
|
void and_assert( const char* test, int line, const char* file, const char* func );
|
||||||
|
@ -117,4 +118,3 @@ extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/* -*-mode: C; compile-command: "../../scripts/ndkbuild.sh"; -*- */
|
/* -*-mode: C; compile-command: "../../scripts/ndkbuild.sh"; -*- */
|
||||||
/*
|
/*
|
||||||
* Copyright © 2009-2010 by Eric House (xwords@eehouse.org). All
|
* Copyright © 2009 - 2011 by Eric House (xwords@eehouse.org). All rights
|
||||||
* rights reserved.
|
* reserved.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License as
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
@ -28,6 +28,8 @@
|
||||||
#include "board.h"
|
#include "board.h"
|
||||||
#include "mempool.h"
|
#include "mempool.h"
|
||||||
#include "strutils.h"
|
#include "strutils.h"
|
||||||
|
#include "dictnry.h"
|
||||||
|
#include "dictiter.h"
|
||||||
|
|
||||||
#include "utilwrapper.h"
|
#include "utilwrapper.h"
|
||||||
#include "drawwrapper.h"
|
#include "drawwrapper.h"
|
||||||
|
@ -265,27 +267,32 @@ Java_org_eehouse_android_xw4_jni_XwJNI_comms_1getInitialAddr
|
||||||
setJAddrRec( env, jaddr, &addr );
|
setJAddrRec( env, jaddr, &addr );
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT void JNICALL
|
JNIEXPORT jboolean JNICALL
|
||||||
Java_org_eehouse_android_xw4_jni_XwJNI_dict_1getInfo
|
Java_org_eehouse_android_xw4_jni_XwJNI_dict_1getInfo
|
||||||
( JNIEnv* env, jclass C, jbyteArray jDictBytes, jstring jpath,
|
( JNIEnv* env, jclass C, jbyteArray jDictBytes, jstring jpath,
|
||||||
jobject jniu, jobject jinfo )
|
jobject jniu, jboolean check, jobject jinfo )
|
||||||
{
|
{
|
||||||
|
jboolean result = false;
|
||||||
#ifdef MEM_DEBUG
|
#ifdef MEM_DEBUG
|
||||||
MemPoolCtx* mpool = mpool_make();
|
MemPoolCtx* mpool = mpool_make();
|
||||||
#endif
|
#endif
|
||||||
JNIUtilCtxt* jniutil = makeJNIUtil( MPPARM(mpool) &env, jniu );
|
JNIUtilCtxt* jniutil = makeJNIUtil( MPPARM(mpool) &env, jniu );
|
||||||
DictionaryCtxt* dict = makeDict( MPPARM(mpool) env, jniutil, NULL,
|
DictionaryCtxt* dict = makeDict( MPPARM(mpool) env, jniutil, NULL,
|
||||||
jDictBytes, jpath, NULL );
|
jDictBytes, jpath, NULL, check );
|
||||||
jint code = dict_getLangCode( dict );
|
if ( NULL != dict ) {
|
||||||
jint nWords = dict_getWordCount( dict );
|
if ( NULL != jinfo ) {
|
||||||
dict_destroy( dict );
|
setInt( env, jinfo, "langCode", dict_getLangCode( dict ) );
|
||||||
|
setInt( env, jinfo, "wordCount", dict_getWordCount( dict ) );
|
||||||
|
}
|
||||||
|
dict_destroy( dict );
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
destroyJNIUtil( &jniutil );
|
destroyJNIUtil( &jniutil );
|
||||||
|
|
||||||
setInt( env, jinfo, "langCode", code );
|
|
||||||
setInt( env, jinfo, "wordCount", nWords );
|
|
||||||
#ifdef MEM_DEBUG
|
#ifdef MEM_DEBUG
|
||||||
mpool_destroy( mpool );
|
mpool_destroy( mpool );
|
||||||
#endif
|
#endif
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Dictionary methods: don't use gamePtr */
|
/* Dictionary methods: don't use gamePtr */
|
||||||
|
@ -1267,3 +1274,205 @@ Java_org_eehouse_android_xw4_jni_XwJNI_server_1sendChat
|
||||||
(*env)->ReleaseStringUTFChars( env, jmsg, msg );
|
(*env)->ReleaseStringUTFChars( env, jmsg, msg );
|
||||||
XWJNI_END();
|
XWJNI_END();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef XWFEATURE_WALKDICT
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Dict iterator
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
typedef struct _DictIterData {
|
||||||
|
JNIEnv* env;
|
||||||
|
JNIUtilCtxt* jniutil;
|
||||||
|
VTableMgr* vtMgr;
|
||||||
|
DictionaryCtxt* dict;
|
||||||
|
DictIter iter;
|
||||||
|
IndexData idata;
|
||||||
|
XP_U16 depth;
|
||||||
|
#ifdef MEM_DEBUG
|
||||||
|
MemPoolCtx* mpool;
|
||||||
|
#endif
|
||||||
|
} DictIterData;
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL
|
||||||
|
Java_org_eehouse_android_xw4_jni_XwJNI_dict_1iter_1init
|
||||||
|
(JNIEnv* env, jclass C, jbyteArray jDictBytes, jstring jpath, jobject jniu )
|
||||||
|
{
|
||||||
|
jint closure = 0;
|
||||||
|
#ifdef MEM_DEBUG
|
||||||
|
MemPoolCtx* mpool = mpool_make();
|
||||||
|
#endif
|
||||||
|
DictIterData* data = XP_CALLOC( mpool, sizeof(*data) );
|
||||||
|
data->env = env;
|
||||||
|
JNIUtilCtxt* jniutil = makeJNIUtil( MPPARM(mpool) &data->env, jniu );
|
||||||
|
DictionaryCtxt* dict = makeDict( MPPARM(mpool) env, jniutil, NULL,
|
||||||
|
jDictBytes, jpath, NULL, false );
|
||||||
|
if ( !!dict ) {
|
||||||
|
data->vtMgr = make_vtablemgr( MPPARM_NOCOMMA(mpool) );
|
||||||
|
data->jniutil = jniutil;
|
||||||
|
data->dict = dict;
|
||||||
|
#ifdef MEM_DEBUG
|
||||||
|
data->mpool = mpool;
|
||||||
|
#endif
|
||||||
|
closure = (int)data;
|
||||||
|
|
||||||
|
dict_initIter( data->dict, &data->iter );
|
||||||
|
(void)dict_firstWord( &data->iter );
|
||||||
|
} else {
|
||||||
|
destroyJNIUtil( &jniutil );
|
||||||
|
XP_FREE( mpool, data );
|
||||||
|
#ifdef MEM_DEBUG
|
||||||
|
mpool_destroy( mpool );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return closure;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_org_eehouse_android_xw4_jni_XwJNI_dict_1iter_1destroy
|
||||||
|
( JNIEnv* env, jclass C, jint closure )
|
||||||
|
{
|
||||||
|
DictIterData* data = (DictIterData*)closure;
|
||||||
|
if ( NULL != data ) {
|
||||||
|
#ifdef MEM_DEBUG
|
||||||
|
MemPoolCtx* mpool = data->mpool;
|
||||||
|
#endif
|
||||||
|
dict_destroy( data->dict );
|
||||||
|
destroyJNIUtil( &data->jniutil );
|
||||||
|
if ( !!data->idata.indices ) {
|
||||||
|
XP_FREE( mpool, data->idata.indices );
|
||||||
|
}
|
||||||
|
if ( !!data->idata.prefixes ) {
|
||||||
|
XP_FREE( mpool, data->idata.prefixes );
|
||||||
|
}
|
||||||
|
vtmgr_destroy( MPPARM(mpool) data->vtMgr );
|
||||||
|
XP_FREE( mpool, data );
|
||||||
|
#ifdef MEM_DEBUG
|
||||||
|
mpool_destroy( mpool );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL
|
||||||
|
Java_org_eehouse_android_xw4_jni_XwJNI_dict_1iter_1wordCount
|
||||||
|
(JNIEnv* env, jclass C, jint closure )
|
||||||
|
{
|
||||||
|
jint result = 0;
|
||||||
|
DictIterData* data = (DictIterData*)closure;
|
||||||
|
if ( NULL != data ) {
|
||||||
|
result = data->iter.nWords;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_org_eehouse_android_xw4_jni_XwJNI_dict_1iter_1makeIndex
|
||||||
|
( JNIEnv* env, jclass C, jint closure )
|
||||||
|
{
|
||||||
|
DictIterData* data = (DictIterData*)closure;
|
||||||
|
if ( NULL != data ) {
|
||||||
|
data->depth = 2; /* for now */
|
||||||
|
XP_U16 nFaces = dict_numTileFaces( data->dict );
|
||||||
|
XP_U16 ii;
|
||||||
|
XP_U16 count;
|
||||||
|
for ( count = 1, ii = 0; ii < data->depth; ++ii ) {
|
||||||
|
count *= nFaces;
|
||||||
|
}
|
||||||
|
|
||||||
|
IndexData* idata = &data->idata;
|
||||||
|
XP_ASSERT( !idata->prefixes );
|
||||||
|
idata->prefixes = XP_MALLOC( data->mpool, count * data->depth
|
||||||
|
* sizeof(*idata->prefixes) );
|
||||||
|
XP_ASSERT( !idata->indices );
|
||||||
|
idata->indices = XP_MALLOC( data->mpool,
|
||||||
|
count * sizeof(*idata->indices) );
|
||||||
|
idata->count = count;
|
||||||
|
|
||||||
|
dict_makeIndex( &data->iter, data->depth, idata );
|
||||||
|
|
||||||
|
idata->prefixes = XP_REALLOC( data->mpool, idata->prefixes,
|
||||||
|
idata->count * data->depth *
|
||||||
|
sizeof(*idata->prefixes) );
|
||||||
|
idata->indices = XP_REALLOC( data->mpool, idata->indices,
|
||||||
|
idata->count * sizeof(*idata->indices) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jobjectArray JNICALL
|
||||||
|
Java_org_eehouse_android_xw4_jni_XwJNI_dict_1iter_1getPrefixes
|
||||||
|
( JNIEnv* env, jclass C, jint closure )
|
||||||
|
{
|
||||||
|
jobjectArray result = NULL;
|
||||||
|
DictIterData* data = (DictIterData*)closure;
|
||||||
|
if ( NULL != data && NULL != data->idata.prefixes ) {
|
||||||
|
result = makeStringArray( env, data->idata.count, NULL );
|
||||||
|
|
||||||
|
int ii;
|
||||||
|
XP_U16 depth = data->depth;
|
||||||
|
for ( ii = 0; ii < data->idata.count; ++ii ) {
|
||||||
|
XP_UCHAR buf[16];
|
||||||
|
(void)dict_tilesToString( data->dict,
|
||||||
|
&data->idata.prefixes[depth*ii],
|
||||||
|
depth, buf, VSIZE(buf) );
|
||||||
|
jstring jstr = (*env)->NewStringUTF( env, buf );
|
||||||
|
(*env)->SetObjectArrayElement( env, result, ii, jstr );
|
||||||
|
(*env)->DeleteLocalRef( env, jstr );
|
||||||
|
}
|
||||||
|
(*env)->DeleteLocalRef( env, result );
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jintArray JNICALL
|
||||||
|
Java_org_eehouse_android_xw4_jni_XwJNI_dict_1iter_1getIndices
|
||||||
|
( JNIEnv* env, jclass C , jint closure )
|
||||||
|
{
|
||||||
|
jintArray jindices = NULL;
|
||||||
|
DictIterData* data = (DictIterData*)closure;
|
||||||
|
if ( NULL != data ) {
|
||||||
|
XP_ASSERT( !!data->idata.indices );
|
||||||
|
XP_ASSERT( sizeof(jint) == sizeof(data->idata.indices[0]) );
|
||||||
|
jindices = makeIntArray( env, data->idata.count,
|
||||||
|
(jint*)data->idata.indices );
|
||||||
|
(*env)->DeleteLocalRef( env, jindices );
|
||||||
|
}
|
||||||
|
return jindices;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jstring JNICALL
|
||||||
|
Java_org_eehouse_android_xw4_jni_XwJNI_dict_1iter_1nthWord
|
||||||
|
( JNIEnv* env, jclass C, jint closure, jint nn)
|
||||||
|
{
|
||||||
|
jstring result = NULL;
|
||||||
|
DictIterData* data = (DictIterData*)closure;
|
||||||
|
if ( NULL != data ) {
|
||||||
|
if ( dict_getNthWord( &data->iter, nn, data->depth, &data->idata ) ) {
|
||||||
|
XP_UCHAR buf[64];
|
||||||
|
dict_wordToString( &data->iter, buf, VSIZE(buf) );
|
||||||
|
result = (*env)->NewStringUTF( env, buf );
|
||||||
|
(*env)->DeleteLocalRef( env, result );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL
|
||||||
|
Java_org_eehouse_android_xw4_jni_XwJNI_dict_1iter_1getStartsWith
|
||||||
|
( JNIEnv* env, jclass C, jint closure, jstring jprefix )
|
||||||
|
{
|
||||||
|
jint result = -1;
|
||||||
|
DictIterData* data = (DictIterData*)closure;
|
||||||
|
if ( NULL != data ) {
|
||||||
|
Tile tiles[MAX_COLS];
|
||||||
|
XP_U16 nTiles = VSIZE(tiles);
|
||||||
|
const char* prefix = (*env)->GetStringUTFChars( env, jprefix, NULL );
|
||||||
|
if ( dict_tilesForString( data->dict, prefix, tiles, &nTiles ) ) {
|
||||||
|
if ( dict_findStartsWith( &data->iter, NULL, tiles, nTiles ) ) {
|
||||||
|
result = dict_getPosition( &data->iter );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(*env)->ReleaseStringUTFChars( env, jprefix, prefix );
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* XWFEATURE_BOARDWORDS */
|
||||||
|
|
|
@ -35,38 +35,47 @@
|
||||||
/>
|
/>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout android:id="@+id/toolbar_horizontal"
|
<HorizontalScrollView android:orientation="horizontal"
|
||||||
android:orientation="horizontal"
|
android:layout_width="fill_parent"
|
||||||
android:layout_width="fill_parent"
|
android:layout_height="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
>
|
||||||
>
|
<LinearLayout android:id="@+id/toolbar_horizontal"
|
||||||
<ImageButton android:id="@+id/prevhint_button_horizontal"
|
android:orientation="horizontal"
|
||||||
style="@style/toolbar_button"
|
android:layout_width="fill_parent"
|
||||||
android:src="@drawable/prev_hint"
|
android:layout_height="wrap_content"
|
||||||
/>
|
>
|
||||||
<ImageButton android:id="@+id/nexthint_button_horizontal"
|
<ImageButton android:id="@+id/prevhint_button_horizontal"
|
||||||
style="@style/toolbar_button"
|
style="@style/toolbar_button"
|
||||||
android:src="@drawable/next_hint"
|
android:src="@drawable/prev_hint"
|
||||||
/>
|
/>
|
||||||
<ImageButton android:id="@+id/shuffle_button_horizontal"
|
<ImageButton android:id="@+id/nexthint_button_horizontal"
|
||||||
style="@style/toolbar_button"
|
style="@style/toolbar_button"
|
||||||
android:src="@drawable/shuffle"
|
android:src="@drawable/next_hint"
|
||||||
/>
|
/>
|
||||||
<ImageButton android:id="@+id/flip_button_horizontal"
|
<ImageButton android:id="@+id/shuffle_button_horizontal"
|
||||||
style="@style/toolbar_button"
|
style="@style/toolbar_button"
|
||||||
android:src="@drawable/flip"
|
android:src="@drawable/shuffle"
|
||||||
/>
|
/>
|
||||||
<ImageButton android:id="@+id/zoom_button_horizontal"
|
<ImageButton android:id="@+id/zoom_button_horizontal"
|
||||||
style="@style/toolbar_button"
|
style="@style/toolbar_button"
|
||||||
android:src="@drawable/zoom"
|
android:src="@drawable/zoom"
|
||||||
/>
|
/>
|
||||||
<ImageButton android:id="@+id/undo_button_horizontal"
|
<ImageButton android:id="@+id/undo_button_horizontal"
|
||||||
style="@style/toolbar_button"
|
style="@style/toolbar_button"
|
||||||
android:src="@drawable/undo"
|
android:src="@drawable/undo"
|
||||||
/>
|
/>
|
||||||
<ImageButton android:id="@+id/chat_button_horizontal"
|
<ImageButton android:id="@+id/flip_button_horizontal"
|
||||||
style="@style/toolbar_button"
|
style="@style/toolbar_button"
|
||||||
android:src="@drawable/stat_notify_chat"
|
android:src="@drawable/flip"
|
||||||
/>
|
/>
|
||||||
</LinearLayout>
|
<ImageButton android:id="@+id/dictlist_button_horizontal"
|
||||||
|
style="@style/toolbar_button"
|
||||||
|
android:src="@drawable/dicticon"
|
||||||
|
/>
|
||||||
|
<ImageButton android:id="@+id/chat_button_horizontal"
|
||||||
|
style="@style/toolbar_button"
|
||||||
|
android:src="@drawable/stat_notify_chat"
|
||||||
|
/>
|
||||||
|
</LinearLayout>
|
||||||
|
</HorizontalScrollView>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
38
xwords4/android/XWords4/res/layout/dict_browser.xml
Normal file
38
xwords4/android/XWords4/res/layout/dict_browser.xml
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="fill_parent"
|
||||||
|
android:paddingLeft="8dp"
|
||||||
|
android:paddingRight="8dp">
|
||||||
|
|
||||||
|
<LinearLayout android:orientation="horizontal"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
>
|
||||||
|
<EditText android:id="@+id/word_edit"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:hint="@string/word_search_hint"
|
||||||
|
android:capitalize="characters"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Button android:id="@+id/search_button"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/button_search"
|
||||||
|
android:layout_weight="0"
|
||||||
|
/>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<ListView android:id="@id/android:list"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="fill_parent"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:drawSelectorOnTop="false"
|
||||||
|
/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
|
@ -217,6 +217,11 @@
|
||||||
android:entries="@array/phony_names"
|
android:entries="@array/phony_names"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<CheckBox android:id="@+id/pick_faceup"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/pick_faceup"
|
||||||
|
/>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,4 @@
|
||||||
<item android:id="@+id/dicts_item_select"
|
<item android:id="@+id/dicts_item_select"
|
||||||
android:title="@string/dicts_item_select"
|
android:title="@string/dicts_item_select"
|
||||||
/>
|
/>
|
||||||
<item android:id="@+id/dicts_item_details"
|
|
||||||
android:title="@string/dicts_item_details"
|
|
||||||
/>
|
|
||||||
</menu>
|
</menu>
|
||||||
|
|
|
@ -6,17 +6,33 @@
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<b>Crosswords 4.4 beta 37 release</b>
|
<b>Crosswords 4.4 beta 38 release</b>
|
||||||
<ul>
|
<ul>
|
||||||
|
|
||||||
<li>Extend ability to look up words to include those already on the
|
<li>Make toolbar buttons slightly wider and the whole thing
|
||||||
board. Hold your finger on any played tile to look up any of the
|
scroll</li>
|
||||||
words that use it. </li>
|
|
||||||
|
<li>Added a wordlist browser, which you can get to by tapping a
|
||||||
|
wordlist in the Wordlist screen, or by using the wordlist
|
||||||
|
button on the game board. Eventually you'll be
|
||||||
|
able to filter based on length, chosen tiles, etc. Right now
|
||||||
|
you can scroll through all the words (even 2.7 million of them
|
||||||
|
if you're playing in Polish) and tap to look them up.</li>
|
||||||
|
|
||||||
<li>Fix password dialog crashes</li>
|
<li>Added the "download directory" to locations I search for
|
||||||
|
wordlists. This means that if you're using a browser like
|
||||||
|
Opera that doesn't respect apps' registering for certain types
|
||||||
|
of data you can still use a wordlist you've downloaded.</li>
|
||||||
|
|
||||||
<li>Show wordlist along with player name in Game Config screen, and
|
<li>Added "Pick tiles face up" option, settable when you create a
|
||||||
move below Language since it changes when language changes.</li>
|
game. This is primarily useful if you want to populate a board to
|
||||||
|
match a game that already exists, say in a newspaper puzzle or
|
||||||
|
online wordgame.</li>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
TODO: test various bogus dicts in downloads/
|
||||||
|
test that opera-downloaded dicts openable/moveable
|
||||||
|
-->
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<!-- Resources in this file do not require localization -->
|
<!-- Resources in this file do not require localization -->
|
||||||
<resources>
|
<resources>
|
||||||
|
|
||||||
<string name="app_version">4.4 beta 37</string>
|
<string name="app_version">4.4 beta 38</string>
|
||||||
|
|
||||||
<!-- prefs keys -->
|
<!-- prefs keys -->
|
||||||
<string name="key_color_tiles">key_color_tiles</string>
|
<string name="key_color_tiles">key_color_tiles</string>
|
||||||
|
@ -75,6 +75,7 @@
|
||||||
<string name="key_notagain_newfrom">key_notagain_newfrom</string>
|
<string name="key_notagain_newfrom">key_notagain_newfrom</string>
|
||||||
<string name="key_notagain_trading">key_notagain_trading</string>
|
<string name="key_notagain_trading">key_notagain_trading</string>
|
||||||
<string name="key_na_lookup">key_na_lookup</string>
|
<string name="key_na_lookup">key_na_lookup</string>
|
||||||
|
<string name="key_na_browse">key_na_browse</string>
|
||||||
|
|
||||||
<!-- Name is not localized -->
|
<!-- Name is not localized -->
|
||||||
<string name="app_name">Crosswords</string>
|
<string name="app_name">Crosswords</string>
|
||||||
|
|
|
@ -242,12 +242,6 @@
|
||||||
key_default_dict and key_default_robodict.) -->
|
key_default_dict and key_default_robodict.) -->
|
||||||
<string name="dicts_item_select">Make default</string>
|
<string name="dicts_item_select">Make default</string>
|
||||||
|
|
||||||
<!-- Title of contextual menu item. If chosen it does nothing,
|
|
||||||
but will eventually bring up a dialog giving additional
|
|
||||||
information about the selected wordlist, possibly including a
|
|
||||||
scrolling list of all its words. -->
|
|
||||||
<string name="dicts_item_details">Details</string>
|
|
||||||
|
|
||||||
<!-- text of confirmation dialog posted when the delete 'X' button
|
<!-- text of confirmation dialog posted when the delete 'X' button
|
||||||
beside the listing of a wordlist is tapped. The name of the
|
beside the listing of a wordlist is tapped. The name of the
|
||||||
wordlist is substituted for %s. Sometimes one of the two
|
wordlist is substituted for %s. Sometimes one of the two
|
||||||
|
@ -308,8 +302,7 @@
|
||||||
is substituted for %1$s. The strings loc_internal and
|
is substituted for %1$s. The strings loc_internal and
|
||||||
loc_internal are substitued for %2$s and %3$s (or vice-versa,
|
loc_internal are substitued for %2$s and %3$s (or vice-versa,
|
||||||
depending on the current location of the wordlist.)-->
|
depending on the current location of the wordlist.)-->
|
||||||
<string name="move_dictf">Move wordlist %1$s from %2$s to %3$s
|
<string name="move_dictf">Location for wordlist %1$s</string>
|
||||||
storage?</string>
|
|
||||||
|
|
||||||
<!-- see move_dictf above -->
|
<!-- see move_dictf above -->
|
||||||
<string name="loc_internal">Internal</string>
|
<string name="loc_internal">Internal</string>
|
||||||
|
@ -1215,9 +1208,8 @@
|
||||||
|
|
||||||
<!-- Text of dialog asking user to confirm a move that exchanges
|
<!-- Text of dialog asking user to confirm a move that exchanges
|
||||||
tiles (instead of forming a new word to earn points) -->
|
tiles (instead of forming a new word to earn points) -->
|
||||||
<string name="query_trade">Are you sure you want to exchange the
|
<string name="query_tradef">Are you sure you want to exchange the
|
||||||
selected tiles?</string>
|
selected tiles (%s)?</string>
|
||||||
|
|
||||||
|
|
||||||
<!-- ############################################################
|
<!-- ############################################################
|
||||||
# :Screens:
|
# :Screens:
|
||||||
|
@ -1764,7 +1756,8 @@
|
||||||
dialog -->
|
dialog -->
|
||||||
<string name="changes_button">Recent changes</string>
|
<string name="changes_button">Recent changes</string>
|
||||||
|
|
||||||
|
<!-- New strings that need to be documented and found a home
|
||||||
|
above. -->
|
||||||
<string name="button_lookup">Look up words</string>
|
<string name="button_lookup">Look up words</string>
|
||||||
<string name="button_lookupf">Look up %s</string>
|
<string name="button_lookupf">Look up %s</string>
|
||||||
<string name="title_lookup">Tap to look up</string>
|
<string name="title_lookup">Tap to look up</string>
|
||||||
|
@ -1782,5 +1775,19 @@
|
||||||
words just played online. (Note that not all languages are
|
words just played online. (Note that not all languages are
|
||||||
supported yet.)</string>
|
supported yet.)</string>
|
||||||
|
|
||||||
</resources>
|
<string name="button_move">Move</string>
|
||||||
|
|
||||||
|
<string name="button_search">Find</string>
|
||||||
|
<string name="word_search_hint">First letters</string>
|
||||||
|
<string name="tilepick_undo">Undo last</string>
|
||||||
|
<string name="tilepick_all">Pick for me</string>
|
||||||
|
<string name="cur_tilesf">Tile picker\n(so far: %s)</string>
|
||||||
|
<string name="pick_faceup">Pick tiles face-up</string>
|
||||||
|
|
||||||
|
<string name="dict_browse_titlef">%1$s (%2$d words)</string>
|
||||||
|
<string name="dict_browse_nowordsf">No word in %1$s starts with
|
||||||
|
%2$s.</string>
|
||||||
|
<string name="not_again_browse">This button opens the wordlist
|
||||||
|
browser on the current player\'s wordlist.</string>
|
||||||
|
|
||||||
|
</resources>
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="toolbar_button">
|
<style name="toolbar_button">
|
||||||
<item name="android:layout_width">48dp</item>
|
<item name="android:layout_width">58dp</item>
|
||||||
<item name="android:layout_height">48dp</item>
|
<item name="android:layout_height">48dp</item>
|
||||||
<item name="android:layout_weight">1</item>
|
<item name="android:layout_weight">1</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -65,7 +65,7 @@ public class BoardActivity extends XWActivity
|
||||||
private static final int DLG_BADWORDS = DLG_OKONLY + 1;
|
private static final int DLG_BADWORDS = DLG_OKONLY + 1;
|
||||||
private static final int QUERY_REQUEST_BLK = DLG_OKONLY + 2;
|
private static final int QUERY_REQUEST_BLK = DLG_OKONLY + 2;
|
||||||
private static final int QUERY_INFORM_BLK = DLG_OKONLY + 3;
|
private static final int QUERY_INFORM_BLK = DLG_OKONLY + 3;
|
||||||
private static final int PICK_TILE_REQUEST_BLK = DLG_OKONLY + 4;
|
private static final int PICK_TILE_REQUESTBLANK_BLK = DLG_OKONLY + 4;
|
||||||
private static final int ASK_PASSWORD_BLK = DLG_OKONLY + 5;
|
private static final int ASK_PASSWORD_BLK = DLG_OKONLY + 5;
|
||||||
private static final int DLG_RETRY = DLG_OKONLY + 6;
|
private static final int DLG_RETRY = DLG_OKONLY + 6;
|
||||||
private static final int QUERY_ENDGAME = DLG_OKONLY + 7;
|
private static final int QUERY_ENDGAME = DLG_OKONLY + 7;
|
||||||
|
@ -73,6 +73,7 @@ public class BoardActivity extends XWActivity
|
||||||
private static final int DLG_INVITE = DLG_OKONLY + 9;
|
private static final int DLG_INVITE = DLG_OKONLY + 9;
|
||||||
private static final int DLG_SCORES_BLK = DLG_OKONLY + 10;
|
private static final int DLG_SCORES_BLK = DLG_OKONLY + 10;
|
||||||
private static final int DLG_LOOKUP = DLG_OKONLY + 11;
|
private static final int DLG_LOOKUP = DLG_OKONLY + 11;
|
||||||
|
private static final int PICK_TILE_REQUESTTRAY_BLK = DLG_OKONLY + 12;
|
||||||
|
|
||||||
private static final int CHAT_REQUEST = 1;
|
private static final int CHAT_REQUEST = 1;
|
||||||
private static final int SCREEN_ON_TIME = 10 * 60 * 1000; // 10 mins
|
private static final int SCREEN_ON_TIME = 10 * 60 * 1000; // 10 mins
|
||||||
|
@ -91,6 +92,7 @@ public class BoardActivity extends XWActivity
|
||||||
private static final int CHAT_ACTION = 12;
|
private static final int CHAT_ACTION = 12;
|
||||||
private static final int START_TRADE_ACTION = 13;
|
private static final int START_TRADE_ACTION = 13;
|
||||||
private static final int LOOKUP_ACTION = 14;
|
private static final int LOOKUP_ACTION = 14;
|
||||||
|
private static final int BUTTON_BROWSE_ACTION = 15;
|
||||||
|
|
||||||
private static final String DLG_TITLE = "DLG_TITLE";
|
private static final String DLG_TITLE = "DLG_TITLE";
|
||||||
private static final String DLG_TITLESTR = "DLG_TITLESTR";
|
private static final String DLG_TITLESTR = "DLG_TITLESTR";
|
||||||
|
@ -122,6 +124,8 @@ public class BoardActivity extends XWActivity
|
||||||
private int m_dlgTitle;
|
private int m_dlgTitle;
|
||||||
private String m_dlgTitleStr;
|
private String m_dlgTitleStr;
|
||||||
private String[] m_texts;
|
private String[] m_texts;
|
||||||
|
private String m_curTiles;
|
||||||
|
private boolean m_canUndoTiles;
|
||||||
private boolean m_firingPrefs;
|
private boolean m_firingPrefs;
|
||||||
private JNIUtils m_jniu;
|
private JNIUtils m_jniu;
|
||||||
private boolean m_volKeysZoom;
|
private boolean m_volKeysZoom;
|
||||||
|
@ -164,7 +168,7 @@ public class BoardActivity extends XWActivity
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Dialog onCreateDialog( int id )
|
protected Dialog onCreateDialog( final int id )
|
||||||
{
|
{
|
||||||
Dialog dialog = super.onCreateDialog( id );
|
Dialog dialog = super.onCreateDialog( id );
|
||||||
if ( null == dialog ) {
|
if ( null == dialog ) {
|
||||||
|
@ -264,9 +268,9 @@ public class BoardActivity extends XWActivity
|
||||||
dialog.setOnDismissListener( makeODLforBlocking( id ) );
|
dialog.setOnDismissListener( makeODLforBlocking( id ) );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PICK_TILE_REQUEST_BLK:
|
case PICK_TILE_REQUESTBLANK_BLK:
|
||||||
ab = new AlertDialog.Builder( this )
|
case PICK_TILE_REQUESTTRAY_BLK:
|
||||||
.setTitle( R.string.title_tile_picker );
|
ab = new AlertDialog.Builder( this );
|
||||||
lstnr = new DialogInterface.OnClickListener() {
|
lstnr = new DialogInterface.OnClickListener() {
|
||||||
public void onClick( DialogInterface dialog,
|
public void onClick( DialogInterface dialog,
|
||||||
int item ) {
|
int item ) {
|
||||||
|
@ -275,6 +279,34 @@ public class BoardActivity extends XWActivity
|
||||||
};
|
};
|
||||||
ab.setItems( m_texts, lstnr );
|
ab.setItems( m_texts, lstnr );
|
||||||
|
|
||||||
|
if ( PICK_TILE_REQUESTBLANK_BLK == id ) {
|
||||||
|
ab.setTitle( R.string.title_tile_picker );
|
||||||
|
} else {
|
||||||
|
ab.setTitle( Utils.format( this, R.string.cur_tilesf,
|
||||||
|
m_curTiles ) );
|
||||||
|
if ( m_canUndoTiles ) {
|
||||||
|
DialogInterface.OnClickListener undoClicked =
|
||||||
|
new DialogInterface.OnClickListener() {
|
||||||
|
public void onClick( DialogInterface dialog,
|
||||||
|
int whichButton ) {
|
||||||
|
m_resultCode = UtilCtxt.PICKER_BACKUP;
|
||||||
|
removeDialog( id );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ab.setPositiveButton( R.string.tilepick_undo,
|
||||||
|
undoClicked );
|
||||||
|
}
|
||||||
|
DialogInterface.OnClickListener doAllClicked =
|
||||||
|
new DialogInterface.OnClickListener() {
|
||||||
|
public void onClick( DialogInterface dialog,
|
||||||
|
int whichButton ) {
|
||||||
|
m_resultCode = UtilCtxt.PICKER_PICKALL;
|
||||||
|
removeDialog( id );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ab.setNegativeButton( R.string.tilepick_all, doAllClicked );
|
||||||
|
}
|
||||||
|
|
||||||
dialog = ab.create();
|
dialog = ab.create();
|
||||||
dialog.setOnDismissListener( makeODLforBlocking( id ) );
|
dialog.setOnDismissListener( makeODLforBlocking( id ) );
|
||||||
break;
|
break;
|
||||||
|
@ -332,15 +364,6 @@ public class BoardActivity extends XWActivity
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DLG_LOOKUP:
|
|
||||||
LookupView view = (LookupView)Utils.inflate( this, R.layout.lookup );
|
|
||||||
dialog = new AlertDialog.Builder( this )
|
|
||||||
.setView( view )
|
|
||||||
.create();
|
|
||||||
view.setDialog( dialog, DLG_LOOKUP );
|
|
||||||
view.setWords( m_words, m_gi.dictLang );
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// just drop it; super.onCreateDialog likely failed
|
// just drop it; super.onCreateDialog likely failed
|
||||||
break;
|
break;
|
||||||
|
@ -598,6 +621,7 @@ public class BoardActivity extends XWActivity
|
||||||
m_jniThread.handle( JNIThread.JNICmd.CMD_REMAINING,
|
m_jniThread.handle( JNIThread.JNICmd.CMD_REMAINING,
|
||||||
R.string.tiles_left_title );
|
R.string.tiles_left_title );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case R.id.board_menu_game_history:
|
case R.id.board_menu_game_history:
|
||||||
m_jniThread.handle( JNIThread.JNICmd.CMD_HISTORY,
|
m_jniThread.handle( JNIThread.JNICmd.CMD_HISTORY,
|
||||||
R.string.history_title );
|
R.string.history_title );
|
||||||
|
@ -669,6 +693,10 @@ public class BoardActivity extends XWActivity
|
||||||
Toast.LENGTH_SHORT).show();
|
Toast.LENGTH_SHORT).show();
|
||||||
m_toastStr = null;
|
m_toastStr = null;
|
||||||
break;
|
break;
|
||||||
|
case BUTTON_BROWSE_ACTION:
|
||||||
|
String dictName = m_gi.dictName( m_view.getCurPlayer() );
|
||||||
|
DictBrowseActivity.launch( this, dictName );
|
||||||
|
break;
|
||||||
case PREV_HINT_ACTION:
|
case PREV_HINT_ACTION:
|
||||||
cmd = JNIThread.JNICmd.CMD_PREV_HINT;
|
cmd = JNIThread.JNICmd.CMD_PREV_HINT;
|
||||||
break;
|
break;
|
||||||
|
@ -696,7 +724,7 @@ public class BoardActivity extends XWActivity
|
||||||
cmd = JNIThread.JNICmd.CMD_TRADE;
|
cmd = JNIThread.JNICmd.CMD_TRADE;
|
||||||
break;
|
break;
|
||||||
case LOOKUP_ACTION:
|
case LOOKUP_ACTION:
|
||||||
launchLookup( m_words );
|
launchLookup( m_words, m_gi.dictLang );
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
Assert.fail();
|
Assert.fail();
|
||||||
|
@ -925,6 +953,7 @@ public class BoardActivity extends XWActivity
|
||||||
super( BoardActivity.this );
|
super( BoardActivity.this );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void requestTime()
|
public void requestTime()
|
||||||
{
|
{
|
||||||
post( new Runnable() {
|
post( new Runnable() {
|
||||||
|
@ -936,12 +965,14 @@ public class BoardActivity extends XWActivity
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void remSelected()
|
public void remSelected()
|
||||||
{
|
{
|
||||||
m_jniThread.handle( JNIThread.JNICmd.CMD_REMAINING,
|
m_jniThread.handle( JNIThread.JNICmd.CMD_REMAINING,
|
||||||
R.string.tiles_left_title );
|
R.string.tiles_left_title );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void setIsServer( boolean isServer )
|
public void setIsServer( boolean isServer )
|
||||||
{
|
{
|
||||||
DeviceRole newRole = isServer? DeviceRole.SERVER_ISSERVER
|
DeviceRole newRole = isServer? DeviceRole.SERVER_ISSERVER
|
||||||
|
@ -1011,11 +1042,12 @@ public class BoardActivity extends XWActivity
|
||||||
{
|
{
|
||||||
post( new Runnable() {
|
post( new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
launchLookup( wordsToArray( words ) );
|
launchLookup( wordsToArray( words ), m_gi.dictLang );
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void setTimer( int why, int when, int handle )
|
public void setTimer( int why, int when, int handle )
|
||||||
{
|
{
|
||||||
if ( null != m_timers[why] ) {
|
if ( null != m_timers[why] ) {
|
||||||
|
@ -1038,6 +1070,7 @@ public class BoardActivity extends XWActivity
|
||||||
postDelayed( m_timers[why], inHowLong );
|
postDelayed( m_timers[why], inHowLong );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void clearTimer( int why )
|
public void clearTimer( int why )
|
||||||
{
|
{
|
||||||
if ( null != m_timers[why] ) {
|
if ( null != m_timers[why] ) {
|
||||||
|
@ -1047,13 +1080,27 @@ public class BoardActivity extends XWActivity
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is supposed to be called from the jni thread
|
// This is supposed to be called from the jni thread
|
||||||
public int userPickTile( int playerNum, String[] texts )
|
@Override
|
||||||
|
public int userPickTileBlank( int playerNum, String[] texts)
|
||||||
{
|
{
|
||||||
m_texts = texts;
|
m_texts = texts;
|
||||||
waitBlockingDialog( PICK_TILE_REQUEST_BLK, 0 );
|
waitBlockingDialog( PICK_TILE_REQUESTBLANK_BLK, 0 );
|
||||||
return m_resultCode;
|
return m_resultCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int userPickTileTray( int playerNum, String[] texts,
|
||||||
|
String[] curTiles, int nPicked )
|
||||||
|
{
|
||||||
|
m_texts = texts;
|
||||||
|
m_curTiles = TextUtils.join( ", ", curTiles );
|
||||||
|
m_canUndoTiles = 0 < nPicked;
|
||||||
|
waitBlockingDialog( PICK_TILE_REQUESTTRAY_BLK,
|
||||||
|
UtilCtxt.PICKER_PICKALL );
|
||||||
|
return m_resultCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String askPassword( String name )
|
public String askPassword( String name )
|
||||||
{
|
{
|
||||||
// call this each time dlg created or will get exception
|
// call this each time dlg created or will get exception
|
||||||
|
@ -1070,6 +1117,7 @@ public class BoardActivity extends XWActivity
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void turnChanged()
|
public void turnChanged()
|
||||||
{
|
{
|
||||||
post( new Runnable() {
|
post( new Runnable() {
|
||||||
|
@ -1081,11 +1129,13 @@ public class BoardActivity extends XWActivity
|
||||||
m_jniThread.handle( JNIThread.JNICmd. CMD_ZOOM, -8 );
|
m_jniThread.handle( JNIThread.JNICmd. CMD_ZOOM, -8 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean engineProgressCallback()
|
public boolean engineProgressCallback()
|
||||||
{
|
{
|
||||||
return ! m_jniThread.busy();
|
return ! m_jniThread.busy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean userQuery( int id, String query )
|
public boolean userQuery( int id, String query )
|
||||||
{
|
{
|
||||||
boolean result;
|
boolean result;
|
||||||
|
@ -1103,13 +1153,8 @@ public class BoardActivity extends XWActivity
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// These *are* blocking dialogs
|
// These *are* blocking dialogs
|
||||||
case UtilCtxt.QUERY_COMMIT_TRADE:
|
|
||||||
case UtilCtxt.QUERY_COMMIT_TURN:
|
case UtilCtxt.QUERY_COMMIT_TURN:
|
||||||
if ( UtilCtxt.QUERY_COMMIT_TRADE == id ) {
|
m_dlgBytes = query;
|
||||||
m_dlgBytes = getString( R.string.query_trade );
|
|
||||||
} else {
|
|
||||||
m_dlgBytes = query;
|
|
||||||
}
|
|
||||||
m_dlgTitle = R.string.query_title;
|
m_dlgTitle = R.string.query_title;
|
||||||
result = 0 != waitBlockingDialog( QUERY_REQUEST_BLK, 0 );
|
result = 0 != waitBlockingDialog( QUERY_REQUEST_BLK, 0 );
|
||||||
break;
|
break;
|
||||||
|
@ -1121,6 +1166,17 @@ public class BoardActivity extends XWActivity
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean confirmTrade( String[] tiles )
|
||||||
|
{
|
||||||
|
m_dlgTitle = R.string.info_title;
|
||||||
|
m_dlgBytes =
|
||||||
|
Utils.format( BoardActivity.this, R.string.query_tradef,
|
||||||
|
TextUtils.join( ", ", tiles ) );
|
||||||
|
return 0 != waitBlockingDialog( QUERY_REQUEST_BLK, 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void userError( int code )
|
public void userError( int code )
|
||||||
{
|
{
|
||||||
int resid = 0;
|
int resid = 0;
|
||||||
|
@ -1176,6 +1232,7 @@ public class BoardActivity extends XWActivity
|
||||||
}
|
}
|
||||||
} // userError
|
} // userError
|
||||||
|
|
||||||
|
@Override
|
||||||
public void informMove( String expl, String words )
|
public void informMove( String expl, String words )
|
||||||
{
|
{
|
||||||
m_dlgBytes = expl;
|
m_dlgBytes = expl;
|
||||||
|
@ -1184,6 +1241,7 @@ public class BoardActivity extends XWActivity
|
||||||
waitBlockingDialog( DLG_SCORES_BLK, 0 );
|
waitBlockingDialog( DLG_SCORES_BLK, 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void notifyGameOver()
|
public void notifyGameOver()
|
||||||
{
|
{
|
||||||
m_jniThread.handle( JNIThread.JNICmd.CMD_POST_OVER );
|
m_jniThread.handle( JNIThread.JNICmd.CMD_POST_OVER );
|
||||||
|
@ -1194,7 +1252,7 @@ public class BoardActivity extends XWActivity
|
||||||
// Utils.logf( "yOffsetChange(maxOffset=%d)", maxOffset );
|
// Utils.logf( "yOffsetChange(maxOffset=%d)", maxOffset );
|
||||||
// m_view.setVerticalScrollBarEnabled( maxOffset > 0 );
|
// m_view.setVerticalScrollBarEnabled( maxOffset > 0 );
|
||||||
// }
|
// }
|
||||||
|
@Override
|
||||||
public boolean warnIllegalWord( String[] words, int turn,
|
public boolean warnIllegalWord( String[] words, int turn,
|
||||||
boolean turnLost )
|
boolean turnLost )
|
||||||
{
|
{
|
||||||
|
@ -1230,6 +1288,7 @@ public class BoardActivity extends XWActivity
|
||||||
// we don't block the jni thread will continue processing messages
|
// we don't block the jni thread will continue processing messages
|
||||||
// and may stack dialogs on top of this one. Including later
|
// and may stack dialogs on top of this one. Including later
|
||||||
// chat-messages.
|
// chat-messages.
|
||||||
|
@Override
|
||||||
public void showChat( final String msg )
|
public void showChat( final String msg )
|
||||||
{
|
{
|
||||||
post( new Runnable() {
|
post( new Runnable() {
|
||||||
|
@ -1305,7 +1364,8 @@ public class BoardActivity extends XWActivity
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case JNIThread.GOT_WORDS:
|
case JNIThread.GOT_WORDS:
|
||||||
launchLookup( wordsToArray((String)msg.obj) );
|
launchLookup( wordsToArray((String)msg.obj),
|
||||||
|
m_gi.dictLang );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1356,6 +1416,10 @@ public class BoardActivity extends XWActivity
|
||||||
|
|
||||||
private void populateToolbar()
|
private void populateToolbar()
|
||||||
{
|
{
|
||||||
|
m_toolbar.setListener( Toolbar.BUTTON_BROWSE_DICT,
|
||||||
|
R.string.not_again_browse,
|
||||||
|
R.string.key_na_browse,
|
||||||
|
BUTTON_BROWSE_ACTION );
|
||||||
m_toolbar.setListener( Toolbar.BUTTON_HINT_PREV,
|
m_toolbar.setListener( Toolbar.BUTTON_HINT_PREV,
|
||||||
R.string.not_again_hintprev,
|
R.string.not_again_hintprev,
|
||||||
R.string.key_notagain_hintprev,
|
R.string.key_notagain_hintprev,
|
||||||
|
@ -1589,12 +1653,6 @@ public class BoardActivity extends XWActivity
|
||||||
return wordsArray;
|
return wordsArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void launchLookup( String[] words )
|
|
||||||
{
|
|
||||||
m_words = words;
|
|
||||||
showDialog( DLG_LOOKUP );
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupPasswdVars()
|
private void setupPasswdVars()
|
||||||
{
|
{
|
||||||
String fmt = getString( R.string.msg_ask_password );
|
String fmt = getString( R.string.msg_ask_password );
|
||||||
|
|
|
@ -338,6 +338,11 @@ public class BoardView extends View implements DrawCtx, BoardHandler,
|
||||||
m_jniThread.handle( JNIThread.JNICmd.CMD_INVALALL );
|
m_jniThread.handle( JNIThread.JNICmd.CMD_INVALALL );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getCurPlayer()
|
||||||
|
{
|
||||||
|
return m_trayOwner;
|
||||||
|
}
|
||||||
|
|
||||||
public int curPending()
|
public int curPending()
|
||||||
{
|
{
|
||||||
return m_pendingScore;
|
return m_pendingScore;
|
||||||
|
|
|
@ -0,0 +1,211 @@
|
||||||
|
/* -*- compile-command: "cd ../../../../../; ant install"; -*- */
|
||||||
|
/*
|
||||||
|
* Copyright 2009 - 2011 by Eric House (xwords@eehouse.org). All
|
||||||
|
* rights reserved.
|
||||||
|
*
|
||||||
|
* 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 2 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.eehouse.android.xw4;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.database.DataSetObserver;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.BaseAdapter;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.EditText;
|
||||||
|
import android.widget.ListAdapter;
|
||||||
|
import android.widget.SectionIndexer;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import junit.framework.Assert;
|
||||||
|
|
||||||
|
import org.eehouse.android.xw4.jni.JNIUtilsImpl;
|
||||||
|
import org.eehouse.android.xw4.jni.XwJNI;
|
||||||
|
|
||||||
|
public class DictBrowseActivity extends XWListActivity
|
||||||
|
implements View.OnClickListener {
|
||||||
|
|
||||||
|
public static final String DICT_NAME = "DICT_NAME";
|
||||||
|
|
||||||
|
private int m_dictClosure = 0;
|
||||||
|
private int m_lang;
|
||||||
|
private String m_name;
|
||||||
|
private int m_nWords;
|
||||||
|
private float m_textSize;
|
||||||
|
|
||||||
|
// - Steps to reproduce the problem:
|
||||||
|
// Create ListView, set custom adapter which implements ListAdapter and
|
||||||
|
// SectionIndexer but do not extends BaseAdapter. Enable fast scroll in
|
||||||
|
// layout. This will effect in ClassCastException.
|
||||||
|
|
||||||
|
|
||||||
|
private class DictListAdapter extends BaseAdapter
|
||||||
|
implements SectionIndexer {
|
||||||
|
|
||||||
|
private String[] m_prefixes;
|
||||||
|
private int[] m_indices;
|
||||||
|
|
||||||
|
public Object getItem( int position )
|
||||||
|
{
|
||||||
|
TextView text = new TextView( DictBrowseActivity.this );
|
||||||
|
String str = XwJNI.dict_iter_nthWord( m_dictClosure, position );
|
||||||
|
if ( null != str ) {
|
||||||
|
text.setText( str );
|
||||||
|
text.setOnClickListener( DictBrowseActivity.this );
|
||||||
|
text.setTextSize( m_textSize );
|
||||||
|
}
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
public View getView( int position, View convertView, ViewGroup parent ) {
|
||||||
|
return (View)getItem( position );
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getItemId( int position ) { return position; }
|
||||||
|
|
||||||
|
public int getCount() {
|
||||||
|
Assert.assertTrue( 0 != m_dictClosure );
|
||||||
|
return m_nWords;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SectionIndexer
|
||||||
|
public int getPositionForSection( int section )
|
||||||
|
{
|
||||||
|
return m_indices[section];
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSectionForPosition( int position )
|
||||||
|
{
|
||||||
|
int section = Arrays.binarySearch( m_indices, position );
|
||||||
|
if ( section < 0 ) {
|
||||||
|
section *= -1;
|
||||||
|
}
|
||||||
|
if ( section >= m_indices.length ) {
|
||||||
|
section = m_indices.length - 1;
|
||||||
|
}
|
||||||
|
return section;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object[] getSections()
|
||||||
|
{
|
||||||
|
m_prefixes = XwJNI.dict_iter_getPrefixes( m_dictClosure );
|
||||||
|
m_indices = XwJNI.dict_iter_getIndices( m_dictClosure );
|
||||||
|
return m_prefixes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate( Bundle savedInstanceState )
|
||||||
|
{
|
||||||
|
super.onCreate( savedInstanceState );
|
||||||
|
|
||||||
|
Intent intent = getIntent();
|
||||||
|
String name = null == intent? null:intent.getStringExtra( DICT_NAME );
|
||||||
|
if ( null == name ) {
|
||||||
|
finish();
|
||||||
|
} else {
|
||||||
|
m_name = name;
|
||||||
|
m_lang = DictLangCache.getDictLangCode( this, name );
|
||||||
|
|
||||||
|
m_textSize = 2.0f + new TextView( this ).getTextSize();
|
||||||
|
|
||||||
|
String[] names = { name };
|
||||||
|
DictUtils.DictPairs pairs = DictUtils.openDicts( this, names );
|
||||||
|
m_dictClosure = XwJNI.dict_iter_init( pairs.m_bytes[0],
|
||||||
|
pairs.m_paths[0],
|
||||||
|
JNIUtilsImpl.get() );
|
||||||
|
m_nWords = XwJNI.dict_iter_wordCount( m_dictClosure );
|
||||||
|
|
||||||
|
setTitle( Utils.format( this, R.string.dict_browse_titlef,
|
||||||
|
name, m_nWords ) );
|
||||||
|
|
||||||
|
Utils.logf( "calling makeIndex" );
|
||||||
|
XwJNI.dict_iter_makeIndex( m_dictClosure );
|
||||||
|
Utils.logf( "makeIndex done" );
|
||||||
|
|
||||||
|
setContentView( R.layout.dict_browser );
|
||||||
|
setListAdapter( new DictListAdapter() );
|
||||||
|
getListView().setFastScrollEnabled( true );
|
||||||
|
|
||||||
|
Button button = (Button)findViewById( R.id.search_button );
|
||||||
|
button.setOnClickListener( new View.OnClickListener() {
|
||||||
|
public void onClick( View view )
|
||||||
|
{
|
||||||
|
findButtonClicked();
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDestroy()
|
||||||
|
{
|
||||||
|
XwJNI.dict_iter_destroy( m_dictClosure );
|
||||||
|
m_dictClosure = 0;
|
||||||
|
super.onDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Just in case onDestroy didn't get called....
|
||||||
|
@Override
|
||||||
|
public void finalize()
|
||||||
|
{
|
||||||
|
XwJNI.dict_iter_destroy( m_dictClosure );
|
||||||
|
try {
|
||||||
|
super.finalize();
|
||||||
|
} catch ( java.lang.Throwable err ){
|
||||||
|
Utils.logf( "%s", err.toString() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////
|
||||||
|
// View.OnClickListener interface
|
||||||
|
//////////////////////////////////////////////////
|
||||||
|
@Override
|
||||||
|
public void onClick( View view )
|
||||||
|
{
|
||||||
|
TextView text = (TextView)view;
|
||||||
|
String[] words = { text.getText().toString() };
|
||||||
|
launchLookup( words, m_lang, true );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void findButtonClicked()
|
||||||
|
{
|
||||||
|
EditText edit = (EditText)findViewById( R.id.word_edit );
|
||||||
|
String text = edit.getText().toString();
|
||||||
|
if ( null != text && 0 < text.length() ) {
|
||||||
|
int pos = XwJNI.dict_iter_getStartsWith( m_dictClosure, text );
|
||||||
|
if ( 0 <= pos ) {
|
||||||
|
getListView().setSelection( pos );
|
||||||
|
} else {
|
||||||
|
Utils.showf( this, R.string.dict_browse_nowordsf,
|
||||||
|
m_name, text );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void launch( Context caller, String name )
|
||||||
|
{
|
||||||
|
Intent intent = new Intent( caller, DictBrowseActivity.class );
|
||||||
|
intent.putExtra( DICT_NAME, name );
|
||||||
|
caller.startActivity( intent );
|
||||||
|
}
|
||||||
|
}
|
|
@ -64,18 +64,19 @@ public class DictLangCache {
|
||||||
|
|
||||||
public static String annotatedDictName( Context context, DictAndLoc dal )
|
public static String annotatedDictName( Context context, DictAndLoc dal )
|
||||||
{
|
{
|
||||||
|
String result = null;
|
||||||
DictInfo info = getInfo( context, dal );
|
DictInfo info = getInfo( context, dal );
|
||||||
int wordCount = info.wordCount;
|
if ( null != info ) {
|
||||||
|
int wordCount = info.wordCount;
|
||||||
|
|
||||||
String langName = getLangName( context, dal.name );
|
String langName = getLangName( context, dal.name );
|
||||||
String result;
|
if ( 0 == wordCount ) {
|
||||||
if ( 0 == wordCount ) {
|
result = String.format( "%s (%s)", dal.name, langName );
|
||||||
result = String.format( "%s (%s)", dal.name, langName );
|
} else {
|
||||||
} else {
|
result = String.format( "%s (%s/%d)", dal.name, langName,
|
||||||
result = String.format( "%s (%s/%d)", dal.name, langName,
|
wordCount );
|
||||||
wordCount );
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,7 +115,7 @@ public class DictLangCache {
|
||||||
DictAndLoc[] dals = DictUtils.dictList( context );
|
DictAndLoc[] dals = DictUtils.dictList( context );
|
||||||
for ( DictAndLoc dal : dals ) {
|
for ( DictAndLoc dal : dals ) {
|
||||||
DictInfo info = getInfo( context, dal );
|
DictInfo info = getInfo( context, dal );
|
||||||
if ( code == info.langCode ) {
|
if ( null != info && code == info.langCode ) {
|
||||||
al.add( info );
|
al.add( info );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -159,7 +160,7 @@ public class DictLangCache {
|
||||||
DictAndLoc[] dals = DictUtils.dictList( context );
|
DictAndLoc[] dals = DictUtils.dictList( context );
|
||||||
for ( DictAndLoc dal : dals ) {
|
for ( DictAndLoc dal : dals ) {
|
||||||
DictInfo info = getInfo( context, dal );
|
DictInfo info = getInfo( context, dal );
|
||||||
if ( code == info.langCode ) {
|
if ( null != info && code == info.langCode ) {
|
||||||
al.add( dal );
|
al.add( dal );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -373,11 +374,23 @@ public class DictLangCache {
|
||||||
|
|
||||||
info = new DictInfo();
|
info = new DictInfo();
|
||||||
|
|
||||||
XwJNI.dict_getInfo( pairs.m_bytes[0], pairs.m_paths[0],
|
// It should not be possible for dict_getInfo to fail
|
||||||
JNIUtilsImpl.get(), info );
|
// unless DictUtils.dictList() isn't doing its job and
|
||||||
|
// puts unchecked dicts on the list. Should probably
|
||||||
|
// assert that this returns true. Open question: do I
|
||||||
|
// always trust dicts in the BUILTIN and INTERNAL
|
||||||
|
// locations? Files can get damaged....
|
||||||
|
if ( XwJNI.dict_getInfo( pairs.m_bytes[0], pairs.m_paths[0],
|
||||||
|
JNIUtilsImpl.get(),
|
||||||
|
DictUtils.DictLoc.DOWNLOAD == dal.loc,
|
||||||
|
info ) ) {
|
||||||
|
|
||||||
info.name = dal.name;
|
info.name = dal.name;
|
||||||
s_nameToLang.put( dal, info );
|
s_nameToLang.put( dal, info );
|
||||||
|
} else {
|
||||||
|
info = null;
|
||||||
|
Utils.logf( "getInfo(): unable to open dict %s", dal.name );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/* -*- compile-command: "cd ../../../../../; ant install"; -*- */
|
/* -*- compile-command: "cd ../../../../../; ant install"; -*- */
|
||||||
/*
|
/*
|
||||||
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
|
* Copyright 2009-2011 by Eric House (xwords@eehouse.org). All rights
|
||||||
* rights reserved.
|
* reserved.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License as
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
@ -114,34 +114,42 @@ public class DictUtils {
|
||||||
// changes?
|
// changes?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void tryDir( File dir, boolean strict, DictLoc loc,
|
||||||
|
ArrayList<DictAndLoc> al )
|
||||||
|
{
|
||||||
|
if ( null != dir ) {
|
||||||
|
String[] list = dir.list();
|
||||||
|
if ( null != list ) {
|
||||||
|
for ( String file : list ) {
|
||||||
|
if ( isDict( file, strict? dir : null ) ) {
|
||||||
|
al.add( new DictAndLoc( removeDictExtn( file ), loc ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static DictAndLoc[] dictList( Context context )
|
public static DictAndLoc[] dictList( Context context )
|
||||||
{
|
{
|
||||||
if ( null == s_dictListCache ) {
|
if ( null == s_dictListCache ) {
|
||||||
ArrayList<DictAndLoc> al = new ArrayList<DictAndLoc>();
|
ArrayList<DictAndLoc> al = new ArrayList<DictAndLoc>();
|
||||||
|
|
||||||
for ( String file : getAssets( context ) ) {
|
for ( String file : getAssets( context ) ) {
|
||||||
if ( isDict( file ) ) {
|
if ( isDict( file, null ) ) {
|
||||||
al.add( new DictAndLoc( removeDictExtn( file ),
|
al.add( new DictAndLoc( removeDictExtn( file ),
|
||||||
DictLoc.BUILT_IN ) );
|
DictLoc.BUILT_IN ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for ( String file : context.fileList() ) {
|
for ( String file : context.fileList() ) {
|
||||||
if ( isDict( file ) ) {
|
if ( isDict( file, null ) ) {
|
||||||
al.add( new DictAndLoc( removeDictExtn( file ),
|
al.add( new DictAndLoc( removeDictExtn( file ),
|
||||||
DictLoc.INTERNAL ) );
|
DictLoc.INTERNAL ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
File sdDir = getSDDir( context );
|
tryDir( getSDDir( context ), false, DictLoc.EXTERNAL, al );
|
||||||
if ( null != sdDir ) {
|
tryDir( getDownloadDir(), true, DictLoc.DOWNLOAD, al );
|
||||||
for ( String file : sdDir.list() ) {
|
|
||||||
if ( isDict( file ) ) {
|
|
||||||
al.add( new DictAndLoc( removeDictExtn( file ),
|
|
||||||
DictLoc.EXTERNAL ) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
s_dictListCache =
|
s_dictListCache =
|
||||||
al.toArray( new DictUtils.DictAndLoc[al.size()] );
|
al.toArray( new DictUtils.DictAndLoc[al.size()] );
|
||||||
|
@ -213,43 +221,38 @@ public class DictUtils {
|
||||||
private static boolean copyDict( Context context, String name,
|
private static boolean copyDict( Context context, String name,
|
||||||
DictLoc from, DictLoc to )
|
DictLoc from, DictLoc to )
|
||||||
{
|
{
|
||||||
|
Assert.assertFalse( from.equals(to) );
|
||||||
boolean success = false;
|
boolean success = false;
|
||||||
|
|
||||||
File file = getSDPathFor( context, name );
|
FileChannel channelIn = null;
|
||||||
if ( null != file ) {
|
FileChannel channelOut = null;
|
||||||
FileChannel channelIn = null;
|
|
||||||
FileChannel channelOut = null;
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
FileInputStream fis = DictLoc.INTERNAL == from
|
||||||
|
? context.openFileInput( name )
|
||||||
|
: new FileInputStream( getDictFile( context, name, from ) );
|
||||||
|
|
||||||
|
FileOutputStream fos = DictLoc.INTERNAL == to
|
||||||
|
? context.openFileOutput( name, Context.MODE_PRIVATE )
|
||||||
|
: new FileOutputStream( getDictFile( context, name, to ) );
|
||||||
|
|
||||||
|
channelIn = fis.getChannel();
|
||||||
|
channelOut = fos.getChannel();
|
||||||
|
channelIn.transferTo( 0, channelIn.size(), channelOut );
|
||||||
|
success = true;
|
||||||
|
|
||||||
|
} catch ( java.io.FileNotFoundException fnfe ) {
|
||||||
|
Utils.logf( "%s", fnfe.toString() );
|
||||||
|
} catch ( java.io.IOException ioe ) {
|
||||||
|
Utils.logf( "%s", ioe.toString() );
|
||||||
|
} finally {
|
||||||
try {
|
try {
|
||||||
FileInputStream fis;
|
// Order should match assignment order to above in
|
||||||
FileOutputStream fos;
|
// case one or both null
|
||||||
if ( DictLoc.INTERNAL == from ) {
|
channelIn.close();
|
||||||
fis = context.openFileInput( name );
|
channelOut.close();
|
||||||
fos = new FileOutputStream( file );
|
} catch ( Exception e ) {
|
||||||
} else {
|
Utils.logf( "%s", e.toString() );
|
||||||
fis = new FileInputStream( file );
|
|
||||||
fos = context.openFileOutput( name, Context.MODE_PRIVATE );
|
|
||||||
}
|
|
||||||
|
|
||||||
channelIn = fis.getChannel();
|
|
||||||
channelOut = fos.getChannel();
|
|
||||||
|
|
||||||
channelIn.transferTo( 0, channelIn.size(), channelOut );
|
|
||||||
success = true;
|
|
||||||
|
|
||||||
} catch ( java.io.FileNotFoundException fnfe ) {
|
|
||||||
Utils.logf( "%s", fnfe.toString() );
|
|
||||||
} catch ( java.io.IOException ioe ) {
|
|
||||||
Utils.logf( "%s", ioe.toString() );
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
// Order should match assignment order to above in
|
|
||||||
// case one or both null
|
|
||||||
channelIn.close();
|
|
||||||
channelOut.close();
|
|
||||||
} catch ( Exception e ) {
|
|
||||||
Utils.logf( "%s", e.toString() );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return success;
|
return success;
|
||||||
|
@ -258,15 +261,25 @@ public class DictUtils {
|
||||||
public static void deleteDict( Context context, String name, DictLoc loc )
|
public static void deleteDict( Context context, String name, DictLoc loc )
|
||||||
{
|
{
|
||||||
name = addDictExtn( name );
|
name = addDictExtn( name );
|
||||||
if ( DictLoc.EXTERNAL == loc ) {
|
File path = null;
|
||||||
File onSD = getSDPathFor( context, name );
|
switch( loc ) {
|
||||||
if ( null != onSD ) {
|
case DOWNLOAD:
|
||||||
onSD.delete();
|
path = getDownloadsPathFor( name );
|
||||||
} // otherwise what?
|
break;
|
||||||
} else {
|
case EXTERNAL:
|
||||||
Assert.assertTrue( DictLoc.INTERNAL == loc );
|
path = getSDPathFor( context, name );
|
||||||
|
break;
|
||||||
|
case INTERNAL:
|
||||||
context.deleteFile( name );
|
context.deleteFile( name );
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Assert.fail();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( null != path ) {
|
||||||
|
path.delete();
|
||||||
|
}
|
||||||
|
|
||||||
invalDictList();
|
invalDictList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -306,6 +319,15 @@ public class DictUtils {
|
||||||
if ( null == bytes ) {
|
if ( null == bytes ) {
|
||||||
try {
|
try {
|
||||||
FileInputStream fis = null;
|
FileInputStream fis = null;
|
||||||
|
if ( null == fis ) {
|
||||||
|
if ( loc == DictLoc.UNKNOWN || loc == DictLoc.DOWNLOAD ) {
|
||||||
|
File path = getDownloadsPathFor( name );
|
||||||
|
if ( null != path && path.exists() ) {
|
||||||
|
Utils.logf( "loading %s from Download", name );
|
||||||
|
fis = new FileInputStream( path );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if ( loc == DictLoc.UNKNOWN || loc == DictLoc.EXTERNAL ) {
|
if ( loc == DictLoc.UNKNOWN || loc == DictLoc.EXTERNAL ) {
|
||||||
File sdFile = getSDPathFor( context, name );
|
File sdFile = getSDPathFor( context, name );
|
||||||
if ( null != sdFile && sdFile.exists() ) {
|
if ( null != sdFile && sdFile.exists() ) {
|
||||||
|
@ -358,6 +380,9 @@ public class DictUtils {
|
||||||
{
|
{
|
||||||
File path;
|
File path;
|
||||||
switch ( to ) {
|
switch ( to ) {
|
||||||
|
case DOWNLOAD:
|
||||||
|
path = getDownloadsPathFor( name );
|
||||||
|
break;
|
||||||
case EXTERNAL:
|
case EXTERNAL:
|
||||||
path = getSDPathFor( context, name );
|
path = getSDPathFor( context, name );
|
||||||
break;
|
break;
|
||||||
|
@ -439,9 +464,15 @@ public class DictUtils {
|
||||||
return file.endsWith( XWConstants.GAME_EXTN );
|
return file.endsWith( XWConstants.GAME_EXTN );
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isDict( String file )
|
private static boolean isDict( String file, File dir )
|
||||||
{
|
{
|
||||||
return file.endsWith( XWConstants.DICT_EXTN );
|
boolean ok = file.endsWith( XWConstants.DICT_EXTN );
|
||||||
|
if ( ok && null != dir ) {
|
||||||
|
String fullPath = new File( dir, file ).getPath();
|
||||||
|
ok = XwJNI.dict_getInfo( null, fullPath, JNIUtilsImpl.get(),
|
||||||
|
true, null );
|
||||||
|
}
|
||||||
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String removeDictExtn( String str )
|
public static String removeDictExtn( String str )
|
||||||
|
@ -510,4 +541,29 @@ public class DictUtils {
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static File getDownloadDir()
|
||||||
|
{
|
||||||
|
File result = null;
|
||||||
|
if ( haveWriteableSD() ) {
|
||||||
|
File storage = Environment.getExternalStorageDirectory();
|
||||||
|
if ( null != storage ) {
|
||||||
|
result = new File( storage.getPath(), "download/" );
|
||||||
|
if ( !result.exists() ) {
|
||||||
|
result = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static File getDownloadsPathFor( String name )
|
||||||
|
{
|
||||||
|
File result = null;
|
||||||
|
File dir = getDownloadDir();
|
||||||
|
if ( dir != null ) {
|
||||||
|
result = new File( dir, name );
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* -*- compile-command: "cd ../../../../../; ant install"; -*- */
|
/* -*- compile-command: "cd ../../../../../; ant install"; -*- */
|
||||||
/*
|
/*
|
||||||
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
|
* Copyright 2009 - 2011 by Eric House (xwords@eehouse.org). All
|
||||||
* rights reserved.
|
* rights reserved.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
|
@ -31,6 +31,7 @@ import android.widget.Button;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
|
import android.content.DialogInterface.OnClickListener;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
|
@ -47,6 +48,7 @@ import android.widget.ExpandableListView.ExpandableListContextMenuInfo;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import junit.framework.Assert;
|
import junit.framework.Assert;
|
||||||
|
|
||||||
|
@ -67,7 +69,6 @@ public class DictsActivity extends ExpandableListActivity
|
||||||
private static final String NAME = "name";
|
private static final String NAME = "name";
|
||||||
private static final String LANG = "lang";
|
private static final String LANG = "lang";
|
||||||
private static final String MOVEFROMLOC = "movefromloc";
|
private static final String MOVEFROMLOC = "movefromloc";
|
||||||
private static final String MOVETOLOC = "movetoloc";
|
|
||||||
|
|
||||||
private static HashMap<String,Boolean> s_openStates =
|
private static HashMap<String,Boolean> s_openStates =
|
||||||
new HashMap<String,Boolean>();
|
new HashMap<String,Boolean>();
|
||||||
|
@ -90,7 +91,8 @@ public class DictsActivity extends ExpandableListActivity
|
||||||
|
|
||||||
private long m_packedPosition;
|
private long m_packedPosition;
|
||||||
private DictUtils.DictLoc m_moveFromLoc;
|
private DictUtils.DictLoc m_moveFromLoc;
|
||||||
private DictUtils.DictLoc m_moveToLoc;
|
private int m_moveFromItem;
|
||||||
|
private int m_moveToItm;
|
||||||
|
|
||||||
private LayoutInflater m_factory;
|
private LayoutInflater m_factory;
|
||||||
|
|
||||||
|
@ -152,6 +154,7 @@ public class DictsActivity extends ExpandableListActivity
|
||||||
}
|
}
|
||||||
|
|
||||||
addToCache( groupPosition, childPosition, view );
|
addToCache( groupPosition, childPosition, view );
|
||||||
|
view.setOnClickListener( DictsActivity.this );
|
||||||
}
|
}
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
@ -244,7 +247,7 @@ public class DictsActivity extends ExpandableListActivity
|
||||||
@Override
|
@Override
|
||||||
protected Dialog onCreateDialog( int id )
|
protected Dialog onCreateDialog( int id )
|
||||||
{
|
{
|
||||||
DialogInterface.OnClickListener lstnr;
|
OnClickListener lstnr;
|
||||||
Dialog dialog;
|
Dialog dialog;
|
||||||
String format;
|
String format;
|
||||||
String message;
|
String message;
|
||||||
|
@ -252,7 +255,7 @@ public class DictsActivity extends ExpandableListActivity
|
||||||
|
|
||||||
switch( id ) {
|
switch( id ) {
|
||||||
case PICK_STORAGE:
|
case PICK_STORAGE:
|
||||||
lstnr = new DialogInterface.OnClickListener() {
|
lstnr = new OnClickListener() {
|
||||||
public void onClick( DialogInterface dlg, int item ) {
|
public void onClick( DialogInterface dlg, int item ) {
|
||||||
startDownload( m_lang, m_name, item !=
|
startDownload( m_lang, m_name, item !=
|
||||||
DialogInterface.BUTTON_POSITIVE );
|
DialogInterface.BUTTON_POSITIVE );
|
||||||
|
@ -267,36 +270,58 @@ public class DictsActivity extends ExpandableListActivity
|
||||||
.create();
|
.create();
|
||||||
break;
|
break;
|
||||||
case MOVE_DICT:
|
case MOVE_DICT:
|
||||||
lstnr = new DialogInterface.OnClickListener() {
|
message = Utils.format( this, R.string.move_dictf,
|
||||||
|
m_adapter.getSelChildView().getText() );
|
||||||
|
|
||||||
|
String[] items = new String[3];
|
||||||
|
for ( int ii = 0; ii < 3; ++ii ) {
|
||||||
|
DictUtils.DictLoc loc = itemToRealLoc(ii);
|
||||||
|
if ( loc.equals( m_moveFromLoc ) ) {
|
||||||
|
m_moveFromItem = ii;
|
||||||
|
}
|
||||||
|
items[ii] = m_locNames[loc.ordinal()];
|
||||||
|
}
|
||||||
|
|
||||||
|
OnClickListener newSelLstnr =
|
||||||
|
new OnClickListener() {
|
||||||
|
public void onClick( DialogInterface dlgi, int item ) {
|
||||||
|
m_moveToItm = item;
|
||||||
|
AlertDialog dlg = (AlertDialog)dlgi;
|
||||||
|
Button btn =
|
||||||
|
dlg.getButton( AlertDialog.BUTTON_POSITIVE );
|
||||||
|
btn.setEnabled( m_moveToItm != m_moveFromItem );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
lstnr = new OnClickListener() {
|
||||||
public void onClick( DialogInterface dlg, int item ) {
|
public void onClick( DialogInterface dlg, int item ) {
|
||||||
XWListItem rowView = m_adapter.getSelChildView();
|
XWListItem rowView = m_adapter.getSelChildView();
|
||||||
|
Assert.assertTrue( m_moveToItm != m_moveFromItem );
|
||||||
|
DictUtils.DictLoc toLoc = itemToRealLoc( m_moveToItm );
|
||||||
if ( DictUtils.moveDict( DictsActivity.this,
|
if ( DictUtils.moveDict( DictsActivity.this,
|
||||||
rowView.getText(),
|
rowView.getText(),
|
||||||
m_moveFromLoc,
|
m_moveFromLoc,
|
||||||
m_moveToLoc ) ) {
|
toLoc ) ) {
|
||||||
rowView.
|
rowView.setComment( m_locNames[toLoc.ordinal()] );
|
||||||
setComment( m_locNames[m_moveToLoc.ordinal()]);
|
rowView.cache( toLoc );
|
||||||
rowView.cache( m_moveToLoc );
|
|
||||||
rowView.invalidate();
|
rowView.invalidate();
|
||||||
} else {
|
} else {
|
||||||
Utils.logf( "moveDict failed" );
|
Utils.logf( "moveDict(%s) failed",
|
||||||
|
rowView.getText() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
format = getString( R.string.move_dictf );
|
|
||||||
message = String.format( format,
|
|
||||||
m_adapter.getSelChildView().getText(),
|
|
||||||
m_locNames[ m_moveFromLoc.ordinal() ],
|
|
||||||
m_locNames[ m_moveToLoc.ordinal() ] );
|
|
||||||
|
|
||||||
dialog = new AlertDialog.Builder( this )
|
dialog = new AlertDialog.Builder( this )
|
||||||
.setMessage( message )
|
.setTitle( message )
|
||||||
.setPositiveButton( R.string.button_ok, lstnr )
|
.setSingleChoiceItems( items, m_moveFromItem, newSelLstnr )
|
||||||
|
.setPositiveButton( R.string.button_move, lstnr )
|
||||||
.setNegativeButton( R.string.button_cancel, null )
|
.setNegativeButton( R.string.button_cancel, null )
|
||||||
.create();
|
.create();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SET_DEFAULT:
|
case SET_DEFAULT:
|
||||||
lstnr = new DialogInterface.OnClickListener() {
|
lstnr = new OnClickListener() {
|
||||||
public void onClick( DialogInterface dlg, int item ) {
|
public void onClick( DialogInterface dlg, int item ) {
|
||||||
if ( DialogInterface.BUTTON_NEGATIVE == item
|
if ( DialogInterface.BUTTON_NEGATIVE == item
|
||||||
|| DialogInterface.BUTTON_POSITIVE == item ) {
|
|| DialogInterface.BUTTON_POSITIVE == item ) {
|
||||||
|
@ -339,6 +364,14 @@ public class DictsActivity extends ExpandableListActivity
|
||||||
{
|
{
|
||||||
super.onPrepareDialog( id, dialog );
|
super.onPrepareDialog( id, dialog );
|
||||||
m_delegate.onPrepareDialog( id, dialog );
|
m_delegate.onPrepareDialog( id, dialog );
|
||||||
|
|
||||||
|
if ( MOVE_DICT == id ) {
|
||||||
|
// The move button should always start out disabled
|
||||||
|
// because the selected location should be where it
|
||||||
|
// currently is.
|
||||||
|
((AlertDialog)dialog).getButton( AlertDialog.BUTTON_POSITIVE )
|
||||||
|
.setEnabled( false );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -401,9 +434,6 @@ public class DictsActivity extends ExpandableListActivity
|
||||||
if ( null != m_moveFromLoc ) {
|
if ( null != m_moveFromLoc ) {
|
||||||
outState.putInt( MOVEFROMLOC, m_moveFromLoc.ordinal() );
|
outState.putInt( MOVEFROMLOC, m_moveFromLoc.ordinal() );
|
||||||
}
|
}
|
||||||
if ( null != m_moveToLoc ) {
|
|
||||||
outState.putInt( MOVETOLOC, m_moveToLoc.ordinal() );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void getBundledData( Bundle savedInstanceState )
|
private void getBundledData( Bundle savedInstanceState )
|
||||||
|
@ -418,10 +448,6 @@ public class DictsActivity extends ExpandableListActivity
|
||||||
if ( -1 != tmp ) {
|
if ( -1 != tmp ) {
|
||||||
m_moveFromLoc = DictUtils.DictLoc.values()[tmp];
|
m_moveFromLoc = DictUtils.DictLoc.values()[tmp];
|
||||||
}
|
}
|
||||||
tmp = savedInstanceState.getInt( MOVETOLOC, -1 );
|
|
||||||
if ( -1 != tmp ) {
|
|
||||||
m_moveToLoc = DictUtils.DictLoc.values()[tmp];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -431,9 +457,14 @@ public class DictsActivity extends ExpandableListActivity
|
||||||
super.onStop();
|
super.onStop();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onClick( View v )
|
public void onClick( View view )
|
||||||
{
|
{
|
||||||
askStartDownload( 0, null );
|
if ( view instanceof Button ) {
|
||||||
|
askStartDownload( 0, null );
|
||||||
|
} else {
|
||||||
|
XWListItem item = (XWListItem)view;
|
||||||
|
DictBrowseActivity.launch( this, item.getText() );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -492,9 +523,6 @@ public class DictsActivity extends ExpandableListActivity
|
||||||
case R.id.dicts_item_select:
|
case R.id.dicts_item_select:
|
||||||
showDialog( SET_DEFAULT );
|
showDialog( SET_DEFAULT );
|
||||||
break;
|
break;
|
||||||
case R.id.dicts_item_details:
|
|
||||||
Utils.notImpl( this );
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return handled;
|
return handled;
|
||||||
|
@ -518,12 +546,6 @@ public class DictsActivity extends ExpandableListActivity
|
||||||
private void askMoveDict( XWListItem item )
|
private void askMoveDict( XWListItem item )
|
||||||
{
|
{
|
||||||
m_moveFromLoc = (DictUtils.DictLoc)item.getCached();
|
m_moveFromLoc = (DictUtils.DictLoc)item.getCached();
|
||||||
if ( m_moveFromLoc == DictUtils.DictLoc.INTERNAL ) {
|
|
||||||
m_moveToLoc = DictUtils.DictLoc.EXTERNAL;
|
|
||||||
} else {
|
|
||||||
m_moveToLoc = DictUtils.DictLoc.INTERNAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
showDialog( MOVE_DICT );
|
showDialog( MOVE_DICT );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -599,6 +621,12 @@ public class DictsActivity extends ExpandableListActivity
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private DictUtils.DictLoc itemToRealLoc( int item )
|
||||||
|
{
|
||||||
|
item += DictUtils.DictLoc.INTERNAL.ordinal();
|
||||||
|
return DictUtils.DictLoc.values()[item];
|
||||||
|
}
|
||||||
|
|
||||||
private void deleteDict( String dict, DictUtils.DictLoc loc )
|
private void deleteDict( String dict, DictUtils.DictLoc loc )
|
||||||
{
|
{
|
||||||
DictUtils.deleteDict( this, dict, loc );
|
DictUtils.deleteDict( this, dict, loc );
|
||||||
|
@ -632,6 +660,7 @@ public class DictsActivity extends ExpandableListActivity
|
||||||
private void mkListAdapter()
|
private void mkListAdapter()
|
||||||
{
|
{
|
||||||
m_langs = DictLangCache.listLangs( this );
|
m_langs = DictLangCache.listLangs( this );
|
||||||
|
Arrays.sort( m_langs );
|
||||||
m_adapter = new DictListAdapter( this );
|
m_adapter = new DictListAdapter( this );
|
||||||
setListAdapter( m_adapter );
|
setListAdapter( m_adapter );
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,8 @@ public class DlgDelegate {
|
||||||
public static final int CONFIRM_THEN = 4;
|
public static final int CONFIRM_THEN = 4;
|
||||||
public static final int TEXT_OR_HTML_THEN = 5;
|
public static final int TEXT_OR_HTML_THEN = 5;
|
||||||
public static final int DLG_DICTGONE = 6;
|
public static final int DLG_DICTGONE = 6;
|
||||||
public static final int DIALOG_LAST = DLG_DICTGONE;
|
public static final int DLG_LOOKUP = 7;
|
||||||
|
public static final int DIALOG_LAST = DLG_LOOKUP;
|
||||||
|
|
||||||
public static final int TEXT_BTN = AlertDialog.BUTTON_POSITIVE;
|
public static final int TEXT_BTN = AlertDialog.BUTTON_POSITIVE;
|
||||||
public static final int HTML_BTN = AlertDialog.BUTTON_NEGATIVE;
|
public static final int HTML_BTN = AlertDialog.BUTTON_NEGATIVE;
|
||||||
|
@ -55,6 +56,9 @@ public class DlgDelegate {
|
||||||
private static final String MSGID = "msgid";
|
private static final String MSGID = "msgid";
|
||||||
private static final String PREFSKEY = "prefskey";
|
private static final String PREFSKEY = "prefskey";
|
||||||
private static final String POSBUTTON = "posbutton";
|
private static final String POSBUTTON = "posbutton";
|
||||||
|
private static final String WORDS = "words";
|
||||||
|
private static final String LANG = "lang";
|
||||||
|
private static final String FORCELIST = "forcelist";
|
||||||
|
|
||||||
// Cache a couple of callback implementations that never change:
|
// Cache a couple of callback implementations that never change:
|
||||||
private DialogInterface.OnClickListener m_cbkOnClickLstnr = null;
|
private DialogInterface.OnClickListener m_cbkOnClickLstnr = null;
|
||||||
|
@ -73,6 +77,9 @@ public class DlgDelegate {
|
||||||
private Activity m_activity;
|
private Activity m_activity;
|
||||||
private DlgClickNotify m_clickCallback;
|
private DlgClickNotify m_clickCallback;
|
||||||
private String m_dictName = null;
|
private String m_dictName = null;
|
||||||
|
private String[] m_words = null;
|
||||||
|
private int m_wordsLang = -1;
|
||||||
|
private boolean m_forceList = false;
|
||||||
|
|
||||||
public DlgDelegate( Activity activity, DlgClickNotify callback,
|
public DlgDelegate( Activity activity, DlgClickNotify callback,
|
||||||
Bundle bundle )
|
Bundle bundle )
|
||||||
|
@ -86,6 +93,9 @@ public class DlgDelegate {
|
||||||
m_msgID = bundle.getInt( MSGID );
|
m_msgID = bundle.getInt( MSGID );
|
||||||
m_posButton = bundle.getInt( POSBUTTON );
|
m_posButton = bundle.getInt( POSBUTTON );
|
||||||
m_prefsKey = bundle.getInt( PREFSKEY );
|
m_prefsKey = bundle.getInt( PREFSKEY );
|
||||||
|
m_words = bundle.getStringArray( WORDS );
|
||||||
|
m_wordsLang = bundle.getInt( LANG );
|
||||||
|
m_forceList = bundle.getBoolean( FORCELIST );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,6 +106,9 @@ public class DlgDelegate {
|
||||||
outState.putInt( MSGID, m_msgID );
|
outState.putInt( MSGID, m_msgID );
|
||||||
outState.putInt( POSBUTTON, m_posButton );
|
outState.putInt( POSBUTTON, m_posButton );
|
||||||
outState.putInt( PREFSKEY, m_prefsKey );
|
outState.putInt( PREFSKEY, m_prefsKey );
|
||||||
|
outState.putStringArray( WORDS, m_words );
|
||||||
|
outState.putInt( LANG, m_wordsLang );
|
||||||
|
outState.putBoolean( FORCELIST, m_forceList );
|
||||||
}
|
}
|
||||||
|
|
||||||
public Dialog onCreateDialog( int id )
|
public Dialog onCreateDialog( int id )
|
||||||
|
@ -120,6 +133,15 @@ public class DlgDelegate {
|
||||||
case DLG_DICTGONE:
|
case DLG_DICTGONE:
|
||||||
dialog = createDictGoneDialog();
|
dialog = createDictGoneDialog();
|
||||||
break;
|
break;
|
||||||
|
case DLG_LOOKUP:
|
||||||
|
LookupView view = (LookupView)Utils.inflate( m_activity,
|
||||||
|
R.layout.lookup );
|
||||||
|
dialog = new AlertDialog.Builder( m_activity )
|
||||||
|
.setView( view )
|
||||||
|
.create();
|
||||||
|
view.setDialog( dialog, DLG_LOOKUP );
|
||||||
|
view.setWords( m_words, m_wordsLang, m_forceList );
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return dialog;
|
return dialog;
|
||||||
}
|
}
|
||||||
|
@ -225,6 +247,14 @@ public class DlgDelegate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void launchLookup( String[] words, int lang, boolean forceList )
|
||||||
|
{
|
||||||
|
m_words = words;
|
||||||
|
m_wordsLang = lang;
|
||||||
|
m_forceList = forceList;
|
||||||
|
m_activity.showDialog( DLG_LOOKUP );
|
||||||
|
}
|
||||||
|
|
||||||
private Dialog createAboutDialog()
|
private Dialog createAboutDialog()
|
||||||
{
|
{
|
||||||
final View view = Utils.inflate( m_activity, R.layout.about_dlg );
|
final View view = Utils.inflate( m_activity, R.layout.about_dlg );
|
||||||
|
|
|
@ -114,6 +114,7 @@ public class GameConfig extends XWActivity
|
||||||
,R.id.room_spinner
|
,R.id.room_spinner
|
||||||
,R.id.refresh_button
|
,R.id.refresh_button
|
||||||
,R.id.hints_allowed
|
,R.id.hints_allowed
|
||||||
|
,R.id.pick_faceup
|
||||||
,R.id.use_timer
|
,R.id.use_timer
|
||||||
,R.id.timer_minutes_edit
|
,R.id.timer_minutes_edit
|
||||||
,R.id.smart_robot
|
,R.id.smart_robot
|
||||||
|
@ -121,7 +122,7 @@ public class GameConfig extends XWActivity
|
||||||
};
|
};
|
||||||
|
|
||||||
class RemoteChoices extends XWListAdapter {
|
class RemoteChoices extends XWListAdapter {
|
||||||
public RemoteChoices() { super( GameConfig.this, m_gi.nPlayers ); }
|
public RemoteChoices() { super( m_gi.nPlayers ); }
|
||||||
|
|
||||||
public Object getItem( int position) { return m_gi.players[position]; }
|
public Object getItem( int position) { return m_gi.players[position]; }
|
||||||
public View getView( final int position, View convertView,
|
public View getView( final int position, View convertView,
|
||||||
|
@ -362,7 +363,10 @@ public class GameConfig extends XWActivity
|
||||||
(ArrayAdapter<String>)spinner.getAdapter();
|
(ArrayAdapter<String>)spinner.getAdapter();
|
||||||
|
|
||||||
if ( position < adapter.getCount() ) {
|
if ( position < adapter.getCount() ) {
|
||||||
lp.dictName = adapter.getItem(position);
|
String name = adapter.getItem(position);
|
||||||
|
if ( ! name.equals( m_browseText ) ) {
|
||||||
|
lp.dictName = name;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lp.setIsRobot( Utils.getChecked( dialog, R.id.robot_check ) );
|
lp.setIsRobot( Utils.getChecked( dialog, R.id.robot_check ) );
|
||||||
|
@ -514,7 +518,10 @@ public class GameConfig extends XWActivity
|
||||||
|
|
||||||
setSmartnessSpinner();
|
setSmartnessSpinner();
|
||||||
|
|
||||||
Utils.setChecked( this, R.id.hints_allowed, !m_gi.hintsNotAllowed );
|
Utils.setChecked( this, R.id.hints_allowed,
|
||||||
|
!m_gi.hintsNotAllowed );
|
||||||
|
Utils.setChecked( this, R.id.pick_faceup,
|
||||||
|
m_gi.allowPickTiles );
|
||||||
Utils.setInt( this, R.id.timer_minutes_edit,
|
Utils.setInt( this, R.id.timer_minutes_edit,
|
||||||
m_gi.gameSeconds/60/m_gi.nPlayers );
|
m_gi.gameSeconds/60/m_gi.nPlayers );
|
||||||
|
|
||||||
|
@ -950,6 +957,7 @@ public class GameConfig extends XWActivity
|
||||||
private void saveChanges()
|
private void saveChanges()
|
||||||
{
|
{
|
||||||
m_gi.hintsNotAllowed = !Utils.getChecked( this, R.id.hints_allowed );
|
m_gi.hintsNotAllowed = !Utils.getChecked( this, R.id.hints_allowed );
|
||||||
|
m_gi.allowPickTiles = Utils.getChecked( this, R.id.pick_faceup );
|
||||||
m_gi.timerEnabled = Utils.getChecked( this, R.id.use_timer );
|
m_gi.timerEnabled = Utils.getChecked( this, R.id.use_timer );
|
||||||
m_gi.gameSeconds = 60 * m_gi.nPlayers *
|
m_gi.gameSeconds = 60 * m_gi.nPlayers *
|
||||||
Utils.getInt( this, R.id.timer_minutes_edit );
|
Utils.getInt( this, R.id.timer_minutes_edit );
|
||||||
|
|
|
@ -229,7 +229,7 @@ public class GameListAdapter extends XWListAdapter {
|
||||||
} // class LoadItemTask
|
} // class LoadItemTask
|
||||||
|
|
||||||
public GameListAdapter( Context context, LoadItemCB cb ) {
|
public GameListAdapter( Context context, LoadItemCB cb ) {
|
||||||
super( context, DBUtils.gamesList(context).length );
|
super( DBUtils.gamesList(context).length );
|
||||||
m_context = context;
|
m_context = context;
|
||||||
m_cb = cb;
|
m_cb = cb;
|
||||||
m_factory = LayoutInflater.from( context );
|
m_factory = LayoutInflater.from( context );
|
||||||
|
|
|
@ -62,6 +62,7 @@ public class LookupView extends LinearLayout
|
||||||
private static int s_lang = -1;
|
private static int s_lang = -1;
|
||||||
|
|
||||||
private String[] m_words;
|
private String[] m_words;
|
||||||
|
private boolean m_forceList;
|
||||||
private static int m_lang;
|
private static int m_lang;
|
||||||
private int m_wordIndex = 0;
|
private int m_wordIndex = 0;
|
||||||
private int m_urlIndex = 0;
|
private int m_urlIndex = 0;
|
||||||
|
@ -79,9 +80,10 @@ public class LookupView extends LinearLayout
|
||||||
m_context = cx;
|
m_context = cx;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setWords( String[] words, int lang )
|
public void setWords( String[] words, int lang, boolean forceList )
|
||||||
{
|
{
|
||||||
m_words = words;
|
m_words = words;
|
||||||
|
m_forceList = forceList;
|
||||||
setLang( lang );
|
setLang( lang );
|
||||||
|
|
||||||
m_state = STATE_DONE;
|
m_state = STATE_DONE;
|
||||||
|
@ -140,7 +142,8 @@ public class LookupView extends LinearLayout
|
||||||
if ( STATE_WORDS == m_state && 1 >= m_words.length ) {
|
if ( STATE_WORDS == m_state && 1 >= m_words.length ) {
|
||||||
m_state += incr;
|
m_state += incr;
|
||||||
}
|
}
|
||||||
if ( STATE_URLS == m_state && 1 >= s_lookupUrls.length ) {
|
if ( STATE_URLS == m_state &&
|
||||||
|
( 1 >= s_lookupUrls.length && !m_forceList ) ) {
|
||||||
m_state += incr;
|
m_state += incr;
|
||||||
}
|
}
|
||||||
if ( m_state == curState ) {
|
if ( m_state == curState ) {
|
||||||
|
|
|
@ -39,15 +39,18 @@ public class Toolbar {
|
||||||
public int m_id;
|
public int m_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final int BUTTON_HINT_PREV = 0;
|
public static final int BUTTON_BROWSE_DICT = 0;
|
||||||
public static final int BUTTON_HINT_NEXT = 1;
|
public static final int BUTTON_HINT_PREV = 1;
|
||||||
public static final int BUTTON_FLIP = 2;
|
public static final int BUTTON_HINT_NEXT = 2;
|
||||||
public static final int BUTTON_JUGGLE = 3;
|
public static final int BUTTON_FLIP = 3;
|
||||||
public static final int BUTTON_ZOOM = 4;
|
public static final int BUTTON_JUGGLE = 4;
|
||||||
public static final int BUTTON_UNDO = 5;
|
public static final int BUTTON_ZOOM = 5;
|
||||||
public static final int BUTTON_CHAT = 6;
|
public static final int BUTTON_UNDO = 6;
|
||||||
|
public static final int BUTTON_CHAT = 7;
|
||||||
|
|
||||||
private static TBButtonInfo[] s_buttonInfo = {
|
private static TBButtonInfo[] s_buttonInfo = {
|
||||||
|
// BUTTON_BROWSE_DICT
|
||||||
|
new TBButtonInfo(R.id.dictlist_button_horizontal ),
|
||||||
// BUTTON_HINT_PREV
|
// BUTTON_HINT_PREV
|
||||||
new TBButtonInfo(R.id.prevhint_button_horizontal ),
|
new TBButtonInfo(R.id.prevhint_button_horizontal ),
|
||||||
// BUTTON_HINT_NEXT
|
// BUTTON_HINT_NEXT
|
||||||
|
|
|
@ -91,6 +91,11 @@ public class Utils {
|
||||||
Toast.makeText( context, msg, Toast.LENGTH_SHORT ).show();
|
Toast.makeText( context, msg, Toast.LENGTH_SHORT ).show();
|
||||||
} // showf
|
} // showf
|
||||||
|
|
||||||
|
public static void showf( Context context, int formatid, Object... args )
|
||||||
|
{
|
||||||
|
showf( context, context.getString( formatid ), args );
|
||||||
|
} // showf
|
||||||
|
|
||||||
public static void printStack( StackTraceElement[] trace )
|
public static void printStack( StackTraceElement[] trace )
|
||||||
{
|
{
|
||||||
if ( s_doLog ) {
|
if ( s_doLog ) {
|
||||||
|
|
|
@ -151,6 +151,11 @@ public class XWActivity extends Activity
|
||||||
m_delegate.doSyncMenuitem();
|
m_delegate.doSyncMenuitem();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void launchLookup( String[] words, int lang )
|
||||||
|
{
|
||||||
|
m_delegate.launchLookup( words, lang, false );
|
||||||
|
}
|
||||||
|
|
||||||
// DlgDelegate.DlgClickNotify interface
|
// DlgDelegate.DlgClickNotify interface
|
||||||
public void dlgButtonClicked( int id, int which )
|
public void dlgButtonClicked( int id, int which )
|
||||||
{
|
{
|
||||||
|
|
|
@ -153,4 +153,14 @@ public class XWListActivity extends ListActivity
|
||||||
Assert.fail();
|
Assert.fail();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void launchLookup( String[] words, int lang )
|
||||||
|
{
|
||||||
|
m_delegate.launchLookup( words, lang, false );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void launchLookup( String[] words, int lang, boolean forceList )
|
||||||
|
{
|
||||||
|
m_delegate.launchLookup( words, lang, forceList );
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,10 @@ import android.database.DataSetObserver;
|
||||||
public abstract class XWListAdapter implements ListAdapter {
|
public abstract class XWListAdapter implements ListAdapter {
|
||||||
private int m_count;
|
private int m_count;
|
||||||
|
|
||||||
public XWListAdapter( Context context, int count ) {
|
public XWListAdapter( ) {
|
||||||
|
this( 0 );
|
||||||
|
}
|
||||||
|
public XWListAdapter( int count ) {
|
||||||
m_count = count;
|
m_count = count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,8 +27,13 @@ public interface UtilCtxt {
|
||||||
static final int BONUS_TRIPLE_LETTER = 3;
|
static final int BONUS_TRIPLE_LETTER = 3;
|
||||||
static final int BONUS_TRIPLE_WORD = 4;
|
static final int BONUS_TRIPLE_WORD = 4;
|
||||||
|
|
||||||
int userPickTile( /* PickInfo* pi, add once tile-picking is enabled */
|
// must match defns in util.h
|
||||||
int playerNum, String[] texts );
|
public static final int PICKER_PICKALL = -1;
|
||||||
|
public static final int PICKER_BACKUP = -2;
|
||||||
|
|
||||||
|
int userPickTileBlank( int playerNum, String[] texts );
|
||||||
|
int userPickTileTray( int playerNum, String[] tiles,
|
||||||
|
String[] curTiles, int nPicked );
|
||||||
|
|
||||||
String askPassword( String name );
|
String askPassword( String name );
|
||||||
void turnChanged();
|
void turnChanged();
|
||||||
|
@ -76,10 +81,10 @@ public interface UtilCtxt {
|
||||||
String getUserString( int stringCode );
|
String getUserString( int stringCode );
|
||||||
|
|
||||||
static final int QUERY_COMMIT_TURN = 0;
|
static final int QUERY_COMMIT_TURN = 0;
|
||||||
static final int QUERY_COMMIT_TRADE = 1;
|
static final int QUERY_ROBOT_TRADE = 1;
|
||||||
static final int QUERY_ROBOT_TRADE = 2;
|
|
||||||
boolean userQuery( int id, String query );
|
boolean userQuery( int id, String query );
|
||||||
|
|
||||||
|
boolean confirmTrade( String[] tiles );
|
||||||
|
|
||||||
// These oughtto be an enum but then I'd have to cons one up in C.
|
// These oughtto be an enum but then I'd have to cons one up in C.
|
||||||
static final int ERR_NONE = 0;
|
static final int ERR_NONE = 0;
|
||||||
|
|
|
@ -40,9 +40,16 @@ public class UtilCtxtImpl implements UtilCtxt {
|
||||||
subclassOverride( "requestTime" );
|
subclassOverride( "requestTime" );
|
||||||
}
|
}
|
||||||
|
|
||||||
public int userPickTile( int playerNum, String[] texts )
|
public int userPickTileBlank( int playerNum, String[] texts )
|
||||||
{
|
{
|
||||||
subclassOverride( "userPickTile" );
|
subclassOverride( "userPickTileBlank" );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int userPickTileTray( int playerNum, String[] texts,
|
||||||
|
String[] curTiles, int nPicked )
|
||||||
|
{
|
||||||
|
subclassOverride( "userPickTileTray" );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,6 +191,12 @@ public class UtilCtxtImpl implements UtilCtxt {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean confirmTrade( String[] tiles )
|
||||||
|
{
|
||||||
|
subclassOverride( "confirmTrade" );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public void userError( int id )
|
public void userError( int id )
|
||||||
{
|
{
|
||||||
subclassOverride( "userError" );
|
subclassOverride( "userError" );
|
||||||
|
|
|
@ -238,7 +238,20 @@ public class XwJNI {
|
||||||
// Dicts
|
// Dicts
|
||||||
public static native boolean dict_tilesAreSame( int dictPtr1, int dictPtr2 );
|
public static native boolean dict_tilesAreSame( int dictPtr1, int dictPtr2 );
|
||||||
public static native String[] dict_getChars( int dictPtr );
|
public static native String[] dict_getChars( int dictPtr );
|
||||||
public static native void dict_getInfo( byte[] dict, String path,
|
public static native boolean dict_getInfo( byte[] dict, String path,
|
||||||
JNIUtils jniu, DictInfo info );
|
JNIUtils jniu, boolean check,
|
||||||
|
DictInfo info );
|
||||||
public static native int dict_getTileValue( int dictPtr, int tile );
|
public static native int dict_getTileValue( int dictPtr, int tile );
|
||||||
|
|
||||||
|
// Dict iterator
|
||||||
|
public static native int dict_iter_init( byte[] dict, String path,
|
||||||
|
JNIUtils jniu );
|
||||||
|
public static native void dict_iter_destroy( int closure );
|
||||||
|
public static native int dict_iter_wordCount( int closure );
|
||||||
|
public static native String dict_iter_nthWord( int closure, int nn );
|
||||||
|
public static native void dict_iter_makeIndex( int closure );
|
||||||
|
public static native String[] dict_iter_getPrefixes( int closure );
|
||||||
|
public static native int[] dict_iter_getIndices( int closure );
|
||||||
|
public static native int dict_iter_getStartsWith( int closure,
|
||||||
|
String prefix );
|
||||||
}
|
}
|
||||||
|
|
|
@ -742,6 +742,20 @@ warnBadWords( const XP_UCHAR* word, XP_Bool isLegal,
|
||||||
return ok;
|
return ok;
|
||||||
} /* warnBadWords */
|
} /* warnBadWords */
|
||||||
|
|
||||||
|
static XP_Bool
|
||||||
|
boardConfirmTrade( BoardCtxt* board, const TrayTileSet* tiles )
|
||||||
|
{
|
||||||
|
const XP_UCHAR* tfaces[MAX_TRAY_TILES];
|
||||||
|
XP_U16 ii;
|
||||||
|
DictionaryCtxt* dict = model_getDictionary( board->model );
|
||||||
|
|
||||||
|
for ( ii = 0; ii < tiles->nTiles; ++ii ) {
|
||||||
|
tfaces[ii] = dict_getTileString( dict, tiles->tiles[ii] );
|
||||||
|
}
|
||||||
|
|
||||||
|
return util_confirmTrade( board->util, tfaces, tiles->nTiles );
|
||||||
|
}
|
||||||
|
|
||||||
XP_Bool
|
XP_Bool
|
||||||
board_commitTurn( BoardCtxt* board )
|
board_commitTurn( BoardCtxt* board )
|
||||||
{
|
{
|
||||||
|
@ -764,12 +778,16 @@ board_commitTurn( BoardCtxt* board )
|
||||||
|
|
||||||
if ( NO_TILES == traySelBits ) {
|
if ( NO_TILES == traySelBits ) {
|
||||||
util_userError( board->util, ERR_NO_EMPTY_TRADE );
|
util_userError( board->util, ERR_NO_EMPTY_TRADE );
|
||||||
} else if ( util_userQuery( board->util, QUERY_COMMIT_TRADE,
|
} else {
|
||||||
(XWStreamCtxt*)NULL ) ) {
|
TrayTileSet selTiles;
|
||||||
/* server_commitTrade() changes selPlayer, so board_endTrade
|
getSelTiles( board, traySelBits, &selTiles );
|
||||||
must be called first() */
|
if ( boardConfirmTrade( board, &selTiles ) ) {
|
||||||
(void)board_endTrade( board );
|
/* server_commitTrade() changes selPlayer, so board_endTrade
|
||||||
(void)server_commitTrade( board->server, traySelBits );
|
must be called first() */
|
||||||
|
(void)board_endTrade( board );
|
||||||
|
|
||||||
|
(void)server_commitTrade( board->server, &selTiles );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
XP_Bool warn, legal;
|
XP_Bool warn, legal;
|
||||||
|
@ -3224,8 +3242,8 @@ keyToIndex( BoardCtxt* board, XP_Key key, Tile* blankFace )
|
||||||
XP_UCHAR buf[2] = { key, '\0' };
|
XP_UCHAR buf[2] = { key, '\0' };
|
||||||
|
|
||||||
/* Figure out if we have the tile in the tray */
|
/* Figure out if we have the tile in the tray */
|
||||||
tile = dict_tileForString( dict, buf );
|
XP_U16 nTiles = 1;
|
||||||
if ( tile != EMPTY_TILE ) { /* in dict? */
|
if ( dict_tilesForString( dict, buf, &tile, &nTiles ) ) { /* in dict? */
|
||||||
XP_S16 turn = board->selPlayer;
|
XP_S16 turn = board->selPlayer;
|
||||||
tileIndex = model_trayContains( model, turn, tile );
|
tileIndex = model_trayContains( model, turn, tile );
|
||||||
if ( tileIndex < 0 ) {
|
if ( tileIndex < 0 ) {
|
||||||
|
|
|
@ -303,6 +303,7 @@ void invalCurHintRect( BoardCtxt* board, XP_U16 player );
|
||||||
|
|
||||||
void moveTileInTray( BoardCtxt* board, XP_U16 moveTo, XP_U16 moveFrom );
|
void moveTileInTray( BoardCtxt* board, XP_U16 moveTo, XP_U16 moveFrom );
|
||||||
XP_Bool handleTrayDuringTrade( BoardCtxt* board, XP_S16 index );
|
XP_Bool handleTrayDuringTrade( BoardCtxt* board, XP_S16 index );
|
||||||
|
void getSelTiles( const BoardCtxt* board, TileBit selBits, TrayTileSet* selTiles );
|
||||||
|
|
||||||
const XP_UCHAR* getTileDrawInfo( const BoardCtxt* board, Tile tile,
|
const XP_UCHAR* getTileDrawInfo( const BoardCtxt* board, Tile tile,
|
||||||
XP_Bool isBlank, XP_Bitmaps* bitmaps,
|
XP_Bool isBlank, XP_Bitmaps* bitmaps,
|
||||||
|
|
|
@ -1649,7 +1649,7 @@ comms_checkIncomingStream( CommsCtxt* comms, XWStreamCtxt* stream,
|
||||||
__func__, channelNo & CHANNEL_MASK, channelNo,
|
__func__, channelNo & CHANNEL_MASK, channelNo,
|
||||||
msgID, lastMsgRcd );
|
msgID, lastMsgRcd );
|
||||||
|
|
||||||
payloadSize = stream_getSize( stream ) > 0; /* anything left? */
|
payloadSize = stream_getSize( stream ); /* anything left? */
|
||||||
|
|
||||||
if ( connID == CONN_ID_NONE ) {
|
if ( connID == CONN_ID_NONE ) {
|
||||||
/* special case: initial message from client or server */
|
/* special case: initial message from client or server */
|
||||||
|
@ -1663,8 +1663,8 @@ comms_checkIncomingStream( CommsCtxt* comms, XWStreamCtxt* stream,
|
||||||
messageValid = (NULL != rec)
|
messageValid = (NULL != rec)
|
||||||
&& (0 == rec->lastMsgRcd || rec->lastMsgRcd <= msgID);
|
&& (0 == rec->lastMsgRcd || rec->lastMsgRcd <= msgID);
|
||||||
if ( messageValid ) {
|
if ( messageValid ) {
|
||||||
XP_LOGF( "got channelNo=%d;msgID=%ld",
|
XP_LOGF( "%s: got channelNo=%d;msgID=%ld;len=%d", __func__,
|
||||||
channelNo & CHANNEL_MASK, msgID );
|
channelNo & CHANNEL_MASK, msgID, payloadSize );
|
||||||
rec->lastMsgRcd = msgID;
|
rec->lastMsgRcd = msgID;
|
||||||
stream_setAddress( stream, channelNo );
|
stream_setAddress( stream, channelNo );
|
||||||
messageValid = payloadSize > 0;
|
messageValid = payloadSize > 0;
|
||||||
|
|
|
@ -115,6 +115,13 @@ typedef enum {
|
||||||
} XWTimerReason;
|
} XWTimerReason;
|
||||||
|
|
||||||
#define MAX_NUM_PLAYERS 4
|
#define MAX_NUM_PLAYERS 4
|
||||||
|
#define MAX_ROWS 16
|
||||||
|
#define MAX_COLS MAX_ROWS
|
||||||
|
#ifdef EIGHT_TILES
|
||||||
|
# define MAX_TRAY_TILES 8
|
||||||
|
#else
|
||||||
|
# define MAX_TRAY_TILES 7
|
||||||
|
#endif
|
||||||
#define PLAYERNUM_NBITS 2
|
#define PLAYERNUM_NBITS 2
|
||||||
#define NDEVICES_NBITS 2 /* 1-4, but reduced by 1 fits in 2 bits */
|
#define NDEVICES_NBITS 2 /* 1-4, but reduced by 1 fits in 2 bits */
|
||||||
#define NPLAYERS_NBITS 3
|
#define NPLAYERS_NBITS 3
|
||||||
|
|
|
@ -36,6 +36,7 @@ COMMONSRC = \
|
||||||
$(COMMONDIR)/game.c \
|
$(COMMONDIR)/game.c \
|
||||||
$(COMMONDIR)/nwgamest.c \
|
$(COMMONDIR)/nwgamest.c \
|
||||||
$(COMMONDIR)/dictnry.c \
|
$(COMMONDIR)/dictnry.c \
|
||||||
|
$(COMMONDIR)/dictiter.c \
|
||||||
$(COMMONDIR)/engine.c \
|
$(COMMONDIR)/engine.c \
|
||||||
$(COMMONDIR)/memstream.c \
|
$(COMMONDIR)/memstream.c \
|
||||||
$(COMMONDIR)/comms.c \
|
$(COMMONDIR)/comms.c \
|
||||||
|
@ -65,6 +66,7 @@ COMMON3 = \
|
||||||
$(COMMONOBJDIR)/game.o \
|
$(COMMONOBJDIR)/game.o \
|
||||||
$(COMMONOBJDIR)/nwgamest.o \
|
$(COMMONOBJDIR)/nwgamest.o \
|
||||||
$(COMMONOBJDIR)/dictnry.o \
|
$(COMMONOBJDIR)/dictnry.o \
|
||||||
|
$(COMMONOBJDIR)/dictiter.o \
|
||||||
$(COMMONOBJDIR)/engine.o \
|
$(COMMONOBJDIR)/engine.o \
|
||||||
|
|
||||||
COMMON4 = \
|
COMMON4 = \
|
||||||
|
|
559
xwords4/common/dictiter.c
Normal file
559
xwords4/common/dictiter.c
Normal file
|
@ -0,0 +1,559 @@
|
||||||
|
/* -*- compile-command: "cd ../linux && make MEMDEBUG=TRUE -j3"; -*- */
|
||||||
|
/*
|
||||||
|
* Copyright 1997-2011 by Eric House (xwords@eehouse.org). All rights
|
||||||
|
* reserved.
|
||||||
|
*
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef XWFEATURE_WALKDICT
|
||||||
|
|
||||||
|
#ifdef USE_STDIO
|
||||||
|
# include <stdio.h>
|
||||||
|
# include <stdlib.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "comtypes.h"
|
||||||
|
#include "dictnryp.h"
|
||||||
|
#include "xwstream.h"
|
||||||
|
#include "strutils.h"
|
||||||
|
#include "dictnry.h"
|
||||||
|
#include "dictiter.h"
|
||||||
|
#include "game.h"
|
||||||
|
|
||||||
|
#ifdef CPLUS
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct _EdgeArray {
|
||||||
|
array_edge* edges[MAX_COLS];
|
||||||
|
XP_U16 nEdges;
|
||||||
|
} EdgeArray;
|
||||||
|
|
||||||
|
/* On entry and exit, edge at end of array should be ACCEPTING. The job of
|
||||||
|
* this function is to iterate from one such edge to the next. Steps are: 1)
|
||||||
|
* try to follow the edge, to expand to a longer word with the last one as a
|
||||||
|
* prefix. 2) If we're at the end of the array, back off the top tile (and
|
||||||
|
* repeat while at end of array); 3) Once the current top edge is not a
|
||||||
|
* LAST_EDGE, try with its next-letter neighbor.
|
||||||
|
*/
|
||||||
|
static XP_Bool
|
||||||
|
nextWord( DictIter* iter )
|
||||||
|
{
|
||||||
|
const DictionaryCtxt* dict = iter->dict;
|
||||||
|
XP_U16 nEdges = iter->nEdges;
|
||||||
|
XP_Bool success = XP_FALSE;
|
||||||
|
while ( 0 < nEdges && ! success ) {
|
||||||
|
array_edge* next = dict_follow( dict, iter->edges[nEdges-1] );
|
||||||
|
if ( !!next ) {
|
||||||
|
iter->edges[nEdges++] = next;
|
||||||
|
success = ISACCEPTING( dict, next );
|
||||||
|
continue; /* try with longer word */
|
||||||
|
}
|
||||||
|
|
||||||
|
while ( IS_LAST_EDGE( dict, iter->edges[nEdges-1] )
|
||||||
|
&& 0 < --nEdges ) {
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( 0 < nEdges ) {
|
||||||
|
iter->edges[nEdges-1] += dict->nodeSize;
|
||||||
|
success = ISACCEPTING( dict, iter->edges[nEdges-1] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
iter->nEdges = nEdges;
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
static XP_Bool
|
||||||
|
isFirstEdge( const DictionaryCtxt* dict, array_edge* edge )
|
||||||
|
{
|
||||||
|
XP_Bool result = edge == dict->base; /* can't back up from first node */
|
||||||
|
if ( !result ) {
|
||||||
|
result = IS_LAST_EDGE( dict, edge - dict->nodeSize );
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static XP_Bool
|
||||||
|
lastEdges( DictIter* iter )
|
||||||
|
{
|
||||||
|
const DictionaryCtxt* dict = iter->dict;
|
||||||
|
array_edge* edge = iter->edges[iter->nEdges-1];
|
||||||
|
for ( ; ; ) {
|
||||||
|
while ( !IS_LAST_EDGE( dict, edge ) ) {
|
||||||
|
edge += dict->nodeSize;
|
||||||
|
}
|
||||||
|
iter->edges[iter->nEdges-1] = edge;
|
||||||
|
|
||||||
|
edge = dict_follow( dict, edge );
|
||||||
|
if ( NULL == edge ) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++iter->nEdges;
|
||||||
|
}
|
||||||
|
return ISACCEPTING( dict, iter->edges[iter->nEdges-1] );
|
||||||
|
}
|
||||||
|
|
||||||
|
static XP_Bool
|
||||||
|
prevWord( DictIter* iter )
|
||||||
|
{
|
||||||
|
const DictionaryCtxt* dict = iter->dict;
|
||||||
|
XP_Bool success = XP_FALSE;
|
||||||
|
while ( 0 < iter->nEdges && ! success ) {
|
||||||
|
if ( isFirstEdge( dict, iter->edges[iter->nEdges-1] ) ) {
|
||||||
|
--iter->nEdges;
|
||||||
|
success = 0 < iter->nEdges
|
||||||
|
&& ISACCEPTING( dict, iter->edges[iter->nEdges-1] );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
iter->edges[iter->nEdges-1] -= dict->nodeSize;
|
||||||
|
array_edge* next = dict_follow( dict, iter->edges[iter->nEdges-1] );
|
||||||
|
if ( NULL != next ) {
|
||||||
|
iter->edges[iter->nEdges++] = next;
|
||||||
|
success = lastEdges( iter );
|
||||||
|
if ( success ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
success = ISACCEPTING( dict, iter->edges[iter->nEdges-1] );
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
static XP_Bool
|
||||||
|
findStartsWith( DictIter* iter, const Tile* tiles, XP_U16 nTiles )
|
||||||
|
{
|
||||||
|
const DictionaryCtxt* dict = iter->dict;
|
||||||
|
XP_Bool success = XP_TRUE;
|
||||||
|
array_edge* edge = dict_getTopEdge( dict );
|
||||||
|
iter->nEdges = 0;
|
||||||
|
|
||||||
|
while ( nTiles-- > 0 ) {
|
||||||
|
Tile tile = *tiles++;
|
||||||
|
edge = dict_edge_with_tile( dict, edge, tile );
|
||||||
|
if ( NULL == edge ) {
|
||||||
|
success = XP_FALSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
iter->edges[iter->nEdges++] = edge;
|
||||||
|
edge = dict_follow( dict, edge );
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
static XP_Bool
|
||||||
|
findWordStartsWith( DictIter* iter, const Tile* tiles, XP_U16 nTiles )
|
||||||
|
{
|
||||||
|
XP_Bool found = XP_FALSE;
|
||||||
|
if ( findStartsWith( iter, tiles, nTiles ) ) {
|
||||||
|
found = ISACCEPTING( iter->dict, iter->edges[iter->nEdges-1] );
|
||||||
|
if ( !found ) {
|
||||||
|
found = nextWord( iter );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
static XP_Bool
|
||||||
|
wordsEqual( const DictIter* word1, const DictIter* word2 )
|
||||||
|
{
|
||||||
|
XP_Bool success = word1->nEdges == word2->nEdges;
|
||||||
|
if ( success ) {
|
||||||
|
success = 0 == memcmp( word1->edges, word2->edges,
|
||||||
|
word1->nEdges * sizeof(word1->edges[0]) );
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
static XP_Bool
|
||||||
|
firstWord( DictIter* iter )
|
||||||
|
{
|
||||||
|
iter->nEdges = 1;
|
||||||
|
iter->edges[0] = dict_getTopEdge( iter->dict );
|
||||||
|
return ISACCEPTING( iter->dict, iter->edges[0] ) || nextWord( iter );
|
||||||
|
}
|
||||||
|
|
||||||
|
XP_U32
|
||||||
|
dict_countWords( const DictionaryCtxt* dict )
|
||||||
|
{
|
||||||
|
XP_U32 count = 0;
|
||||||
|
DictIter iter;
|
||||||
|
dict_initIter( dict, &iter );
|
||||||
|
|
||||||
|
XP_Bool ok;
|
||||||
|
for ( ok = firstWord( &iter ); ok; ok = nextWord( &iter ) ) {
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define GUARD_VALUE 0x12345678
|
||||||
|
#define ASSERT_INITED( iter ) XP_ASSERT( (iter)->guard == GUARD_VALUE )
|
||||||
|
void
|
||||||
|
dict_initIter( const DictionaryCtxt* dict, DictIter* iter )
|
||||||
|
{
|
||||||
|
XP_MEMSET( iter, 0, sizeof(*iter) );
|
||||||
|
iter->dict = dict;
|
||||||
|
#ifdef DEBUG
|
||||||
|
iter->guard = GUARD_VALUE;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
copyIter( DictIter* dest, const DictIter* src )
|
||||||
|
{
|
||||||
|
XP_U16 nEdges = src->nEdges;
|
||||||
|
dest->nEdges = nEdges;
|
||||||
|
XP_MEMCPY( dest->edges, src->edges, nEdges * sizeof(dest->edges[0]) );
|
||||||
|
}
|
||||||
|
|
||||||
|
static DictPosition
|
||||||
|
placeWordClose( DictIter* iter, DictPosition position, XP_U16 depth,
|
||||||
|
const IndexData* data )
|
||||||
|
{
|
||||||
|
XP_S16 low = 0;
|
||||||
|
XP_S16 high = data->count - 1;
|
||||||
|
XP_S16 index = -1;
|
||||||
|
for ( ; ; ) {
|
||||||
|
if ( low > high ) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
index = low + ( (high - low) / 2);
|
||||||
|
if ( position < data->indices[index] ) {
|
||||||
|
high = index - 1;
|
||||||
|
} else if ( data->indices[index+1] <= position) {
|
||||||
|
low = index + 1;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now we have the index immediately below the position we want. But we
|
||||||
|
may be better off starting with the next if it's closer. The last
|
||||||
|
index is a special case since we use lastWord rather than a prefix to
|
||||||
|
init */
|
||||||
|
if ( ( index + 1 < data->count )
|
||||||
|
&& (data->indices[index + 1] - position)
|
||||||
|
< (position - data->indices[index]) ) {
|
||||||
|
++index;
|
||||||
|
}
|
||||||
|
if ( !findWordStartsWith( iter, &data->prefixes[depth*index], depth ) ) {
|
||||||
|
XP_ASSERT(0);
|
||||||
|
}
|
||||||
|
return data->indices[index];
|
||||||
|
} /* placeWordClose */
|
||||||
|
|
||||||
|
static void
|
||||||
|
iterToString( const DictIter* iter, XP_UCHAR* buf, XP_U16 buflen )
|
||||||
|
{
|
||||||
|
XP_U16 ii;
|
||||||
|
XP_U16 nEdges = iter->nEdges;
|
||||||
|
Tile tiles[nEdges];
|
||||||
|
for ( ii = 0; ii < nEdges; ++ii ) {
|
||||||
|
tiles[ii] = EDGETILE( iter->dict, iter->edges[ii] );
|
||||||
|
}
|
||||||
|
(void)dict_tilesToString( iter->dict, tiles, nEdges, buf, buflen );
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
static void
|
||||||
|
printEdges( DictIter* iter, char* comment )
|
||||||
|
{
|
||||||
|
XP_UCHAR buf[32];
|
||||||
|
iterToString( dict, edges, buf, VSIZE(buf) );
|
||||||
|
XP_LOGF( "%s: %s", comment, buf );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void
|
||||||
|
indexOne( XP_U16 depth, Tile* tiles, IndexData* data, DictIter* prevIter,
|
||||||
|
DictPosition* prevIndex )
|
||||||
|
{
|
||||||
|
DictIter curIter;
|
||||||
|
dict_initIter( prevIter->dict, &curIter );
|
||||||
|
if ( findWordStartsWith( &curIter, tiles, depth ) ) {
|
||||||
|
while ( !wordsEqual( &curIter, prevIter ) ) {
|
||||||
|
++*prevIndex;
|
||||||
|
if ( !nextWord( prevIter ) ) {
|
||||||
|
XP_ASSERT( 0 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
XP_ASSERT( data->count == 0 ||
|
||||||
|
data->indices[data->count-1] < *prevIndex );
|
||||||
|
data->indices[data->count] = *prevIndex;
|
||||||
|
|
||||||
|
if ( NULL != data->prefixes ) {
|
||||||
|
XP_MEMCPY( data->prefixes + (data->count * depth), tiles, depth );
|
||||||
|
}
|
||||||
|
++data->count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
doOneDepth( const Tile* allTiles, XP_U16 nTiles, Tile* prefix,
|
||||||
|
XP_U16 curDepth, XP_U16 maxDepth, IndexData* data,
|
||||||
|
DictIter* prevIter, DictPosition* prevIndex )
|
||||||
|
{
|
||||||
|
XP_U16 ii;
|
||||||
|
for ( ii = 0; ii < nTiles; ++ii ) {
|
||||||
|
prefix[curDepth] = allTiles[ii];
|
||||||
|
if ( curDepth + 1 == maxDepth ) {
|
||||||
|
indexOne( maxDepth, prefix, data, prevIter, prevIndex );
|
||||||
|
} else {
|
||||||
|
doOneDepth( allTiles, nTiles, prefix, curDepth+1, maxDepth,
|
||||||
|
data, prevIter, prevIndex );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
dict_makeIndex( const DictIter* iter, XP_U16 depth, IndexData* data )
|
||||||
|
{
|
||||||
|
ASSERT_INITED( iter );
|
||||||
|
const DictionaryCtxt* dict = iter->dict;
|
||||||
|
XP_ASSERT( depth < MAX_COLS );
|
||||||
|
XP_U16 ii, needCount;
|
||||||
|
const XP_U16 nFaces = dict_numTileFaces( dict );
|
||||||
|
XP_U16 nNonBlankFaces = nFaces;
|
||||||
|
XP_Bool hasBlank = dict_hasBlankTile( dict );
|
||||||
|
if ( hasBlank ) {
|
||||||
|
--nNonBlankFaces;
|
||||||
|
}
|
||||||
|
for ( ii = 1, needCount = nNonBlankFaces; ii < depth; ++ii ) {
|
||||||
|
needCount *= nNonBlankFaces;
|
||||||
|
}
|
||||||
|
XP_ASSERT( needCount <= data->count );
|
||||||
|
|
||||||
|
Tile allTiles[nNonBlankFaces];
|
||||||
|
XP_U16 nTiles = 0;
|
||||||
|
for ( ii = 0; ii < nFaces; ++ii ) {
|
||||||
|
if ( hasBlank && ii == dict_getBlankTile( dict ) ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
allTiles[nTiles++] = (Tile)ii;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For each tile string implied by depth (A if depth == 1, AAA if == 3 ),
|
||||||
|
* find the first word starting with that IF EXISTS. If it does, find its
|
||||||
|
* index. As an optimization, find index starting with the previous word.
|
||||||
|
*/
|
||||||
|
data->count = 0;
|
||||||
|
DictIter prevIter;
|
||||||
|
dict_initIter( dict, &prevIter );
|
||||||
|
if ( firstWord( &prevIter ) ) {
|
||||||
|
DictPosition prevIndex = 0;
|
||||||
|
Tile prefix[depth];
|
||||||
|
doOneDepth( allTiles, nNonBlankFaces, prefix, 0, depth,
|
||||||
|
data, &prevIter, &prevIndex );
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
DictPosition pos;
|
||||||
|
for ( pos = 1; pos < data->count; ++pos ) {
|
||||||
|
XP_ASSERT( data->indices[pos-1] < data->indices[pos] );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} /* dict_makeIndex */
|
||||||
|
|
||||||
|
static void
|
||||||
|
initWord( DictIter* iter )
|
||||||
|
{
|
||||||
|
iter->nWords = dict_getWordCount( iter->dict );
|
||||||
|
}
|
||||||
|
|
||||||
|
XP_Bool
|
||||||
|
dict_firstWord( DictIter* iter )
|
||||||
|
{
|
||||||
|
ASSERT_INITED( iter );
|
||||||
|
XP_Bool success = firstWord( iter );
|
||||||
|
if ( success ) {
|
||||||
|
initWord( iter );
|
||||||
|
iter->position = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
XP_Bool
|
||||||
|
dict_getNextWord( DictIter* iter )
|
||||||
|
{
|
||||||
|
ASSERT_INITED( iter );
|
||||||
|
XP_Bool success = nextWord( iter );
|
||||||
|
if ( success ) {
|
||||||
|
++iter->position;
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
XP_Bool
|
||||||
|
dict_lastWord( DictIter* iter )
|
||||||
|
{
|
||||||
|
ASSERT_INITED( iter );
|
||||||
|
iter->nEdges = 1;
|
||||||
|
iter->edges[0] = dict_getTopEdge( iter->dict );
|
||||||
|
|
||||||
|
XP_Bool success = lastEdges( iter );
|
||||||
|
if ( success ) {
|
||||||
|
initWord( iter );
|
||||||
|
iter->position = iter->nWords - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
XP_Bool
|
||||||
|
dict_getPrevWord( DictIter* iter )
|
||||||
|
{
|
||||||
|
ASSERT_INITED( iter );
|
||||||
|
XP_Bool success = prevWord( iter );
|
||||||
|
if ( success ) {
|
||||||
|
--iter->position;
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we start without an initialized word, init it to be closer to what's
|
||||||
|
sought. OR if we're father than necessary from what's sought, start over
|
||||||
|
at the closer end. Then move as many steps as necessary to reach it. */
|
||||||
|
XP_Bool
|
||||||
|
dict_getNthWord( DictIter* iter, DictPosition position, XP_U16 depth,
|
||||||
|
const IndexData* data )
|
||||||
|
{
|
||||||
|
ASSERT_INITED( iter );
|
||||||
|
const DictionaryCtxt* dict = iter->dict;
|
||||||
|
XP_U32 wordCount;
|
||||||
|
XP_Bool validWord = 0 < iter->nEdges;
|
||||||
|
if ( validWord ) { /* uninitialized */
|
||||||
|
wordCount = iter->nWords;
|
||||||
|
XP_ASSERT( wordCount == dict_getWordCount( dict ) );
|
||||||
|
} else {
|
||||||
|
wordCount = dict_getWordCount( dict );
|
||||||
|
}
|
||||||
|
XP_Bool success = position < wordCount;
|
||||||
|
if ( success ) {
|
||||||
|
/* super common cases first */
|
||||||
|
success = XP_FALSE;
|
||||||
|
if ( validWord ) {
|
||||||
|
if ( iter->position == position ) {
|
||||||
|
success = XP_TRUE;
|
||||||
|
/* do nothing; we're done */
|
||||||
|
} else if ( iter->position == position - 1 ) {
|
||||||
|
success = dict_getNextWord( iter );
|
||||||
|
} else if ( iter->position == position + 1 ) {
|
||||||
|
success = dict_getPrevWord( iter );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !success ) {
|
||||||
|
XP_U32 wordIndex;
|
||||||
|
if ( !!data && !!data->prefixes && !!data->indices ) {
|
||||||
|
wordIndex = placeWordClose( iter, position, depth, data );
|
||||||
|
if ( !validWord ) {
|
||||||
|
initWord( iter );
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
wordCount /= 2; /* mid-point */
|
||||||
|
|
||||||
|
/* If word's inited but farther from target than either
|
||||||
|
endpoint, better to start with an endpoint */
|
||||||
|
if ( validWord &&
|
||||||
|
XP_ABS( position - iter->position ) > wordCount ) {
|
||||||
|
validWord = XP_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !validWord ) {
|
||||||
|
if ( position >= wordCount ) {
|
||||||
|
dict_lastWord( iter );
|
||||||
|
} else {
|
||||||
|
dict_firstWord( iter );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wordIndex = iter->position;
|
||||||
|
}
|
||||||
|
|
||||||
|
XP_Bool (*finder)( DictIter* iter ) = NULL;/* stupid compiler */
|
||||||
|
XP_U32 repeats = 0;
|
||||||
|
if ( wordIndex < position ) {
|
||||||
|
finder = nextWord;
|
||||||
|
repeats = position - wordIndex;
|
||||||
|
} else if ( wordIndex > position ) {
|
||||||
|
finder = prevWord;
|
||||||
|
repeats = wordIndex - position;
|
||||||
|
}
|
||||||
|
while ( repeats-- ) {
|
||||||
|
if ( !(*finder)( iter ) ) {
|
||||||
|
XP_ASSERT(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
iter->position = position;
|
||||||
|
success = XP_TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
} /* dict_getNthWord */
|
||||||
|
|
||||||
|
XP_Bool
|
||||||
|
dict_findStartsWith( DictIter* iter, const IndexData* data,
|
||||||
|
const Tile* prefix, XP_U16 len )
|
||||||
|
{
|
||||||
|
XP_Bool success = XP_FALSE;
|
||||||
|
ASSERT_INITED( iter );
|
||||||
|
XP_USE(data);
|
||||||
|
XP_LOGF( "%s: not using data", __func__ );
|
||||||
|
|
||||||
|
DictIter targetIter;
|
||||||
|
dict_initIter( iter->dict, &targetIter );
|
||||||
|
if ( findWordStartsWith( &targetIter, prefix, len ) ) {
|
||||||
|
|
||||||
|
DictPosition result = 0;
|
||||||
|
DictIter iterZero;
|
||||||
|
dict_initIter( iter->dict, &iterZero );
|
||||||
|
if ( !firstWord( &iterZero ) ) {
|
||||||
|
XP_ASSERT( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
while ( ! wordsEqual( &iterZero, &targetIter ) ) {
|
||||||
|
++result;
|
||||||
|
if ( !nextWord( &iterZero ) ) {
|
||||||
|
XP_ASSERT( 0 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
copyIter( iter, &iterZero );
|
||||||
|
iter->position = result;
|
||||||
|
success = XP_TRUE;
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
dict_wordToString( const DictIter* iter, XP_UCHAR* buf, XP_U16 buflen )
|
||||||
|
{
|
||||||
|
ASSERT_INITED( iter );
|
||||||
|
iterToString( iter, buf, buflen );
|
||||||
|
}
|
||||||
|
|
||||||
|
DictPosition
|
||||||
|
dict_getPosition( const DictIter* iter )
|
||||||
|
{
|
||||||
|
ASSERT_INITED( iter );
|
||||||
|
return iter->position;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CPLUS
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif /* XWFEATURE_WALKDICT */
|
75
xwords4/common/dictiter.h
Normal file
75
xwords4/common/dictiter.h
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
/* -*- compile-command: "cd ../linux && make MEMDEBUG=TRUE -j3"; -*- */
|
||||||
|
/*
|
||||||
|
* Copyright 1997 - 2011 by Eric House (xwords@eehouse.org). All rights
|
||||||
|
* reserved.
|
||||||
|
*
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __DICTITER_H__
|
||||||
|
#define __DICTITER_H__
|
||||||
|
|
||||||
|
#ifdef XWFEATURE_WALKDICT
|
||||||
|
|
||||||
|
#include "comtypes.h"
|
||||||
|
|
||||||
|
#include "dawg.h"
|
||||||
|
#include "model.h"
|
||||||
|
#include "mempool.h"
|
||||||
|
|
||||||
|
#ifdef CPLUS
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* API for iterating over a dict */
|
||||||
|
typedef XP_S32 DictPosition;
|
||||||
|
typedef struct _DictIter {
|
||||||
|
#ifdef DEBUG
|
||||||
|
XP_U32 guard;
|
||||||
|
#endif
|
||||||
|
const DictionaryCtxt* dict;
|
||||||
|
XP_U32 nWords;
|
||||||
|
|
||||||
|
DictPosition position;
|
||||||
|
XP_U16 nEdges;
|
||||||
|
array_edge* edges[MAX_COLS];
|
||||||
|
} DictIter;
|
||||||
|
|
||||||
|
typedef struct _IndexData {
|
||||||
|
DictPosition* indices;
|
||||||
|
Tile* prefixes;
|
||||||
|
XP_U16 count; /* in-out: must indicate others are large enough */
|
||||||
|
} IndexData;
|
||||||
|
|
||||||
|
XP_U32 dict_countWords( const DictionaryCtxt* dict );
|
||||||
|
void dict_initIter( const DictionaryCtxt* dict, DictIter* iter );
|
||||||
|
void dict_makeIndex( const DictIter* iter, XP_U16 depth, IndexData* data );
|
||||||
|
XP_Bool dict_firstWord( DictIter* iter );
|
||||||
|
XP_Bool dict_lastWord( DictIter* iter );
|
||||||
|
XP_Bool dict_getNextWord( DictIter* iter );
|
||||||
|
XP_Bool dict_getPrevWord( DictIter* iter );
|
||||||
|
XP_Bool dict_getNthWord( DictIter* iter, DictPosition position, XP_U16 depth,
|
||||||
|
const IndexData* data );
|
||||||
|
void dict_wordToString( const DictIter* iter, XP_UCHAR* buf, XP_U16 buflen );
|
||||||
|
XP_Bool dict_findStartsWith( DictIter* iter, const IndexData* data,
|
||||||
|
const Tile* prefix, XP_U16 len );
|
||||||
|
DictPosition dict_getPosition( const DictIter* iter );
|
||||||
|
#ifdef CPLUS
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* XWFEATURE_WALKDICT */
|
||||||
|
#endif
|
|
@ -1,6 +1,7 @@
|
||||||
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
|
/* -*- compile-command: "cd ../linux && make MEMDEBUG=TRUE -j3"; -*- */
|
||||||
/*
|
/*
|
||||||
* Copyright 1997-2000 by Eric House (xwords@eehouse.org). All rights reserved.
|
* Copyright 1997-2011 by Eric House (xwords@eehouse.org). All rights
|
||||||
|
* reserved.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
|
@ -24,8 +25,10 @@
|
||||||
|
|
||||||
#include "comtypes.h"
|
#include "comtypes.h"
|
||||||
#include "dictnryp.h"
|
#include "dictnryp.h"
|
||||||
|
#include "dictiter.h"
|
||||||
#include "xwstream.h"
|
#include "xwstream.h"
|
||||||
#include "strutils.h"
|
#include "strutils.h"
|
||||||
|
#include "dictiter.h"
|
||||||
#include "game.h"
|
#include "game.h"
|
||||||
|
|
||||||
#ifdef CPLUS
|
#ifdef CPLUS
|
||||||
|
@ -150,27 +153,41 @@ dict_tilesToString( const DictionaryCtxt* dict, const Tile* tiles,
|
||||||
return result;
|
return result;
|
||||||
} /* dict_tilesToString */
|
} /* dict_tilesToString */
|
||||||
|
|
||||||
/* dict_tileForString: used to map user keys to tiles in the tray. Returns
|
/* Convert str to an array of tiles, continuing until we fail to match or we
|
||||||
* EMPTY_TILE if no match found.
|
* run out of room in which to return tiles. Failure to match means return of
|
||||||
|
* XP_FALSE, but if we run out of room before failing we return XP_TRUE.
|
||||||
*/
|
*/
|
||||||
Tile
|
XP_Bool
|
||||||
dict_tileForString( const DictionaryCtxt* dict, const XP_UCHAR* key )
|
dict_tilesForString( const DictionaryCtxt* dict, const XP_UCHAR* str,
|
||||||
|
Tile* tiles, XP_U16* nTilesP )
|
||||||
{
|
{
|
||||||
XP_U16 nFaces = dict_numTileFaces( dict );
|
XP_U16 nFaces = dict_numTileFaces( dict );
|
||||||
Tile tile = EMPTY_TILE;
|
XP_U16 nTiles = 0;
|
||||||
XP_U16 ii;
|
XP_Bool success = XP_TRUE;
|
||||||
|
XP_ASSERT( 0 < *nTilesP );
|
||||||
|
|
||||||
for ( ii = 0; ii < nFaces; ++ii ) {
|
while ( str[0] != '\0' && success && nTiles < *nTilesP ) {
|
||||||
if ( ii != dict->blankTile ) {
|
Tile tile;
|
||||||
const XP_UCHAR* facep = dict_getTileString( dict, ii );
|
const XP_UCHAR* prevstr = str;
|
||||||
if ( 0 == XP_STRCMP( facep, key ) ) {
|
for ( tile = 0; tile < nFaces; ++tile ) {
|
||||||
tile = (Tile)ii;
|
if ( tile != dict->blankTile ) {
|
||||||
break;
|
const XP_UCHAR* facep = dict_getTileString( dict, tile );
|
||||||
|
XP_U16 faceLen = XP_STRLEN( facep );
|
||||||
|
if ( 0 == XP_STRNCMP( facep, str, faceLen ) ) {
|
||||||
|
tiles[nTiles++] = tile;
|
||||||
|
str += faceLen;
|
||||||
|
if ( nTiles == *nTilesP ) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
success = str > prevstr;
|
||||||
}
|
}
|
||||||
return tile;
|
XP_ASSERT( nTiles <= *nTilesP );
|
||||||
} /* dict_tileForChar */
|
*nTilesP = nTiles;
|
||||||
|
return success;
|
||||||
|
} /* dict_tilesForString */
|
||||||
|
|
||||||
XP_Bool
|
XP_Bool
|
||||||
dict_tilesAreSame( const DictionaryCtxt* dict1, const DictionaryCtxt* dict2 )
|
dict_tilesAreSame( const DictionaryCtxt* dict1, const DictionaryCtxt* dict2 )
|
||||||
|
@ -461,7 +478,13 @@ dict_getLangCode( const DictionaryCtxt* dict )
|
||||||
XP_U32
|
XP_U32
|
||||||
dict_getWordCount( const DictionaryCtxt* dict )
|
dict_getWordCount( const DictionaryCtxt* dict )
|
||||||
{
|
{
|
||||||
return dict->nWords;
|
XP_U32 nWords = dict->nWords;
|
||||||
|
#ifdef XWFEATURE_WALKDICT
|
||||||
|
if ( 0 == nWords ) {
|
||||||
|
nWords = dict_countWords( dict );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return nWords;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef STUBBED_DICT
|
#ifdef STUBBED_DICT
|
||||||
|
@ -597,12 +620,76 @@ dict_super_getTopEdge( const DictionaryCtxt* dict )
|
||||||
return dict->topEdge;
|
return dict->topEdge;
|
||||||
} /* dict_super_getTopEdge */
|
} /* dict_super_getTopEdge */
|
||||||
|
|
||||||
|
static unsigned long
|
||||||
|
dict_super_index_from( const DictionaryCtxt* dict, array_edge* p_edge )
|
||||||
|
{
|
||||||
|
unsigned long result;
|
||||||
|
|
||||||
|
#ifdef NODE_CAN_4
|
||||||
|
array_edge_new* edge = (array_edge_new*)p_edge;
|
||||||
|
result = ((edge->highByte << 8) | edge->lowByte) & 0x0000FFFF;
|
||||||
|
|
||||||
|
if ( dict->is_4_byte ) {
|
||||||
|
result |= ((XP_U32)edge->moreBits) << 16;
|
||||||
|
} else {
|
||||||
|
XP_ASSERT( dict->nodeSize == 3 );
|
||||||
|
if ( (edge->bits & EXTRABITMASK_NEW) != 0 ) {
|
||||||
|
result |= 0x00010000; /* using | instead of + saves 4 bytes */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
array_edge_old* edge = (array_edge_old*)p_edge;
|
||||||
|
result = ((edge->highByte << 8) | edge->lowByte) & 0x0000FFFF;
|
||||||
|
if ( (edge->bits & EXTRABITMASK_OLD) != 0 ) {
|
||||||
|
result |= 0x00010000; /* using | instead of + saves 4 bytes */
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return result;
|
||||||
|
} /* dict_super_index_from */
|
||||||
|
|
||||||
|
static array_edge*
|
||||||
|
dict_super_follow( const DictionaryCtxt* dict, array_edge* in )
|
||||||
|
{
|
||||||
|
XP_U32 index = dict_index_from( dict, in );
|
||||||
|
array_edge* result = index > 0?
|
||||||
|
dict_edge_for_index( dict, index ): (array_edge*)NULL;
|
||||||
|
return result;
|
||||||
|
} /* dict_super_follow */
|
||||||
|
|
||||||
|
static array_edge*
|
||||||
|
dict_super_edge_with_tile( const DictionaryCtxt* dict, array_edge* from,
|
||||||
|
Tile tile )
|
||||||
|
{
|
||||||
|
for ( ; ; ) {
|
||||||
|
Tile candidate = EDGETILE(dict,from);
|
||||||
|
if ( candidate == tile ) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( IS_LAST_EDGE(dict, from ) ) {
|
||||||
|
from = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#ifdef NODE_CAN_4
|
||||||
|
from += dict->nodeSize;
|
||||||
|
#else
|
||||||
|
from += 3;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return from;
|
||||||
|
} /* edge_with_tile */
|
||||||
|
|
||||||
void
|
void
|
||||||
dict_super_init( DictionaryCtxt* dict )
|
dict_super_init( DictionaryCtxt* dict )
|
||||||
{
|
{
|
||||||
/* subclass may change these later.... */
|
/* subclass may change these later.... */
|
||||||
dict->func_edge_for_index = dict_super_edge_for_index;
|
dict->func_edge_for_index = dict_super_edge_for_index;
|
||||||
dict->func_dict_getTopEdge = dict_super_getTopEdge;
|
dict->func_dict_getTopEdge = dict_super_getTopEdge;
|
||||||
|
dict->func_dict_index_from = dict_super_index_from;
|
||||||
|
dict->func_dict_follow = dict_super_follow;
|
||||||
|
dict->func_dict_edge_with_tile = dict_super_edge_with_tile;
|
||||||
dict->func_dict_getShortName = dict_getName;
|
dict->func_dict_getShortName = dict_getName;
|
||||||
} /* dict_super_init */
|
} /* dict_super_init */
|
||||||
|
|
||||||
|
@ -612,6 +699,49 @@ dict_getLangName( const DictionaryCtxt* ctxt )
|
||||||
return ctxt->langName;
|
return ctxt->langName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef XWFEATURE_DICTSANITY
|
||||||
|
XP_Bool
|
||||||
|
checkSanity( DictionaryCtxt* dict, const XP_U32 numEdges )
|
||||||
|
{
|
||||||
|
XP_U32 ii;
|
||||||
|
XP_Bool passed = XP_TRUE;
|
||||||
|
XP_U16 nFaces = dict_numTileFaces( dict );
|
||||||
|
|
||||||
|
array_edge* edge = dict->base;
|
||||||
|
Tile prevTile = 0;
|
||||||
|
for ( ii = 0; ii < numEdges && passed; ++ii ) {
|
||||||
|
Tile tile = EDGETILE( dict, edge );
|
||||||
|
if ( tile < prevTile || tile >= nFaces ) {
|
||||||
|
XP_LOGF( "%s: node %ld (out of %ld) has too-large or "
|
||||||
|
"out-of-order tile", __func__, ii, numEdges );
|
||||||
|
passed = XP_FALSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
prevTile = tile;
|
||||||
|
|
||||||
|
unsigned long index = dict_index_from( dict, edge );
|
||||||
|
if ( index >= numEdges ) {
|
||||||
|
XP_LOGF( "%s: node %ld (out of %ld) has too-high index %ld", __func__,
|
||||||
|
ii, numEdges, index );
|
||||||
|
passed = XP_FALSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( IS_LAST_EDGE( dict, edge ) ) {
|
||||||
|
prevTile = 0;
|
||||||
|
}
|
||||||
|
edge += dict->nodeSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( passed ) {
|
||||||
|
passed = 0 == prevTile; /* last edge seen was a LAST_EDGE */
|
||||||
|
}
|
||||||
|
|
||||||
|
XP_LOGF( "%s(numEdges=%ld)=>%d", __func__, numEdges, passed );
|
||||||
|
return passed;
|
||||||
|
} /* checkSanity */
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef CPLUS
|
#ifdef CPLUS
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -66,8 +66,15 @@ typedef struct _XP_Bitmaps {
|
||||||
struct DictionaryCtxt {
|
struct DictionaryCtxt {
|
||||||
void (*destructor)( DictionaryCtxt* dict );
|
void (*destructor)( DictionaryCtxt* dict );
|
||||||
|
|
||||||
array_edge* (*func_edge_for_index)( const DictionaryCtxt* dict, XP_U32 index );
|
array_edge* (*func_edge_for_index)( const DictionaryCtxt* dict,
|
||||||
|
XP_U32 index );
|
||||||
array_edge* (*func_dict_getTopEdge)( const DictionaryCtxt* dict );
|
array_edge* (*func_dict_getTopEdge)( const DictionaryCtxt* dict );
|
||||||
|
unsigned long (*func_dict_index_from)( const DictionaryCtxt* dict,
|
||||||
|
array_edge* p_edge );
|
||||||
|
array_edge* (*func_dict_follow)( const DictionaryCtxt* dict,
|
||||||
|
array_edge* in );
|
||||||
|
array_edge* (*func_dict_edge_with_tile)( const DictionaryCtxt* dict,
|
||||||
|
array_edge* from, Tile tile );
|
||||||
const XP_UCHAR* (*func_dict_getShortName)( const DictionaryCtxt* dict );
|
const XP_UCHAR* (*func_dict_getShortName)( const DictionaryCtxt* dict );
|
||||||
|
|
||||||
array_edge* topEdge;
|
array_edge* topEdge;
|
||||||
|
@ -128,8 +135,27 @@ struct DictionaryCtxt {
|
||||||
#define dict_destroy(d) (*((d)->destructor))(d)
|
#define dict_destroy(d) (*((d)->destructor))(d)
|
||||||
#define dict_edge_for_index(d, i) (*((d)->func_edge_for_index))((d), (i))
|
#define dict_edge_for_index(d, i) (*((d)->func_edge_for_index))((d), (i))
|
||||||
#define dict_getTopEdge(d) (*((d)->func_dict_getTopEdge))(d)
|
#define dict_getTopEdge(d) (*((d)->func_dict_getTopEdge))(d)
|
||||||
|
#define dict_index_from(d,e) (*((d)->func_dict_index_from))(d,e)
|
||||||
|
#define dict_follow(d,e) (*((d)->func_dict_follow))(d,e)
|
||||||
|
#define dict_edge_with_tile(d,e,t) (*((d)->func_dict_edge_with_tile))(d,e,t)
|
||||||
#define dict_getShortName(d) (*((d)->func_dict_getShortName))(d)
|
#define dict_getShortName(d) (*((d)->func_dict_getShortName))(d)
|
||||||
|
|
||||||
|
#ifdef NODE_CAN_4
|
||||||
|
# define ISACCEPTING(d,e) \
|
||||||
|
((ACCEPTINGMASK_NEW & ((array_edge_old*)(e))->bits) != 0)
|
||||||
|
# define IS_LAST_EDGE(d,e) \
|
||||||
|
((LASTEDGEMASK_NEW & ((array_edge_old*)(e))->bits) != 0)
|
||||||
|
# define EDGETILE(d,edge) \
|
||||||
|
((Tile)(((array_edge_old*)(edge))->bits & \
|
||||||
|
((d)->is_4_byte?LETTERMASK_NEW_4:LETTERMASK_NEW_3)))
|
||||||
|
#else
|
||||||
|
# define ISACCEPTING(d,e) \
|
||||||
|
((ACCEPTINGMASK_OLD & ((array_edge_old*)(e))->bits) != 0)
|
||||||
|
# define IS_LAST_EDGE(d,e) \
|
||||||
|
((LASTEDGEMASK_OLD & ((array_edge_old*)(e))->bits) != 0)
|
||||||
|
# define EDGETILE(d,edge) \
|
||||||
|
((Tile)(((array_edge_old*)(edge))->bits & LETTERMASK_OLD))
|
||||||
|
#endif
|
||||||
|
|
||||||
XP_Bool dict_tilesAreSame( const DictionaryCtxt* dict1,
|
XP_Bool dict_tilesAreSame( const DictionaryCtxt* dict1,
|
||||||
const DictionaryCtxt* dict2 );
|
const DictionaryCtxt* dict2 );
|
||||||
|
@ -148,7 +174,8 @@ const XP_UCHAR* dict_getLangName(const DictionaryCtxt* ctxt );
|
||||||
|
|
||||||
XP_Bool dict_isUTF8( const DictionaryCtxt* ctxt );
|
XP_Bool dict_isUTF8( const DictionaryCtxt* ctxt );
|
||||||
|
|
||||||
Tile dict_tileForString( const DictionaryCtxt* dict, const XP_UCHAR* key );
|
XP_Bool dict_tilesForString( const DictionaryCtxt* dict, const XP_UCHAR* key,
|
||||||
|
Tile* tiles, XP_U16* nTiles );
|
||||||
|
|
||||||
XP_Bool dict_faceIsBitmap( const DictionaryCtxt* dict, Tile tile );
|
XP_Bool dict_faceIsBitmap( const DictionaryCtxt* dict, Tile tile );
|
||||||
void dict_getFaceBitmaps( const DictionaryCtxt* dict, Tile tile,
|
void dict_getFaceBitmaps( const DictionaryCtxt* dict, Tile tile,
|
||||||
|
@ -180,6 +207,8 @@ void dict_super_init( DictionaryCtxt* ctxt );
|
||||||
void dict_splitFaces( DictionaryCtxt* dict, const XP_U8* bytes,
|
void dict_splitFaces( DictionaryCtxt* dict, const XP_U8* bytes,
|
||||||
XP_U16 nBytes, XP_U16 nFaces );
|
XP_U16 nBytes, XP_U16 nFaces );
|
||||||
|
|
||||||
|
XP_Bool checkSanity( DictionaryCtxt* dict, XP_U32 numEdges );
|
||||||
|
|
||||||
#ifdef CPLUS
|
#ifdef CPLUS
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -121,8 +121,6 @@ struct EngineCtxt {
|
||||||
static void findMovesOneRow( EngineCtxt* engine );
|
static void findMovesOneRow( EngineCtxt* engine );
|
||||||
static Tile localGetBoardTile( EngineCtxt* engine, XP_U16 col,
|
static Tile localGetBoardTile( EngineCtxt* engine, XP_U16 col,
|
||||||
XP_U16 row, XP_Bool substBlank );
|
XP_U16 row, XP_Bool substBlank );
|
||||||
static array_edge* edge_with_tile( const DictionaryCtxt* dict,
|
|
||||||
array_edge* from, Tile tile );
|
|
||||||
static XP_Bool scoreQualifies( EngineCtxt* engine, XP_U16 score );
|
static XP_Bool scoreQualifies( EngineCtxt* engine, XP_U16 score );
|
||||||
static void findMovesForAnchor( EngineCtxt* engine, XP_S16* prevAnchor,
|
static void findMovesForAnchor( EngineCtxt* engine, XP_S16* prevAnchor,
|
||||||
XP_U16 col, XP_U16 row ) ;
|
XP_U16 col, XP_U16 row ) ;
|
||||||
|
@ -130,7 +128,6 @@ static void figureCrosschecks( EngineCtxt* engine, XP_U16 col,
|
||||||
XP_U16 row, XP_U16* scoreP,
|
XP_U16 row, XP_U16* scoreP,
|
||||||
Crosscheck* check );
|
Crosscheck* check );
|
||||||
static XP_Bool isAnchorSquare( EngineCtxt* engine, XP_U16 col, XP_U16 row );
|
static XP_Bool isAnchorSquare( EngineCtxt* engine, XP_U16 col, XP_U16 row );
|
||||||
static array_edge* follow( const DictionaryCtxt* dict, array_edge* in );
|
|
||||||
static array_edge* edge_from_tile( const DictionaryCtxt* dict,
|
static array_edge* edge_from_tile( const DictionaryCtxt* dict,
|
||||||
array_edge* from, Tile tile );
|
array_edge* from, Tile tile );
|
||||||
static void leftPart( EngineCtxt* engine, Tile* tiles, XP_U16 tileLength,
|
static void leftPart( EngineCtxt* engine, Tile* tiles, XP_U16 tileLength,
|
||||||
|
@ -166,23 +163,6 @@ static XP_S16 cmpMoves( PossibleMove* m1, PossibleMove* m2 );
|
||||||
error: need to pick one!!!
|
error: need to pick one!!!
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef NODE_CAN_4
|
|
||||||
# define ISACCEPTING(d,e) \
|
|
||||||
((ACCEPTINGMASK_NEW & ((array_edge_old*)(e))->bits) != 0)
|
|
||||||
# define IS_LAST_EDGE(d,e) \
|
|
||||||
((LASTEDGEMASK_NEW & ((array_edge_old*)(e))->bits) != 0)
|
|
||||||
# define EDGETILE(e,edge) \
|
|
||||||
((Tile)(((array_edge_old*)(edge))->bits & \
|
|
||||||
((e)->is_4_byte?LETTERMASK_NEW_4:LETTERMASK_NEW_3)))
|
|
||||||
#else
|
|
||||||
# define ISACCEPTING(d,e) \
|
|
||||||
((ACCEPTINGMASK_OLD & ((array_edge_old*)(e))->bits) != 0)
|
|
||||||
# define IS_LAST_EDGE(d,e) \
|
|
||||||
((LASTEDGEMASK_OLD & ((array_edge_old*)(e))->bits) != 0)
|
|
||||||
# define EDGETILE(d,edge) \
|
|
||||||
((Tile)(((array_edge_old*)(edge))->bits & LETTERMASK_OLD))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* #define CROSSCHECK_CONTAINS(chk,tile) (((chk) & (1L<<(tile))) != 0) */
|
/* #define CROSSCHECK_CONTAINS(chk,tile) (((chk) & (1L<<(tile))) != 0) */
|
||||||
#define CROSSCHECK_CONTAINS(chk,tile) checkIsSet( (chk), (tile) )
|
#define CROSSCHECK_CONTAINS(chk,tile) checkIsSet( (chk), (tile) )
|
||||||
|
|
||||||
|
@ -608,14 +588,14 @@ lookup( const DictionaryCtxt* dict, array_edge* edge, Tile* buf,
|
||||||
{
|
{
|
||||||
while ( edge != NULL ) {
|
while ( edge != NULL ) {
|
||||||
Tile targetTile = buf[tileIndex];
|
Tile targetTile = buf[tileIndex];
|
||||||
edge = edge_with_tile( dict, edge, targetTile );
|
edge = dict_edge_with_tile( dict, edge, targetTile );
|
||||||
if ( edge == NULL ) { /* tile not available out of this node */
|
if ( edge == NULL ) { /* tile not available out of this node */
|
||||||
return XP_FALSE;
|
return XP_FALSE;
|
||||||
} else {
|
} else {
|
||||||
if ( ++tileIndex == length ) { /* is this the last tile? */
|
if ( ++tileIndex == length ) { /* is this the last tile? */
|
||||||
return ISACCEPTING(dict, edge);
|
return ISACCEPTING(dict, edge);
|
||||||
} else {
|
} else {
|
||||||
edge = follow( dict, edge );
|
edge = dict_follow( dict, edge );
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -915,7 +895,7 @@ leftPart( EngineCtxt* engine, Tile* tiles, XP_U16 tileLength,
|
||||||
if ( rack_remove( engine, tile, &isBlank ) ) {
|
if ( rack_remove( engine, tile, &isBlank ) ) {
|
||||||
tiles[tileLength] = tile;
|
tiles[tileLength] = tile;
|
||||||
leftPart( engine, tiles, tileLength+1,
|
leftPart( engine, tiles, tileLength+1,
|
||||||
follow( engine->dict, edge ),
|
dict_follow( engine->dict, edge ),
|
||||||
limit-1, firstCol-1, anchorCol, row );
|
limit-1, firstCol-1, anchorCol, row );
|
||||||
rack_replace( engine, tile, isBlank );
|
rack_replace( engine, tile, isBlank );
|
||||||
}
|
}
|
||||||
|
@ -1000,9 +980,9 @@ extendRight( EngineCtxt* engine, Tile* tiles, XP_U16 tileLength,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if ( (edge = edge_with_tile( dict, edge, tile ) ) != NULL ) {
|
} else if ( (edge = dict_edge_with_tile( dict, edge, tile ) ) != NULL ) {
|
||||||
accepting = ISACCEPTING( dict, edge );
|
accepting = ISACCEPTING( dict, edge );
|
||||||
extendRight( engine, tiles, tileLength, follow(dict, edge),
|
extendRight( engine, tiles, tileLength, dict_follow(dict, edge),
|
||||||
accepting, firstCol, col+1, row );
|
accepting, firstCol, col+1, row );
|
||||||
goto no_check; /* don't do the check at the end */
|
goto no_check; /* don't do the check at the end */
|
||||||
} else {
|
} else {
|
||||||
|
@ -1352,73 +1332,12 @@ scoreQualifies( EngineCtxt* engine, XP_U16 score )
|
||||||
return qualifies;
|
return qualifies;
|
||||||
} /* scoreQualifies */
|
} /* scoreQualifies */
|
||||||
|
|
||||||
static array_edge*
|
|
||||||
edge_with_tile( const DictionaryCtxt* dict, array_edge* from, Tile tile )
|
|
||||||
{
|
|
||||||
for ( ; ; ) {
|
|
||||||
Tile candidate = EDGETILE(dict,from);
|
|
||||||
if ( candidate == tile ) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( IS_LAST_EDGE(dict, from ) ) {
|
|
||||||
from = NULL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#ifdef NODE_CAN_4
|
|
||||||
from += dict->nodeSize;
|
|
||||||
#else
|
|
||||||
from += 3;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return from;
|
|
||||||
} /* edge_with_tile */
|
|
||||||
|
|
||||||
static unsigned long
|
|
||||||
index_from( const DictionaryCtxt* dict, array_edge* p_edge )
|
|
||||||
{
|
|
||||||
unsigned long result;
|
|
||||||
|
|
||||||
#ifdef NODE_CAN_4
|
|
||||||
array_edge_new* edge = (array_edge_new*)p_edge;
|
|
||||||
result = ((edge->highByte << 8) | edge->lowByte) & 0x0000FFFF;
|
|
||||||
|
|
||||||
if ( dict->is_4_byte ) {
|
|
||||||
result |= ((XP_U32)edge->moreBits) << 16;
|
|
||||||
} else {
|
|
||||||
XP_ASSERT( dict->nodeSize == 3 );
|
|
||||||
if ( (edge->bits & EXTRABITMASK_NEW) != 0 ) {
|
|
||||||
result |= 0x00010000; /* using | instead of + saves 4 bytes */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
array_edge_old* edge = (array_edge_old*)p_edge;
|
|
||||||
result = ((edge->highByte << 8) | edge->lowByte) & 0x0000FFFF;
|
|
||||||
if ( (edge->bits & EXTRABITMASK_OLD) != 0 ) {
|
|
||||||
result |= 0x00010000; /* using | instead of + saves 4 bytes */
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return result;
|
|
||||||
} /* index_from */
|
|
||||||
|
|
||||||
static array_edge*
|
|
||||||
follow( const DictionaryCtxt* dict, array_edge* in )
|
|
||||||
{
|
|
||||||
XP_U32 index = index_from( dict, in );
|
|
||||||
array_edge* result = index > 0?
|
|
||||||
dict_edge_for_index( dict, index ): (array_edge*)NULL;
|
|
||||||
return result;
|
|
||||||
} /* follow */
|
|
||||||
|
|
||||||
static array_edge*
|
static array_edge*
|
||||||
edge_from_tile( const DictionaryCtxt* dict, array_edge* from, Tile tile )
|
edge_from_tile( const DictionaryCtxt* dict, array_edge* from, Tile tile )
|
||||||
{
|
{
|
||||||
array_edge* edge = edge_with_tile( dict, from, tile );
|
array_edge* edge = dict_edge_with_tile( dict, from, tile );
|
||||||
if ( edge != NULL ) {
|
if ( edge != NULL ) {
|
||||||
edge = follow( dict, edge );
|
edge = dict_follow( dict, edge );
|
||||||
}
|
}
|
||||||
return edge;
|
return edge;
|
||||||
} /* edge_from_tile */
|
} /* edge_from_tile */
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
|
/* -*- compile-command: "cd ../linux && make MEMDEBUG=TRUE -j3"; -*- */
|
||||||
/*
|
/*
|
||||||
* Copyright 2001-2009 by Eric House (xwords@eehouse.org). All rights
|
* Copyright 2001-2009 by Eric House (xwords@eehouse.org). All rights
|
||||||
* reserved.
|
* reserved.
|
||||||
|
@ -206,6 +206,7 @@ mpool_realloc( MemPoolCtx* mpool, void* ptr, XP_U32 newsize, const char* file,
|
||||||
entry->fileName = file;
|
entry->fileName = file;
|
||||||
entry->func = func;
|
entry->func = func;
|
||||||
entry->lineNo = lineNo;
|
entry->lineNo = lineNo;
|
||||||
|
entry->size = newsize;
|
||||||
}
|
}
|
||||||
return entry->ptr;
|
return entry->ptr;
|
||||||
} /* mpool_realloc */
|
} /* mpool_realloc */
|
||||||
|
|
|
@ -835,7 +835,7 @@ model_currentMoveToStream( ModelCtxt* model, XP_S16 turn,
|
||||||
stream_putBits( stream, NUMCOLS_NBITS, row );
|
stream_putBits( stream, NUMCOLS_NBITS, row );
|
||||||
stream_putBits( stream, 1, isBlank );
|
stream_putBits( stream, 1, isBlank );
|
||||||
}
|
}
|
||||||
} /* model_turnToStream */
|
} /* model_currentMoveToStream */
|
||||||
|
|
||||||
/* Take stream as the source of info about what tiles to move from tray to
|
/* Take stream as the source of info about what tiles to move from tray to
|
||||||
* board. Undo any current move first -- a player on this device might be
|
* board. Undo any current move first -- a player on this device might be
|
||||||
|
@ -877,15 +877,15 @@ model_makeTurnFromStream( ModelCtxt* model, XP_U16 playerNum,
|
||||||
|
|
||||||
foundAt = model_trayContains( model, playerNum, moveTile );
|
foundAt = model_trayContains( model, playerNum, moveTile );
|
||||||
if ( foundAt == -1 ) {
|
if ( foundAt == -1 ) {
|
||||||
XP_ASSERT( EMPTY_TILE==model_getPlayerTile(model, playerNum, 0));
|
XP_ASSERT( EMPTY_TILE == model_getPlayerTile(model, playerNum, 0));
|
||||||
|
|
||||||
(void)model_removePlayerTile( model, playerNum, -1 );
|
(void)model_removePlayerTile( model, playerNum, -1 );
|
||||||
model_addPlayerTile( model, playerNum, -1, moveTile );
|
model_addPlayerTile( model, playerNum, -1, moveTile );
|
||||||
}
|
}
|
||||||
|
|
||||||
model_moveTrayToBoard( model, playerNum, col, row, foundAt, tileFace);
|
model_moveTrayToBoard( model, playerNum, col, row, foundAt, tileFace );
|
||||||
}
|
}
|
||||||
} /* model_makeMoveFromStream */
|
} /* model_makeTurnFromStream */
|
||||||
|
|
||||||
void
|
void
|
||||||
model_makeTurnFromMoveInfo( ModelCtxt* model, XP_U16 playerNum,
|
model_makeTurnFromMoveInfo( ModelCtxt* model, XP_U16 playerNum,
|
||||||
|
@ -1095,17 +1095,11 @@ askBlankTile( ModelCtxt* model, XP_U16 turn )
|
||||||
XP_S16 chosen;
|
XP_S16 chosen;
|
||||||
const XP_UCHAR* tfaces[MAX_UNIQUE_TILES];
|
const XP_UCHAR* tfaces[MAX_UNIQUE_TILES];
|
||||||
Tile tiles[MAX_UNIQUE_TILES];
|
Tile tiles[MAX_UNIQUE_TILES];
|
||||||
PickInfo pi;
|
|
||||||
|
|
||||||
pi.why = PICK_FOR_BLANK;
|
|
||||||
pi.nTotal = 1;
|
|
||||||
pi.thisPick = 1;
|
|
||||||
|
|
||||||
model_packTilesUtil( model, NULL, XP_FALSE,
|
model_packTilesUtil( model, NULL, XP_FALSE,
|
||||||
&nUsed, tfaces, tiles );
|
&nUsed, tfaces, tiles );
|
||||||
|
|
||||||
chosen = util_userPickTile( model->vol.util, &pi,
|
chosen = util_userPickTileBlank( model->vol.util, turn, tfaces, nUsed );
|
||||||
turn, tfaces, nUsed );
|
|
||||||
|
|
||||||
if ( chosen < 0 ) {
|
if ( chosen < 0 ) {
|
||||||
chosen = 0;
|
chosen = 0;
|
||||||
|
@ -1501,24 +1495,25 @@ static void
|
||||||
makeTileTrade( ModelCtxt* model, XP_S16 player, const TrayTileSet* oldTiles,
|
makeTileTrade( ModelCtxt* model, XP_S16 player, const TrayTileSet* oldTiles,
|
||||||
const TrayTileSet* newTiles )
|
const TrayTileSet* newTiles )
|
||||||
{
|
{
|
||||||
XP_U16 i;
|
XP_U16 ii;
|
||||||
XP_U16 nTiles;
|
XP_U16 nTiles;
|
||||||
|
|
||||||
XP_ASSERT( newTiles->nTiles == oldTiles->nTiles );
|
XP_ASSERT( newTiles->nTiles == oldTiles->nTiles );
|
||||||
|
XP_ASSERT( oldTiles != &model->players[player].trayTiles );
|
||||||
|
|
||||||
for ( nTiles = newTiles->nTiles, i = 0; i < nTiles; ++i ) {
|
for ( nTiles = newTiles->nTiles, ii = 0; ii < nTiles; ++ii ) {
|
||||||
Tile oldTile = oldTiles->tiles[i];
|
Tile oldTile = oldTiles->tiles[ii];
|
||||||
|
|
||||||
XP_S16 tileIndex = model_trayContains( model, player, oldTile );
|
XP_S16 tileIndex = model_trayContains( model, player, oldTile );
|
||||||
XP_ASSERT( tileIndex >= 0 );
|
XP_ASSERT( tileIndex >= 0 );
|
||||||
model_removePlayerTile( model, player, tileIndex );
|
model_removePlayerTile( model, player, tileIndex );
|
||||||
model_addPlayerTile( model, player, tileIndex, newTiles->tiles[i] );
|
model_addPlayerTile( model, player, tileIndex, newTiles->tiles[ii] );
|
||||||
}
|
}
|
||||||
} /* makeTileTrade */
|
} /* makeTileTrade */
|
||||||
|
|
||||||
void
|
void
|
||||||
model_makeTileTrade( ModelCtxt* model, XP_S16 player,
|
model_makeTileTrade( ModelCtxt* model, XP_S16 player,
|
||||||
TrayTileSet* oldTiles, TrayTileSet* newTiles )
|
const TrayTileSet* oldTiles, const TrayTileSet* newTiles )
|
||||||
{
|
{
|
||||||
stack_addTrade( model->vol.stack, player, oldTiles, newTiles );
|
stack_addTrade( model->vol.stack, player, oldTiles, newTiles );
|
||||||
|
|
||||||
|
@ -1526,9 +1521,9 @@ model_makeTileTrade( ModelCtxt* model, XP_S16 player,
|
||||||
} /* model_makeTileTrade */
|
} /* model_makeTileTrade */
|
||||||
|
|
||||||
Tile
|
Tile
|
||||||
model_getPlayerTile( ModelCtxt* model, XP_S16 turn, XP_S16 index )
|
model_getPlayerTile( const ModelCtxt* model, XP_S16 turn, XP_S16 index )
|
||||||
{
|
{
|
||||||
PlayerCtxt* player;
|
const PlayerCtxt* player;
|
||||||
XP_ASSERT( turn >= 0 );
|
XP_ASSERT( turn >= 0 );
|
||||||
player = &model->players[turn];
|
player = &model->players[turn];
|
||||||
|
|
||||||
|
@ -1551,8 +1546,23 @@ model_getPlayerTiles( const ModelCtxt* model, XP_S16 turn )
|
||||||
return (const TrayTileSet*)&player->trayTiles;
|
return (const TrayTileSet*)&player->trayTiles;
|
||||||
} /* model_getPlayerTile */
|
} /* model_getPlayerTile */
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
XP_UCHAR*
|
||||||
|
formatTileSet( const TrayTileSet* tiles, XP_UCHAR* buf, XP_U16 len )
|
||||||
|
{
|
||||||
|
XP_U16 ii, used;
|
||||||
|
for ( ii = 0, used = 0; ii < tiles->nTiles && used < len; ++ii ) {
|
||||||
|
used += XP_SNPRINTF( &buf[used], len - used, "%d,", tiles->tiles[ii] );
|
||||||
|
}
|
||||||
|
if ( used > len ) {
|
||||||
|
buf[len-1] = '\0';
|
||||||
|
}
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void
|
static void
|
||||||
addPlayerTile( ModelCtxt* model, XP_S16 turn, XP_S16 index, Tile tile )
|
addPlayerTile( ModelCtxt* model, XP_S16 turn, XP_S16 index, const Tile tile )
|
||||||
{
|
{
|
||||||
PlayerCtxt* player;
|
PlayerCtxt* player;
|
||||||
short ii;
|
short ii;
|
||||||
|
@ -1901,7 +1911,7 @@ printMovePost( ModelCtxt* model, XP_U16 XP_UNUSED(moveN),
|
||||||
static void
|
static void
|
||||||
copyStack( ModelCtxt* model, StackCtxt* destStack, const StackCtxt* srcStack )
|
copyStack( ModelCtxt* model, StackCtxt* destStack, const StackCtxt* srcStack )
|
||||||
{
|
{
|
||||||
XWStreamCtxt* stream = mem_stream_make( MPPARM(model->vol.mpool)
|
XWStreamCtxt* stream = mem_stream_make( MPPARM(model->vol.mpool)
|
||||||
util_getVTManager(model->vol.util),
|
util_getVTManager(model->vol.util),
|
||||||
NULL, 0, NULL );
|
NULL, 0, NULL );
|
||||||
|
|
||||||
|
@ -1958,7 +1968,8 @@ typedef struct _FirstWordData {
|
||||||
static XP_Bool
|
static XP_Bool
|
||||||
getFirstWord( const XP_UCHAR* word, XP_Bool isLegal,
|
getFirstWord( const XP_UCHAR* word, XP_Bool isLegal,
|
||||||
#ifdef XWFEATURE_BOARDWORDS
|
#ifdef XWFEATURE_BOARDWORDS
|
||||||
const MoveInfo* XP_UNUSED(movei), XP_U16 XP_UNUSED(start), XP_U16 XP_UNUSED(end),
|
const MoveInfo* XP_UNUSED(movei), XP_U16 XP_UNUSED(start),
|
||||||
|
XP_U16 XP_UNUSED(end),
|
||||||
#endif
|
#endif
|
||||||
void* closure )
|
void* closure )
|
||||||
{
|
{
|
||||||
|
@ -1990,10 +2001,10 @@ scoreLastMove( ModelCtxt* model, MoveInfo* moveInfo, XP_U16 howMany,
|
||||||
ModelCtxt* tmpModel = makeTmpModel( model, NULL, NULL, NULL, NULL );
|
ModelCtxt* tmpModel = makeTmpModel( model, NULL, NULL, NULL, NULL );
|
||||||
XP_U16 turn;
|
XP_U16 turn;
|
||||||
XP_S16 moveNum = -1;
|
XP_S16 moveNum = -1;
|
||||||
|
|
||||||
copyStack( model, tmpModel->vol.stack, model->vol.stack );
|
copyStack( model, tmpModel->vol.stack, model->vol.stack );
|
||||||
|
|
||||||
if ( !model_undoLatestMoves( tmpModel, NULL, howMany, &turn,
|
if ( !model_undoLatestMoves( tmpModel, NULL, howMany, &turn,
|
||||||
&moveNum ) ) {
|
&moveNum ) ) {
|
||||||
XP_ASSERT( 0 );
|
XP_ASSERT( 0 );
|
||||||
}
|
}
|
||||||
|
@ -2001,7 +2012,7 @@ scoreLastMove( ModelCtxt* model, MoveInfo* moveInfo, XP_U16 howMany,
|
||||||
data.word[0] = '\0';
|
data.word[0] = '\0';
|
||||||
notifyInfo.proc = getFirstWord;
|
notifyInfo.proc = getFirstWord;
|
||||||
notifyInfo.closure = &data;
|
notifyInfo.closure = &data;
|
||||||
score = figureMoveScore( tmpModel, turn, moveInfo, (EngineCtxt*)NULL,
|
score = figureMoveScore( tmpModel, turn, moveInfo, (EngineCtxt*)NULL,
|
||||||
(XWStreamCtxt*)NULL, ¬ifyInfo );
|
(XWStreamCtxt*)NULL, ¬ifyInfo );
|
||||||
|
|
||||||
model_destroy( tmpModel );
|
model_destroy( tmpModel );
|
||||||
|
|
|
@ -29,16 +29,12 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define MAX_ROWS 16
|
|
||||||
#define MAX_COLS 16
|
|
||||||
#define NUMCOLS_NBITS 4
|
#define NUMCOLS_NBITS 4
|
||||||
|
|
||||||
#ifdef EIGHT_TILES
|
#ifdef EIGHT_TILES
|
||||||
#define MAX_TRAY_TILES 8
|
# define NTILES_NBITS 4
|
||||||
#define NTILES_NBITS 4
|
|
||||||
#else
|
#else
|
||||||
#define MAX_TRAY_TILES 7
|
# define NTILES_NBITS 3
|
||||||
#define NTILES_NBITS 3
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Try making this 0, as some local rules, e.g. Spanish, allow. Will need to
|
/* Try making this 0, as some local rules, e.g. Spanish, allow. Will need to
|
||||||
|
@ -137,7 +133,7 @@ XP_U16 model_getCellOwner( ModelCtxt* model, XP_U16 col, XP_U16 row );
|
||||||
|
|
||||||
void model_assignPlayerTiles( ModelCtxt* model, XP_S16 turn,
|
void model_assignPlayerTiles( ModelCtxt* model, XP_S16 turn,
|
||||||
const TrayTileSet* tiles );
|
const TrayTileSet* tiles );
|
||||||
Tile model_getPlayerTile( ModelCtxt* model, XP_S16 turn, XP_S16 index );
|
Tile model_getPlayerTile( const ModelCtxt* model, XP_S16 turn, XP_S16 index );
|
||||||
|
|
||||||
Tile model_removePlayerTile( ModelCtxt* model, XP_S16 turn, XP_S16 index );
|
Tile model_removePlayerTile( ModelCtxt* model, XP_S16 turn, XP_S16 index );
|
||||||
void model_addPlayerTile( ModelCtxt* model, XP_S16 turn, XP_S16 index,
|
void model_addPlayerTile( ModelCtxt* model, XP_S16 turn, XP_S16 index,
|
||||||
|
@ -149,6 +145,10 @@ void model_moveTileOnTray( ModelCtxt* model, XP_S16 turn, XP_S16 indexCur,
|
||||||
player. Don't even think about modifying the array!!!! */
|
player. Don't even think about modifying the array!!!! */
|
||||||
const TrayTileSet* model_getPlayerTiles( const ModelCtxt* model, XP_S16 turn );
|
const TrayTileSet* model_getPlayerTiles( const ModelCtxt* model, XP_S16 turn );
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
XP_UCHAR* formatTileSet( const TrayTileSet* tiles, XP_UCHAR* buf, XP_U16 len );
|
||||||
|
#endif
|
||||||
|
|
||||||
void model_sortTiles( ModelCtxt* model, XP_S16 turn );
|
void model_sortTiles( ModelCtxt* model, XP_S16 turn );
|
||||||
XP_U16 model_getNumTilesInTray( ModelCtxt* model, XP_S16 turn );
|
XP_U16 model_getNumTilesInTray( ModelCtxt* model, XP_S16 turn );
|
||||||
XP_U16 model_getNumTilesTotal( ModelCtxt* model, XP_S16 turn );
|
XP_U16 model_getNumTilesTotal( ModelCtxt* model, XP_S16 turn );
|
||||||
|
@ -182,7 +182,8 @@ void model_commitTurn( ModelCtxt* model, XP_S16 player,
|
||||||
TrayTileSet* newTiles );
|
TrayTileSet* newTiles );
|
||||||
void model_commitRejectedPhony( ModelCtxt* model, XP_S16 player );
|
void model_commitRejectedPhony( ModelCtxt* model, XP_S16 player );
|
||||||
void model_makeTileTrade( ModelCtxt* model, XP_S16 player,
|
void model_makeTileTrade( ModelCtxt* model, XP_S16 player,
|
||||||
TrayTileSet* oldTiles, TrayTileSet* newTiles );
|
const TrayTileSet* oldTiles,
|
||||||
|
const TrayTileSet* newTiles );
|
||||||
|
|
||||||
XP_Bool model_undoLatestMoves( ModelCtxt* model, PoolContext* pool,
|
XP_Bool model_undoLatestMoves( ModelCtxt* model, PoolContext* pool,
|
||||||
XP_U16 nMovesSought, XP_U16* turn,
|
XP_U16 nMovesSought, XP_U16* turn,
|
||||||
|
|
|
@ -295,7 +295,7 @@ stack_addPhony( StackCtxt* stack, XP_U16 turn, MoveInfo* moveInfo )
|
||||||
|
|
||||||
void
|
void
|
||||||
stack_addTrade( StackCtxt* stack, XP_U16 turn,
|
stack_addTrade( StackCtxt* stack, XP_U16 turn,
|
||||||
TrayTileSet* oldTiles, TrayTileSet* newTiles )
|
const TrayTileSet* oldTiles, const TrayTileSet* newTiles )
|
||||||
{
|
{
|
||||||
StackEntry move;
|
StackEntry move;
|
||||||
|
|
||||||
|
|
|
@ -79,7 +79,8 @@ void stack_addMove( StackCtxt* stack, XP_U16 turn, const MoveInfo* moveInfo,
|
||||||
const TrayTileSet* newTiles );
|
const TrayTileSet* newTiles );
|
||||||
void stack_addPhony( StackCtxt* stack, XP_U16 turn, MoveInfo* moveInfo );
|
void stack_addPhony( StackCtxt* stack, XP_U16 turn, MoveInfo* moveInfo );
|
||||||
void stack_addTrade( StackCtxt* stack, XP_U16 turn,
|
void stack_addTrade( StackCtxt* stack, XP_U16 turn,
|
||||||
TrayTileSet* oldTiles, TrayTileSet* newTiles );
|
const TrayTileSet* oldTiles,
|
||||||
|
const TrayTileSet* newTiles );
|
||||||
void stack_addAssign( StackCtxt* stack, XP_U16 turn,
|
void stack_addAssign( StackCtxt* stack, XP_U16 turn,
|
||||||
const TrayTileSet* tiles );
|
const TrayTileSet* tiles );
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
|
/* -*- compile-command: "cd ../linux && make -j3 MEMDEBUG=TRUE"; -*- */
|
||||||
/*
|
/*
|
||||||
* Copyright 1998-2001 by Eric House (xwords@eehouse.org). All rights reserved.
|
* Copyright 1998 - 2011 by Eric House (xwords@eehouse.org). All rights
|
||||||
|
* reserved.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
|
|
|
@ -171,10 +171,10 @@ pool_requestTiles( PoolContext* pool, Tile* tiles, XP_U8* maxNum )
|
||||||
} /* pool_requestTiles */
|
} /* pool_requestTiles */
|
||||||
|
|
||||||
void
|
void
|
||||||
pool_replaceTiles( PoolContext* pool, TrayTileSet* tiles )
|
pool_replaceTiles( PoolContext* pool, const TrayTileSet* tiles )
|
||||||
{
|
{
|
||||||
XP_U16 nTiles = tiles->nTiles;
|
XP_U16 nTiles = tiles->nTiles;
|
||||||
Tile* tilesP = tiles->tiles;
|
const Tile* tilesP = tiles->tiles;
|
||||||
|
|
||||||
while ( nTiles-- ) {
|
while ( nTiles-- ) {
|
||||||
Tile tile = *tilesP++; /* do I need to filter off high bits? */
|
Tile tile = *tilesP++; /* do I need to filter off high bits? */
|
||||||
|
@ -188,10 +188,10 @@ pool_replaceTiles( PoolContext* pool, TrayTileSet* tiles )
|
||||||
} /* pool_replaceTiles */
|
} /* pool_replaceTiles */
|
||||||
|
|
||||||
void
|
void
|
||||||
pool_removeTiles( PoolContext* pool, TrayTileSet* tiles )
|
pool_removeTiles( PoolContext* pool, const TrayTileSet* tiles )
|
||||||
{
|
{
|
||||||
XP_U16 nTiles = tiles->nTiles;
|
XP_U16 nTiles = tiles->nTiles;
|
||||||
Tile* tilesP = tiles->tiles;
|
const Tile* tilesP = tiles->tiles;
|
||||||
|
|
||||||
XP_ASSERT( nTiles <= MAX_TRAY_TILES );
|
XP_ASSERT( nTiles <= MAX_TRAY_TILES );
|
||||||
|
|
||||||
|
|
|
@ -26,8 +26,8 @@
|
||||||
|
|
||||||
void pool_requestTiles( PoolContext* pool, Tile* tiles,
|
void pool_requestTiles( PoolContext* pool, Tile* tiles,
|
||||||
/*in out*/ XP_U8* maxNum );
|
/*in out*/ XP_U8* maxNum );
|
||||||
void pool_replaceTiles( PoolContext* pool, TrayTileSet* tiles );
|
void pool_replaceTiles( PoolContext* pool, const TrayTileSet* tiles );
|
||||||
void pool_removeTiles( PoolContext* pool, TrayTileSet* tiles );
|
void pool_removeTiles( PoolContext* pool, const TrayTileSet* tiles );
|
||||||
|
|
||||||
XP_U16 pool_getNTilesLeft( PoolContext* pool );
|
XP_U16 pool_getNTilesLeft( PoolContext* pool );
|
||||||
XP_U16 pool_getNTilesLeftFor( PoolContext* pool, Tile tile );
|
XP_U16 pool_getNTilesLeftFor( PoolContext* pool, Tile tile );
|
||||||
|
|
|
@ -727,7 +727,9 @@ makeRobotMove( ServerCtxt* server )
|
||||||
|
|
||||||
/* trade if unable to find a move */
|
/* trade if unable to find a move */
|
||||||
if ( trade ) {
|
if ( trade ) {
|
||||||
result = server_commitTrade( server, ALLTILES );
|
TrayTileSet oldTiles = *model_getPlayerTiles( model, turn );
|
||||||
|
XP_LOGF( "%s: robot trading %d tiles", __func__, oldTiles.nTiles );
|
||||||
|
result = server_commitTrade( server, &oldTiles );
|
||||||
|
|
||||||
/* Quick hack to fix gremlin bug where all-robot game seen none
|
/* Quick hack to fix gremlin bug where all-robot game seen none
|
||||||
able to trade for tiles to move and blowing the undo stack.
|
able to trade for tiles to move and blowing the undo stack.
|
||||||
|
@ -748,6 +750,7 @@ makeRobotMove( ServerCtxt* server )
|
||||||
|
|
||||||
if ( canMove || NPASSES_OK(server) ) {
|
if ( canMove || NPASSES_OK(server) ) {
|
||||||
model_makeTurnFromMoveInfo( model, turn, &newMove );
|
model_makeTurnFromMoveInfo( model, turn, &newMove );
|
||||||
|
XP_LOGF( "%s: robot making %d tile move", __func__, newMove.nTiles );
|
||||||
|
|
||||||
if ( !!stream ) {
|
if ( !!stream ) {
|
||||||
XWStreamCtxt* wordsStream = mkServerStream( server );
|
XWStreamCtxt* wordsStream = mkServerStream( server );
|
||||||
|
@ -1552,7 +1555,6 @@ fetchTiles( ServerCtxt* server, XP_U16 playerNum, XP_U16 nToFetch,
|
||||||
|
|
||||||
oneTile.nTiles = 1;
|
oneTile.nTiles = 1;
|
||||||
|
|
||||||
pi.why = PICK_FOR_CHEAT;
|
|
||||||
pi.nTotal = nToFetch;
|
pi.nTotal = nToFetch;
|
||||||
pi.thisPick = 0;
|
pi.thisPick = 0;
|
||||||
pi.curTiles = curTray;
|
pi.curTiles = curTray;
|
||||||
|
@ -1570,8 +1572,8 @@ fetchTiles( ServerCtxt* server, XP_U16 playerNum, XP_U16 nToFetch,
|
||||||
model_packTilesUtil( server->vol.model, pool,
|
model_packTilesUtil( server->vol.model, pool,
|
||||||
XP_TRUE, &nUsed, texts, tiles );
|
XP_TRUE, &nUsed, texts, tiles );
|
||||||
|
|
||||||
chosen = util_userPickTile( server->vol.util, &pi, playerNum,
|
chosen = util_userPickTileTray( server->vol.util, &pi, playerNum,
|
||||||
texts, nUsed );
|
texts, nUsed );
|
||||||
|
|
||||||
if ( chosen == PICKER_PICKALL ) {
|
if ( chosen == PICKER_PICKALL ) {
|
||||||
ask = XP_FALSE;
|
ask = XP_FALSE;
|
||||||
|
@ -1778,7 +1780,7 @@ checkMoveAllowed( ServerCtxt* server, XP_U16 playerNum )
|
||||||
static void
|
static void
|
||||||
sendMoveTo( ServerCtxt* server, XP_U16 devIndex, XP_U16 turn,
|
sendMoveTo( ServerCtxt* server, XP_U16 devIndex, XP_U16 turn,
|
||||||
XP_Bool legal, TrayTileSet* newTiles,
|
XP_Bool legal, TrayTileSet* newTiles,
|
||||||
TrayTileSet* tradedTiles ) /* null if a move, set if a trade */
|
const TrayTileSet* tradedTiles ) /* null if a move, set if a trade */
|
||||||
{
|
{
|
||||||
XWStreamCtxt* stream;
|
XWStreamCtxt* stream;
|
||||||
XP_Bool isTrade = !!tradedTiles;
|
XP_Bool isTrade = !!tradedTiles;
|
||||||
|
@ -1835,6 +1837,7 @@ readMoveInfo( ServerCtxt* server, XWStreamCtxt* stream,
|
||||||
|
|
||||||
if ( isTrade ) {
|
if ( isTrade ) {
|
||||||
traySetFromStream( stream, tradedTiles );
|
traySetFromStream( stream, tradedTiles );
|
||||||
|
XP_LOGF( "%s: got trade of %d tiles", __func__, tradedTiles->nTiles );
|
||||||
} else {
|
} else {
|
||||||
legalMove = stream_getBits( stream, 1 );
|
legalMove = stream_getBits( stream, 1 );
|
||||||
model_makeTurnFromStream( server->vol.model, whoMoved, stream );
|
model_makeTurnFromStream( server->vol.model, whoMoved, stream );
|
||||||
|
@ -1851,7 +1854,7 @@ readMoveInfo( ServerCtxt* server, XWStreamCtxt* stream,
|
||||||
|
|
||||||
static void
|
static void
|
||||||
sendMoveToClientsExcept( ServerCtxt* server, XP_U16 whoMoved, XP_Bool legal,
|
sendMoveToClientsExcept( ServerCtxt* server, XP_U16 whoMoved, XP_Bool legal,
|
||||||
TrayTileSet* newTiles, TrayTileSet* tradedTiles,
|
TrayTileSet* newTiles, const TrayTileSet* tradedTiles,
|
||||||
XP_U16 skip )
|
XP_U16 skip )
|
||||||
{
|
{
|
||||||
XP_U16 devIndex;
|
XP_U16 devIndex;
|
||||||
|
@ -2123,49 +2126,27 @@ server_commitMove( ServerCtxt* server )
|
||||||
return XP_TRUE;
|
return XP_TRUE;
|
||||||
} /* server_commitMove */
|
} /* server_commitMove */
|
||||||
|
|
||||||
static void
|
|
||||||
removeTradedTiles( ServerCtxt* server, TileBit selBits, TrayTileSet* tiles )
|
|
||||||
{
|
|
||||||
XP_U8 nTiles = 0;
|
|
||||||
XP_S16 index;
|
|
||||||
XP_S16 turn = server->nv.currentTurn;
|
|
||||||
|
|
||||||
/* selBits: It's gross that server knows this much about tray's
|
|
||||||
implementation. PENDING(ehouse) */
|
|
||||||
|
|
||||||
for ( index = 0; selBits != 0; selBits >>= 1, ++index ) {
|
|
||||||
if ( (selBits & 0x01) != 0 ) {
|
|
||||||
Tile tile = model_getPlayerTile( server->vol.model, turn, index );
|
|
||||||
tiles->tiles[nTiles++] = tile;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tiles->nTiles = nTiles;
|
|
||||||
} /* saveTradedTiles */
|
|
||||||
|
|
||||||
XP_Bool
|
XP_Bool
|
||||||
server_commitTrade( ServerCtxt* server, TileBit selBits )
|
server_commitTrade( ServerCtxt* server, const TrayTileSet* oldTiles )
|
||||||
{
|
{
|
||||||
TrayTileSet oldTiles;
|
|
||||||
TrayTileSet newTiles;
|
TrayTileSet newTiles;
|
||||||
XP_U16 turn = server->nv.currentTurn;
|
XP_U16 turn = server->nv.currentTurn;
|
||||||
|
|
||||||
removeTradedTiles( server, selBits, &oldTiles );
|
fetchTiles( server, turn, oldTiles->nTiles, oldTiles, &newTiles );
|
||||||
|
|
||||||
fetchTiles( server, turn, oldTiles.nTiles, &oldTiles, &newTiles );
|
|
||||||
|
|
||||||
#ifndef XWFEATURE_STANDALONE_ONLY
|
#ifndef XWFEATURE_STANDALONE_ONLY
|
||||||
if ( server->vol.gi->serverRole == SERVER_ISCLIENT ) {
|
if ( server->vol.gi->serverRole == SERVER_ISCLIENT ) {
|
||||||
/* just send to server */
|
/* just send to server */
|
||||||
sendMoveTo(server, SERVER_DEVICE, turn, XP_TRUE, &newTiles, &oldTiles);
|
sendMoveTo(server, SERVER_DEVICE, turn, XP_TRUE, &newTiles, oldTiles);
|
||||||
} else {
|
} else {
|
||||||
sendMoveToClientsExcept( server, turn, XP_TRUE, &newTiles, &oldTiles,
|
sendMoveToClientsExcept( server, turn, XP_TRUE, &newTiles, oldTiles,
|
||||||
SERVER_DEVICE );
|
SERVER_DEVICE );
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
pool_replaceTiles( server->pool, &oldTiles );
|
pool_replaceTiles( server->pool, oldTiles );
|
||||||
model_makeTileTrade( server->vol.model, server->nv.currentTurn,
|
XP_ASSERT( turn == server->nv.currentTurn );
|
||||||
&oldTiles, &newTiles );
|
model_makeTileTrade( server->vol.model, turn, oldTiles, &newTiles );
|
||||||
sortTilesIf( server, turn );
|
sortTilesIf( server, turn );
|
||||||
|
|
||||||
nextTurn( server, PICK_NEXT );
|
nextTurn( server, PICK_NEXT );
|
||||||
|
@ -2527,6 +2508,7 @@ server_receiveMessage( ServerCtxt* server, XWStreamCtxt* incoming )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case XWPROTO_MOVEMADE_INFO_SERVER: /* server telling me about a move */
|
case XWPROTO_MOVEMADE_INFO_SERVER: /* server telling me about a move */
|
||||||
|
XP_ASSERT( SERVER_ISCLIENT == server->vol.gi->serverRole );
|
||||||
accepted = reflectMove( server, incoming );
|
accepted = reflectMove( server, incoming );
|
||||||
if ( accepted ) {
|
if ( accepted ) {
|
||||||
nextTurn( server, PICK_NEXT );
|
nextTurn( server, PICK_NEXT );
|
||||||
|
|
|
@ -101,7 +101,7 @@ XP_S16 server_countTilesInPool( ServerCtxt* server );
|
||||||
XP_Bool server_do( ServerCtxt* server, XP_Bool* moreToDoP );
|
XP_Bool server_do( ServerCtxt* server, XP_Bool* moreToDoP );
|
||||||
|
|
||||||
XP_Bool server_commitMove( ServerCtxt* server );
|
XP_Bool server_commitMove( ServerCtxt* server );
|
||||||
XP_Bool server_commitTrade( ServerCtxt* server, TileBit bits );
|
XP_Bool server_commitTrade( ServerCtxt* server, const TrayTileSet* oldTiles );
|
||||||
|
|
||||||
/* call this when user wants to end the game */
|
/* call this when user wants to end the game */
|
||||||
void server_endGame( ServerCtxt* server );
|
void server_endGame( ServerCtxt* server );
|
||||||
|
|
|
@ -379,6 +379,24 @@ handleTrayDuringTrade( BoardCtxt* board, XP_S16 index )
|
||||||
return XP_TRUE;
|
return XP_TRUE;
|
||||||
} /* handleTrayDuringTrade */
|
} /* handleTrayDuringTrade */
|
||||||
|
|
||||||
|
void
|
||||||
|
getSelTiles( const BoardCtxt* board, TileBit selBits, TrayTileSet* selTiles )
|
||||||
|
{
|
||||||
|
XP_U16 nTiles = 0;
|
||||||
|
XP_S16 index;
|
||||||
|
XP_S16 turn = board->selPlayer;
|
||||||
|
const ModelCtxt* model = board->model;
|
||||||
|
|
||||||
|
for ( index = 0; selBits != 0; selBits >>= 1, ++index ) {
|
||||||
|
if ( 0 != (selBits & 0x01) ) {
|
||||||
|
Tile tile = model_getPlayerTile( model, turn, index );
|
||||||
|
XP_ASSERT( nTiles < VSIZE(selTiles->tiles) );
|
||||||
|
selTiles->tiles[nTiles++] = tile;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
selTiles->nTiles = nTiles;
|
||||||
|
}
|
||||||
|
|
||||||
static XP_Bool
|
static XP_Bool
|
||||||
handleActionInTray( BoardCtxt* board, XP_S16 index, XP_Bool onDivider )
|
handleActionInTray( BoardCtxt* board, XP_S16 index, XP_Bool onDivider )
|
||||||
{
|
{
|
||||||
|
|
|
@ -65,17 +65,11 @@ typedef enum {
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
QUERY_COMMIT_TURN, /* 0 means cancel; 1 means commit */
|
QUERY_COMMIT_TURN, /* 0 means cancel; 1 means commit */
|
||||||
QUERY_COMMIT_TRADE,
|
|
||||||
QUERY_ROBOT_TRADE,
|
QUERY_ROBOT_TRADE,
|
||||||
|
|
||||||
QUERY_LAST_COMMON
|
QUERY_LAST_COMMON
|
||||||
} UtilQueryID;
|
} UtilQueryID;
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
PICK_FOR_BLANK
|
|
||||||
, PICK_FOR_CHEAT
|
|
||||||
} PICK_WHY;
|
|
||||||
|
|
||||||
#define PICKER_PICKALL -1
|
#define PICKER_PICKALL -1
|
||||||
#define PICKER_BACKUP -2
|
#define PICKER_BACKUP -2
|
||||||
|
|
||||||
|
@ -84,7 +78,6 @@ typedef struct PickInfo {
|
||||||
XP_U16 nCurTiles;
|
XP_U16 nCurTiles;
|
||||||
XP_U16 nTotal; /* count to fetch for turn, <= MAX_TRAY_TILES */
|
XP_U16 nTotal; /* count to fetch for turn, <= MAX_TRAY_TILES */
|
||||||
XP_U16 thisPick; /* <= nTotal */
|
XP_U16 thisPick; /* <= nTotal */
|
||||||
PICK_WHY why;
|
|
||||||
} PickInfo;
|
} PickInfo;
|
||||||
|
|
||||||
typedef struct BadWordInfo {
|
typedef struct BadWordInfo {
|
||||||
|
@ -113,11 +106,15 @@ typedef struct UtilVtable {
|
||||||
|
|
||||||
XP_Bool (*m_util_userQuery)( XW_UtilCtxt* uc, UtilQueryID id,
|
XP_Bool (*m_util_userQuery)( XW_UtilCtxt* uc, UtilQueryID id,
|
||||||
XWStreamCtxt* stream );
|
XWStreamCtxt* stream );
|
||||||
|
XP_Bool (*m_util_confirmTrade)( XW_UtilCtxt* uc, const XP_UCHAR** tiles,
|
||||||
|
XP_U16 nTiles );
|
||||||
/* return of < 0 means computer should pick */
|
/* return of < 0 means computer should pick */
|
||||||
XP_S16 (*m_util_userPickTile)( XW_UtilCtxt* uc, const PickInfo* pi,
|
XP_S16 (*m_util_userPickTileBlank)( XW_UtilCtxt* uc, XP_U16 playerNum,
|
||||||
XP_U16 playerNum,
|
const XP_UCHAR** tileFaces,
|
||||||
const XP_UCHAR** texts, XP_U16 nTiles );
|
XP_U16 nTiles );
|
||||||
|
XP_S16 (*m_util_userPickTileTray)( XW_UtilCtxt* uc, const PickInfo* pi,
|
||||||
|
XP_U16 playerNum,
|
||||||
|
const XP_UCHAR** texts, XP_U16 nTiles );
|
||||||
|
|
||||||
XP_Bool (*m_util_askPassword)( XW_UtilCtxt* uc, const XP_UCHAR* name,
|
XP_Bool (*m_util_askPassword)( XW_UtilCtxt* uc, const XP_UCHAR* name,
|
||||||
XP_UCHAR* buf, XP_U16* len );
|
XP_UCHAR* buf, XP_U16* len );
|
||||||
|
@ -213,8 +210,13 @@ struct XW_UtilCtxt {
|
||||||
#define util_userQuery(uc,qcode,str) \
|
#define util_userQuery(uc,qcode,str) \
|
||||||
(uc)->vtable->m_util_userQuery((uc),(qcode),(str))
|
(uc)->vtable->m_util_userQuery((uc),(qcode),(str))
|
||||||
|
|
||||||
#define util_userPickTile( uc, w, n, tx, nt ) \
|
#define util_confirmTrade( uc, tx, nt ) \
|
||||||
(uc)->vtable->m_util_userPickTile( (uc), (w), (n), (tx), (nt) )
|
(uc)->vtable->m_util_confirmTrade((uc),(tx),(nt))
|
||||||
|
|
||||||
|
#define util_userPickTileBlank( uc, n, tx, nt ) \
|
||||||
|
(uc)->vtable->m_util_userPickTileBlank( (uc), (n), (tx), (nt) )
|
||||||
|
#define util_userPickTileTray( uc, w, n, tx, nt ) \
|
||||||
|
(uc)->vtable->m_util_userPickTileTray( (uc), (w), (n), (tx), (nt) )
|
||||||
#define util_askPassword( uc, n, b, lp ) \
|
#define util_askPassword( uc, n, b, lp ) \
|
||||||
(uc)->vtable->m_util_askPassword( (uc), (n), (b), (lp) )
|
(uc)->vtable->m_util_askPassword( (uc), (n), (b), (lp) )
|
||||||
|
|
||||||
|
|
|
@ -91,6 +91,8 @@ DEFINES += -DXWFEATURE_CHAT
|
||||||
DEFINES += -DDISABLE_TILE_SEL
|
DEFINES += -DDISABLE_TILE_SEL
|
||||||
DEFINES += -DSET_GAMESEED
|
DEFINES += -DSET_GAMESEED
|
||||||
DEFINES += -DTEXT_MODEL
|
DEFINES += -DTEXT_MODEL
|
||||||
|
DEFINES += -DXWFEATURE_WALKDICT
|
||||||
|
DEFINES += -DXWFEATURE_DICTSANITY
|
||||||
|
|
||||||
ifdef CURSES_CELL_HT
|
ifdef CURSES_CELL_HT
|
||||||
DEFINES += -DCURSES_CELL_HT=$(CURSES_CELL_HT)
|
DEFINES += -DCURSES_CELL_HT=$(CURSES_CELL_HT)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* -*- compile-command: "make MEMDEBUG=TRUE -j3"; -*- */
|
/* -*- compile-command: "make MEMDEBUG=TRUE -j3"; -*- */
|
||||||
/*
|
/*
|
||||||
* Copyright 2000-2011 by Eric House (xwords@eehouse.org). All rights
|
* Copyright 2000 - 2011 by Eric House (xwords@eehouse.org). All rights
|
||||||
* reserved.
|
* reserved.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
|
@ -229,9 +229,26 @@ cursesUserError( CursesAppGlobals* globals, const char* format, ... )
|
||||||
} /* cursesUserError */
|
} /* cursesUserError */
|
||||||
|
|
||||||
static XP_S16
|
static XP_S16
|
||||||
curses_util_userPickTile( XW_UtilCtxt* uc, const PickInfo* XP_UNUSED(pi),
|
curses_util_userPickTileBlank( XW_UtilCtxt* uc, XP_U16 playerNum,
|
||||||
XP_U16 playerNum, const XP_UCHAR** texts,
|
const XP_UCHAR** texts, XP_U16 nTiles )
|
||||||
XP_U16 nTiles )
|
{
|
||||||
|
CursesAppGlobals* globals = (CursesAppGlobals*)uc->closure;
|
||||||
|
char query[128];
|
||||||
|
XP_S16 index;
|
||||||
|
char* playerName = globals->cGlobals.params->gi.players[playerNum].name;
|
||||||
|
|
||||||
|
snprintf( query, sizeof(query),
|
||||||
|
"Pick tile for %s! (Tab or type letter to select "
|
||||||
|
"then hit <cr>.)", playerName );
|
||||||
|
|
||||||
|
index = curses_askLetter( globals, query, texts, nTiles );
|
||||||
|
return index;
|
||||||
|
} /* util_userPickTile */
|
||||||
|
|
||||||
|
static XP_S16
|
||||||
|
curses_util_userPickTileTray( XW_UtilCtxt* uc, const PickInfo* XP_UNUSED(pi),
|
||||||
|
XP_U16 playerNum, const XP_UCHAR** texts,
|
||||||
|
XP_U16 nTiles )
|
||||||
{
|
{
|
||||||
CursesAppGlobals* globals = (CursesAppGlobals*)uc->closure;
|
CursesAppGlobals* globals = (CursesAppGlobals*)uc->closure;
|
||||||
char query[128];
|
char query[128];
|
||||||
|
@ -278,11 +295,6 @@ curses_util_userQuery( XW_UtilCtxt* uc, UtilQueryID id, XWStreamCtxt* stream )
|
||||||
answers[numAnswers++] = "Cancel";
|
answers[numAnswers++] = "Cancel";
|
||||||
answers[numAnswers++] = "Ok";
|
answers[numAnswers++] = "Ok";
|
||||||
break;
|
break;
|
||||||
case QUERY_COMMIT_TRADE:
|
|
||||||
question = "Commit trade?";
|
|
||||||
answers[numAnswers++] = "Cancel";
|
|
||||||
answers[numAnswers++] = "Ok";
|
|
||||||
break;
|
|
||||||
case QUERY_ROBOT_TRADE:
|
case QUERY_ROBOT_TRADE:
|
||||||
question = strFromStream( stream );
|
question = strFromStream( stream );
|
||||||
freeMe = XP_TRUE;
|
freeMe = XP_TRUE;
|
||||||
|
@ -305,6 +317,16 @@ curses_util_userQuery( XW_UtilCtxt* uc, UtilQueryID id, XWStreamCtxt* stream )
|
||||||
return result;
|
return result;
|
||||||
} /* curses_util_userQuery */
|
} /* curses_util_userQuery */
|
||||||
|
|
||||||
|
static XP_Bool
|
||||||
|
curses_util_confirmTrade( XW_UtilCtxt* uc, const XP_UCHAR** tiles,
|
||||||
|
XP_U16 nTiles )
|
||||||
|
{
|
||||||
|
CursesAppGlobals* globals = (CursesAppGlobals*)uc->closure;
|
||||||
|
char question[256];
|
||||||
|
formatConfirmTrade( tiles, nTiles, question, sizeof(question) );
|
||||||
|
return 1 == cursesask( globals, question, 2, "Cancel", "Ok" );
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
curses_util_trayHiddenChange( XW_UtilCtxt* XP_UNUSED(uc),
|
curses_util_trayHiddenChange( XW_UtilCtxt* XP_UNUSED(uc),
|
||||||
XW_TrayVisState XP_UNUSED(state),
|
XW_TrayVisState XP_UNUSED(state),
|
||||||
|
@ -427,7 +449,6 @@ curses_util_clearTimer( XW_UtilCtxt* uc, XWTimerReason why )
|
||||||
static gboolean
|
static gboolean
|
||||||
onetime_idle( gpointer data )
|
onetime_idle( gpointer data )
|
||||||
{
|
{
|
||||||
LOG_FUNC();
|
|
||||||
CursesAppGlobals* globals = (CursesAppGlobals*)data;
|
CursesAppGlobals* globals = (CursesAppGlobals*)data;
|
||||||
if ( server_do( globals->cGlobals.game.server, NULL ) ) {
|
if ( server_do( globals->cGlobals.game.server, NULL ) ) {
|
||||||
if ( !!globals->cGlobals.game.board ) {
|
if ( !!globals->cGlobals.game.board ) {
|
||||||
|
@ -443,7 +464,12 @@ curses_util_requestTime( XW_UtilCtxt* uc )
|
||||||
{
|
{
|
||||||
CursesAppGlobals* globals = (CursesAppGlobals*)uc->closure;
|
CursesAppGlobals* globals = (CursesAppGlobals*)uc->closure;
|
||||||
#ifdef USE_GLIBLOOP
|
#ifdef USE_GLIBLOOP
|
||||||
|
# if 0
|
||||||
(void)g_idle_add( onetime_idle, globals );
|
(void)g_idle_add( onetime_idle, globals );
|
||||||
|
# else
|
||||||
|
(void)g_timeout_add( 1,// interval,
|
||||||
|
onetime_idle, globals );
|
||||||
|
# endif
|
||||||
#else
|
#else
|
||||||
/* I've created a pipe whose read-only end is plugged into the array of
|
/* I've created a pipe whose read-only end is plugged into the array of
|
||||||
fds that my event loop polls so that I can write to it to simulate
|
fds that my event loop polls so that I can write to it to simulate
|
||||||
|
@ -1040,7 +1066,7 @@ data_socket_proc( GIOChannel* source, GIOCondition condition, gpointer data )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
} /* data_socket_proc */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -1473,7 +1499,9 @@ setupCursesUtilCallbacks( CursesAppGlobals* globals, XW_UtilCtxt* util )
|
||||||
util->vtable->m_util_makeStreamFromAddr = curses_util_makeStreamFromAddr;
|
util->vtable->m_util_makeStreamFromAddr = curses_util_makeStreamFromAddr;
|
||||||
#endif
|
#endif
|
||||||
util->vtable->m_util_userQuery = curses_util_userQuery;
|
util->vtable->m_util_userQuery = curses_util_userQuery;
|
||||||
util->vtable->m_util_userPickTile = curses_util_userPickTile;
|
util->vtable->m_util_confirmTrade = curses_util_confirmTrade;
|
||||||
|
util->vtable->m_util_userPickTileBlank = curses_util_userPickTileBlank;
|
||||||
|
util->vtable->m_util_userPickTileTray = curses_util_userPickTileTray;
|
||||||
util->vtable->m_util_trayHiddenChange = curses_util_trayHiddenChange;
|
util->vtable->m_util_trayHiddenChange = curses_util_trayHiddenChange;
|
||||||
util->vtable->m_util_informMove = curses_util_informMove;
|
util->vtable->m_util_informMove = curses_util_informMove;
|
||||||
util->vtable->m_util_notifyGameOver = curses_util_notifyGameOver;
|
util->vtable->m_util_notifyGameOver = curses_util_notifyGameOver;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
|
/* -*- compile-command: "make -j3 MEMDEBUG=TRUE"; -*- */
|
||||||
/*
|
/*
|
||||||
* Copyright 2000-2009 by Eric House (xwords@eehouse.org). All rights
|
* Copyright 2000-2009 by Eric House (xwords@eehouse.org). All rights
|
||||||
* reserved.
|
* reserved.
|
||||||
|
@ -24,11 +24,10 @@
|
||||||
#include "gtkask.h"
|
#include "gtkask.h"
|
||||||
|
|
||||||
static void
|
static void
|
||||||
button_event( GtkWidget* XP_UNUSED(widget), gpointer closure )
|
set_bool_and_quit( GtkWidget* XP_UNUSED(widget), gpointer closure )
|
||||||
{
|
{
|
||||||
XP_Bool* whichSet = (XP_Bool*)closure;
|
XP_Bool* whichSet = (XP_Bool*)closure;
|
||||||
*whichSet = 1;
|
*whichSet = XP_TRUE;
|
||||||
|
|
||||||
gtk_main_quit();
|
gtk_main_quit();
|
||||||
} /* button_event */
|
} /* button_event */
|
||||||
|
|
||||||
|
@ -43,7 +42,7 @@ abort_button_event( GtkWidget* XP_UNUSED(widget), gpointer XP_UNUSED(closure) )
|
||||||
#define BUTTONS_PER_ROW 13
|
#define BUTTONS_PER_ROW 13
|
||||||
|
|
||||||
XP_S16
|
XP_S16
|
||||||
gtkletterask( const PickInfo* pi, const XP_UCHAR* name,
|
gtkletterask( const PickInfo* pi, XP_Bool forTray, const XP_UCHAR* name,
|
||||||
XP_U16 nTiles, const XP_UCHAR** texts )
|
XP_U16 nTiles, const XP_UCHAR** texts )
|
||||||
{
|
{
|
||||||
GtkWidget* dialog;
|
GtkWidget* dialog;
|
||||||
|
@ -55,8 +54,9 @@ gtkletterask( const PickInfo* pi, const XP_UCHAR* name,
|
||||||
XP_S16 ii;
|
XP_S16 ii;
|
||||||
GtkWidget* button;
|
GtkWidget* button;
|
||||||
XP_UCHAR buf[64];
|
XP_UCHAR buf[64];
|
||||||
|
XP_Bool backedUp = XP_FALSE;
|
||||||
|
|
||||||
XP_MEMSET( results, 0, sizeof(results) );
|
XP_MEMSET( results, XP_FALSE, sizeof(results) );
|
||||||
|
|
||||||
vbox = gtk_vbox_new( FALSE, 0 );
|
vbox = gtk_vbox_new( FALSE, 0 );
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ gtkletterask( const PickInfo* pi, const XP_UCHAR* name,
|
||||||
|
|
||||||
gtk_box_pack_start( GTK_BOX(hbox), button, FALSE, TRUE, 0 );
|
gtk_box_pack_start( GTK_BOX(hbox), button, FALSE, TRUE, 0 );
|
||||||
g_signal_connect( GTK_OBJECT(button), "clicked",
|
g_signal_connect( GTK_OBJECT(button), "clicked",
|
||||||
G_CALLBACK(button_event), &results[ii] );
|
G_CALLBACK(set_bool_and_quit), &results[ii] );
|
||||||
gtk_widget_show( button );
|
gtk_widget_show( button );
|
||||||
|
|
||||||
if ( ii+1 == nTiles || (ii % BUTTONS_PER_ROW == 0) ) {
|
if ( ii+1 == nTiles || (ii % BUTTONS_PER_ROW == 0) ) {
|
||||||
|
@ -79,12 +79,20 @@ gtkletterask( const PickInfo* pi, const XP_UCHAR* name,
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef FEATURE_TRAY_EDIT
|
#ifdef FEATURE_TRAY_EDIT
|
||||||
button = gtk_button_new_with_label( "Just pick em!" );
|
|
||||||
hbox = gtk_hbox_new( FALSE, 0 );
|
hbox = gtk_hbox_new( FALSE, 0 );
|
||||||
|
|
||||||
|
button = gtk_button_new_with_label( "Just pick em!" );
|
||||||
g_signal_connect( GTK_OBJECT(button), "clicked",
|
g_signal_connect( GTK_OBJECT(button), "clicked",
|
||||||
G_CALLBACK(abort_button_event), NULL );
|
G_CALLBACK(abort_button_event), NULL );
|
||||||
gtk_box_pack_start( GTK_BOX(hbox), button, FALSE, TRUE, 0 );
|
gtk_box_pack_start( GTK_BOX(hbox), button, FALSE, TRUE, 0 );
|
||||||
gtk_widget_show( button );
|
gtk_widget_show( button );
|
||||||
|
|
||||||
|
button = gtk_button_new_with_label( "Back up" );
|
||||||
|
g_signal_connect( GTK_OBJECT(button), "clicked",
|
||||||
|
G_CALLBACK(set_bool_and_quit), &backedUp );
|
||||||
|
gtk_box_pack_start( GTK_BOX(hbox), button, FALSE, TRUE, 0 );
|
||||||
|
gtk_widget_show( button );
|
||||||
|
|
||||||
gtk_widget_show( hbox );
|
gtk_widget_show( hbox );
|
||||||
gtk_box_pack_start( GTK_BOX(vbox), hbox, FALSE, TRUE, 0 );
|
gtk_box_pack_start( GTK_BOX(vbox), hbox, FALSE, TRUE, 0 );
|
||||||
#endif
|
#endif
|
||||||
|
@ -95,19 +103,18 @@ gtkletterask( const PickInfo* pi, const XP_UCHAR* name,
|
||||||
dialog = gtk_dialog_new();
|
dialog = gtk_dialog_new();
|
||||||
gtk_window_set_modal( GTK_WINDOW( dialog ), TRUE );
|
gtk_window_set_modal( GTK_WINDOW( dialog ), TRUE );
|
||||||
|
|
||||||
XP_Bool forBlank = PICK_FOR_BLANK == pi->why;
|
if ( forTray ) {
|
||||||
if ( forBlank ) {
|
|
||||||
txt = "Choose a letter for your blank.";
|
|
||||||
} else {
|
|
||||||
char* fmt = "Choose a tile for %s.";
|
char* fmt = "Choose a tile for %s.";
|
||||||
XP_SNPRINTF( buf, sizeof(buf), fmt, name );
|
XP_SNPRINTF( buf, sizeof(buf), fmt, name );
|
||||||
txt = buf;
|
txt = buf;
|
||||||
|
} else {
|
||||||
|
txt = "Choose a letter for your blank.";
|
||||||
}
|
}
|
||||||
label = gtk_label_new( txt );
|
label = gtk_label_new( txt );
|
||||||
gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox),
|
gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox),
|
||||||
label);
|
label);
|
||||||
|
|
||||||
if ( !forBlank ) {
|
if ( forTray ) {
|
||||||
char curTilesBuf[64];
|
char curTilesBuf[64];
|
||||||
int len = snprintf( curTilesBuf, sizeof(curTilesBuf), "%s",
|
int len = snprintf( curTilesBuf, sizeof(curTilesBuf), "%s",
|
||||||
"Tiles so far: " );
|
"Tiles so far: " );
|
||||||
|
@ -128,13 +135,17 @@ gtkletterask( const PickInfo* pi, const XP_UCHAR* name,
|
||||||
|
|
||||||
gtk_widget_destroy( dialog );
|
gtk_widget_destroy( dialog );
|
||||||
|
|
||||||
for ( ii = 0; ii < nTiles; ++ii ) {
|
if ( backedUp ) {
|
||||||
if ( results[ii] ) {
|
ii = PICKER_BACKUP;
|
||||||
break;
|
} else {
|
||||||
|
for ( ii = 0; ii < nTiles; ++ii ) {
|
||||||
|
if ( results[ii] ) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( ii == nTiles ) {
|
||||||
|
ii = PICKER_PICKALL;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if ( ii == nTiles ) {
|
|
||||||
ii = -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ii;
|
return ii;
|
||||||
|
|
|
@ -26,7 +26,8 @@
|
||||||
|
|
||||||
#include "gtkmain.h"
|
#include "gtkmain.h"
|
||||||
|
|
||||||
XP_S16 gtkletterask( const PickInfo* pi, const XP_UCHAR* name,
|
XP_S16 gtkletterask( const PickInfo* pi, XP_Bool forTray,
|
||||||
|
const XP_UCHAR* name,
|
||||||
XP_U16 nTiles, const XP_UCHAR** texts );
|
XP_U16 nTiles, const XP_UCHAR** texts );
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1300,15 +1300,27 @@ gtk_util_getVTManager(XW_UtilCtxt* uc)
|
||||||
} /* linux_util_getVTManager */
|
} /* linux_util_getVTManager */
|
||||||
|
|
||||||
static XP_S16
|
static XP_S16
|
||||||
gtk_util_userPickTile( XW_UtilCtxt* uc, const PickInfo* pi,
|
gtk_util_userPickTileBlank( XW_UtilCtxt* uc, XP_U16 playerNum,
|
||||||
XP_U16 playerNum, const XP_UCHAR** texts,
|
const XP_UCHAR** texts, XP_U16 nTiles )
|
||||||
XP_U16 nTiles )
|
|
||||||
{
|
{
|
||||||
XP_S16 chosen;
|
XP_S16 chosen;
|
||||||
GtkAppGlobals* globals = (GtkAppGlobals*)uc->closure;
|
GtkAppGlobals* globals = (GtkAppGlobals*)uc->closure;
|
||||||
XP_UCHAR* name = globals->cGlobals.params->gi.players[playerNum].name;
|
XP_UCHAR* name = globals->cGlobals.params->gi.players[playerNum].name;
|
||||||
|
|
||||||
chosen = gtkletterask( pi, name, nTiles, texts );
|
chosen = gtkletterask( NULL, XP_FALSE, name, nTiles, texts );
|
||||||
|
return chosen;
|
||||||
|
}
|
||||||
|
|
||||||
|
static XP_S16
|
||||||
|
gtk_util_userPickTileTray( XW_UtilCtxt* uc, const PickInfo* pi,
|
||||||
|
XP_U16 playerNum, const XP_UCHAR** texts,
|
||||||
|
XP_U16 nTiles )
|
||||||
|
{
|
||||||
|
XP_S16 chosen;
|
||||||
|
GtkAppGlobals* globals = (GtkAppGlobals*)uc->closure;
|
||||||
|
XP_UCHAR* name = globals->cGlobals.params->gi.players[playerNum].name;
|
||||||
|
|
||||||
|
chosen = gtkletterask( pi, XP_TRUE, name, nTiles, texts );
|
||||||
return chosen;
|
return chosen;
|
||||||
} /* gtk_util_userPickTile */
|
} /* gtk_util_userPickTile */
|
||||||
|
|
||||||
|
@ -1761,9 +1773,6 @@ gtk_util_userQuery( XW_UtilCtxt* XP_UNUSED(uc), UtilQueryID id,
|
||||||
question = strFromStream( stream );
|
question = strFromStream( stream );
|
||||||
freeMe = XP_TRUE;
|
freeMe = XP_TRUE;
|
||||||
break;
|
break;
|
||||||
case QUERY_COMMIT_TRADE:
|
|
||||||
question = "Are you sure you want to trade the selected tiles?";
|
|
||||||
break;
|
|
||||||
case QUERY_ROBOT_TRADE:
|
case QUERY_ROBOT_TRADE:
|
||||||
question = strFromStream( stream );
|
question = strFromStream( stream );
|
||||||
freeMe = XP_TRUE;
|
freeMe = XP_TRUE;
|
||||||
|
@ -1784,6 +1793,15 @@ gtk_util_userQuery( XW_UtilCtxt* XP_UNUSED(uc), UtilQueryID id,
|
||||||
return result;
|
return result;
|
||||||
} /* gtk_util_userQuery */
|
} /* gtk_util_userQuery */
|
||||||
|
|
||||||
|
static XP_Bool
|
||||||
|
gtk_util_confirmTrade( XW_UtilCtxt* XP_UNUSED(uc),
|
||||||
|
const XP_UCHAR** tiles, XP_U16 nTiles )
|
||||||
|
{
|
||||||
|
char question[256];
|
||||||
|
formatConfirmTrade( tiles, nTiles, question, sizeof(question) );
|
||||||
|
return gtkask( question, GTK_BUTTONS_YES_NO );
|
||||||
|
}
|
||||||
|
|
||||||
static GtkWidget*
|
static GtkWidget*
|
||||||
makeShowButtonFromBitmap( void* closure, const gchar* filename,
|
makeShowButtonFromBitmap( void* closure, const gchar* filename,
|
||||||
const gchar* alt, GCallback func )
|
const gchar* alt, GCallback func )
|
||||||
|
@ -1922,8 +1940,10 @@ setupGtkUtilCallbacks( GtkAppGlobals* globals, XW_UtilCtxt* util )
|
||||||
{
|
{
|
||||||
util->vtable->m_util_userError = gtk_util_userError;
|
util->vtable->m_util_userError = gtk_util_userError;
|
||||||
util->vtable->m_util_userQuery = gtk_util_userQuery;
|
util->vtable->m_util_userQuery = gtk_util_userQuery;
|
||||||
|
util->vtable->m_util_confirmTrade = gtk_util_confirmTrade;
|
||||||
util->vtable->m_util_getVTManager = gtk_util_getVTManager;
|
util->vtable->m_util_getVTManager = gtk_util_getVTManager;
|
||||||
util->vtable->m_util_userPickTile = gtk_util_userPickTile;
|
util->vtable->m_util_userPickTileBlank = gtk_util_userPickTileBlank;
|
||||||
|
util->vtable->m_util_userPickTileTray = gtk_util_userPickTileTray;
|
||||||
util->vtable->m_util_askPassword = gtk_util_askPassword;
|
util->vtable->m_util_askPassword = gtk_util_askPassword;
|
||||||
util->vtable->m_util_trayHiddenChange = gtk_util_trayHiddenChange;
|
util->vtable->m_util_trayHiddenChange = gtk_util_trayHiddenChange;
|
||||||
util->vtable->m_util_yOffsetChange = gtk_util_yOffsetChange;
|
util->vtable->m_util_yOffsetChange = gtk_util_yOffsetChange;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; compile-command: "make MEMDEBUG=TRUE"; -*- */
|
/* -*- compile-command: "make MEMDEBUG=TRUE -j3"; -*- */
|
||||||
/*
|
/*
|
||||||
* Copyright 1997-2009 by Eric House (xwords@eehouse.org). All rights
|
* Copyright 1997 - 2011 by Eric House (xwords@eehouse.org). All rights
|
||||||
* reserved.
|
* reserved.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
|
@ -219,23 +219,25 @@ initFromDictFile( LinuxDictionaryCtxt* dctx, const char* fileName )
|
||||||
const XP_U8* ptr;
|
const XP_U8* ptr;
|
||||||
|
|
||||||
struct stat statbuf;
|
struct stat statbuf;
|
||||||
if ( 0 != stat( fileName, &statbuf ) ) {
|
if ( 0 != stat( fileName, &statbuf ) || 0 == statbuf.st_size ) {
|
||||||
goto closeAndExit;
|
goto closeAndExit;
|
||||||
}
|
}
|
||||||
dctx->dictLength = statbuf.st_size;
|
dctx->dictLength = statbuf.st_size;
|
||||||
|
|
||||||
{
|
{
|
||||||
FILE* dictF = fopen( fileName, "r" );
|
FILE* dictF = fopen( fileName, "r" );
|
||||||
XP_ASSERT( !!dictF );
|
XP_ASSERT( !!dictF );
|
||||||
if ( dctx->useMMap ) {
|
if ( dctx->useMMap ) {
|
||||||
dctx->dictBase = mmap( NULL, dctx->dictLength, PROT_READ, MAP_PRIVATE, fileno(dictF), 0 );
|
dctx->dictBase = mmap( NULL, dctx->dictLength, PROT_READ,
|
||||||
} else {
|
MAP_PRIVATE, fileno(dictF), 0 );
|
||||||
dctx->dictBase = XP_MALLOC( dctx->super.mpool, dctx->dictLength );
|
} else {
|
||||||
if ( dctx->dictLength != fread( dctx->dictBase, 1, dctx->dictLength, dictF ) ) {
|
dctx->dictBase = XP_MALLOC( dctx->super.mpool, dctx->dictLength );
|
||||||
XP_ASSERT( 0 );
|
if ( dctx->dictLength != fread( dctx->dictBase, 1,
|
||||||
}
|
dctx->dictLength, dictF ) ) {
|
||||||
}
|
XP_ASSERT( 0 );
|
||||||
fclose( dictF );
|
}
|
||||||
|
}
|
||||||
|
fclose( dictF );
|
||||||
}
|
}
|
||||||
|
|
||||||
ptr = dctx->dictBase;
|
ptr = dctx->dictBase;
|
||||||
|
@ -247,65 +249,65 @@ initFromDictFile( LinuxDictionaryCtxt* dctx, const char* fileName )
|
||||||
XP_DEBUGF( "flags=0X%X", flags );
|
XP_DEBUGF( "flags=0X%X", flags );
|
||||||
hasHeader = 0 != (DICT_HEADER_MASK & flags);
|
hasHeader = 0 != (DICT_HEADER_MASK & flags);
|
||||||
if ( hasHeader ) {
|
if ( hasHeader ) {
|
||||||
flags &= ~DICT_HEADER_MASK;
|
flags &= ~DICT_HEADER_MASK;
|
||||||
XP_DEBUGF( "has header!" );
|
XP_DEBUGF( "has header!" );
|
||||||
}
|
}
|
||||||
#ifdef NODE_CAN_4
|
#ifdef NODE_CAN_4
|
||||||
if ( flags == 0x0001 ) {
|
if ( flags == 0x0001 ) {
|
||||||
dctx->super.nodeSize = 3;
|
dctx->super.nodeSize = 3;
|
||||||
charSize = 1;
|
charSize = 1;
|
||||||
dctx->super.is_4_byte = XP_FALSE;
|
dctx->super.is_4_byte = XP_FALSE;
|
||||||
} else if ( flags == 0x0002 ) {
|
} else if ( flags == 0x0002 ) {
|
||||||
dctx->super.nodeSize = 3;
|
dctx->super.nodeSize = 3;
|
||||||
charSize = 2;
|
charSize = 2;
|
||||||
dctx->super.is_4_byte = XP_FALSE;
|
dctx->super.is_4_byte = XP_FALSE;
|
||||||
} else if ( flags == 0x0003 ) {
|
} else if ( flags == 0x0003 ) {
|
||||||
dctx->super.nodeSize = 4;
|
dctx->super.nodeSize = 4;
|
||||||
charSize = 2;
|
charSize = 2;
|
||||||
dctx->super.is_4_byte = XP_TRUE;
|
dctx->super.is_4_byte = XP_TRUE;
|
||||||
} else if ( flags == 0x0004 ) {
|
} else if ( flags == 0x0004 ) {
|
||||||
dctx->super.nodeSize = 3;
|
dctx->super.nodeSize = 3;
|
||||||
dctx->super.isUTF8 = XP_TRUE;
|
dctx->super.isUTF8 = XP_TRUE;
|
||||||
isUTF8 = XP_TRUE;
|
isUTF8 = XP_TRUE;
|
||||||
dctx->super.is_4_byte = XP_FALSE;
|
dctx->super.is_4_byte = XP_FALSE;
|
||||||
} else if ( flags == 0x0005 ) {
|
} else if ( flags == 0x0005 ) {
|
||||||
dctx->super.nodeSize = 4;
|
dctx->super.nodeSize = 4;
|
||||||
dctx->super.isUTF8 = XP_TRUE;
|
dctx->super.isUTF8 = XP_TRUE;
|
||||||
isUTF8 = XP_TRUE;
|
isUTF8 = XP_TRUE;
|
||||||
dctx->super.is_4_byte = XP_TRUE;
|
dctx->super.is_4_byte = XP_TRUE;
|
||||||
} else {
|
} else {
|
||||||
/* case I don't know how to deal with */
|
/* case I don't know how to deal with */
|
||||||
formatOk = XP_FALSE;
|
formatOk = XP_FALSE;
|
||||||
XP_ASSERT(0);
|
XP_ASSERT(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
XP_ASSERT( flags == 0x0001 );
|
XP_ASSERT( flags == 0x0001 );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if ( formatOk ) {
|
if ( formatOk ) {
|
||||||
XP_U8 numFaceBytes, numFaces;
|
XP_U8 numFaceBytes, numFaces;
|
||||||
|
|
||||||
if ( hasHeader ) {
|
if ( hasHeader ) {
|
||||||
XP_U16 headerLen;
|
XP_U16 headerLen;
|
||||||
XP_U32 wordCount;
|
XP_U32 wordCount;
|
||||||
|
|
||||||
memcpy( &headerLen, ptr, sizeof(headerLen) );
|
memcpy( &headerLen, ptr, sizeof(headerLen) );
|
||||||
ptr += sizeof(headerLen);
|
ptr += sizeof(headerLen);
|
||||||
headerLen = ntohs( headerLen );
|
headerLen = ntohs( headerLen );
|
||||||
if ( headerLen != sizeof(wordCount) ) { /* the only case we know right now */
|
if ( headerLen != sizeof(wordCount) ) { /* the only case we know right now */
|
||||||
goto closeAndExit;
|
goto closeAndExit;
|
||||||
}
|
}
|
||||||
memcpy( &wordCount, ptr, sizeof(wordCount) );
|
memcpy( &wordCount, ptr, sizeof(wordCount) );
|
||||||
ptr += sizeof(wordCount);
|
ptr += sizeof(wordCount);
|
||||||
dctx->super.nWords = ntohl( wordCount );
|
dctx->super.nWords = ntohl( wordCount );
|
||||||
XP_DEBUGF( "dict contains %ld words", dctx->super.nWords );
|
XP_DEBUGF( "dict contains %ld words", dctx->super.nWords );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( isUTF8 ) {
|
if ( isUTF8 ) {
|
||||||
numFaceBytes = *ptr++;
|
numFaceBytes = *ptr++;
|
||||||
}
|
}
|
||||||
numFaces = *ptr++;
|
numFaces = *ptr++;
|
||||||
if ( !isUTF8 ) {
|
if ( !isUTF8 ) {
|
||||||
numFaceBytes = numFaces * charSize;
|
numFaceBytes = numFaces * charSize;
|
||||||
}
|
}
|
||||||
|
@ -320,42 +322,47 @@ XP_ASSERT( flags == 0x0001 );
|
||||||
}
|
}
|
||||||
|
|
||||||
XP_U8 tmp[numFaceBytes];
|
XP_U8 tmp[numFaceBytes];
|
||||||
memcpy( tmp, ptr, numFaceBytes );
|
memcpy( tmp, ptr, numFaceBytes );
|
||||||
ptr += numFaceBytes;
|
ptr += numFaceBytes;
|
||||||
|
|
||||||
dict_splitFaces( &dctx->super, tmp, numFaceBytes, numFaces );
|
dict_splitFaces( &dctx->super, tmp, numFaceBytes, numFaces );
|
||||||
|
|
||||||
memcpy( &xloc, ptr, sizeof(xloc) );
|
memcpy( &xloc, ptr, sizeof(xloc) );
|
||||||
ptr += sizeof(xloc);
|
ptr += sizeof(xloc);
|
||||||
memcpy( dctx->super.countsAndValues, ptr, numFaces*2 );
|
memcpy( dctx->super.countsAndValues, ptr, numFaces*2 );
|
||||||
ptr += numFaces*2;
|
ptr += numFaces*2;
|
||||||
}
|
}
|
||||||
|
|
||||||
dctx->super.langCode = xloc & 0x7F;
|
dctx->super.langCode = xloc & 0x7F;
|
||||||
|
|
||||||
if ( formatOk ) {
|
if ( formatOk ) {
|
||||||
|
XP_U32 numEdges;
|
||||||
skipBitmaps( dctx, &ptr );
|
skipBitmaps( dctx, &ptr );
|
||||||
|
|
||||||
curPos = ptr - dctx->dictBase;
|
curPos = ptr - dctx->dictBase;
|
||||||
dictLength = dctx->dictLength - curPos;
|
dictLength = dctx->dictLength - curPos;
|
||||||
|
|
||||||
if ( dictLength > 0 ) {
|
if ( dictLength > 0 ) {
|
||||||
memcpy( &topOffset, ptr, sizeof(topOffset) );
|
memcpy( &topOffset, ptr, sizeof(topOffset) );
|
||||||
/* it's in big-endian order */
|
/* it's in big-endian order */
|
||||||
topOffset = ntohl(topOffset);
|
topOffset = ntohl(topOffset);
|
||||||
dictLength -= sizeof(topOffset); /* first four bytes are offset */
|
dictLength -= sizeof(topOffset); /* first four bytes are offset */
|
||||||
ptr += sizeof(topOffset);
|
ptr += sizeof(topOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( dictLength > 0 ) {
|
if ( dictLength > 0 ) {
|
||||||
|
# ifdef NODE_CAN_4
|
||||||
|
numEdges = dictLength / dctx->super.nodeSize;
|
||||||
|
# else
|
||||||
|
numEdges = dictLength / 3;
|
||||||
|
# endif
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
# ifdef NODE_CAN_4
|
# ifdef NODE_CAN_4
|
||||||
dctx->super.numEdges = dictLength / dctx->super.nodeSize;
|
|
||||||
XP_ASSERT( (dictLength % dctx->super.nodeSize) == 0 );
|
XP_ASSERT( (dictLength % dctx->super.nodeSize) == 0 );
|
||||||
# else
|
# else
|
||||||
dctx->super.numEdges = dictLength / 3;
|
|
||||||
XP_ASSERT( (dictLength % 3) == 0 );
|
XP_ASSERT( (dictLength % 3) == 0 );
|
||||||
# endif
|
# endif
|
||||||
|
dctx->super.numEdges = numEdges;
|
||||||
#endif
|
#endif
|
||||||
dctx->super.base = (array_edge*)ptr;
|
dctx->super.base = (array_edge*)ptr;
|
||||||
|
|
||||||
|
@ -366,6 +373,10 @@ XP_ASSERT( flags == 0x0001 );
|
||||||
}
|
}
|
||||||
|
|
||||||
dctx->super.name = copyString( dctx->super.mpool, fileName );
|
dctx->super.name = copyString( dctx->super.mpool, fileName );
|
||||||
|
|
||||||
|
if ( ! checkSanity( &dctx->super, numEdges ) ) {
|
||||||
|
goto closeAndExit;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
goto ok;
|
goto ok;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; compile-command: "make MEMDEBUG=TRUE"; -*- */
|
/* -*- compile-command: "make MEMDEBUG=TRUE -j3"; -*- */
|
||||||
/*
|
/*
|
||||||
* Copyright 2000-2009 by Eric House (xwords@eehouse.org). All rights
|
* Copyright 2000 - 2011 by Eric House (xwords@eehouse.org). All rights
|
||||||
* reserved.
|
* reserved.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
|
@ -50,6 +50,7 @@
|
||||||
#include "linuxbt.h"
|
#include "linuxbt.h"
|
||||||
#include "linuxsms.h"
|
#include "linuxsms.h"
|
||||||
#include "linuxudp.h"
|
#include "linuxudp.h"
|
||||||
|
#include "dictiter.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#ifdef PLATFORM_NCURSES
|
#ifdef PLATFORM_NCURSES
|
||||||
# include "cursesmain.h"
|
# include "cursesmain.h"
|
||||||
|
@ -60,6 +61,7 @@
|
||||||
#include "model.h"
|
#include "model.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "strutils.h"
|
#include "strutils.h"
|
||||||
|
#include "dictiter.h"
|
||||||
/* #include "commgr.h" */
|
/* #include "commgr.h" */
|
||||||
/* #include "compipe.h" */
|
/* #include "compipe.h" */
|
||||||
#include "memstream.h"
|
#include "memstream.h"
|
||||||
|
@ -374,11 +376,15 @@ typedef enum {
|
||||||
,CMD_SHOW_OTHERSCORES
|
,CMD_SHOW_OTHERSCORES
|
||||||
,CMD_HOSTIP
|
,CMD_HOSTIP
|
||||||
,CMD_DICT
|
,CMD_DICT
|
||||||
|
#ifdef XWFEATURE_WALKDICT
|
||||||
|
,CMD_TESTDICT
|
||||||
|
,CMD_TESTPRFX
|
||||||
|
#endif
|
||||||
,CMD_PLAYERDICT
|
,CMD_PLAYERDICT
|
||||||
,CMD_SEED
|
,CMD_SEED
|
||||||
,CMD_GAMESEED
|
,CMD_GAMESEED
|
||||||
,CMD_GAMEFILE
|
,CMD_GAMEFILE
|
||||||
,CMD_MMAP
|
,CMD_NOMMAP
|
||||||
,CMD_PRINTHISORY
|
,CMD_PRINTHISORY
|
||||||
,CMD_SKIPWARNINGS
|
,CMD_SKIPWARNINGS
|
||||||
,CMD_LOCALPWD
|
,CMD_LOCALPWD
|
||||||
|
@ -449,11 +455,15 @@ static CmdInfoRec CmdInfoRecs[] = {
|
||||||
,{ CMD_SHOW_OTHERSCORES, false, "show-other", "show robot/remote scores" }
|
,{ CMD_SHOW_OTHERSCORES, false, "show-other", "show robot/remote scores" }
|
||||||
,{ CMD_HOSTIP, true, "hostip", "remote host ip address (for direct connect)" }
|
,{ CMD_HOSTIP, true, "hostip", "remote host ip address (for direct connect)" }
|
||||||
,{ CMD_DICT, true, "game-dict", "dictionary name for game" }
|
,{ CMD_DICT, true, "game-dict", "dictionary name for game" }
|
||||||
|
#ifdef XWFEATURE_WALKDICT
|
||||||
|
,{ CMD_TESTDICT, true, "test-dict", "dictionary to be used for iterator test" }
|
||||||
|
,{ CMD_TESTPRFX, true, "test-prefix", "list first word starting with this" }
|
||||||
|
#endif
|
||||||
,{ CMD_PLAYERDICT, true, "player-dict", "dictionary name for player (in sequence)" }
|
,{ CMD_PLAYERDICT, true, "player-dict", "dictionary name for player (in sequence)" }
|
||||||
,{ CMD_SEED, true, "seed", "random seed" }
|
,{ CMD_SEED, true, "seed", "random seed" }
|
||||||
,{ CMD_GAMESEED, true, "game-seed", "game seed (for relay play)" }
|
,{ CMD_GAMESEED, true, "game-seed", "game seed (for relay play)" }
|
||||||
,{ CMD_GAMEFILE, true, "file", "file to save to/read from" }
|
,{ CMD_GAMEFILE, true, "file", "file to save to/read from" }
|
||||||
,{ CMD_MMAP, false, "use-mmap", "mmap dicts rather than copy them to memory" }
|
,{ CMD_NOMMAP, false, "no-mmap", "copy dicts to memory rather than mmap them" }
|
||||||
,{ CMD_PRINTHISORY, false, "print-history", "print history on game over" }
|
,{ CMD_PRINTHISORY, false, "print-history", "print history on game over" }
|
||||||
,{ CMD_SKIPWARNINGS, false, "skip-warnings", "no modals on phonies" }
|
,{ CMD_SKIPWARNINGS, false, "skip-warnings", "no modals on phonies" }
|
||||||
,{ CMD_LOCALPWD, true, "password", "password for user (in sequence)" }
|
,{ CMD_LOCALPWD, true, "password", "password for user (in sequence)" }
|
||||||
|
@ -1022,6 +1032,198 @@ tmp_noop_sigintterm( int XP_UNUSED(sig) )
|
||||||
LOG_FUNC();
|
LOG_FUNC();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef XWFEATURE_WALKDICT
|
||||||
|
//# define PRINT_ALL
|
||||||
|
static void
|
||||||
|
testGetNthWord( const DictionaryCtxt* dict, char** words,
|
||||||
|
XP_U16 depth, IndexData* data )
|
||||||
|
{
|
||||||
|
XP_U32 half = dict_getWordCount( dict ) / 2;
|
||||||
|
XP_UCHAR buf[64];
|
||||||
|
XP_U32 ii, jj;
|
||||||
|
DictIter iter;
|
||||||
|
XP_U32 interval = 1000;
|
||||||
|
|
||||||
|
dict_initIter( dict, &iter );
|
||||||
|
|
||||||
|
for ( ii = 0, jj = half; ii < half; ii += interval, jj += interval ) {
|
||||||
|
if ( dict_getNthWord( &iter, ii, depth, data ) ) {
|
||||||
|
dict_wordToString( &iter, buf, VSIZE(buf) );
|
||||||
|
XP_ASSERT( 0 == strcmp( buf, words[ii] ) );
|
||||||
|
// XP_LOGF( "%s: word[%ld]: %s", __func__, ii, buf );
|
||||||
|
} else {
|
||||||
|
XP_ASSERT( 0 );
|
||||||
|
}
|
||||||
|
if ( dict_getNthWord( &iter, jj, depth, data ) ) {
|
||||||
|
dict_wordToString( &iter, buf, VSIZE(buf) );
|
||||||
|
XP_ASSERT( 0 == strcmp( buf, words[jj] ) );
|
||||||
|
// XP_LOGF( "%s: word[%ld]: %s", __func__, jj, buf );
|
||||||
|
} else {
|
||||||
|
XP_ASSERT( 0 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
walk_dict_test( const LaunchParams* params, const DictionaryCtxt* dict,
|
||||||
|
GSList* testPrefixes )
|
||||||
|
{
|
||||||
|
/* This is just to test that the dict-iterating code works. The words are
|
||||||
|
meant to be printed e.g. in a scrolling dialog on Android. */
|
||||||
|
DictIter iter;
|
||||||
|
long jj;
|
||||||
|
XP_Bool gotOne;
|
||||||
|
|
||||||
|
XP_U32 count = dict_getWordCount( dict );
|
||||||
|
XP_ASSERT( count > 0 );
|
||||||
|
XP_ASSERT( count == dict_countWords( dict ) );
|
||||||
|
char** words = g_malloc( count * sizeof(char*) );
|
||||||
|
XP_ASSERT( !!words );
|
||||||
|
|
||||||
|
/* if ( dict_firstWord( dict, &word ) */
|
||||||
|
/* && dict_getNextWord( dict, &word ) */
|
||||||
|
/* && dict_getPrevWord( dict, &word ) ) { */
|
||||||
|
/* fprintf( stderr, "yay!: dict_getPrevWord returned\n" ); */
|
||||||
|
/* } */
|
||||||
|
/* exit( 0 ); */
|
||||||
|
|
||||||
|
dict_initIter( dict, &iter );
|
||||||
|
for ( jj = 0, gotOne = dict_firstWord( &iter );
|
||||||
|
gotOne;
|
||||||
|
++jj, gotOne = dict_getNextWord( &iter ) ) {
|
||||||
|
XP_ASSERT( dict_getPosition( &iter ) == jj );
|
||||||
|
XP_UCHAR buf[64];
|
||||||
|
dict_wordToString( &iter, buf, VSIZE(buf) );
|
||||||
|
# ifdef PRINT_ALL
|
||||||
|
fprintf( stderr, "%.6ld: %s\n", jj, buf );
|
||||||
|
# endif
|
||||||
|
if ( !!words ) {
|
||||||
|
words[jj] = g_strdup( buf );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
XP_ASSERT( count == jj );
|
||||||
|
|
||||||
|
for ( jj = 0, gotOne = dict_lastWord( &iter );
|
||||||
|
gotOne;
|
||||||
|
++jj, gotOne = dict_getPrevWord( &iter ) ) {
|
||||||
|
XP_ASSERT( dict_getPosition(&iter) == count-jj-1 );
|
||||||
|
XP_UCHAR buf[64];
|
||||||
|
dict_wordToString( &iter, buf, VSIZE(buf) );
|
||||||
|
# ifdef PRINT_ALL
|
||||||
|
fprintf( stderr, "%.6ld: %s\n", jj, buf );
|
||||||
|
# endif
|
||||||
|
if ( !!words ) {
|
||||||
|
if ( strcmp( buf, words[count-jj-1] ) ) {
|
||||||
|
fprintf( stderr, "failure at %ld: %s going forward; %s "
|
||||||
|
"going backward\n", jj, words[count-jj-1], buf );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
XP_ASSERT( count == jj );
|
||||||
|
XP_LOGF( "finished comparing runs in both directions" );
|
||||||
|
|
||||||
|
XP_LOGF( "testing getNth" );
|
||||||
|
testGetNthWord( dict, words, 0, NULL );
|
||||||
|
|
||||||
|
XP_U16 depth = 2;
|
||||||
|
XP_U16 maxCount = dict_numTileFaces( dict );
|
||||||
|
IndexData data;
|
||||||
|
data.count = maxCount * maxCount;
|
||||||
|
data.indices = XP_MALLOC( params->util->mpool,
|
||||||
|
data.count * depth * sizeof(data.indices[0]) );
|
||||||
|
data.prefixes = XP_MALLOC( params->util->mpool,
|
||||||
|
depth * data.count * sizeof(data.prefixes[0]) );
|
||||||
|
|
||||||
|
XP_LOGF( "making index..." );
|
||||||
|
dict_makeIndex( &iter, depth, &data );
|
||||||
|
XP_LOGF( "DONE making index" );
|
||||||
|
|
||||||
|
data.indices = XP_REALLOC( params->util->mpool, data.indices,
|
||||||
|
data.count * depth * sizeof(*data.indices) );
|
||||||
|
data.prefixes = XP_REALLOC( params->util->mpool, data.prefixes,
|
||||||
|
depth * data.count * sizeof(*data.prefixes) );
|
||||||
|
#if 0
|
||||||
|
for ( ii = 0; ii < nIndices; ++ii ) {
|
||||||
|
if ( !dict_getNthWord( dict, &word, indices[ii] ) ) {
|
||||||
|
XP_ASSERT( 0 );
|
||||||
|
}
|
||||||
|
XP_ASSERT( word.index == indices[ii] );
|
||||||
|
XP_UCHAR buf1[64];
|
||||||
|
dict_wordToString( dict, &word, buf1, VSIZE(buf1) );
|
||||||
|
XP_UCHAR buf2[64] = {0};
|
||||||
|
if ( ii > 0 && dict_getNthWord( dict, &word, indices[ii]-1 ) ) {
|
||||||
|
dict_wordToString( dict, &word, buf2, VSIZE(buf2) );
|
||||||
|
}
|
||||||
|
char prfx[8];
|
||||||
|
dict_tilesToString( dict, &prefixes[depth*ii], depth, prfx, VSIZE(prfx) );
|
||||||
|
fprintf( stderr, "%d: index: %ld; prefix: %s; word: %s (prev: %s)\n",
|
||||||
|
ii, indices[ii], prfx, buf1, buf2 );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
XP_LOGF( "testing getNth WITH INDEXING" );
|
||||||
|
testGetNthWord( dict, words, depth, &data );
|
||||||
|
|
||||||
|
if ( !!testPrefixes ) {
|
||||||
|
int ii;
|
||||||
|
guint count = g_slist_length( testPrefixes );
|
||||||
|
for ( ii = 0; ii < count; ++ii ) {
|
||||||
|
gchar* prefix = (gchar*)g_slist_nth_data( testPrefixes, ii );
|
||||||
|
Tile tiles[MAX_COLS];
|
||||||
|
XP_U16 nTiles = VSIZE(tiles);
|
||||||
|
if ( dict_tilesForString( dict, prefix, tiles, &nTiles ) ) {
|
||||||
|
if ( dict_findStartsWith( &iter, NULL, tiles, nTiles ) ) {
|
||||||
|
XP_UCHAR buf[32];
|
||||||
|
XP_UCHAR bufPrev[32] = {0};
|
||||||
|
dict_wordToString( &iter, buf, VSIZE(buf) );
|
||||||
|
|
||||||
|
XP_ASSERT( 0 == strncmp( buf, prefix, strlen(prefix) ) );
|
||||||
|
|
||||||
|
DictPosition pos = dict_getPosition( &iter );
|
||||||
|
XP_ASSERT( 0 == strcmp( buf, words[pos] ) );
|
||||||
|
if ( pos > 0 ) {
|
||||||
|
if ( !dict_getNthWord( &iter, pos-1, depth, &data ) ) {
|
||||||
|
XP_ASSERT( 0 );
|
||||||
|
}
|
||||||
|
dict_wordToString( &iter, bufPrev, VSIZE(bufPrev) );
|
||||||
|
XP_ASSERT( 0 == strcmp( bufPrev, words[pos-1] ) );
|
||||||
|
}
|
||||||
|
XP_LOGF( "dict_getStartsWith(%s) => %s (prev=%s)",
|
||||||
|
prefix, buf, bufPrev );
|
||||||
|
} else {
|
||||||
|
XP_LOGF( "nothing starts with %s", prefix );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
XP_LOGF( "done" );
|
||||||
|
|
||||||
|
XP_FREE( params->util->mpool, data.indices );
|
||||||
|
XP_FREE( params->util->mpool, data.prefixes );
|
||||||
|
} /* walk_dict_test */
|
||||||
|
|
||||||
|
static void
|
||||||
|
walk_dict_test_all( const LaunchParams* params, GSList* testDicts,
|
||||||
|
GSList* testPrefixes )
|
||||||
|
{
|
||||||
|
int ii;
|
||||||
|
guint count = g_slist_length( testDicts );
|
||||||
|
for ( ii = 0; ii < count; ++ii ) {
|
||||||
|
gchar* name = (gchar*)g_slist_nth_data( testDicts, ii );
|
||||||
|
DictionaryCtxt* dict =
|
||||||
|
linux_dictionary_make( MPPARM(params->util->mpool) name,
|
||||||
|
params->useMmap );
|
||||||
|
if ( NULL != dict ) {
|
||||||
|
XP_LOGF( "walk_dict_test(%s)", name );
|
||||||
|
walk_dict_test( params, dict, testPrefixes );
|
||||||
|
dict_destroy( dict );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
int
|
int
|
||||||
main( int argc, char** argv )
|
main( int argc, char** argv )
|
||||||
{
|
{
|
||||||
|
@ -1037,6 +1239,10 @@ main( int argc, char** argv )
|
||||||
XP_U16 nPlayerDicts = 0;
|
XP_U16 nPlayerDicts = 0;
|
||||||
XP_U16 robotCount = 0;
|
XP_U16 robotCount = 0;
|
||||||
XP_U16 ii;
|
XP_U16 ii;
|
||||||
|
#ifdef XWFEATURE_WALKDICT
|
||||||
|
GSList* testDicts = NULL;
|
||||||
|
GSList* testPrefixes = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* install a no-op signal handler. Later curses- or gtk-specific code
|
/* install a no-op signal handler. Later curses- or gtk-specific code
|
||||||
will install one that does the right thing in that context */
|
will install one that does the right thing in that context */
|
||||||
|
@ -1109,6 +1315,7 @@ main( int argc, char** argv )
|
||||||
mainParams.showColors = XP_TRUE;
|
mainParams.showColors = XP_TRUE;
|
||||||
mainParams.allowPeek = XP_TRUE;
|
mainParams.allowPeek = XP_TRUE;
|
||||||
mainParams.showRobotScores = XP_FALSE;
|
mainParams.showRobotScores = XP_FALSE;
|
||||||
|
mainParams.useMmap = XP_TRUE;
|
||||||
|
|
||||||
/* serverName = mainParams.info.clientInfo.serverName = "localhost"; */
|
/* serverName = mainParams.info.clientInfo.serverName = "localhost"; */
|
||||||
|
|
||||||
|
@ -1152,6 +1359,14 @@ main( int argc, char** argv )
|
||||||
mainParams.gi.dictName = copyString( mainParams.util->mpool,
|
mainParams.gi.dictName = copyString( mainParams.util->mpool,
|
||||||
(XP_UCHAR*)optarg );
|
(XP_UCHAR*)optarg );
|
||||||
break;
|
break;
|
||||||
|
#ifdef XWFEATURE_WALKDICT
|
||||||
|
case CMD_TESTDICT:
|
||||||
|
testDicts = g_slist_prepend( testDicts, g_strdup(optarg) );
|
||||||
|
break;
|
||||||
|
case CMD_TESTPRFX:
|
||||||
|
testPrefixes = g_slist_prepend( testPrefixes, g_strdup(optarg) );
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
case CMD_PLAYERDICT:
|
case CMD_PLAYERDICT:
|
||||||
mainParams.gi.players[nPlayerDicts++].dictName = optarg;
|
mainParams.gi.players[nPlayerDicts++].dictName = optarg;
|
||||||
break;
|
break;
|
||||||
|
@ -1164,8 +1379,8 @@ main( int argc, char** argv )
|
||||||
case CMD_GAMEFILE:
|
case CMD_GAMEFILE:
|
||||||
mainParams.fileName = optarg;
|
mainParams.fileName = optarg;
|
||||||
break;
|
break;
|
||||||
case CMD_MMAP:
|
case CMD_NOMMAP:
|
||||||
mainParams.useMmap = true;
|
mainParams.useMmap = false;
|
||||||
break;
|
break;
|
||||||
case CMD_PRINTHISORY:
|
case CMD_PRINTHISORY:
|
||||||
mainParams.printHistory = 1;
|
mainParams.printHistory = 1;
|
||||||
|
@ -1375,8 +1590,9 @@ main( int argc, char** argv )
|
||||||
|
|
||||||
if ( !!mainParams.gi.dictName ) {
|
if ( !!mainParams.gi.dictName ) {
|
||||||
mainParams.dict =
|
mainParams.dict =
|
||||||
linux_dictionary_make(MPPARM(mainParams.util->mpool) mainParams.gi.dictName,
|
linux_dictionary_make( MPPARM(mainParams.util->mpool)
|
||||||
mainParams.useMmap );
|
mainParams.gi.dictName,
|
||||||
|
mainParams.useMmap );
|
||||||
XP_ASSERT( !!mainParams.dict );
|
XP_ASSERT( !!mainParams.dict );
|
||||||
mainParams.gi.dictLang = dict_getLangCode( mainParams.dict );
|
mainParams.gi.dictLang = dict_getLangCode( mainParams.dict );
|
||||||
} else if ( isServer ) {
|
} else if ( isServer ) {
|
||||||
|
@ -1413,7 +1629,12 @@ main( int argc, char** argv )
|
||||||
/* mainParams.needsNewGame = XP_TRUE; */
|
/* mainParams.needsNewGame = XP_TRUE; */
|
||||||
/* } */
|
/* } */
|
||||||
/* } */
|
/* } */
|
||||||
|
#ifdef XWFEATURE_WALKDICT
|
||||||
|
if ( !!testDicts ) {
|
||||||
|
walk_dict_test_all( &mainParams, testDicts, testPrefixes );
|
||||||
|
exit( 0 );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
if ( 0 ) {
|
if ( 0 ) {
|
||||||
#ifdef XWFEATURE_RELAY
|
#ifdef XWFEATURE_RELAY
|
||||||
} else if ( conType == COMMS_CONN_RELAY ) {
|
} else if ( conType == COMMS_CONN_RELAY ) {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; compile-command: "make MEMDEBUG=TRUE"; -*- */
|
/* -*- compile-command: "make MEMDEBUG=TRUE -j3"; -*- */
|
||||||
/*
|
/*
|
||||||
* Copyright 2000-2009 by Eric House (xwords@eehouse.org). All rights
|
* Copyright 2000-2011 by Eric House (xwords@eehouse.org). All rights
|
||||||
* reserved.
|
* reserved.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
|
@ -150,6 +150,8 @@ linux_util_getSquareBonus( XW_UtilCtxt* uc, const ModelCtxt* model,
|
||||||
XP_U16 col, XP_U16 row )
|
XP_U16 col, XP_U16 row )
|
||||||
{
|
{
|
||||||
static XWBonusType* parsedFile = NULL;
|
static XWBonusType* parsedFile = NULL;
|
||||||
|
XWBonusType result = EM;
|
||||||
|
|
||||||
CommonGlobals* cGlobals = (CommonGlobals*)uc->closure;
|
CommonGlobals* cGlobals = (CommonGlobals*)uc->closure;
|
||||||
XP_U16 nCols = model_numCols( model );
|
XP_U16 nCols = model_numCols( model );
|
||||||
if ( NULL == parsedFile && NULL != cGlobals->params->bonusFile ) {
|
if ( NULL == parsedFile && NULL != cGlobals->params->bonusFile ) {
|
||||||
|
@ -158,34 +160,42 @@ linux_util_getSquareBonus( XW_UtilCtxt* uc, const ModelCtxt* model,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( NULL != parsedFile ) {
|
if ( NULL != parsedFile ) {
|
||||||
return parsedFile[(row*nCols) + col];
|
result = parsedFile[(row*nCols) + col];
|
||||||
} else {
|
} else {
|
||||||
XP_U16 index;
|
XP_U16 index, ii;
|
||||||
/* This must be static or won't compile under multilink (for Palm).
|
/* This must be static or won't compile under multilink (for Palm).
|
||||||
Fix! */
|
Fix! */
|
||||||
static char scrabbleBoard[8*8] = {
|
static char scrabbleBoard[8*8] = {
|
||||||
TW,EM,EM,DL,EM,EM,EM,TW,
|
TW,//EM,EM,DL,EM,EM,EM,TW,
|
||||||
EM,DW,EM,EM,EM,TL,EM,EM,
|
EM,DW,//EM,EM,EM,TL,EM,EM,
|
||||||
|
|
||||||
EM,EM,DW,EM,EM,EM,DL,EM,
|
EM,EM,DW,//EM,EM,EM,DL,EM,
|
||||||
DL,EM,EM,DW,EM,EM,EM,DL,
|
DL,EM,EM,DW,//EM,EM,EM,DL,
|
||||||
|
|
||||||
EM,EM,EM,EM,DW,EM,EM,EM,
|
EM,EM,EM,EM,DW,//EM,EM,EM,
|
||||||
EM,TL,EM,EM,EM,TL,EM,EM,
|
EM,TL,EM,EM,EM,TL,//EM,EM,
|
||||||
|
|
||||||
EM,EM,DL,EM,EM,EM,DL,EM,
|
EM,EM,DL,EM,EM,EM,DL,//EM,
|
||||||
TW,EM,EM,DL,EM,EM,EM,DW,
|
TW,EM,EM,DL,EM,EM,EM,DW,
|
||||||
}; /* scrabbleBoard */
|
}; /* scrabbleBoard */
|
||||||
|
|
||||||
if ( col > 7 ) col = 14 - col;
|
if ( col > 7 ) col = 14 - col;
|
||||||
if ( row > 7 ) row = 14 - row;
|
if ( row > 7 ) row = 14 - row;
|
||||||
index = (row*8) + col;
|
if ( col > row ) {
|
||||||
if ( index >= 8*8 ) {
|
XP_U16 tmp = col;
|
||||||
return (XWBonusType)EM;
|
col = row;
|
||||||
} else {
|
row = tmp;
|
||||||
return (XWBonusType)scrabbleBoard[index];
|
}
|
||||||
|
index = col;
|
||||||
|
for ( ii = 1; ii <= row; ++ii ) {
|
||||||
|
index += ii;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( index < VSIZE(scrabbleBoard) ) {
|
||||||
|
result = (XWBonusType)scrabbleBoard[index];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return result;
|
||||||
} /* linux_util_getSquareBonus */
|
} /* linux_util_getSquareBonus */
|
||||||
|
|
||||||
static XP_U32
|
static XP_U32
|
||||||
|
@ -407,6 +417,27 @@ linux_getErrString( UtilErrID id, XP_Bool* silent )
|
||||||
return (XP_UCHAR*)message;
|
return (XP_UCHAR*)message;
|
||||||
} /* linux_getErrString */
|
} /* linux_getErrString */
|
||||||
|
|
||||||
|
void
|
||||||
|
formatConfirmTrade( const XP_UCHAR** tiles, XP_U16 nTiles,
|
||||||
|
char* buf, XP_U16 buflen )
|
||||||
|
{
|
||||||
|
char tileBuf[128];
|
||||||
|
int offset = 0;
|
||||||
|
int ii;
|
||||||
|
|
||||||
|
XP_ASSERT( nTiles > 0 );
|
||||||
|
for ( ii = 0; ii < nTiles; ++ii ) {
|
||||||
|
offset += snprintf( &tileBuf[offset], sizeof(tileBuf) - offset,
|
||||||
|
"%s, ", tiles[ii] );
|
||||||
|
XP_ASSERT( offset < sizeof(tileBuf) );
|
||||||
|
}
|
||||||
|
tileBuf[offset-2] = '\0';
|
||||||
|
|
||||||
|
snprintf( buf, buflen,
|
||||||
|
"Are you sure you want to trade the selected tiles (%s)?",
|
||||||
|
tileBuf );
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef TEXT_MODEL
|
#ifdef TEXT_MODEL
|
||||||
/* This is broken for UTF-8, even Spanish */
|
/* This is broken for UTF-8, even Spanish */
|
||||||
void
|
void
|
||||||
|
|
|
@ -38,4 +38,7 @@ void linux_util_vt_destroy( XW_UtilCtxt* util );
|
||||||
|
|
||||||
const XP_UCHAR* linux_getErrString( UtilErrID id, XP_Bool* silent );
|
const XP_UCHAR* linux_getErrString( UtilErrID id, XP_Bool* silent );
|
||||||
|
|
||||||
|
void formatConfirmTrade( const XP_UCHAR** tiles, XP_U16 nTiles, char* buf,
|
||||||
|
XP_U16 buflen );
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -139,7 +139,7 @@ build_cmds() {
|
||||||
CMD="./obj_linux_memdbg/xwords --room $ROOM"
|
CMD="./obj_linux_memdbg/xwords --room $ROOM"
|
||||||
CMD="$CMD --robot ${NAMES[$DEV]} --robot-iq $((1 + (RANDOM%100))) "
|
CMD="$CMD --robot ${NAMES[$DEV]} --robot-iq $((1 + (RANDOM%100))) "
|
||||||
CMD="$CMD $OTHERS --game-dict $DICT --port $PORT --host $HOST "
|
CMD="$CMD $OTHERS --game-dict $DICT --port $PORT --host $HOST "
|
||||||
CMD="$CMD --file $FILE --slow-robot 1:3 --skip-confirm --use-mmap"
|
CMD="$CMD --file $FILE --slow-robot 1:3 --skip-confirm"
|
||||||
CMD="$CMD --drop-nth-packet $DROP_N $PLAT_PARMS"
|
CMD="$CMD --drop-nth-packet $DROP_N $PLAT_PARMS"
|
||||||
|
|
||||||
CMD="$CMD $PUBLIC"
|
CMD="$CMD $PUBLIC"
|
||||||
|
@ -279,14 +279,14 @@ check_game() {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -n "$OTHERS" ]; then
|
if [ -n "$OTHERS" ]; then
|
||||||
echo -n "Closing $CONNNAME: "
|
echo -n "Closing $CONNNAME [$(date)]: "
|
||||||
# kill_from_logs $OTHERS $KEY
|
# kill_from_logs $OTHERS $KEY
|
||||||
for ID in $OTHERS $KEY; do
|
for ID in $OTHERS $KEY; do
|
||||||
echo -n "${LOGS[$ID]}, "
|
echo -n "${LOGS[$ID]}, "
|
||||||
kill_from_log ${LOGS[$ID]} || true
|
kill_from_log ${LOGS[$ID]} || true
|
||||||
close_device $ID $DONEDIR "game over"
|
close_device $ID $DONEDIR "game over"
|
||||||
done
|
done
|
||||||
date
|
echo ""
|
||||||
# XWRELAY_ERROR_DELETED may be old
|
# XWRELAY_ERROR_DELETED may be old
|
||||||
elif grep -q 'relay_error_curses(XWRELAY_ERROR_DELETED)' $LOG; then
|
elif grep -q 'relay_error_curses(XWRELAY_ERROR_DELETED)' $LOG; then
|
||||||
echo "deleting $LOG $(connName $LOG) b/c another resigned"
|
echo "deleting $LOG $(connName $LOG) b/c another resigned"
|
||||||
|
|
25
xwords4/linux/scripts/game_with_seed.sh
Executable file
25
xwords4/linux/scripts/game_with_seed.sh
Executable file
|
@ -0,0 +1,25 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -u -e
|
||||||
|
|
||||||
|
|
||||||
|
PARAMS="--curses --robot Kati --remote-player --game-dict dict.xwd --quit-after 1 --sort-tiles"
|
||||||
|
|
||||||
|
|
||||||
|
run() {
|
||||||
|
SEED=$1
|
||||||
|
LOG=LOG__${SEED}.txt
|
||||||
|
ROOM=ROOM_${SEED}
|
||||||
|
> $LOG
|
||||||
|
./obj_linux_memdbg/xwords $PARAMS --room $ROOM \
|
||||||
|
--seed $SEED >/dev/null 2>>$LOG &
|
||||||
|
sleep 1
|
||||||
|
./obj_linux_memdbg/xwords $PARAMS --room $ROOM \
|
||||||
|
--seed $((SEED+1000)) >/dev/null 2>>$LOG &
|
||||||
|
}
|
||||||
|
|
||||||
|
for SEED in $(seq 1 1000); do
|
||||||
|
echo "trying seed $SEED"
|
||||||
|
run $SEED
|
||||||
|
wait
|
||||||
|
done
|
Loading…
Add table
Reference in a new issue