diff --git a/common/board.c b/common/board.c index 635f1e9ad..d2d781971 100644 --- a/common/board.c +++ b/common/board.c @@ -1376,7 +1376,7 @@ preflight( BoardCtxt* board ) * any redrawing to be done. */ XP_Bool -board_requestHint( BoardCtxt* board, XP_Bool* workRemainsP ) +board_requestHint( BoardCtxt* board, XP_U16 nTilesToUse, XP_Bool* workRemainsP ) { MoveInfo newMove; XP_Bool result = XP_FALSE; @@ -1422,7 +1422,8 @@ board_requestHint( BoardCtxt* board, XP_Bool* workRemainsP ) searchComplete = engine_findMove(engine, model, model_getDictionary(model), - tiles, nTiles, NO_SCORE_LIMIT, + tiles, nTiles, nTilesToUse, + NO_SCORE_LIMIT, &canMove, &newMove ); board_popTimerSave( board ); diff --git a/common/board.h b/common/board.h index cd2ae6894..97e3fbd4f 100644 --- a/common/board.h +++ b/common/board.h @@ -104,7 +104,7 @@ XP_Bool board_getShowColors( BoardCtxt* board ); XP_Bool board_setShowColors( BoardCtxt* board, XP_Bool showColors ); XP_Bool board_replaceTiles( BoardCtxt* board ); -XP_Bool board_requestHint( BoardCtxt* board, XP_Bool* workRemainsP ); +XP_Bool board_requestHint( BoardCtxt* board, XP_U16 nTilesToUse, XP_Bool* workRemainsP ); void board_setScale( BoardCtxt* board, XP_U16 hScale, XP_U16 vScale ); void board_getScale( BoardCtxt* board, XP_U16* hScale, XP_U16* vScale ); diff --git a/common/engine.c b/common/engine.c index a4a8177d8..7a57e2b44 100644 --- a/common/engine.c +++ b/common/engine.c @@ -62,6 +62,7 @@ struct EngineCtxt { XW_UtilCtxt* util; Engine_rack rack; + XP_U16 nTilesToUse; Tile blankTile; XP_Bool searchInProgress; XP_Bool searchHorizontal; @@ -320,15 +321,26 @@ chooseMove( EngineCtxt* engine, PossibleMove** move ) XP_Bool engine_findMove( EngineCtxt* engine, ModelCtxt* model, DictionaryCtxt* dict, const Tile* tiles, - XP_U16 numTiles, XP_U16 targetScore, XP_Bool* canMoveP, + XP_U16 nTiles, XP_U16 nTilesToUse, + XP_U16 targetScore, XP_Bool* canMoveP, MoveInfo* newMove ) { XP_Bool result = XP_TRUE; XP_Bool firstMove; XP_U16 star_row; + if ( nTilesToUse == 0 ) { + nTilesToUse = nTiles; + } + + if ( nTilesToUse != engine->nTilesToUse ) { + /* invalidate the cache; it may contain bad results */ + engine_reset( engine ); + } + engine->model = model; engine->dict = dict; + engine->nTilesToUse = nTilesToUse; engine->blankTile = dict_getBlankTile( dict ); engine->returnNOW = XP_FALSE; @@ -340,7 +352,7 @@ engine_findMove( EngineCtxt* engine, ModelCtxt* model, dictionary's emtpy or there are no tiles, still return TRUE so we don't get scheduled again. Fixes infinite loop with empty dict and a robot. */ - *canMoveP = dict_getTopEdge(dict) != NULL && initTray( engine, tiles, numTiles ); + *canMoveP = dict_getTopEdge(dict) != NULL && initTray( engine, tiles, nTiles ); if ( *canMoveP ) { util_engineStarting( engine->util ); @@ -740,26 +752,28 @@ leftPart( EngineCtxt* engine, Tile* tiles, XP_U16 tileLength, #ifdef NODE_CAN_4 XP_U16 nodeSize = engine->dict->nodeSize; #endif - for ( ; ; ) { - XP_Bool isBlank; - Tile tile = EDGETILE( engine->dict, edge ); - if ( rack_remove( engine, tile, &isBlank ) ) { - tiles[tileLength] = tile; - leftPart( engine, tiles, tileLength+1, - follow( engine->dict, edge ), - limit-1, firstCol-1, anchorCol, row ); - rack_replace( engine, tile, isBlank ); - } + if ( engine->nTilesToUse > 0 ) { + for ( ; ; ) { + XP_Bool isBlank; + Tile tile = EDGETILE( engine->dict, edge ); + if ( rack_remove( engine, tile, &isBlank ) ) { + tiles[tileLength] = tile; + leftPart( engine, tiles, tileLength+1, + follow( engine->dict, edge ), + limit-1, firstCol-1, anchorCol, row ); + rack_replace( engine, tile, isBlank ); + } - if ( IS_LAST_EDGE( dict, edge ) || engine->returnNOW ) { - break; - } + if ( IS_LAST_EDGE( dict, edge ) || engine->returnNOW ) { + break; + } #ifdef NODE_CAN_4 - edge += nodeSize; + edge += nodeSize; #else - edge += 3; + edge += 3; #endif + } } } } @@ -785,30 +799,32 @@ extendRight( EngineCtxt* engine, Tile* tiles, XP_U16 tileLength, } else if ( tile == EMPTY_TILE ) { Crosscheck check = engine->rowChecks[col]; /* make a local copy */ - for ( ; ; ) { - tile = EDGETILE( dict, edge ); - if ( CROSSCHECK_CONTAINS( check, tile ) ) { - XP_Bool isBlank; - if ( rack_remove( engine, tile, &isBlank ) ) { - tiles[tileLength] = tile; - extendRight( engine, tiles, tileLength+1, - edge_from_tile( dict, edge, tile ), - ISACCEPTING( dict, edge ), firstCol, col+1, row ); - rack_replace( engine, tile, isBlank ); - if ( engine->returnNOW ) { - return; + if ( engine->nTilesToUse > 0 ) { + for ( ; ; ) { + tile = EDGETILE( dict, edge ); + if ( CROSSCHECK_CONTAINS( check, tile ) ) { + XP_Bool isBlank; + if ( rack_remove( engine, tile, &isBlank ) ) { + tiles[tileLength] = tile; + extendRight( engine, tiles, tileLength+1, + edge_from_tile( dict, edge, tile ), + ISACCEPTING( dict, edge ), firstCol, col+1, row ); + rack_replace( engine, tile, isBlank ); + if ( engine->returnNOW ) { + return; + } } } - } - if ( IS_LAST_EDGE( dict, edge ) ) { - break; - } + if ( IS_LAST_EDGE( dict, edge ) ) { + break; + } #ifdef NODE_CAN_4 - edge += dict->nodeSize; + edge += dict->nodeSize; #else - edge += 3; + edge += 3; #endif + } } } else if ( (edge = edge_with_tile( dict, edge, tile ) ) != NULL ) { @@ -832,6 +848,7 @@ rack_remove( EngineCtxt* engine, Tile tile, XP_Bool* isBlank ) XP_ASSERT( tile < 32 ); XP_ASSERT( tile != blankIndex ); + XP_ASSERT( engine->nTilesToUse > 0 ); if ( engine->rack[(short)tile] > 0 ) { /* we have the tile itself */ --engine->rack[(short)tile]; @@ -844,6 +861,8 @@ rack_remove( EngineCtxt* engine, Tile tile, XP_Bool* isBlank ) } else { /* we can't satisfy the request */ return XP_FALSE; } + + --engine->nTilesToUse; return XP_TRUE; } /* rack_remove */ @@ -855,6 +874,8 @@ rack_replace( EngineCtxt* engine, Tile tile, XP_Bool isBlank ) tile = engine->blankTile; } ++engine->rack[(short)tile]; + + ++engine->nTilesToUse; } /* rack_replace */ static void diff --git a/common/engine.h b/common/engine.h index 0946729f6..46cd6b46e 100644 --- a/common/engine.h +++ b/common/engine.h @@ -48,7 +48,8 @@ void engine_destroy( EngineCtxt* ctxt ); #define NO_SCORE_LIMIT 10000 /* for targetScore */ XP_Bool engine_findMove( EngineCtxt* ctxt, ModelCtxt* model, DictionaryCtxt* dict, const Tile* tiles, - XP_U16 numTiles, XP_U16 targetScore, XP_Bool* canMove, + XP_U16 nTiles, XP_U16 nTilesToUse, + XP_U16 targetScore, XP_Bool* canMove, MoveInfo* result ); XP_Bool engine_check( DictionaryCtxt* dict, Tile* buf, XP_U16 buflen );