mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2024-12-27 09:58:45 +01:00
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:
parent
201c32e4db
commit
7c7cd82e0a
7 changed files with 234 additions and 68 deletions
|
@ -115,6 +115,13 @@ typedef enum {
|
|||
} XWTimerReason;
|
||||
|
||||
#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 NDEVICES_NBITS 2 /* 1-4, but reduced by 1 fits in 2 bits */
|
||||
#define NPLAYERS_NBITS 3
|
||||
|
|
|
@ -597,12 +597,51 @@ dict_super_getTopEdge( const DictionaryCtxt* dict )
|
|||
return dict->topEdge;
|
||||
} /* 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
|
||||
dict_super_init( DictionaryCtxt* dict )
|
||||
{
|
||||
/* subclass may change these later.... */
|
||||
dict->func_edge_for_index = dict_super_edge_for_index;
|
||||
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_super_init */
|
||||
|
||||
|
@ -612,6 +651,126 @@ dict_getLangName( const DictionaryCtxt* ctxt )
|
|||
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
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -66,8 +66,13 @@ typedef struct _XP_Bitmaps {
|
|||
struct DictionaryCtxt {
|
||||
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 );
|
||||
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 );
|
||||
|
||||
array_edge* topEdge;
|
||||
|
@ -128,8 +133,26 @@ struct DictionaryCtxt {
|
|||
#define dict_destroy(d) (*((d)->destructor))(d)
|
||||
#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_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)
|
||||
|
||||
#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,
|
||||
const DictionaryCtxt* dict2 );
|
||||
|
@ -180,6 +203,24 @@ void dict_super_init( DictionaryCtxt* ctxt );
|
|||
void dict_splitFaces( DictionaryCtxt* dict, const XP_U8* bytes,
|
||||
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
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -130,7 +130,6 @@ static void figureCrosschecks( EngineCtxt* engine, XP_U16 col,
|
|||
XP_U16 row, XP_U16* scoreP,
|
||||
Crosscheck* check );
|
||||
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,
|
||||
array_edge* from, Tile tile );
|
||||
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!!!
|
||||
#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) checkIsSet( (chk), (tile) )
|
||||
|
||||
|
@ -615,7 +597,7 @@ lookup( const DictionaryCtxt* dict, array_edge* edge, Tile* buf,
|
|||
if ( ++tileIndex == length ) { /* is this the last tile? */
|
||||
return ISACCEPTING(dict, edge);
|
||||
} else {
|
||||
edge = follow( dict, edge );
|
||||
edge = dict_follow( dict, edge );
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -915,7 +897,7 @@ leftPart( EngineCtxt* engine, Tile* tiles, XP_U16 tileLength,
|
|||
if ( rack_remove( engine, tile, &isBlank ) ) {
|
||||
tiles[tileLength] = tile;
|
||||
leftPart( engine, tiles, tileLength+1,
|
||||
follow( engine->dict, edge ),
|
||||
dict_follow( engine->dict, edge ),
|
||||
limit-1, firstCol-1, anchorCol, row );
|
||||
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 ) {
|
||||
accepting = ISACCEPTING( dict, edge );
|
||||
extendRight( engine, tiles, tileLength, follow(dict, edge),
|
||||
extendRight( engine, tiles, tileLength, dict_follow(dict, edge),
|
||||
accepting, firstCol, col+1, row );
|
||||
goto no_check; /* don't do the check at the end */
|
||||
} else {
|
||||
|
@ -1376,49 +1358,12 @@ edge_with_tile( const DictionaryCtxt* dict, array_edge* from, Tile tile )
|
|||
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*
|
||||
edge_from_tile( const DictionaryCtxt* dict, array_edge* from, Tile tile )
|
||||
{
|
||||
array_edge* edge = edge_with_tile( dict, from, tile );
|
||||
if ( edge != NULL ) {
|
||||
edge = follow( dict, edge );
|
||||
edge = dict_follow( dict, edge );
|
||||
}
|
||||
return edge;
|
||||
} /* edge_from_tile */
|
||||
|
|
|
@ -29,16 +29,12 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define MAX_ROWS 16
|
||||
#define MAX_COLS 16
|
||||
#define NUMCOLS_NBITS 4
|
||||
|
||||
#ifdef EIGHT_TILES
|
||||
#define MAX_TRAY_TILES 8
|
||||
#define NTILES_NBITS 4
|
||||
# define NTILES_NBITS 4
|
||||
#else
|
||||
#define MAX_TRAY_TILES 7
|
||||
#define NTILES_NBITS 3
|
||||
# define NTILES_NBITS 3
|
||||
#endif
|
||||
|
||||
/* Try making this 0, as some local rules, e.g. Spanish, allow. Will need to
|
||||
|
|
|
@ -91,6 +91,7 @@ DEFINES += -DXWFEATURE_CHAT
|
|||
DEFINES += -DDISABLE_TILE_SEL
|
||||
DEFINES += -DSET_GAMESEED
|
||||
DEFINES += -DTEXT_MODEL
|
||||
# DEFINES += -DXWFEATURE_WALKDICT
|
||||
|
||||
ifdef CURSES_CELL_HT
|
||||
DEFINES += -DCURSES_CELL_HT=$(CURSES_CELL_HT)
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
* 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 ) {
|
||||
#ifdef XWFEATURE_RELAY
|
||||
} else if ( conType == COMMS_CONN_RELAY ) {
|
||||
|
|
Loading…
Reference in a new issue