From f2c4e39cd460acb4237e42433f9eaa0ae4dcdc0b Mon Sep 17 00:00:00 2001 From: Eric House Date: Wed, 26 Oct 2011 07:10:50 -0700 Subject: [PATCH 1/3] add dict_makeIndex(). Works, but only for depth==1 so far (A, not AA or AAA). --- xwords4/common/dictnry.c | 124 ++++++++++++++++++++++++++++++++++++++ xwords4/common/dictnry.h | 11 +++- xwords4/common/engine.c | 32 +--------- xwords4/linux/linuxmain.c | 20 +++++- 4 files changed, 155 insertions(+), 32 deletions(-) diff --git a/xwords4/common/dictnry.c b/xwords4/common/dictnry.c index ccb0e6061..b699babba 100644 --- a/xwords4/common/dictnry.c +++ b/xwords4/common/dictnry.c @@ -639,6 +639,30 @@ dict_super_follow( const DictionaryCtxt* dict, array_edge* in ) 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 dict_super_init( DictionaryCtxt* dict ) { @@ -647,6 +671,7 @@ dict_super_init( DictionaryCtxt* dict ) 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_super_init */ @@ -786,6 +811,40 @@ dict_getWord( const DictionaryCtxt* dict, DictWord* word, WordFinder finder ) return success; } +static XP_Bool +findStartsWith( const DictionaryCtxt* dict, Tile* tiles, XP_U16 nTiles, + array_edge** edges, XP_U16* nEdgesP ) +{ + XP_Bool success = XP_TRUE; + XP_U16 nEdges = 0; + array_edge* edge = dict_getTopEdge( dict ); + + while ( nTiles-- > 0 ) { + Tile tile = *tiles++; + edge = dict_edge_with_tile( dict, edge, tile ); + if ( NULL == edge ) { + success = XP_FALSE; + break; + } + edges[nEdges++] = edge; + edge = dict_follow( dict, edge ); + } + *nEdgesP = nEdges; + return success; +} + +static XP_Bool +wordsEqual( array_edge** edges1, XP_U16 nEdges1, + array_edge** edges2, XP_U16 nEdges2 ) +{ + XP_Bool success = nEdges1 == nEdges2; + if ( success ) { + success = 0 == memcmp( edges1, edges2, nEdges1 * sizeof(edges1[0]) ); + } + return success; +} + + XP_U32 dict_countWords( const DictionaryCtxt* dict ) { @@ -802,6 +861,71 @@ dict_countWords( const DictionaryCtxt* dict ) return count; } +void +dict_makeIndex( const DictionaryCtxt* dict, XP_U16 depth, + DictIndex* indices, XP_U16 count ) +{ + XP_USE( indices ); + XP_ASSERT( depth == 1 ); /* so far */ + XP_U16 ii, needCount; + XP_U16 nextIndex = 0; + XP_U16 nFaces = dict_numTileFaces( dict ); + XP_Bool hasBlank = dict_hasBlankTile( dict ); + if ( hasBlank ) { + --nFaces; + } + for ( ii = 1, needCount = nFaces; ii < depth; ++ii ) { + needCount *= nFaces; + } + XP_ASSERT( needCount <= count ); + + /* 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. + */ + DictWord firstWord; + if ( dict_firstWord( dict, &firstWord ) ) { + array_edge* prevEdges[MAX_COLS]; + indicesToEdges( dict, &firstWord, prevEdges ); + XP_U16 prevNEdges = firstWord.nTiles; + DictIndex index = 0; + + Tile tiles[1]; + nFaces = dict_numTileFaces( dict ); + for ( tiles[0] = 0; tiles[0] < nFaces; ++tiles[0] ) { + if ( hasBlank && tiles[0] == dict_getBlankTile( dict ) ) { + continue; + } + + array_edge* curEdges[MAX_COLS]; + XP_U16 curNEdges; + if ( !findStartsWith( dict, tiles, 1, curEdges, &curNEdges ) ) { + indices[nextIndex++] = NO_INDEX; + } else { + XP_ASSERT( curNEdges == depth ); + if ( ! ISACCEPTING( dict, curEdges[curNEdges-1] ) ) { + if ( !nextWord( dict, curEdges, &curNEdges ) ) { + XP_ASSERT( 0 ); + } + } + if ( wordsEqual( curEdges, curNEdges, prevEdges, prevNEdges ) ) { + XP_ASSERT( index == 0 ); + } else { + /* Walk the prev word forward until they're the same */ + while ( nextWord( dict, prevEdges, &prevNEdges ) ) { + ++index; + if ( wordsEqual( curEdges, curNEdges, prevEdges, prevNEdges ) ) { + break; + } + } + } + indices[nextIndex++] = index; + } + } + } + +} + XP_Bool dict_firstWord( const DictionaryCtxt* dict, DictWord* word ) { diff --git a/xwords4/common/dictnry.h b/xwords4/common/dictnry.h index 437fa4a12..4f1de065f 100644 --- a/xwords4/common/dictnry.h +++ b/xwords4/common/dictnry.h @@ -73,6 +73,8 @@ struct DictionaryCtxt { 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 ); array_edge* topEdge; @@ -135,6 +137,7 @@ struct DictionaryCtxt { #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) #ifdef NODE_CAN_4 @@ -206,14 +209,18 @@ void dict_splitFaces( DictionaryCtxt* dict, const XP_U8* bytes, #ifdef XWFEATURE_WALKDICT /* API for iterating over a dict */ +typedef XP_U32 DictIndex; +#define NO_INDEX 0xFFFFFFFF typedef struct _DictWord { XP_U32 wordCount; - XP_U32 index; + DictIndex index; XP_U16 nTiles; XP_U32 indices[MAX_COLS]; } DictWord; XP_U32 dict_countWords( const DictionaryCtxt* dict ); +void dict_makeIndex( const DictionaryCtxt* dict, XP_U16 depth, + DictIndex* indices, XP_U16 count ); 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 ); @@ -223,7 +230,7 @@ XP_Bool dict_getNthWord( const DictionaryCtxt* dict, DictWord* word, void dict_wordToString( const DictionaryCtxt* dict, const DictWord* word, XP_UCHAR* buf, XP_U16 buflen ); -#endif +#endif /* XWFEATURE_WALKDICT */ #ifdef CPLUS } diff --git a/xwords4/common/engine.c b/xwords4/common/engine.c index 97ac9ff54..ad462b4d2 100644 --- a/xwords4/common/engine.c +++ b/xwords4/common/engine.c @@ -121,8 +121,6 @@ struct EngineCtxt { static void findMovesOneRow( EngineCtxt* engine ); static Tile localGetBoardTile( EngineCtxt* engine, XP_U16 col, 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 void findMovesForAnchor( EngineCtxt* engine, XP_S16* prevAnchor, XP_U16 col, XP_U16 row ) ; @@ -590,7 +588,7 @@ lookup( const DictionaryCtxt* dict, array_edge* edge, Tile* buf, { while ( edge != NULL ) { 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 */ return XP_FALSE; } else { @@ -982,7 +980,7 @@ 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 ); extendRight( engine, tiles, tileLength, dict_follow(dict, edge), accepting, firstCol, col+1, row ); @@ -1334,34 +1332,10 @@ scoreQualifies( EngineCtxt* engine, XP_U16 score ) return qualifies; } /* 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 array_edge* 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 ) { edge = dict_follow( dict, edge ); } diff --git a/xwords4/linux/linuxmain.c b/xwords4/linux/linuxmain.c index cb7893c9a..f18f4e95c 100644 --- a/xwords4/linux/linuxmain.c +++ b/xwords4/linux/linuxmain.c @@ -955,7 +955,7 @@ walk_dict_test( const DictionaryCtxt* dict ) fprintf( stderr, "testing getNth\n" ); int ii; - for ( ii = 0 ; ii < 1000; ++ii ) { + for ( ii = 0 ; ii < 100; ++ii ) { long index = XP_RANDOM() % count; if ( dict_getNthWord( dict, &word, index ) ) { XP_ASSERT( word.index == index ); @@ -967,6 +967,24 @@ walk_dict_test( const DictionaryCtxt* dict ) } } + DictIndex indices[26]; + dict_makeIndex( dict, 1, indices, VSIZE(indices) ); + for ( ii = 0; ii < VSIZE(indices); ++ii ) { + DictIndex index = indices[ii]; + if ( NO_INDEX == index ) { + continue; + } else if ( dict_getNthWord( dict, &word, indices[ii] ) ) { + 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) ); + } + fprintf( stderr, "%d: index: %ld; word: %s (prev: %s)\n", ii, indices[ii], buf1, buf2 ); + } + } + exit( 0 ); } #else From 412a58f6b9d741a0f87e87a8734397bdd5f6c81b Mon Sep 17 00:00:00 2001 From: Eric House Date: Wed, 26 Oct 2011 22:20:21 -0700 Subject: [PATCH 2/3] make dict_makeIndex work for depth > 1. --- xwords4/common/dictnry.c | 272 +++++++++++++++++++++----------------- xwords4/common/dictnry.h | 5 +- xwords4/linux/linuxmain.c | 76 +++++++++-- 3 files changed, 219 insertions(+), 134 deletions(-) diff --git a/xwords4/common/dictnry.c b/xwords4/common/dictnry.c index b699babba..3e930e9d5 100644 --- a/xwords4/common/dictnry.c +++ b/xwords4/common/dictnry.c @@ -682,27 +682,33 @@ dict_getLangName( const DictionaryCtxt* ctxt ) } #ifdef XWFEATURE_WALKDICT +typedef struct _EdgeArray { + array_edge* edges[MAX_COLS]; + XP_U16 nEdges; +} EdgeArray; + static void -edgesToIndices( const DictionaryCtxt* dict, XP_U16 nEdges, - array_edge** edges, DictWord* word ) +edgesToIndices( const DictionaryCtxt* dict, const EdgeArray* edges, + DictWord* word ) { XP_U16 ii; - word->nTiles = nEdges; - for ( ii = 0; ii < nEdges; ++ii ) { - word->indices[ii] = edges[ii] - dict->base; + word->nTiles = edges->nEdges; + for ( ii = 0; ii < edges->nEdges; ++ii ) { + word->indices[ii] = edges->edges[ii] - dict->base; } } static void indicesToEdges( const DictionaryCtxt* dict, - const DictWord* word, array_edge** edges ) + const DictWord* word, EdgeArray* edges ) { XP_U16 nEdges = word->nTiles; XP_U16 ii; for ( ii = 0; ii < nEdges; ++ii ) { - edges[ii] = &dict->base[word->indices[ii]]; + edges->edges[ii] = &dict->base[word->indices[ii]]; } + edges->nEdges = nEdges; } /* On entry and exit, edge at end of array should be ACCEPTING. The job of @@ -713,28 +719,28 @@ indicesToEdges( const DictionaryCtxt* dict, * LAST_EDGE, try with its next-letter neighbor. */ static XP_Bool -nextWord( const DictionaryCtxt* dict, array_edge** edges, XP_U16* nTilesP ) +nextWord( const DictionaryCtxt* dict, EdgeArray* edges ) { - XP_U16 nTiles = *nTilesP; + XP_U16 nTiles = edges->nEdges; XP_Bool success = XP_FALSE; while ( 0 < nTiles && ! success ) { - array_edge* next = dict_follow( dict, edges[nTiles-1] ); + array_edge* next = dict_follow( dict, edges->edges[nTiles-1] ); if ( !!next ) { - edges[nTiles++] = next; + edges->edges[nTiles++] = next; success = ISACCEPTING( dict, next ); continue; /* try with longer word */ } - while ( IS_LAST_EDGE( dict, edges[nTiles-1] ) && 0 < --nTiles ) { + while ( IS_LAST_EDGE( dict, edges->edges[nTiles-1] ) && 0 < --nTiles ) { } if ( 0 < nTiles ) { - edges[nTiles-1] += dict->nodeSize; - success = ISACCEPTING( dict, edges[nTiles-1] ); + edges->edges[nTiles-1] += dict->nodeSize; + success = ISACCEPTING( dict, edges->edges[nTiles-1] ); } } - *nTilesP = nTiles; + edges->nEdges = nTiles; return success; } @@ -749,74 +755,66 @@ isFirstEdge( const DictionaryCtxt* dict, array_edge* edge ) } static XP_Bool -lastEdges( const DictionaryCtxt* dict, array_edge** edges, XP_U16* nEdgesP ) +lastEdges( const DictionaryCtxt* dict, EdgeArray* edges ) { - XP_U16 nEdges = *nEdgesP; - array_edge* edge = edges[nEdges-1]; + array_edge* edge = edges->edges[edges->nEdges-1]; for ( ; ; ) { while ( !IS_LAST_EDGE( dict, edge ) ) { edge += dict->nodeSize; } - edges[nEdges-1] = edge; + edges->edges[edges->nEdges-1] = edge; edge = dict_follow( dict, edge ); if ( NULL == edge ) { break; } - ++nEdges; + ++edges->nEdges; } - *nEdgesP = nEdges; - return ISACCEPTING( dict, edges[nEdges-1] ); + return ISACCEPTING( dict, edges->edges[edges->nEdges-1] ); } static XP_Bool -prevWord( const DictionaryCtxt* dict, array_edge** edges, XP_U16* nEdgesP ) +prevWord( const DictionaryCtxt* dict, EdgeArray* edges ) { - XP_U16 nEdges = *nEdgesP; XP_Bool success = XP_FALSE; - while ( 0 < nEdges && ! success ) { - if ( isFirstEdge( dict, edges[nEdges-1] ) ) { - --nEdges; - success = 0 < nEdges && ISACCEPTING( dict, edges[nEdges-1] ); + while ( 0 < edges->nEdges && ! success ) { + if ( isFirstEdge( dict, edges->edges[edges->nEdges-1] ) ) { + --edges->nEdges; + success = 0 < edges->nEdges && ISACCEPTING( dict, edges->edges[edges->nEdges-1] ); continue; } - edges[nEdges-1] -= dict->nodeSize; - array_edge* next = dict_follow( dict, edges[nEdges-1] ); + edges->edges[edges->nEdges-1] -= dict->nodeSize; + array_edge* next = dict_follow( dict, edges->edges[edges->nEdges-1] ); if ( NULL != next ) { - edges[nEdges++] = next; - success = lastEdges( dict, edges, &nEdges ); + edges->edges[edges->nEdges++] = next; + success = lastEdges( dict, edges ); if ( success ) { continue; } } - success = ISACCEPTING( dict, edges[nEdges-1] ); + success = ISACCEPTING( dict, edges->edges[edges->nEdges-1] ); } - *nEdgesP = nEdges; return success; } -typedef XP_Bool (*WordFinder)(const DictionaryCtxt* dict, array_edge** edges, - XP_U16* nTilesP ); +typedef XP_Bool (*WordFinder)(const DictionaryCtxt* dict, EdgeArray* edges ); static XP_Bool dict_getWord( const DictionaryCtxt* dict, DictWord* word, WordFinder finder ) { - XP_U16 nTiles = word->nTiles; - array_edge* edges[MAX_COLS]; - indicesToEdges( dict, word, edges ); - XP_Bool success = (*finder)( dict, edges, &nTiles ); + EdgeArray edges; + indicesToEdges( dict, word, &edges ); + XP_Bool success = (*finder)( dict, &edges ); if ( success ) { - edgesToIndices( dict, nTiles, edges, word ); + edgesToIndices( dict, &edges, word ); } return success; } static XP_Bool -findStartsWith( const DictionaryCtxt* dict, Tile* tiles, XP_U16 nTiles, - array_edge** edges, XP_U16* nEdgesP ) +findStartsWith( const DictionaryCtxt* dict, Tile* tiles, XP_U16 nTiles, EdgeArray* edges ) { XP_Bool success = XP_TRUE; - XP_U16 nEdges = 0; array_edge* edge = dict_getTopEdge( dict ); while ( nTiles-- > 0 ) { @@ -826,49 +824,102 @@ findStartsWith( const DictionaryCtxt* dict, Tile* tiles, XP_U16 nTiles, success = XP_FALSE; break; } - edges[nEdges++] = edge; + edges->edges[edges->nEdges++] = edge; edge = dict_follow( dict, edge ); } - *nEdgesP = nEdges; return success; } static XP_Bool -wordsEqual( array_edge** edges1, XP_U16 nEdges1, - array_edge** edges2, XP_U16 nEdges2 ) +wordsEqual( EdgeArray* word1, EdgeArray* word2 ) { - XP_Bool success = nEdges1 == nEdges2; + XP_Bool success = word1->nEdges == word2->nEdges; if ( success ) { - success = 0 == memcmp( edges1, edges2, nEdges1 * sizeof(edges1[0]) ); + success = 0 == memcmp( word1->edges, word2->edges, + word1->nEdges * sizeof(word1->edges[0]) ); } return success; } - XP_U32 dict_countWords( const DictionaryCtxt* dict ) { - array_edge* edges[MAX_COLS]; - XP_U16 nEdges = 0; + EdgeArray edges = { .nEdges = 0 }; XP_U32 count = 0; - edges[nEdges++] = dict_getTopEdge( dict ); - if ( ISACCEPTING( dict, edges[0] ) ) { + edges.edges[edges.nEdges++] = dict_getTopEdge( dict ); + if ( ISACCEPTING( dict, edges.edges[0] ) ) { ++count; } - while ( nextWord( dict, edges, &nEdges ) ) { + while ( nextWord( dict, &edges ) ) { ++count; } return count; } -void -dict_makeIndex( const DictionaryCtxt* dict, XP_U16 depth, - DictIndex* indices, XP_U16 count ) +static void +indexOne( const DictionaryCtxt* dict, XP_U16 depth, Tile* tiles, + DictIndex* indices, XP_U16* nextIndex, + XWStreamCtxt* stream, EdgeArray* prevEdges, DictIndex* prevIndex ) { - XP_USE( indices ); - XP_ASSERT( depth == 1 ); /* so far */ - XP_U16 ii, needCount; - XP_U16 nextIndex = 0; + EdgeArray curEdges = { .nEdges = 0 }; + if ( !findStartsWith( dict, tiles, depth, &curEdges ) ) { + indices[(*nextIndex)++] = NO_INDEX; + } else { + XP_ASSERT( curEdges.nEdges == depth ); + if ( ! ISACCEPTING( dict, curEdges.edges[curEdges.nEdges-1] ) ) { + if ( !nextWord( dict, &curEdges ) ) { + XP_ASSERT( 0 ); + } + } + if ( wordsEqual( &curEdges, prevEdges ) ) { + XP_ASSERT( *prevIndex == 0 ); + } else { + /* Walk the prev word forward until they're the same */ + while ( nextWord( dict, prevEdges ) ) { + ++*prevIndex; + if ( wordsEqual( &curEdges, prevEdges ) ) { + break; + } + } + } + indices[(*nextIndex)++] = *prevIndex; + if ( NULL != stream ) { + XP_UCHAR prefix[8]; + (void)dict_tilesToString( dict, tiles, depth, prefix, VSIZE(prefix) ); + stream_catString( stream, prefix ); + } + } + if ( NULL != stream ) { + stream_catString( stream, "\n" ); + } +} + +static void +doOneDepth( const DictionaryCtxt* dict, + const Tile* allTiles, XP_U16 nTiles, Tile* prefix, + XP_U16 curDepth, XP_U16 maxDepth, + DictIndex* indices, XP_U16* nextEntry, + XWStreamCtxt* stream, EdgeArray* prevEdges, DictIndex* prevIndex ) +{ + XP_U16 ii; + for ( ii = 0; ii < nTiles; ++ii ) { + prefix[curDepth] = allTiles[ii]; + if ( curDepth + 1 == maxDepth ) { + indexOne( dict, maxDepth, prefix, indices, nextEntry, + stream, prevEdges, prevIndex); + } else { + doOneDepth( dict, allTiles, nTiles, prefix, curDepth+1, maxDepth, + indices, nextEntry, stream, prevEdges, prevIndex ); + } + } +} + +XP_U16 +dict_makeIndex( const DictionaryCtxt* dict, XP_U16 depth, + DictIndex* indices, XP_U16 count, XWStreamCtxt* stream ) +{ + XP_ASSERT( depth < MAX_COLS ); + XP_U16 ii, needCount, nTiles; XP_U16 nFaces = dict_numTileFaces( dict ); XP_Bool hasBlank = dict_hasBlankTile( dict ); if ( hasBlank ) { @@ -879,66 +930,46 @@ dict_makeIndex( const DictionaryCtxt* dict, XP_U16 depth, } XP_ASSERT( needCount <= count ); + Tile allTiles[nFaces]; + 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. */ + XP_U16 nextIndex = 0; DictWord firstWord; if ( dict_firstWord( dict, &firstWord ) ) { - array_edge* prevEdges[MAX_COLS]; - indicesToEdges( dict, &firstWord, prevEdges ); - XP_U16 prevNEdges = firstWord.nTiles; - DictIndex index = 0; + EdgeArray prevEdges; + DictIndex prevIndex = 0; + Tile prefix[depth]; + indicesToEdges( dict, &firstWord, &prevEdges ); - Tile tiles[1]; - nFaces = dict_numTileFaces( dict ); - for ( tiles[0] = 0; tiles[0] < nFaces; ++tiles[0] ) { - if ( hasBlank && tiles[0] == dict_getBlankTile( dict ) ) { - continue; - } + doOneDepth( dict, allTiles, nFaces, prefix, 0, depth, + indices, &nextIndex, stream, &prevEdges, &prevIndex ); - array_edge* curEdges[MAX_COLS]; - XP_U16 curNEdges; - if ( !findStartsWith( dict, tiles, 1, curEdges, &curNEdges ) ) { - indices[nextIndex++] = NO_INDEX; - } else { - XP_ASSERT( curNEdges == depth ); - if ( ! ISACCEPTING( dict, curEdges[curNEdges-1] ) ) { - if ( !nextWord( dict, curEdges, &curNEdges ) ) { - XP_ASSERT( 0 ); - } - } - if ( wordsEqual( curEdges, curNEdges, prevEdges, prevNEdges ) ) { - XP_ASSERT( index == 0 ); - } else { - /* Walk the prev word forward until they're the same */ - while ( nextWord( dict, prevEdges, &prevNEdges ) ) { - ++index; - if ( wordsEqual( curEdges, curNEdges, prevEdges, prevNEdges ) ) { - break; - } - } - } - indices[nextIndex++] = index; - } - } } - + return nextIndex; } XP_Bool dict_firstWord( const DictionaryCtxt* dict, DictWord* word ) { - array_edge* edges[MAX_COLS]; - XP_U16 nEdges = 0; - edges[nEdges++] = dict_getTopEdge( dict ); + EdgeArray edges = { .nEdges = 0 }; + edges.edges[edges.nEdges++] = dict_getTopEdge( dict ); - XP_Bool success = ISACCEPTING( dict, edges[0] ) - || nextWord( dict, edges, &nEdges ); + XP_Bool success = ISACCEPTING( dict, edges.edges[0] ) + || nextWord( dict, &edges ); if ( success ) { word->wordCount = dict_getWordCount( dict ); - edgesToIndices( dict, nEdges, edges, word ); + edgesToIndices( dict, &edges, word ); word->index = 0; } @@ -958,15 +989,14 @@ dict_getNextWord( const DictionaryCtxt* dict, DictWord* word ) XP_Bool dict_lastWord( const DictionaryCtxt* dict, DictWord* word ) { - array_edge* edges[MAX_COLS]; - XP_U16 nEdges = 0; - edges[nEdges++] = dict_getTopEdge( dict ); + EdgeArray edges = { .nEdges = 0 }; + edges.edges[edges.nEdges++] = dict_getTopEdge( dict ); - XP_Bool success = lastEdges( dict, edges, &nEdges ); + XP_Bool success = lastEdges( dict, &edges ); if ( success ) { word->wordCount = dict_getWordCount( dict ); - edgesToIndices( dict, nEdges, edges, word ); + edgesToIndices( dict, &edges, word ); word->index = word->wordCount - 1; } @@ -1017,23 +1047,22 @@ dict_getNthWord( const DictionaryCtxt* dict, DictWord* word, XP_U32 nn ) } } - array_edge* edges[MAX_COLS]; - XP_U16 nEdges = word->nTiles; - indicesToEdges( dict, word, edges ); + EdgeArray edges; + indicesToEdges( dict, word, &edges ); if ( word->index < nn ) { for ( ii = nn - word->index; ii > 0; --ii ) { - if ( !nextWord( dict, edges, &nEdges ) ) { + if ( !nextWord( dict, &edges ) ) { XP_ASSERT( 0 ); } } } else if ( word->index > nn ) { for ( ii = word->index - nn; ii > 0; --ii ) { - if ( !prevWord( dict, edges, &nEdges ) ) { + if ( !prevWord( dict, &edges ) ) { XP_ASSERT( 0 ); } } } - edgesToIndices( dict, nEdges, edges, word ); + edgesToIndices( dict, &edges, word ); word->index = nn; } return success; @@ -1044,15 +1073,16 @@ dict_wordToString( const DictionaryCtxt* dict, const DictWord* word, XP_UCHAR* buf, XP_U16 buflen ) { XP_U16 ii; - array_edge* edges[MAX_COLS]; + const XP_U16 nTiles = word->nTiles; Tile tiles[MAX_COLS]; + EdgeArray edges; - indicesToEdges( dict, word, edges ); + indicesToEdges( dict, word, &edges ); - for ( ii = 0; ii < word->nTiles; ++ii ) { - tiles[ii] = EDGETILE( dict, edges[ii] ); + for ( ii = 0; ii < nTiles; ++ii ) { + tiles[ii] = EDGETILE( dict, edges.edges[ii] ); } - (void)dict_tilesToString( dict, tiles, word->nTiles, buf, buflen ); + (void)dict_tilesToString( dict, tiles, nTiles, buf, buflen ); } #endif /* XWFEATURE_WALKDICT */ diff --git a/xwords4/common/dictnry.h b/xwords4/common/dictnry.h index 4f1de065f..c6c291c36 100644 --- a/xwords4/common/dictnry.h +++ b/xwords4/common/dictnry.h @@ -219,8 +219,9 @@ typedef struct _DictWord { } DictWord; XP_U32 dict_countWords( const DictionaryCtxt* dict ); -void dict_makeIndex( const DictionaryCtxt* dict, XP_U16 depth, - DictIndex* indices, XP_U16 count ); +XP_U16 dict_makeIndex( const DictionaryCtxt* dict, XP_U16 depth, + DictIndex* indices, XP_U16 count, + XWStreamCtxt* stream ); 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 ); diff --git a/xwords4/linux/linuxmain.c b/xwords4/linux/linuxmain.c index f18f4e95c..7b46ee2f9 100644 --- a/xwords4/linux/linuxmain.c +++ b/xwords4/linux/linuxmain.c @@ -893,9 +893,39 @@ tmp_noop_sigintterm( int XP_UNUSED(sig) ) } #ifdef XWFEATURE_WALKDICT -static void -walk_dict_test( const DictionaryCtxt* dict ) +#if 0 +static char* +mkPrefix( const DictionaryCtxt* dict, int index, int depth, char* buf, int len ) { + Tile tiles[depth]; + Tile blank; + XP_U16 nTiles = dict_numTileFaces( dict ); + if ( dict_hasBlankTile( dict ) ) { + blank = dict_getBlankTile( dict ); + --nTiles; + } else { + blank = -1; + } + int ii; + + for ( ii = depth-1; ii >= 0; --ii ) { + Tile tile = index % nTiles; + if ( -1 != blank && blank <= tile ) { + ++tile; + } + tiles[ii] = tile; + index /= nTiles; + } + + dict_tilesToString( dict, tiles, depth, buf, len ); + return buf; +} +#endif + +static void +walk_dict_test( const LaunchParams* params ) +{ + const DictionaryCtxt* dict = params->dict; /* 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; @@ -967,13 +997,20 @@ walk_dict_test( const DictionaryCtxt* dict ) } } - DictIndex indices[26]; - dict_makeIndex( dict, 1, indices, VSIZE(indices) ); - for ( ii = 0; ii < VSIZE(indices); ++ii ) { - DictIndex index = indices[ii]; - if ( NO_INDEX == index ) { - continue; - } else if ( dict_getNthWord( dict, &word, indices[ii] ) ) { + XP_U16 depth = 2; + DictIndex indices[26*26]; /* pow(26,depth) */ + XWStreamCtxt* stream = mem_stream_make( MPPARM(params->util->mpool) + params->vtMgr, + NULL, CHANNEL_NONE, NULL ); + XP_U16 nIndices = dict_makeIndex( dict, depth, indices, VSIZE(indices), stream ); + const char* ptr = (char*)stream_getPtr( stream ); + for ( ii = 0; ii < nIndices; ++ii ) { + char* next = strstr( (char*)ptr, "\n" ); + XP_ASSERT( !!next ); + if ( next > ptr && indices[ii] != NO_INDEX ) { + 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) ); @@ -981,10 +1018,27 @@ walk_dict_test( const DictionaryCtxt* dict ) if ( ii > 0 && dict_getNthWord( dict, &word, indices[ii]-1 ) ) { dict_wordToString( dict, &word, buf2, VSIZE(buf2) ); } - fprintf( stderr, "%d: index: %ld; word: %s (prev: %s)\n", ii, indices[ii], buf1, buf2 ); + char prfx[8]; + snprintf( prfx, depth+1, "%s", ptr ); + prfx[depth] = '\0'; + fprintf( stderr, + "%d: index: %ld; prefix: %s; word: %s (prev: %s)\n", + ii, indices[ii], prfx, buf1, buf2 ); + } else if ( next == ptr && indices[ii] == NO_INDEX ) { + } else { + XP_ASSERT( 0 ); } + ptr = next + 1; } + /* for ( ii = 0; ii < VSIZE(indices); ++ii ) { */ + /* DictIndex index = indices[ii]; */ + /* if ( NO_INDEX == index ) { */ + /* continue; */ + /* } */ + /* catOnClose( stream, NULL ); */ + stream_destroy( stream ); + exit( 0 ); } #else @@ -1380,7 +1434,7 @@ main( int argc, char** argv ) /* } */ /* } */ - walk_dict_test( mainParams.dict ); + walk_dict_test( &mainParams ); if ( 0 ) { #ifdef XWFEATURE_RELAY From 42d1a48a1d5a62839e44a3734bc0dcfe5fda8f58 Mon Sep 17 00:00:00 2001 From: Eric House Date: Wed, 26 Oct 2011 22:25:21 -0700 Subject: [PATCH 3/3] don't include indices for prefixes that don't exist. --- xwords4/common/dictnry.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/xwords4/common/dictnry.c b/xwords4/common/dictnry.c index 3e930e9d5..febe38dcd 100644 --- a/xwords4/common/dictnry.c +++ b/xwords4/common/dictnry.c @@ -862,9 +862,7 @@ indexOne( const DictionaryCtxt* dict, XP_U16 depth, Tile* tiles, XWStreamCtxt* stream, EdgeArray* prevEdges, DictIndex* prevIndex ) { EdgeArray curEdges = { .nEdges = 0 }; - if ( !findStartsWith( dict, tiles, depth, &curEdges ) ) { - indices[(*nextIndex)++] = NO_INDEX; - } else { + if ( findStartsWith( dict, tiles, depth, &curEdges ) ) { XP_ASSERT( curEdges.nEdges == depth ); if ( ! ISACCEPTING( dict, curEdges.edges[curEdges.nEdges-1] ) ) { if ( !nextWord( dict, &curEdges ) ) { @@ -883,15 +881,14 @@ indexOne( const DictionaryCtxt* dict, XP_U16 depth, Tile* tiles, } } indices[(*nextIndex)++] = *prevIndex; + if ( NULL != stream ) { XP_UCHAR prefix[8]; (void)dict_tilesToString( dict, tiles, depth, prefix, VSIZE(prefix) ); stream_catString( stream, prefix ); + stream_catString( stream, "\n" ); } } - if ( NULL != stream ) { - stream_catString( stream, "\n" ); - } } static void @@ -906,7 +903,7 @@ doOneDepth( const DictionaryCtxt* dict, prefix[curDepth] = allTiles[ii]; if ( curDepth + 1 == maxDepth ) { indexOne( dict, maxDepth, prefix, indices, nextEntry, - stream, prevEdges, prevIndex); + stream, prevEdges, prevIndex ); } else { doOneDepth( dict, allTiles, nTiles, prefix, curDepth+1, maxDepth, indices, nextEntry, stream, prevEdges, prevIndex );