Fix bug: when using hint limits to restrict first move on empty board

limits were ignored for the vertical search.  Fix is to make
special-case treatment of first move more integrated so special limits
code isn't needed.
This commit is contained in:
ehouse 2008-11-22 19:32:42 +00:00
parent b24f3d66a7
commit 6e9f5791d6
2 changed files with 61 additions and 97 deletions

View file

@ -1,4 +1,4 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
/* -*- fill-column: 78; compile-command: "cd ../linux && make -j MEMDEBUG=TRUE"; -*- */
/*
* Copyright 1997 - 2006 by Eric House (xwords@eehouse.org). All rights
* reserved.
@ -69,6 +69,7 @@ struct EngineCtxt {
XP_Bool searchInProgress;
XP_Bool searchHorizontal;
XP_Bool isRobot;
XP_Bool isFirstMove;
XP_U16 numRows, numCols;
XP_U16 curRow;
XP_U16 blankCount;
@ -86,9 +87,9 @@ struct EngineCtxt {
XP_U16 nTilesMin;
XP_U16 nTilesMinUser, nTilesMaxUser;
XP_Bool tileLimitsKnown;
BdHintLimits* searchLimits;
const BdHintLimits* searchLimits;
#endif
XP_U16 numRowsToFill;
XP_U16 lastRowToFill;
#ifdef DEBUG
XP_U16 curLimit;
@ -257,47 +258,6 @@ initTray( EngineCtxt* engine, const Tile* tiles, XP_U16 numTiles )
return result;
} /* initTray */
static void
findFirstMoves( EngineCtxt* engine )
{
XP_S16 prevAnchor = -1;
XP_U16 star_row = engine->star_row;
if ( 0 ) {
#ifdef XWFEATURE_SEARCHLIMIT
} else if ( !!engine->searchLimits ) {
if ( engine->searchLimits->top > star_row
|| engine->searchLimits->bottom < star_row ) {
return;
} else {
XP_U16 left = engine->searchLimits->left;
XP_U16 nHintCols = engine->searchLimits->right - left + 1;
XP_MEMSET( engine->rowChecks, 0x00, sizeof(engine->rowChecks) );
XP_MEMSET( &engine->rowChecks[left], 0xFF,
sizeof(engine->rowChecks[0]) * nHintCols );
prevAnchor += left;
}
#endif
} else {
/* all have trivial crosschecks */
XP_MEMSET( engine->rowChecks, 0xFF, sizeof(engine->rowChecks) );
}
/* middle square is the only legal anchor */
engine->searchHorizontal = XP_TRUE;
findMovesForAnchor( engine, &prevAnchor, star_row, star_row );
#ifdef XWFEATURE_SEARCHLIMIT
/* If there's a hint region try vertical also since results could differ. */
if ( !!engine->searchLimits && !engine->returnNOW ) {
engine->searchHorizontal = XP_FALSE;
findMovesForAnchor( engine, &prevAnchor, star_row, star_row );
}
#endif
HILITE_CELL( engine, star_row, star_row );
} /* findFirstMoves */
#if defined __LITTLE_ENDIAN
static XP_S16
cmpMoves( PossibleMove* m1, PossibleMove* m2 )
@ -384,14 +344,13 @@ engine_findMove( EngineCtxt* engine, const ModelCtxt* model,
const DictionaryCtxt* dict, const Tile* tiles,
XP_U16 nTiles,
#ifdef XWFEATURE_SEARCHLIMIT
BdHintLimits* searchLimits,
const BdHintLimits* searchLimits,
XP_Bool useTileLimits,
#endif
XP_U16 targetScore, XP_Bool* canMoveP,
MoveInfo* newMove )
{
XP_Bool result = XP_TRUE;
XP_Bool firstMove;
XP_U16 star_row;
engine->nTilesMax = MAX_TRAY_TILES;
@ -432,8 +391,9 @@ engine_findMove( EngineCtxt* engine, const ModelCtxt* model,
#endif
engine->star_row = star_row = model_numRows(model) / 2;
firstMove = EMPTY_TILE == localGetBoardTile( engine, star_row, star_row,
XP_FALSE );
engine->isFirstMove =
EMPTY_TILE == localGetBoardTile( engine, star_row,
star_row, XP_FALSE );
/* If we've been asked to generate a move but can't because the
dictionary's emtpy or there are no tiles, still return TRUE so we don't
@ -453,9 +413,6 @@ engine_findMove( EngineCtxt* engine, const ModelCtxt* model,
XP_MEMSET( engine->miData.savedMoves, 0,
sizeof(engine->miData.savedMoves) );
if ( firstMove ) {
findFirstMoves( engine );
} else {
if ( engine->searchInProgress ) {
goto resumePoint;
} else {
@ -477,36 +434,39 @@ engine_findMove( EngineCtxt* engine, const ModelCtxt* model,
} else if ( !!engine->searchLimits ) {
if ( engine->searchHorizontal ) {
firstRowToFill = searchLimits->top;
engine->numRowsToFill = searchLimits->bottom;
engine->lastRowToFill = searchLimits->bottom;
} else {
firstRowToFill = searchLimits->left;
engine->numRowsToFill = searchLimits->right;
engine->lastRowToFill = searchLimits->right;
}
#endif
} else {
engine->numRowsToFill = engine->numRows - 1;
engine->lastRowToFill = engine->numRows - 1;
}
for ( engine->curRow = firstRowToFill;
engine->curRow <= engine->numRowsToFill;
engine->curRow <= engine->lastRowToFill;
++engine->curRow ) {
resumePoint:
if ( engine->isFirstMove && (engine->curRow != star_row)) {
continue;
}
findMovesOneRow( engine );
if ( engine->returnNOW ) {
goto outer;
}
}
if ( engine->searchHorizontal ) {
engine->searchHorizontal = XP_FALSE;
} else {
if ( !engine->searchHorizontal ||
(engine->isFirstMove && !engine->searchLimits) ) {
engine->searchInProgress = XP_FALSE;
break;
} else {
engine->searchHorizontal = XP_FALSE;
}
} /* forever */
outer:
result = result; /* c++ wants a statement after the label */
} /* if not firstMove */
}
/* Search is finished. Choose (or just return) the best move found. */
if ( engine->returnNOW ) {
@ -750,7 +710,7 @@ localGetBoardTile( EngineCtxt* engine, XP_U16 col, XP_U16 row,
/*****************************************************************************
* Return true if the tile is empty and has a filled-in square on any of the
* four sides.
* four sides. First move is a special case: empty and 7,7
****************************************************************************/
static XP_Bool
isAnchorSquare( EngineCtxt* engine, XP_U16 col, XP_U16 row )
@ -759,6 +719,10 @@ isAnchorSquare( EngineCtxt* engine, XP_U16 col, XP_U16 row )
return XP_FALSE;
}
if ( engine->isFirstMove ) {
return col == engine->star_row && row == engine->star_row;
}
if ( (col != 0) &&
localGetBoardTile( engine, col-1, row, XP_FALSE ) != EMPTY_TILE ) {
return XP_TRUE;

View file

@ -53,7 +53,7 @@ XP_Bool engine_findMove( EngineCtxt* ctxt, const ModelCtxt* model,
const DictionaryCtxt* dict, const Tile* tiles,
XP_U16 nTiles,
#ifdef XWFEATURE_SEARCHLIMIT
BdHintLimits* boardLimits,
const BdHintLimits* boardLimits,
XP_Bool useTileLimits,
#endif
XP_U16 targetScore, XP_Bool* canMove,