switch from tracking robot intelligence as a per-game boolean

implemented (when not smart) as trying to match the human's score to a
per-robot value between 1 and 100 that gives the percentage of best
moves to store before picking randomly from among them.  So a 1 means
save only the best move and always pick it; 100 means save all the
best moves (how many are saved is compile-time configurable) and pick
one of them.  Because it's settable per-robot a smarter robot can be
played against a dumber one (though I may choose not to make it
settable per-robot on shipping versions.)
This commit is contained in:
Andy2 2011-01-10 06:44:28 -08:00
parent fc23080120
commit f111b78714
8 changed files with 109 additions and 128 deletions

View file

@ -564,7 +564,7 @@ board_canHint( const BoardCtxt* board )
&& 0 < model_getNumTilesTotal( board->model, board->selPlayer );
if ( canHint ) {
LocalPlayer* lp = &board->gi->players[board->selPlayer];
canHint = lp->isLocal && !lp->isRobot;
canHint = lp->isLocal && !LP_IS_ROBOT(lp);
}
return canHint;
}
@ -1412,7 +1412,7 @@ chooseBestSelPlayer( BoardCtxt* board )
for ( i = 0; i < nPlayers; ++i ) {
LocalPlayer* lp = &board->gi->players[curTurn];
if ( !lp->isRobot && lp->isLocal ) {
if ( !LP_IS_ROBOT(lp) && lp->isLocal ) {
return curTurn;
}
curTurn = (curTurn + 1) % nPlayers;
@ -1707,7 +1707,7 @@ board_requestHint( BoardCtxt* board,
#ifdef XWFEATURE_SEARCHLIMIT
lp, useTileLimits,
#endif
NO_SCORE_LIMIT,
0, /* 0: not a robot */
&canMove, &newMove );
board_popTimerSave( board );
@ -2160,7 +2160,7 @@ askRevealTray( BoardCtxt* board )
} else if ( !lp->isLocal ) {
util_userError( board->util, ERR_NO_PEEK_REMOTE_TILES );
#endif
} else if ( lp->isRobot ) {
} else if ( LP_IS_ROBOT(lp) ) {
if ( reversed ) {
util_userError( board->util, ERR_NO_PEEK_ROBOT_TILES );
} else {

View file

@ -90,12 +90,11 @@ struct EngineCtxt {
XP_Bool usePrev;
XP_Bool searchInProgress;
XP_Bool searchHorizontal;
XP_Bool isRobot;
XP_Bool isFirstMove;
XP_U16 numRows, numCols;
XP_U16 curRow;
XP_U16 blankCount;
XP_U16 targetScore;
XP_U16 nMovesToSave;
XP_U16 star_row;
XP_Bool returnNOW;
MoveIterationData miData;
@ -202,7 +201,7 @@ engine_getScoreCache( EngineCtxt* engine, XP_U16 row )
* turn it into a separate code module later.
****************************************************************************/
EngineCtxt*
engine_make( MPFORMAL XW_UtilCtxt* util, XP_Bool isRobot )
engine_make( MPFORMAL XW_UtilCtxt* util )
{
EngineCtxt* result = (EngineCtxt*)XP_MALLOC( mpool, sizeof(*result) );
XP_MEMSET( result, 0, sizeof(*result) );
@ -211,8 +210,6 @@ engine_make( MPFORMAL XW_UtilCtxt* util, XP_Bool isRobot )
result->util = util;
result->isRobot = isRobot;
engine_reset( result );
return result;
@ -230,9 +227,9 @@ engine_writeToStream( EngineCtxt* XP_UNUSED(ctxt),
EngineCtxt*
engine_makeFromStream( MPFORMAL XWStreamCtxt* XP_UNUSED_DBG(stream),
XW_UtilCtxt* util, XP_Bool isRobot )
XW_UtilCtxt* util )
{
EngineCtxt* engine = engine_make( MPPARM(mpool) util, isRobot );
EngineCtxt* engine = engine_make( MPPARM(mpool) util );
/* All the engine's data seems to be used only in the process of finding a
move. So if we're willing to have the set of moves found lost across
@ -306,7 +303,7 @@ print_savedMoves( const EngineCtxt* engine, const char* label )
int ii;
int pos = 0;
char buf[(NUM_SAVED_ENGINE_MOVES*10) + 3] = {0};
for ( ii = 0; ii < NUM_SAVED_ENGINE_MOVES; ++ii ) {
for ( ii = 0; ii < engine->nMovesToSave; ++ii ) {
if ( 0 < engine->miData.savedMoves[ii].score ) {
pos += XP_SNPRINTF( &buf[pos], VSIZE(buf)-pos, "[%d]: %d; ",
ii, engine->miData.savedMoves[ii].score );
@ -324,6 +321,8 @@ chooseMove( EngineCtxt* engine, PossibleMove** move )
XP_U16 ii;
PossibleMove* chosen;
XP_Bool result;
XP_Bool done;
XP_Bool isRobot;
print_savedMoves( engine, "unsorted moves" );
@ -331,32 +330,40 @@ chooseMove( EngineCtxt* engine, PossibleMove** move )
get picked up first. Don't sort if we're working for a robot; we've
only been saving the single best move anyway. At least not until we
start applying other criteria than score to moves. */
if ( engine->isRobot ) {
chosen = &engine->miData.savedMoves[0];
} else {
XP_Bool done = !move_cache_empty( engine );
while ( !done ) { /* while so can break */
done = XP_TRUE;
PossibleMove* cur = engine->miData.savedMoves;
for ( ii = 0; ii < NUM_SAVED_ENGINE_MOVES-1; ++ii ) {
PossibleMove* next = cur + 1;
if ( CMPMOVES( cur, next ) > 0 ) {
PossibleMove tmp;
XP_MEMCPY( &tmp, cur, sizeof(tmp) );
XP_MEMCPY( cur, next, sizeof(*cur) );
XP_MEMCPY( next, &tmp, sizeof(*next) );
done = XP_FALSE;
}
cur = next;
done = !move_cache_empty( engine );
isRobot = 0 < engine->nMovesToSave;
while ( !done ) { /* while so can break */
done = XP_TRUE;
PossibleMove* cur = engine->miData.savedMoves;
for ( ii = 0; ii < engine->nMovesToSave-1; ++ii ) {
PossibleMove* next = cur + 1;
if ( CMPMOVES( cur, next ) > 0 ) {
PossibleMove tmp;
XP_MEMCPY( &tmp, cur, sizeof(tmp) );
XP_MEMCPY( cur, next, sizeof(*cur) );
XP_MEMCPY( next, &tmp, sizeof(*next) );
done = XP_FALSE;
}
if ( done ) {
cur = next;
}
if ( done ) {
if ( !isRobot ) {
init_move_cache( engine );
print_savedMoves( engine, "sorted moves" );
}
print_savedMoves( engine, "sorted moves" );
}
/* now pick the one we're supposed to return */
chosen = next_from_cache( engine );
if ( isRobot ) {
XP_ASSERT( engine->miData.nInMoveCache <= NUM_SAVED_ENGINE_MOVES );
XP_ASSERT( engine->miData.nInMoveCache <= engine->nMovesToSave );
/* PENDING not nInMoveCache-1 below?? */
chosen = &engine->miData.savedMoves[engine->miData.nInMoveCache];
} else {
chosen = next_from_cache( engine );
}
}
*move = chosen; /* set either way */
@ -370,6 +377,27 @@ chooseMove( EngineCtxt* engine, PossibleMove** move )
return result;
} /* chooseMove */
/* Robot smartness is a number between 0 and 100, inclusive. 0 means a human
* player who may want to iterate, so save all moves. If a robot player, we
* want a random move within a range proportional to the 1-100 range, so we
* figure out now what we'll be picking, save only that many moves and take
* the worst of 'em in chooseMove().
*/
static void
normalizeIQ( EngineCtxt* engine, XP_U16 iq )
{
if ( 0 == iq ) { /* human */
engine->nMovesToSave = NUM_SAVED_ENGINE_MOVES; /* save 'em all */
} else if ( 1 == iq ) { /* human */
engine->nMovesToSave = 1;
} else {
XP_U16 count = NUM_SAVED_ENGINE_MOVES * iq / 100;
engine->nMovesToSave = 1 + (XP_RANDOM() % count);
}
XP_LOGF( "%s: set nMovesToSave=%d (iq=%d; NUM_SAVED_ENGINE_MOVES=%d)",
__func__, engine->nMovesToSave, iq, NUM_SAVED_ENGINE_MOVES );
}
/* Return of XP_TRUE means that we ran to completion. XP_FALSE means we were
* interrupted. Whether an actual move was found is indicated by what's
* filled in in *newMove.
@ -382,8 +410,7 @@ engine_findMove( EngineCtxt* engine, const ModelCtxt* model,
const BdHintLimits* searchLimits,
XP_Bool useTileLimits,
#endif
XP_U16 targetScore, XP_Bool* canMoveP,
MoveInfo* newMove )
XP_U16 robotIQ, XP_Bool* canMoveP, MoveInfo* newMove )
{
XP_Bool result = XP_TRUE;
XP_U16 star_row;
@ -442,7 +469,7 @@ engine_findMove( EngineCtxt* engine, const ModelCtxt* model,
util_engineStarting( engine->util,
engine->rack[engine->blankTile] );
engine->targetScore = targetScore;
normalizeIQ( engine, robotIQ );
if ( move_cache_empty( engine ) ) {
set_search_limits( engine );
@ -1141,7 +1168,9 @@ saveMoveIfQualifies( EngineCtxt* engine, PossibleMove* posmove )
XP_Bool usePrev = engine->usePrev;
XP_Bool foundEmpty = XP_FALSE;
if ( !engine->isRobot ) { /* robot doesn't ask for next hint.... */
if ( 1 == engine->nMovesToSave ) { /* only saving one */
mostest = 0;
} else {
mostest = -1;
/* we're not interested if we've seen this */
cmpVal = CMPMOVES( posmove, &engine->miData.lastSeenMove );
@ -1154,7 +1183,7 @@ saveMoveIfQualifies( EngineCtxt* engine, PossibleMove* posmove )
} else {
XP_S16 ii;
/* terminate i at 1 because mostest starts at 0 */
for ( ii = 0; ii < NUM_SAVED_ENGINE_MOVES; ++ii ) {
for ( ii = 0; ii < engine->nMovesToSave; ++ii ) {
/* Find the mostest value move and overwrite it. Note that
there might not be one, as all may have the same or higher
scores and those that have the same score may compare
@ -1222,7 +1251,7 @@ set_search_limits( EngineCtxt* engine )
move as the limit; otherwise the lowest */
if ( 0 < engine->miData.nInMoveCache ) {
XP_U16 srcIndx = engine->usePrev
? NUM_SAVED_ENGINE_MOVES-1 : engine->miData.bottom;
? engine->nMovesToSave-1 : engine->miData.bottom;
XP_MEMCPY( &engine->miData.lastSeenMove,
&engine->miData.savedMoves[srcIndx],
sizeof(engine->miData.lastSeenMove) );
@ -1238,9 +1267,11 @@ set_search_limits( EngineCtxt* engine )
static void
init_move_cache( EngineCtxt* engine )
{
XP_U16 nInMoveCache = NUM_SAVED_ENGINE_MOVES;
XP_U16 nInMoveCache = engine->nMovesToSave;
XP_U16 ii;
XP_ASSERT( engine->nMovesToSave == NUM_SAVED_ENGINE_MOVES );
for ( ii = 0; ii < NUM_SAVED_ENGINE_MOVES; ++ii ) {
if ( 0 == engine->miData.savedMoves[ii].score ) {
--nInMoveCache;
@ -1306,9 +1337,7 @@ scoreQualifies( EngineCtxt* engine, XP_U16 score )
XP_Bool qualifies = XP_FALSE;
XP_Bool usePrev = engine->usePrev;
if ( score > engine->targetScore ) {
/* drop it */
} else if ( usePrev && score < engine->miData.lastSeenMove.score ) {
if ( usePrev && score < engine->miData.lastSeenMove.score ) {
/* drop it */
} else if ( !usePrev && score > engine->miData.lastSeenMove.score
/* || (score < engine->miData.lowestSavedScore) */ ) {
@ -1322,7 +1351,7 @@ scoreQualifies( EngineCtxt* engine, XP_U16 score )
NUM_SAVED_ENGINE_MOVES moves in here* and doing a quick test on
that. Or better, keeping the list in sorted order. */
for ( ii = 0, savedMoves = engine->miData.savedMoves;
ii < NUM_SAVED_ENGINE_MOVES; ++ii, ++savedMoves ) {
ii < engine->nMovesToSave; ++ii, ++savedMoves ) {
if ( savedMoves->score == 0 ) { /* empty slot */
qualifies = XP_TRUE;
} else if ( usePrev && score <= savedMoves->score ) {
@ -1332,9 +1361,6 @@ scoreQualifies( EngineCtxt* engine, XP_U16 score )
qualifies = XP_TRUE;
break;
}
if ( engine->isRobot ) { /* we look at only one for robot */
break;
}
}
}
//XP_LOGF( "%s(%d)->%d", __func__, score, qualifies );

View file

@ -38,17 +38,16 @@ typedef struct BdHintLimits {
XP_U16 engine_getScoreCache( EngineCtxt* engine, XP_U16 row );
EngineCtxt* engine_make( MPFORMAL XW_UtilCtxt* util, XP_Bool isRobot );
EngineCtxt* engine_make( MPFORMAL XW_UtilCtxt* util );
void engine_writeToStream( EngineCtxt* ctxt, XWStreamCtxt* stream );
EngineCtxt* engine_makeFromStream( MPFORMAL XWStreamCtxt* stream,
XW_UtilCtxt* util, XP_Bool isRobot );
XW_UtilCtxt* util );
void engine_init( EngineCtxt* ctxt );
void engine_reset( EngineCtxt* ctxt );
void engine_destroy( EngineCtxt* ctxt );
#define NO_SCORE_LIMIT 10000 /* for targetScore */
XP_Bool engine_findMove( EngineCtxt* ctxt, const ModelCtxt* model,
const DictionaryCtxt* dict, const Tile* tiles,
XP_U16 nTiles, XP_Bool usePrev,
@ -56,8 +55,7 @@ XP_Bool engine_findMove( EngineCtxt* ctxt, const ModelCtxt* model,
const BdHintLimits* boardLimits,
XP_Bool useTileLimits,
#endif
XP_U16 targetScore, XP_Bool* canMove,
MoveInfo* result );
XP_U16 robotIQ, XP_Bool* canMove, MoveInfo* result );
XP_Bool engine_check( DictionaryCtxt* dict, Tile* buf, XP_U16 buflen );
#ifdef CPLUS

View file

@ -297,7 +297,6 @@ gi_initPlayerInfo( MPFORMAL CurGameInfo* gi, const XP_UCHAR* nameTemplate )
gi->serverRole = SERVER_STANDALONE;
gi->nPlayers = 2;
gi->boardSize = 15;
gi->robotSmartness = SMART_ROBOT;
gi->gameSeconds = 25 * 60; /* 25 minute game is common? */
gi->confirmBTConnect = XP_TRUE;
@ -312,7 +311,7 @@ gi_initPlayerInfo( MPFORMAL CurGameInfo* gi, const XP_UCHAR* nameTemplate )
fp->name = copyString( mpool, buf );
}
fp->isRobot = (i == 0); /* one robot */
fp->robotIQ = (i == 0) ? 1 : 0; /* one robot */
fp->isLocal = XP_TRUE;
fp->secondsUsed = 0;
}
@ -367,7 +366,6 @@ gi_copy( MPFORMAL CurGameInfo* destGI, const CurGameInfo* srcGI )
destGI->hintsNotAllowed = srcGI->hintsNotAllowed;
destGI->timerEnabled = srcGI->timerEnabled;
destGI->robotSmartness = (XP_U8)srcGI->robotSmartness;
destGI->phoniesAction = srcGI->phoniesAction;
destGI->allowPickTiles = srcGI->allowPickTiles;
@ -378,7 +376,7 @@ gi_copy( MPFORMAL CurGameInfo* destGI, const CurGameInfo* srcGI )
replaceStringIfDifferent( mpool, &destPl->password,
srcPl->password );
destPl->secondsUsed = srcPl->secondsUsed;
destPl->isRobot = srcPl->isRobot;
destPl->robotIQ = srcPl->robotIQ;
destPl->isLocal = srcPl->isLocal;
}
} /* gi_copy */
@ -391,7 +389,7 @@ gi_countLocalPlayers( const CurGameInfo* gi, XP_Bool humanOnly )
const LocalPlayer* lp = gi->players;
while ( nPlayers-- ) {
if ( lp->isLocal ) {
if ( humanOnly && lp->isRobot ) {
if ( humanOnly && LP_IS_ROBOT(lp) ) {
// skip
} else {
++count;
@ -420,7 +418,9 @@ gi_readFromStream( MPFORMAL XWStreamCtxt* stream, CurGameInfo* gi )
gi->boardSize = (XP_U8)stream_getBits( stream, 4 );
gi->serverRole = (DeviceRole)stream_getBits( stream, 2 );
gi->hintsNotAllowed = stream_getBits( stream, 1 );
gi->robotSmartness = (XP_U8)stream_getBits( stream, 2 );
if ( strVersion < STREAM_VERS_ROBOTIQ ) {
(void)stream_getBits( stream, 2 );
}
gi->phoniesAction = (XWPhoniesChoice)stream_getBits( stream, 2 );
gi->timerEnabled = stream_getBits( stream, 1 );
@ -459,7 +459,9 @@ gi_readFromStream( MPFORMAL XWStreamCtxt* stream, CurGameInfo* gi )
}
pl->secondsUsed = stream_getU16( stream );
pl->isRobot = stream_getBits( stream, 1 );
pl->robotIQ = ( strVersion < STREAM_VERS_ROBOTIQ )
? (XP_U8)stream_getBits( stream, 1 )
: pl->robotIQ = stream_getU8( stream );
pl->isLocal = stream_getBits( stream, 1 );
}
} /* gi_readFromStream */
@ -476,7 +478,6 @@ gi_writeToStream( XWStreamCtxt* stream, const CurGameInfo* gi )
stream_putBits( stream, 4, gi->boardSize );
stream_putBits( stream, 2, gi->serverRole );
stream_putBits( stream, 1, gi->hintsNotAllowed );
stream_putBits( stream, 2, gi->robotSmartness );
stream_putBits( stream, 2, gi->phoniesAction );
stream_putBits( stream, 1, gi->timerEnabled );
stream_putBits( stream, 1, gi->allowPickTiles );
@ -491,7 +492,7 @@ gi_writeToStream( XWStreamCtxt* stream, const CurGameInfo* gi )
stringToStream( stream, pl->name );
stringToStream( stream, pl->password );
stream_putU16( stream, pl->secondsUsed );
stream_putBits( stream, 1, pl->isRobot );
stream_putU8( stream, pl->robotIQ );
stream_putBits( stream, 1, pl->isLocal );
}
} /* gi_writeToStream */

View file

@ -31,6 +31,7 @@
extern "C" {
#endif
#define STREAM_VERS_ROBOTIQ 0x0E /* robots have different smarts */
#define STREAM_VERS_DICTLANG 0x0D /* save dict lang code in CurGameInfo */
#define STREAM_VERS_NUNDONE 0x0C /* save undone tile in model */
#define STREAM_VERS_GAMESECONDS 0x0B /* save gameSeconds whether or not
@ -48,16 +49,20 @@ extern "C" {
#define STREAM_VERS_41B4 0x02
#define STREAM_VERS_405 0x01
#define CUR_STREAM_VERS STREAM_VERS_DICTLANG
#define CUR_STREAM_VERS STREAM_VERS_ROBOTIQ
typedef struct LocalPlayer {
XP_UCHAR* name;
XP_UCHAR* password;
XP_U16 secondsUsed;
XP_Bool isRobot;
XP_Bool isLocal;
XP_U8 robotIQ; /* 0 means not a robot; 1-100 means how
dumb is it with 1 meaning very smart */
} LocalPlayer;
#define LP_IS_ROBOT(lp) ((lp)->robotIQ != 0)
#define LP_IS_LOCAL(lp) ((lp)->isLocal)
#define DUMB_ROBOT 0
#define SMART_ROBOT 1
@ -75,7 +80,6 @@ typedef struct CurGameInfo {
XP_Bool timerEnabled;
XP_Bool allowPickTiles;
XP_Bool allowHintRect;
XP_U8 robotSmartness;
XWPhoniesChoice phoniesAction;
XP_Bool confirmBTConnect; /* only used for BT */
} CurGameInfo;

View file

@ -198,7 +198,7 @@ cpToLP( NGValue value, const void* cbClosure )
strAddr = &lp->password;
break;
case NG_COL_ROBOT:
lp->isRobot = value.ng_bool;
lp->robotIQ = value.ng_bool ? 1 : 0;
break;
}
@ -591,7 +591,7 @@ loadPlayer( NewGameCtx* ngc, XP_U16 player, const LocalPlayer* lp )
value.ng_cp = lp->password;
(*ngc->setColProc)(closure, player, NG_COL_PASSWD, value );
value.ng_bool = lp->isRobot;
value.ng_bool = LP_IS_ROBOT(lp);
(*ngc->setColProc)(closure, player, NG_COL_ROBOT, value );
}

View file

@ -161,7 +161,7 @@ drawScoreBoard( BoardCtxt* board )
dp->dsi.name = emptyStringIfNull(lp->name);
dp->dsi.selected = board->trayVisState != TRAY_HIDDEN
&& ii==selPlayer;
dp->dsi.isRobot = lp->isRobot;
dp->dsi.isRobot = LP_IS_ROBOT(lp);
dp->dsi.isRemote = !lp->isLocal;
dp->dsi.nTilesLeft = (nTilesInPool > 0)? -1:
model_getNumTilesTotal( model, ii );

View file

@ -45,9 +45,6 @@ extern "C" {
#define LOCAL_ADDR NULL
#define IS_ROBOT(p) ((p)->isRobot)
#define IS_LOCAL(p) ((p)->isLocal)
enum {
END_REASON_USER_REQUEST,
END_REASON_OUT_OF_TILES,
@ -309,7 +306,6 @@ server_makeFromStream( MPFORMAL XWStreamCtxt* stream, ModelCtxt* model,
{
ServerCtxt* server;
short i;
CurGameInfo* gi = util->gameInfo;
server = server_make( MPPARM(mpool) model, comms, util );
getNV( stream, &server->nv, nPlayers );
@ -324,10 +320,8 @@ server_makeFromStream( MPFORMAL XWStreamCtxt* stream, ModelCtxt* model,
player->deviceIndex = stream_getU8( stream );
if ( stream_getU8( stream ) != 0 ) {
LocalPlayer* lp = &gi->players[i];
player->engine = engine_makeFromStream( MPPARM(mpool)
stream, util,
lp->isRobot );
stream, util );
}
}
@ -504,7 +498,7 @@ server_initClientConnection( ServerCtxt* server, XWStreamCtxt* stream )
continue;
}
stream_putBits( stream, 1, lp->isRobot ); /* better not to send this */
stream_putBits( stream, 1, LP_IS_ROBOT(lp) ); /* better not to send this */
/* The first nPlayers players are the ones we'll use. The local flag
doesn't matter when for SERVER_ISCLIENT. */
@ -635,43 +629,6 @@ robotTradeTiles( ServerCtxt* server, MoveInfo* newMove )
} /* robotTradeTiles */
#endif
#define FUDGE_RANGE 10
#define MINIMUM_SCORE 5
static XP_U16
figureTargetScore( ServerCtxt* server, XP_U16 turn )
{
XP_S16 result = 1000;
XP_S16 highScore = 0;
ModelCtxt* model = server->vol.model;
XP_U16 nPlayers = server->vol.gi->nPlayers;
XP_U16 i;
XP_ASSERT( IS_ROBOT(&server->vol.gi->players[turn]) );
if ( 1 /* server->nHumanPlayers > 0 */ ) {
result = 0;
/* find the highest score anybody but the current player has */
for ( i = 0; i < nPlayers; ++i ) {
if ( i != turn ) {
XP_S16 score = model_getPlayerScore( model, i );
XP_ASSERT( score >= 0 );
if ( highScore < score ) {
highScore = score;
}
}
}
result = (XP_S16)(highScore - model_getPlayerScore( model, turn )
+ (FUDGE_RANGE-(XP_RANDOM() % (FUDGE_RANGE*2))));
if ( result < 0 ) {
result = MINIMUM_SCORE;
}
}
return result;
} /* figureTargetScore */
static XWStreamCtxt*
mkServerStream( ServerCtxt* server )
{
@ -697,7 +654,6 @@ makeRobotMove( ServerCtxt* server )
XP_Bool timerEnabled = gi->timerEnabled;
XP_Bool canMove;
XP_U32 time = 0L; /* stupid compiler.... */
XP_U16 targetScore = NO_SCORE_LIMIT;
XW_UtilCtxt* util = server->vol.util;
if ( timerEnabled ) {
@ -715,10 +671,6 @@ makeRobotMove( ServerCtxt* server )
tileSet = model_getPlayerTiles( model, turn );
if ( gi->robotSmartness == DUMB_ROBOT ) {
targetScore = figureTargetScore( server, turn );
}
XP_ASSERT( !!server_getEngineFor( server, turn ) );
searchComplete = engine_findMove( server_getEngineFor( server, turn ),
model, model_getDictionary( model ),
@ -726,7 +678,8 @@ makeRobotMove( ServerCtxt* server )
#ifdef XWFEATURE_SEARCHLIMIT
NULL, XP_FALSE,
#endif
targetScore, &canMove, &newMove );
server->vol.gi->players[turn].robotIQ,
&canMove, &newMove );
if ( searchComplete ) {
const XP_UCHAR* str;
XWStreamCtxt* stream = NULL;
@ -806,7 +759,7 @@ robotMovePending( const ServerCtxt* server )
if ( turn >= 0 && tileCountsOk(server) && NPASSES_OK(server) ) {
CurGameInfo* gi = server->vol.gi;
LocalPlayer* player = &gi->players[turn];
result = IS_ROBOT(player) && IS_LOCAL(player);
result = LP_IS_ROBOT(player) && LP_IS_LOCAL(player);
}
return result;
} /* robotMovePending */
@ -852,8 +805,8 @@ showPrevScore( ServerCtxt* server )
prevTurn = (server->nv.currentTurn + nPlayers - 1) % nPlayers;
lp = &gi->players[prevTurn];
wasRobot = lp->isRobot;
wasLocal = lp->isLocal;
wasRobot = LP_IS_ROBOT(lp);
wasLocal = LP_IS_LOCAL(lp);
if ( wasLocal ) {
XP_ASSERT( wasRobot );
@ -1023,7 +976,7 @@ registerRemotePlayer( ServerCtxt* server, XWStreamCtxt* stream )
lp = findFirstPending( server, &player );
/* get data from stream */
lp->isRobot = stream_getBits( stream, 1 );
lp->robotIQ = 1 == stream_getBits( stream, 1 )? 1 : 0;
nameLen = stream_getBits( stream, NAME_LEN_NBITS );
name = (XP_UCHAR*)XP_MALLOC( server->mpool, nameLen + 1 );
stream_getBytes( stream, name, nameLen );
@ -1060,8 +1013,8 @@ clearLocalRobots( ServerCtxt* server )
for ( i = 0; i < nPlayers; ++i ) {
LocalPlayer* player = &gi->players[i];
if ( IS_LOCAL( player ) ) {
player->isRobot = XP_FALSE;
if ( LP_IS_LOCAL( player ) ) {
player->robotIQ = 0;
}
}
} /* clearLocalRobots */
@ -1409,8 +1362,7 @@ server_getEngineFor( ServerCtxt* server, XP_U16 playerNum )
engine = player->engine;
if ( !engine && server->vol.gi->players[playerNum].isLocal ) {
engine = engine_make( MPPARM(server->mpool)
server->vol.util,
server->vol.gi->players[playerNum].isRobot );
server->vol.util );
player->engine = engine;
}
@ -1542,7 +1494,7 @@ fetchTiles( ServerCtxt* server, XP_U16 playerNum, XP_U16 nToFetch,
XP_ASSERT( !!pool );
#ifdef FEATURE_TRAY_EDIT
ask = server->vol.gi->allowPickTiles
&& !server->vol.gi->players[playerNum].isRobot;
&& !LP_IS_ROBOT(&server->vol.gi->players[playerNum]);
#else
ask = XP_FALSE;
#endif
@ -2060,7 +2012,7 @@ server_commitMove( ServerCtxt* server )
XP_Bool isClient = gi->serverRole == SERVER_ISCLIENT;
#ifdef DEBUG
if ( IS_ROBOT( &gi->players[turn] ) ) {
if ( LP_IS_ROBOT( &gi->players[turn] ) ) {
XP_ASSERT( model_checkMoveLegal( model, turn, (XWStreamCtxt*)NULL,
(WordNotifierInfo*)NULL ) );
}
@ -2388,7 +2340,7 @@ server_handleUndo( ServerCtxt* server )
++nUndone;
XP_ASSERT( moveNum >= 0 );
lastUndone = moveNum;
if ( !IS_ROBOT(&gi->players[lastTurnUndone]) ) {
if ( !LP_IS_ROBOT(&gi->players[lastTurnUndone]) ) {
break;
}
}