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 * Copyright 1997 - 2006 by Eric House (xwords@eehouse.org). All rights
* reserved. * reserved.
@ -69,6 +69,7 @@ struct EngineCtxt {
XP_Bool searchInProgress; XP_Bool searchInProgress;
XP_Bool searchHorizontal; XP_Bool searchHorizontal;
XP_Bool isRobot; XP_Bool isRobot;
XP_Bool isFirstMove;
XP_U16 numRows, numCols; XP_U16 numRows, numCols;
XP_U16 curRow; XP_U16 curRow;
XP_U16 blankCount; XP_U16 blankCount;
@ -86,9 +87,9 @@ struct EngineCtxt {
XP_U16 nTilesMin; XP_U16 nTilesMin;
XP_U16 nTilesMinUser, nTilesMaxUser; XP_U16 nTilesMinUser, nTilesMaxUser;
XP_Bool tileLimitsKnown; XP_Bool tileLimitsKnown;
BdHintLimits* searchLimits; const BdHintLimits* searchLimits;
#endif #endif
XP_U16 numRowsToFill; XP_U16 lastRowToFill;
#ifdef DEBUG #ifdef DEBUG
XP_U16 curLimit; XP_U16 curLimit;
@ -257,47 +258,6 @@ initTray( EngineCtxt* engine, const Tile* tiles, XP_U16 numTiles )
return result; return result;
} /* initTray */ } /* 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 #if defined __LITTLE_ENDIAN
static XP_S16 static XP_S16
cmpMoves( PossibleMove* m1, PossibleMove* m2 ) cmpMoves( PossibleMove* m1, PossibleMove* m2 )
@ -384,14 +344,13 @@ engine_findMove( EngineCtxt* engine, const ModelCtxt* model,
const DictionaryCtxt* dict, const Tile* tiles, const DictionaryCtxt* dict, const Tile* tiles,
XP_U16 nTiles, XP_U16 nTiles,
#ifdef XWFEATURE_SEARCHLIMIT #ifdef XWFEATURE_SEARCHLIMIT
BdHintLimits* searchLimits, const BdHintLimits* searchLimits,
XP_Bool useTileLimits, XP_Bool useTileLimits,
#endif #endif
XP_U16 targetScore, XP_Bool* canMoveP, XP_U16 targetScore, XP_Bool* canMoveP,
MoveInfo* newMove ) MoveInfo* newMove )
{ {
XP_Bool result = XP_TRUE; XP_Bool result = XP_TRUE;
XP_Bool firstMove;
XP_U16 star_row; XP_U16 star_row;
engine->nTilesMax = MAX_TRAY_TILES; engine->nTilesMax = MAX_TRAY_TILES;
@ -432,8 +391,9 @@ engine_findMove( EngineCtxt* engine, const ModelCtxt* model,
#endif #endif
engine->star_row = star_row = model_numRows(model) / 2; engine->star_row = star_row = model_numRows(model) / 2;
firstMove = EMPTY_TILE == localGetBoardTile( engine, star_row, star_row, engine->isFirstMove =
XP_FALSE ); EMPTY_TILE == localGetBoardTile( engine, star_row,
star_row, XP_FALSE );
/* If we've been asked to generate a move but can't because the /* 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 dictionary's emtpy or there are no tiles, still return TRUE so we don't
@ -453,60 +413,60 @@ engine_findMove( EngineCtxt* engine, const ModelCtxt* model,
XP_MEMSET( engine->miData.savedMoves, 0, XP_MEMSET( engine->miData.savedMoves, 0,
sizeof(engine->miData.savedMoves) ); sizeof(engine->miData.savedMoves) );
if ( firstMove ) { if ( engine->searchInProgress ) {
findFirstMoves( engine ); goto resumePoint;
} else { } else {
if ( engine->searchInProgress ) { engine->searchHorizontal = XP_TRUE;
goto resumePoint; engine->searchInProgress = XP_TRUE;
} else { }
engine->searchHorizontal = XP_TRUE; for ( ; ; ) {
engine->searchInProgress = XP_TRUE; XP_U16 firstRowToFill = 0;
engine->numRows = model_numRows(engine->model);
engine->numCols = model_numCols(engine->model);
if ( !engine->searchHorizontal ) {
XP_U16 tmp = engine->numRows;
engine->numRows = engine->numCols;
engine->numCols = tmp;
} }
for ( ; ; ) {
XP_U16 firstRowToFill = 0;
engine->numRows = model_numRows(engine->model);
engine->numCols = model_numCols(engine->model);
if ( !engine->searchHorizontal ) {
XP_U16 tmp = engine->numRows;
engine->numRows = engine->numCols;
engine->numCols = tmp;
}
if ( 0 ) { if ( 0 ) {
#ifdef XWFEATURE_SEARCHLIMIT #ifdef XWFEATURE_SEARCHLIMIT
} else if ( !!engine->searchLimits ) { } else if ( !!engine->searchLimits ) {
if ( engine->searchHorizontal ) {
firstRowToFill = searchLimits->top;
engine->numRowsToFill = searchLimits->bottom;
} else {
firstRowToFill = searchLimits->left;
engine->numRowsToFill = searchLimits->right;
}
#endif
} else {
engine->numRowsToFill = engine->numRows - 1;
}
for ( engine->curRow = firstRowToFill;
engine->curRow <= engine->numRowsToFill;
++engine->curRow ) {
resumePoint:
findMovesOneRow( engine );
if ( engine->returnNOW ) {
goto outer;
}
}
if ( engine->searchHorizontal ) { if ( engine->searchHorizontal ) {
engine->searchHorizontal = XP_FALSE; firstRowToFill = searchLimits->top;
engine->lastRowToFill = searchLimits->bottom;
} else { } else {
engine->searchInProgress = XP_FALSE; firstRowToFill = searchLimits->left;
break; engine->lastRowToFill = searchLimits->right;
} }
} /* forever */ #endif
outer: } else {
result = result; /* c++ wants a statement after the label */ engine->lastRowToFill = engine->numRows - 1;
} /* if not firstMove */ }
for ( engine->curRow = firstRowToFill;
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->isFirstMove && !engine->searchLimits) ) {
engine->searchInProgress = XP_FALSE;
break;
} else {
engine->searchHorizontal = XP_FALSE;
}
} /* forever */
outer:
result = result; /* c++ wants a statement after the label */
} }
/* Search is finished. Choose (or just return) the best move found. */ /* Search is finished. Choose (or just return) the best move found. */
if ( engine->returnNOW ) { 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 * 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 static XP_Bool
isAnchorSquare( EngineCtxt* engine, XP_U16 col, XP_U16 row ) 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; return XP_FALSE;
} }
if ( engine->isFirstMove ) {
return col == engine->star_row && row == engine->star_row;
}
if ( (col != 0) && if ( (col != 0) &&
localGetBoardTile( engine, col-1, row, XP_FALSE ) != EMPTY_TILE ) { localGetBoardTile( engine, col-1, row, XP_FALSE ) != EMPTY_TILE ) {
return XP_TRUE; return XP_TRUE;

View file

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