add code to iterate over words in a dict. Works on Linux (iterating

forward only) but disabled at compile time.  Idea's to have a dict
browser.  There was some simple refactoring in common code Android
uses, and that tests fine.
This commit is contained in:
Andy2 2011-10-21 18:51:33 -07:00
parent 201c32e4db
commit 7c7cd82e0a
7 changed files with 234 additions and 68 deletions

View file

@ -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

View file

@ -597,12 +597,51 @@ 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 */
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_getShortName = dict_getName; dict->func_dict_getShortName = dict_getName;
} /* dict_super_init */ } /* dict_super_init */
@ -612,6 +651,126 @@ dict_getLangName( const DictionaryCtxt* ctxt )
return ctxt->langName; return ctxt->langName;
} }
#ifdef XWFEATURE_WALKDICT
static void
edgesToIndices( const DictionaryCtxt* dict, XP_U16 nEdges,
array_edge** edges, DictWord* word )
{
XP_U16 ii;
word->nTiles = nEdges;
for ( ii = 0; ii < nEdges; ++ii ) {
word->indices[ii] = edges[ii] - dict->base;
}
}
static void
indicesToEdges( const DictionaryCtxt* dict,
DictWord* word, array_edge** edges )
{
XP_U16 nEdges = word->nTiles;
XP_U16 ii;
for ( ii = 0; ii < nEdges; ++ii ) {
edges[ii] = &dict->base[word->indices[ii]];
}
}
/* 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( const DictionaryCtxt* dict, array_edge** edges, XP_U16* nTilesP )
{
XP_U16 nTiles = *nTilesP;
XP_Bool success = XP_FALSE;
while ( 0 < nTiles && ! success ) {
array_edge* next = dict_follow( dict, edges[nTiles-1] );
if ( !!next ) {
edges[nTiles++] = next;
success = ISACCEPTING( dict, next );
continue; /* try with longer word */
}
while ( IS_LAST_EDGE( dict, edges[nTiles-1] ) && 0 < --nTiles ) {
}
if ( 0 < nTiles ) {
edges[nTiles-1] += dict->nodeSize;
success = ISACCEPTING( dict, edges[nTiles-1] );
}
}
*nTilesP = nTiles;
return success;
}
XP_Bool
dict_firstWord( const DictionaryCtxt* dict, DictWord* word )
{
array_edge* edges[MAX_COLS];
XP_U16 nEdges = 0;
edges[nEdges++] = dict_getTopEdge( dict );
XP_Bool success = ISACCEPTING( dict, edges[0] ) /* */
|| nextWord( dict, edges, &nEdges );
if ( success ) {
edgesToIndices( dict, nEdges, edges, word );
}
return success;
}
XP_Bool
dict_getNextWord( const DictionaryCtxt* dict, DictWord* word )
{
XP_U16 nTiles = word->nTiles;
array_edge* edges[MAX_COLS];
indicesToEdges( dict, word, edges );
XP_Bool success = nextWord( dict, edges, &nTiles );
if ( success ) {
edgesToIndices( dict, nTiles, edges, word );
}
return success;
}
XP_Bool
dict_lastWord( const DictionaryCtxt* dict, DictWord* word )
{
XP_ASSERT( 0 );
XP_USE( dict );
word->nTiles = 0;
return XP_FALSE;
}
XP_Bool
dict_getPrevWord( const DictionaryCtxt* dict, DictWord* word )
{
XP_USE( dict );
XP_ASSERT( 0 );
return word->nTiles > 0;
}
void
dict_wordToString( const DictionaryCtxt* dict, DictWord* word,
XP_UCHAR* buf, XP_U16 buflen )
{
XP_U16 ii;
array_edge* edges[MAX_COLS];
Tile tiles[MAX_COLS];
indicesToEdges( dict, word, edges );
for ( ii = 0; ii < word->nTiles; ++ii ) {
tiles[ii] = EDGETILE( dict, edges[ii] );
}
(void)dict_tilesToString( dict, tiles, word->nTiles, buf, buflen );
}
#endif /* XWFEATURE_WALKDICT */
#ifdef CPLUS #ifdef CPLUS
} }
#endif #endif

View file

@ -66,8 +66,13 @@ 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 );
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 +133,26 @@ 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_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 );
@ -180,6 +203,24 @@ 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 );
#ifdef XWFEATURE_WALKDICT
/* API for iterating over a dict */
typedef struct _DictWord {
XP_U32 index;
XP_U16 nTiles;
XP_U32 indices[MAX_COLS];
} DictWord;
XP_Bool dict_firstWord( const DictionaryCtxt* dict, DictWord* word );
XP_Bool dict_lastWord( const DictionaryCtxt* dict, DictWord* word );
XP_Bool dict_getNextWord( const DictionaryCtxt* dict, DictWord* word );
XP_Bool dict_getPrevWord( const DictionaryCtxt* dict, DictWord* word );
void dict_wordToString( const DictionaryCtxt* dict, DictWord* word,
XP_UCHAR* buf, XP_U16 buflen );
#endif
#ifdef CPLUS #ifdef CPLUS
} }
#endif #endif

View file

@ -130,7 +130,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 +165,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) )
@ -615,7 +597,7 @@ lookup( const DictionaryCtxt* dict, array_edge* edge, Tile* buf,
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 +897,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 );
} }
@ -1002,7 +984,7 @@ extendRight( EngineCtxt* engine, Tile* tiles, XP_U16 tileLength,
} else if ( (edge = edge_with_tile( dict, edge, tile ) ) != NULL ) { } else if ( (edge = 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 {
@ -1376,49 +1358,12 @@ edge_with_tile( const DictionaryCtxt* dict, array_edge* from, Tile tile )
return from; return from;
} /* edge_with_tile */ } /* 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 = 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 */

View file

@ -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

View file

@ -91,6 +91,7 @@ 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
ifdef CURSES_CELL_HT ifdef CURSES_CELL_HT
DEFINES += -DCURSES_CELL_HT=$(CURSES_CELL_HT) DEFINES += -DCURSES_CELL_HT=$(CURSES_CELL_HT)

View file

@ -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
@ -1281,6 +1281,23 @@ main( int argc, char** argv )
/* } */ /* } */
/* } */ /* } */
#ifdef XWFEATURE_WALKDICT
/* 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. */
DictWord word;
int jj;
XP_Bool gotOne;
for ( jj = 0, gotOne = dict_firstWord( mainParams.dict, &word );
gotOne;
++jj, gotOne = dict_getNextWord( mainParams.dict, &word ) ) {
XP_UCHAR buf[64];
dict_wordToString( mainParams.dict, &word, buf, VSIZE(buf) );
fprintf( stderr, "%.6d: %s\n", jj, buf );
}
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 ) {