mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2025-01-13 08:01:33 +01:00
Merge branch 'android_branch' into android_bt
This commit is contained in:
commit
d59b19514b
16 changed files with 418 additions and 233 deletions
|
@ -198,6 +198,7 @@ typedef struct CommonPrefs {
|
|||
XP_Bool sortNewTiles; /* applies to all games */
|
||||
#ifdef XWFEATURE_SLOW_ROBOT
|
||||
XP_U16 robotThinkMin, robotThinkMax;
|
||||
XP_U16 robotTradePct;
|
||||
#endif
|
||||
XP_Bool showColors; /* applies to all games */
|
||||
XP_Bool allowPeek; /* applies to all games */
|
||||
|
|
|
@ -250,7 +250,7 @@ putOneBit( MemStreamCtxt* stream, XP_U16 bit )
|
|||
if ( stream->curWritePos == stream->nBytesWritten ) {
|
||||
stream_putU8( (XWStreamCtxt*)stream, 0 ); /* increments curPos */
|
||||
} else {
|
||||
++stream->curWritePos;
|
||||
stream->buf[stream->curWritePos++] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -71,6 +71,8 @@ static void buildModelFromStack( ModelCtxt* model, StackCtxt* stack,
|
|||
MovePrintFuncPre mpfpr,
|
||||
MovePrintFuncPost mpfpo, void* closure );
|
||||
static void setPendingCounts( ModelCtxt* model, XP_S16 turn );
|
||||
static XP_S16 setContains( const TrayTileSet* tiles, Tile tile );
|
||||
static void removeTile( TrayTileSet* tiles, XP_U16 index );
|
||||
static void loadPlayerCtxt( const ModelCtxt* model, XWStreamCtxt* stream,
|
||||
XP_U16 version, PlayerCtxt* pc );
|
||||
static void writePlayerCtxt( const ModelCtxt* model, XWStreamCtxt* stream,
|
||||
|
@ -290,6 +292,13 @@ model_destroy( ModelCtxt* model )
|
|||
XP_FREE( model->vol.mpool, model );
|
||||
} /* model_destroy */
|
||||
|
||||
XP_U32
|
||||
model_getHash( const ModelCtxt* model )
|
||||
{
|
||||
XP_ASSERT( !!model->vol.stack );
|
||||
return stack_getHash( model->vol.stack );
|
||||
}
|
||||
|
||||
#ifdef STREAM_VERS_BIGBOARD
|
||||
void
|
||||
model_setSquareBonuses( ModelCtxt* model, XWBonusType* bonuses, XP_U16 nBonuses )
|
||||
|
@ -787,39 +796,31 @@ model_undoLatestMoves( ModelCtxt* model, PoolContext* pool,
|
|||
XP_U16 nMovesSought, XP_U16* turnP, XP_S16* moveNumP )
|
||||
{
|
||||
StackCtxt* stack = model->vol.stack;
|
||||
StackEntry entry;
|
||||
XP_U16 turn = 0;
|
||||
Tile blankTile = dict_getBlankTile( model_getDictionary(model) );
|
||||
XP_Bool success = XP_TRUE;
|
||||
XP_Bool success;
|
||||
XP_S16 moveSought = !!moveNumP ? *moveNumP : -1;
|
||||
XP_U16 nMovesUndone;
|
||||
XP_U16 nStackEntries;
|
||||
XP_U16 nStackEntries = stack_getNEntries( stack );
|
||||
|
||||
nStackEntries = stack_getNEntries( stack );
|
||||
if ( nStackEntries < nMovesSought ) {
|
||||
return XP_FALSE;
|
||||
} else if ( nStackEntries <= model->nPlayers ) {
|
||||
return XP_FALSE;
|
||||
}
|
||||
if ( (0 <= moveSought && moveSought >= nStackEntries)
|
||||
|| ( nStackEntries < nMovesSought )
|
||||
|| ( nStackEntries <= model->nPlayers ) ) {
|
||||
success = XP_FALSE;
|
||||
} else {
|
||||
XP_U16 nMovesUndone = 0;
|
||||
XP_U16 turn;
|
||||
StackEntry entry;
|
||||
Tile blankTile = dict_getBlankTile( model_getDictionary(model) );
|
||||
|
||||
for ( nMovesUndone = 0; success && nMovesUndone < nMovesSought; ) {
|
||||
|
||||
success = stack_popEntry( stack, &entry );
|
||||
if ( success ) {
|
||||
++nMovesUndone;
|
||||
|
||||
if ( moveSought < 0 ) {
|
||||
moveSought = entry.moveNum - 1;
|
||||
} else if ( moveSought-- != entry.moveNum ) {
|
||||
success = XP_FALSE;
|
||||
for ( ; ; ) {
|
||||
success = stack_popEntry( stack, &entry );
|
||||
if ( !success ) {
|
||||
break;
|
||||
}
|
||||
++nMovesUndone;
|
||||
|
||||
turn = entry.playerNum;
|
||||
model_resetCurrentTurn( model, turn );
|
||||
|
||||
if ( entry.moveType == MOVE_TYPE ) {
|
||||
|
||||
/* get the tiles out of player's tray and back into the
|
||||
pool */
|
||||
replaceNewTiles( model, pool, turn, &entry.u.move.newTiles);
|
||||
|
@ -839,73 +840,87 @@ model_undoLatestMoves( ModelCtxt* model, PoolContext* pool,
|
|||
}
|
||||
|
||||
} else if ( entry.moveType == PHONY_TYPE ) {
|
||||
|
||||
/* nothing to do, since nothing happened */
|
||||
|
||||
} else {
|
||||
XP_ASSERT( entry.moveType == ASSIGN_TYPE );
|
||||
success = XP_FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Find the first MOVE still on the stack and highlight its tiles since
|
||||
they're now the most recent move. Trades and lost turns ignored. */
|
||||
nStackEntries = stack_getNEntries( stack );
|
||||
for ( ; ; ) {
|
||||
StackEntry entry;
|
||||
if ( nStackEntries == 0 ||
|
||||
!stack_getNthEntry( stack, nStackEntries - 1, &entry ) ) {
|
||||
break;
|
||||
}
|
||||
if ( entry.moveType == MOVE_TYPE ) {
|
||||
XP_U16 nTiles = entry.u.move.moveInfo.nTiles;
|
||||
XP_U16 col, row;
|
||||
XP_U16* varies;
|
||||
|
||||
if ( entry.u.move.moveInfo.isHorizontal ) {
|
||||
row = entry.u.move.moveInfo.commonCoord;
|
||||
varies = &col;
|
||||
} else {
|
||||
col = entry.u.move.moveInfo.commonCoord;
|
||||
varies = &row;
|
||||
/* exit if we've undone what we're supposed to. If the sought
|
||||
stack height has been provided, use that. Otherwise go by move
|
||||
count. */
|
||||
if ( 0 <= moveSought ) {
|
||||
if ( moveSought == entry.moveNum ) {
|
||||
break;
|
||||
}
|
||||
} else if ( nMovesSought == nMovesUndone ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while ( nTiles-- ) {
|
||||
CellTile tile;
|
||||
|
||||
*varies = entry.u.move.moveInfo.tiles[nTiles].varCoord;
|
||||
tile = getModelTileRaw( model, col, row );
|
||||
setModelTileRaw( model, col, row,
|
||||
(CellTile)(tile | PREV_MOVE_BIT) );
|
||||
notifyBoardListeners( model, entry.playerNum, col, row,
|
||||
XP_FALSE );
|
||||
/* Find the first MOVE still on the stack and highlight its tiles since
|
||||
they're now the most recent move. Trades and lost turns ignored. */
|
||||
for ( nStackEntries = stack_getNEntries( stack );
|
||||
0 < nStackEntries; --nStackEntries ) {
|
||||
StackEntry entry;
|
||||
if ( !stack_getNthEntry( stack, nStackEntries - 1, &entry ) ) {
|
||||
break;
|
||||
}
|
||||
if ( entry.moveType == ASSIGN_TYPE ) {
|
||||
break;
|
||||
} else if ( entry.moveType == MOVE_TYPE ) {
|
||||
XP_U16 nTiles = entry.u.move.moveInfo.nTiles;
|
||||
XP_U16 col, row;
|
||||
XP_U16* varies;
|
||||
|
||||
if ( entry.u.move.moveInfo.isHorizontal ) {
|
||||
row = entry.u.move.moveInfo.commonCoord;
|
||||
varies = &col;
|
||||
} else {
|
||||
col = entry.u.move.moveInfo.commonCoord;
|
||||
varies = &row;
|
||||
}
|
||||
|
||||
while ( nTiles-- ) {
|
||||
CellTile tile;
|
||||
|
||||
*varies = entry.u.move.moveInfo.tiles[nTiles].varCoord;
|
||||
tile = getModelTileRaw( model, col, row );
|
||||
setModelTileRaw( model, col, row,
|
||||
(CellTile)(tile | PREV_MOVE_BIT) );
|
||||
notifyBoardListeners( model, entry.playerNum, col, row,
|
||||
XP_FALSE );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* We fail if we didn't undo as many as requested UNLESS the lower
|
||||
limit is the trumping target/test. */
|
||||
if ( 0 <= moveSought ) {
|
||||
if ( moveSought != entry.moveNum ) {
|
||||
success = XP_FALSE;
|
||||
}
|
||||
break;
|
||||
} else if ( entry.moveType == ASSIGN_TYPE ) {
|
||||
break;
|
||||
} else {
|
||||
--nStackEntries; /* look at the next one */
|
||||
if ( nMovesUndone != nMovesSought ) {
|
||||
success = XP_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( nMovesUndone != nMovesSought ) {
|
||||
success = XP_FALSE;
|
||||
}
|
||||
|
||||
if ( success ) {
|
||||
if ( !!turnP ) {
|
||||
*turnP = turn;
|
||||
}
|
||||
if ( !!moveNumP ) {
|
||||
*moveNumP = entry.moveNum;
|
||||
}
|
||||
} else {
|
||||
while ( nMovesUndone-- ) {
|
||||
/* undo isn't enough here: pool's got tiles in it!! */
|
||||
XP_ASSERT( 0 );
|
||||
(void)stack_redo( stack, NULL );
|
||||
if ( success ) {
|
||||
if ( !!turnP ) {
|
||||
*turnP = turn;
|
||||
}
|
||||
if ( !!moveNumP ) {
|
||||
*moveNumP = entry.moveNum;
|
||||
}
|
||||
} else {
|
||||
while ( nMovesUndone-- ) {
|
||||
/* redo isn't enough here: pool's got tiles in it!! */
|
||||
XP_ASSERT( 0 );
|
||||
(void)stack_redo( stack, NULL );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -963,10 +978,11 @@ model_currentMoveToStream( ModelCtxt* model, XP_S16 turn,
|
|||
* assert that it's in the tray, remove it from the tray, and place it on the
|
||||
* board.
|
||||
*/
|
||||
void
|
||||
XP_Bool
|
||||
model_makeTurnFromStream( ModelCtxt* model, XP_U16 playerNum,
|
||||
XWStreamCtxt* stream )
|
||||
{
|
||||
XP_Bool success = XP_TRUE;
|
||||
XP_U16 numTiles, ii;
|
||||
Tile blank = dict_getBlankTile( model_getDictionary(model) );
|
||||
XP_U16 nColsNBits;
|
||||
|
@ -978,40 +994,57 @@ model_makeTurnFromStream( ModelCtxt* model, XP_U16 playerNum,
|
|||
#endif
|
||||
|
||||
model_resetCurrentTurn( model, playerNum );
|
||||
if ( success ) {
|
||||
numTiles = (XP_U16)stream_getBits( stream, NTILES_NBITS );
|
||||
|
||||
numTiles = (XP_U16)stream_getBits( stream, NTILES_NBITS );
|
||||
XP_LOGF( "%s: numTiles=%d", __func__, numTiles );
|
||||
|
||||
XP_LOGF( "%s: numTiles=%d", __func__, numTiles );
|
||||
Tile tileFaces[numTiles];
|
||||
XP_U16 cols[numTiles];
|
||||
XP_U16 rows[numTiles];
|
||||
XP_Bool isBlanks[numTiles];
|
||||
Tile moveTiles[numTiles];
|
||||
TrayTileSet curTiles = *model_getPlayerTiles( model, playerNum );
|
||||
|
||||
for ( ii = 0; ii < numTiles; ++ii ) {
|
||||
XP_S16 foundAt;
|
||||
Tile moveTile;
|
||||
Tile tileFace = (Tile)stream_getBits( stream, TILE_NBITS );
|
||||
XP_U16 col = (XP_U16)stream_getBits( stream, nColsNBits );
|
||||
XP_U16 row = (XP_U16)stream_getBits( stream, nColsNBits );
|
||||
XP_Bool isBlank = stream_getBits( stream, 1 );
|
||||
for ( ii = 0; success && ii < numTiles; ++ii ) {
|
||||
tileFaces[ii] = (Tile)stream_getBits( stream, TILE_NBITS );
|
||||
cols[ii] = (XP_U16)stream_getBits( stream, nColsNBits );
|
||||
rows[ii] = (XP_U16)stream_getBits( stream, nColsNBits );
|
||||
isBlanks[ii] = stream_getBits( stream, 1 );
|
||||
|
||||
/* This code gets called both for the server, which has all the
|
||||
tiles in its tray, and for a client, which has "EMPTY" tiles
|
||||
only. If it's the empty case, we stuff a real tile into the
|
||||
tray before falling through to the normal case */
|
||||
if ( isBlanks[ii] ) {
|
||||
moveTiles[ii] = blank;
|
||||
} else {
|
||||
moveTiles[ii] = tileFaces[ii];
|
||||
}
|
||||
|
||||
if ( isBlank ) {
|
||||
moveTile = blank;
|
||||
} else {
|
||||
moveTile = tileFace;
|
||||
XP_S16 index = setContains( &curTiles, moveTiles[ii] );
|
||||
if ( 0 <= index ) {
|
||||
removeTile( &curTiles, index );
|
||||
} else {
|
||||
success = XP_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
foundAt = model_trayContains( model, playerNum, moveTile );
|
||||
if ( foundAt == -1 ) {
|
||||
XP_ASSERT( EMPTY_TILE == model_getPlayerTile(model, playerNum, 0));
|
||||
if ( success ) {
|
||||
for ( ii = 0; ii < numTiles; ++ii ) {
|
||||
XP_S16 foundAt = model_trayContains( model, playerNum, moveTiles[ii] );
|
||||
if ( foundAt == -1 ) {
|
||||
XP_ASSERT( EMPTY_TILE == model_getPlayerTile(model, playerNum,
|
||||
0));
|
||||
/* Does this ever happen? */
|
||||
XP_LOGF( "%s: found empty tile and it's ok", __func__ );
|
||||
|
||||
(void)model_removePlayerTile( model, playerNum, -1 );
|
||||
model_addPlayerTile( model, playerNum, -1, moveTile );
|
||||
(void)model_removePlayerTile( model, playerNum, -1 );
|
||||
model_addPlayerTile( model, playerNum, -1, moveTiles[ii] );
|
||||
}
|
||||
|
||||
model_moveTrayToBoard( model, playerNum, cols[ii], rows[ii], foundAt,
|
||||
tileFaces[ii] );
|
||||
}
|
||||
}
|
||||
|
||||
model_moveTrayToBoard( model, playerNum, col, row, foundAt, tileFace );
|
||||
}
|
||||
return success;
|
||||
} /* model_makeTurnFromStream */
|
||||
|
||||
void
|
||||
|
@ -1090,25 +1123,11 @@ model_countAllTrayTiles( ModelCtxt* model, XP_U16* counts,
|
|||
XP_S16
|
||||
model_trayContains( ModelCtxt* model, XP_S16 turn, Tile tile )
|
||||
{
|
||||
PlayerCtxt* player;
|
||||
XP_S16 i;
|
||||
XP_S16 result = -1;
|
||||
|
||||
XP_ASSERT( turn >= 0 );
|
||||
XP_ASSERT( turn < model->nPlayers );
|
||||
|
||||
player = &model->players[turn];
|
||||
|
||||
/* search from top down so don't pull out of below divider */
|
||||
for ( i = player->trayTiles.nTiles - 1; i >= 0 ; --i ) {
|
||||
Tile playerTile = player->trayTiles.tiles[i];
|
||||
if ( playerTile == tile ) {
|
||||
result = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
const TrayTileSet* tiles = model_getPlayerTiles( model, turn );
|
||||
return setContains( tiles, tile );
|
||||
} /* model_trayContains */
|
||||
|
||||
XP_U16
|
||||
|
@ -1531,7 +1550,7 @@ commitTurn( ModelCtxt* model, XP_S16 turn, const TrayTileSet* newTiles,
|
|||
XP_U16 ii;
|
||||
PlayerCtxt* player;
|
||||
PendingTile* pt;
|
||||
XP_S16 score;
|
||||
XP_S16 score = -1;
|
||||
XP_Bool inLine, isHorizontal;
|
||||
const Tile* newTilesP;
|
||||
XP_U16 nTiles;
|
||||
|
@ -1551,7 +1570,7 @@ commitTurn( ModelCtxt* model, XP_S16 turn, const TrayTileSet* newTiles,
|
|||
player = &model->players[turn];
|
||||
|
||||
if ( useStack ) {
|
||||
MoveInfo moveInfo;
|
||||
MoveInfo moveInfo = {0};
|
||||
inLine = tilesInLine( model, turn, &isHorizontal );
|
||||
XP_ASSERT( inLine );
|
||||
normalizeMoves( model, turn, isHorizontal, &moveInfo );
|
||||
|
@ -1603,15 +1622,14 @@ commitTurn( ModelCtxt* model, XP_S16 turn, const TrayTileSet* newTiles,
|
|||
while ( nTiles-- ) {
|
||||
model_addPlayerTile( model, turn, -1, *newTilesP++ );
|
||||
}
|
||||
|
||||
return score;
|
||||
} /* commitTurn */
|
||||
|
||||
void
|
||||
XP_Bool
|
||||
model_commitTurn( ModelCtxt* model, XP_S16 turn, TrayTileSet* newTiles )
|
||||
{
|
||||
(void)commitTurn( model, turn, newTiles, (XWStreamCtxt*)NULL,
|
||||
(WordNotifierInfo*)NULL, XP_TRUE );
|
||||
XP_S16 score = commitTurn( model, turn, newTiles, NULL, NULL, XP_TRUE );
|
||||
return 0 <= score;
|
||||
} /* model_commitTurn */
|
||||
|
||||
/* Given a rack of new tiles and of old, remove all the old from the tray and
|
||||
|
@ -2316,7 +2334,7 @@ model_getPlayersLastScore( ModelCtxt* model, XP_S16 player,
|
|||
switch ( entry.moveType ) {
|
||||
case MOVE_TYPE:
|
||||
scoreLastMove( model, &entry.u.move.moveInfo,
|
||||
nEntries - which - 1, expl, explLen );
|
||||
nEntries - which, expl, explLen );
|
||||
break;
|
||||
case TRADE_TYPE:
|
||||
nTiles = entry.u.trade.oldTiles.nTiles;
|
||||
|
@ -2405,6 +2423,32 @@ writePlayerCtxt( const ModelCtxt* model, XWStreamCtxt* stream,
|
|||
}
|
||||
} /* writePlayerCtxt */
|
||||
|
||||
static void
|
||||
removeTile( TrayTileSet* tiles, XP_U16 index )
|
||||
{
|
||||
XP_U16 ii;
|
||||
--tiles->nTiles;
|
||||
for ( ii = index; ii < tiles->nTiles; ++ii ) {
|
||||
tiles->tiles[ii] = tiles->tiles[ii+1];
|
||||
}
|
||||
}
|
||||
|
||||
static XP_S16
|
||||
setContains( const TrayTileSet* tiles, Tile tile )
|
||||
{
|
||||
XP_S16 result = -1;
|
||||
XP_S16 ii;
|
||||
/* search from top down so don't pull out of below divider */
|
||||
for ( ii = tiles->nTiles - 1; ii >= 0 ; --ii ) {
|
||||
Tile playerTile = tiles->tiles[ii];
|
||||
if ( playerTile == tile ) {
|
||||
result = ii;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef CPLUS
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -114,6 +114,7 @@ void model_writeToTextStream( const ModelCtxt* model, XWStreamCtxt* stream );
|
|||
|
||||
void model_setSize( ModelCtxt* model, XP_U16 boardSize );
|
||||
void model_destroy( ModelCtxt* model );
|
||||
XP_U32 model_getHash( const ModelCtxt* model );
|
||||
void model_setNPlayers( ModelCtxt* model, XP_U16 numPlayers );
|
||||
XP_U16 model_getNPlayers( const ModelCtxt* model );
|
||||
|
||||
|
@ -181,8 +182,8 @@ void model_getCurrentMoveTile( ModelCtxt* model, XP_S16 turn, XP_S16* index,
|
|||
Tile* tile, XP_U16* col, XP_U16* row,
|
||||
XP_Bool* isBlank );
|
||||
|
||||
void model_commitTurn( ModelCtxt* model, XP_S16 player,
|
||||
TrayTileSet* newTiles );
|
||||
XP_Bool model_commitTurn( ModelCtxt* model, XP_S16 player,
|
||||
TrayTileSet* newTiles );
|
||||
void model_commitRejectedPhony( ModelCtxt* model, XP_S16 player );
|
||||
void model_makeTileTrade( ModelCtxt* model, XP_S16 player,
|
||||
const TrayTileSet* oldTiles,
|
||||
|
@ -198,8 +199,8 @@ void model_trayToStream( ModelCtxt* model, XP_S16 turn,
|
|||
XWStreamCtxt* stream );
|
||||
void model_currentMoveToStream( ModelCtxt* model, XP_S16 turn,
|
||||
XWStreamCtxt* stream);
|
||||
void model_makeTurnFromStream( ModelCtxt* model, XP_U16 playerNum,
|
||||
XWStreamCtxt* stream );
|
||||
XP_Bool model_makeTurnFromStream( ModelCtxt* model, XP_U16 playerNum,
|
||||
XWStreamCtxt* stream );
|
||||
void model_makeTurnFromMoveInfo( ModelCtxt* model, XP_U16 playerNum,
|
||||
const MoveInfo* newMove );
|
||||
|
||||
|
|
|
@ -57,6 +57,68 @@ stack_init( StackCtxt* stack )
|
|||
shrunk to fit as soon as we serialize/deserialize anyway. */
|
||||
} /* stack_init */
|
||||
|
||||
#ifdef STREAM_VERS_BIGBOARD
|
||||
static XP_U32
|
||||
augmentHash( XP_U32 hash, XP_U8* ptr, XP_U16 len )
|
||||
{
|
||||
XP_ASSERT( 0 < len );
|
||||
// see http://en.wikipedia.org/wiki/Jenkins_hash_function
|
||||
XP_U16 ii;
|
||||
for ( ii = 0; ii < len; ++ii ) {
|
||||
hash += *ptr++;
|
||||
hash += (hash << 10);
|
||||
hash ^= (hash >> 6);
|
||||
}
|
||||
hash += (hash << 3);
|
||||
hash ^= (hash >> 11);
|
||||
hash += (hash << 15);
|
||||
return hash;
|
||||
}
|
||||
|
||||
static XP_U32
|
||||
augmentFor( XP_U32 hash, const StackEntry* entry )
|
||||
{
|
||||
switch( entry->moveType ) {
|
||||
case ASSIGN_TYPE:
|
||||
hash = augmentHash( hash, (XP_U8*)&entry->u.assign,
|
||||
sizeof(entry->u.assign) );
|
||||
break;
|
||||
case MOVE_TYPE:
|
||||
hash = augmentHash( hash, (XP_U8*)&entry->u.move,
|
||||
sizeof(entry->u.move) );
|
||||
break;
|
||||
case TRADE_TYPE:
|
||||
hash = augmentHash( hash, (XP_U8*)&entry->u.trade,
|
||||
sizeof(entry->u.trade) );
|
||||
break;
|
||||
case PHONY_TYPE:
|
||||
hash = augmentHash( hash, (XP_U8*)&entry->u.phony,
|
||||
sizeof(entry->u.phony) );
|
||||
break;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
XP_U32
|
||||
stack_getHash( StackCtxt* stack )
|
||||
{
|
||||
XP_U32 hash = 0L;
|
||||
XP_U16 nn, nEntries = stack->nEntries;
|
||||
for ( nn = 0; nn < nEntries; ++nn ) {
|
||||
StackEntry entry;
|
||||
XP_MEMSET( &entry, 0, sizeof(entry) );
|
||||
if ( !stack_getNthEntry( stack, nn, &entry ) ) {
|
||||
XP_ASSERT( 0 );
|
||||
}
|
||||
hash = augmentFor( hash, &entry );
|
||||
// XP_LOGF( "hash after %d: %.8X", nn, (unsigned int)hash );
|
||||
}
|
||||
XP_ASSERT( 0 != hash );
|
||||
// LOG_RETURNF( "%.8X", (unsigned int)hash );
|
||||
return hash;
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
stack_setBitsPerTile( StackCtxt* stack, XP_U16 bitsPerTile )
|
||||
{
|
||||
|
|
|
@ -69,6 +69,7 @@ StackCtxt* stack_make( MPFORMAL VTableMgr* vtmgr );
|
|||
void stack_destroy( StackCtxt* stack );
|
||||
|
||||
void stack_init( StackCtxt* stack );
|
||||
XP_U32 stack_getHash( StackCtxt* stack );
|
||||
void stack_setBitsPerTile( StackCtxt* stack, XP_U16 bitsPerTile );
|
||||
|
||||
void stack_loadFromStream( StackCtxt* stack, XWStreamCtxt* stream );
|
||||
|
|
|
@ -280,7 +280,7 @@ void
|
|||
normalizeMoves( ModelCtxt* model, XP_S16 turn, XP_Bool isHorizontal,
|
||||
MoveInfo* moveInfo )
|
||||
{
|
||||
XP_S16 lowCol, i, j, thisCol; /* unsigned is a problem on palm */
|
||||
XP_S16 lowCol, ii, jj, thisCol; /* unsigned is a problem on palm */
|
||||
PlayerCtxt* player = &model->players[turn];
|
||||
XP_U16 nTiles = player->nPending;
|
||||
XP_S16 lastTaken;
|
||||
|
@ -291,27 +291,29 @@ normalizeMoves( ModelCtxt* model, XP_S16 turn, XP_Bool isHorizontal,
|
|||
moveInfo->nTiles = (XP_U8)nTiles;
|
||||
|
||||
lastTaken = -1;
|
||||
for ( i = 0; i < nTiles; ++i ) {
|
||||
for ( ii = 0; ii < nTiles; ++ii ) {
|
||||
lowCol = 100; /* high enough to always be changed */
|
||||
for ( j = 0; j < nTiles; ++j ) {
|
||||
pt = &player->pendingTiles[j];
|
||||
for ( jj = 0; jj < nTiles; ++jj ) {
|
||||
pt = &player->pendingTiles[jj];
|
||||
thisCol = isHorizontal? pt->col:pt->row;
|
||||
if (thisCol < lowCol && thisCol > lastTaken ) {
|
||||
lowCol = thisCol;
|
||||
lowIndex = j;
|
||||
lowIndex = jj;
|
||||
}
|
||||
}
|
||||
/* we've found the next to transfer (4 bytes smaller without a temp
|
||||
local ptr. */
|
||||
pt = &player->pendingTiles[lowIndex];
|
||||
lastTaken = lowCol;
|
||||
moveInfo->tiles[i].varCoord = (XP_U8)lastTaken;
|
||||
moveInfo->tiles[ii].varCoord = (XP_U8)lastTaken;
|
||||
|
||||
moveInfo->tiles[i].tile = pt->tile;
|
||||
moveInfo->tiles[ii].tile = pt->tile;
|
||||
}
|
||||
|
||||
pt = &player->pendingTiles[0];
|
||||
moveInfo->commonCoord = isHorizontal? pt->row:pt->col;
|
||||
if ( 0 < nTiles ) {
|
||||
pt = &player->pendingTiles[0];
|
||||
moveInfo->commonCoord = isHorizontal? pt->row:pt->col;
|
||||
}
|
||||
} /* normalizeMoves */
|
||||
|
||||
static XP_Bool
|
||||
|
|
|
@ -208,6 +208,22 @@ pool_removeTiles( PoolContext* pool, const TrayTileSet* tiles )
|
|||
XP_LOGF( "%s: %d tiles left in pool", __func__, pool->numTilesLeft );
|
||||
} /* pool_removeTiles */
|
||||
|
||||
XP_Bool
|
||||
pool_containsTiles( const PoolContext* pool, const TrayTileSet* tiles )
|
||||
{
|
||||
XP_Bool allThere = XP_TRUE;
|
||||
XP_U16 ii;
|
||||
XP_U8 counts[pool->numFaces];
|
||||
XP_MEMCPY( counts, pool->lettersLeft, sizeof(counts) );
|
||||
|
||||
/* In case we have duplicates, make count of each type */
|
||||
for ( ii = 0; allThere && ii < tiles->nTiles; ++ii ) {
|
||||
allThere = 0 < counts[tiles->tiles[ii]]--;
|
||||
}
|
||||
|
||||
return allThere;
|
||||
}
|
||||
|
||||
XP_U16
|
||||
pool_getNTilesLeft( PoolContext* pool )
|
||||
{
|
||||
|
|
|
@ -28,6 +28,8 @@ void pool_requestTiles( PoolContext* pool, Tile* tiles,
|
|||
/*in out*/ XP_U8* maxNum );
|
||||
void pool_replaceTiles( PoolContext* pool, const TrayTileSet* tiles );
|
||||
void pool_removeTiles( PoolContext* pool, const TrayTileSet* tiles );
|
||||
XP_Bool pool_containsTiles( const PoolContext* pool,
|
||||
const TrayTileSet* tiles );
|
||||
|
||||
XP_U16 pool_getNTilesLeft( PoolContext* pool );
|
||||
XP_U16 pool_getNTilesLeftFor( PoolContext* pool, Tile tile );
|
||||
|
|
|
@ -92,6 +92,7 @@ typedef struct ServerNonvolatiles {
|
|||
#endif
|
||||
#ifdef XWFEATURE_SLOW_ROBOT
|
||||
XP_U16 robotThinkMin, robotThinkMax; /* not saved (yet) */
|
||||
XP_U16 robotTradePct;
|
||||
#endif
|
||||
|
||||
RemoteAddress addresses[MAX_NUM_PLAYERS];
|
||||
|
@ -516,6 +517,7 @@ server_prefsChanged( ServerCtxt* server, CommonPrefs* cp )
|
|||
#ifdef XWFEATURE_SLOW_ROBOT
|
||||
server->nv.robotThinkMin = cp->robotThinkMin;
|
||||
server->nv.robotThinkMax = cp->robotThinkMax;
|
||||
server->nv.robotTradePct = cp->robotTradePct;
|
||||
#endif
|
||||
} /* server_prefsChanged */
|
||||
|
||||
|
@ -784,11 +786,20 @@ makeRobotMove( ServerCtxt* server )
|
|||
XP_Bool canMove;
|
||||
XP_U32 time = 0L; /* stupid compiler.... */
|
||||
XW_UtilCtxt* util = server->vol.util;
|
||||
XP_Bool forceTrade = XP_FALSE;
|
||||
|
||||
if ( timerEnabled ) {
|
||||
time = util_getCurSeconds( util );
|
||||
}
|
||||
|
||||
#ifdef XWFEATURE_SLOW_ROBOT
|
||||
if ( 0 != server->nv.robotTradePct
|
||||
&& (server_countTilesInPool( server ) >= MAX_TRAY_TILES) ) {
|
||||
XP_U16 pct = XP_RANDOM() % 100;
|
||||
forceTrade = pct < server->nv.robotTradePct ;
|
||||
}
|
||||
#endif
|
||||
|
||||
turn = server->nv.currentTurn;
|
||||
XP_ASSERT( turn >= 0 );
|
||||
|
||||
|
@ -798,23 +809,26 @@ makeRobotMove( ServerCtxt* server )
|
|||
paranoid. PENDING(ehouse) */
|
||||
model_resetCurrentTurn( model, turn );
|
||||
|
||||
tileSet = model_getPlayerTiles( model, turn );
|
||||
if ( !forceTrade ) {
|
||||
tileSet = model_getPlayerTiles( model, turn );
|
||||
|
||||
XP_ASSERT( !!server_getEngineFor( server, turn ) );
|
||||
searchComplete = engine_findMove( server_getEngineFor( server, turn ),
|
||||
model, turn, tileSet->tiles,
|
||||
tileSet->nTiles, XP_FALSE,
|
||||
XP_ASSERT( !!server_getEngineFor( server, turn ) );
|
||||
searchComplete = engine_findMove( server_getEngineFor( server, turn ),
|
||||
model, turn, tileSet->tiles,
|
||||
tileSet->nTiles, XP_FALSE,
|
||||
#ifdef XWFEATURE_SEARCHLIMIT
|
||||
NULL, XP_FALSE,
|
||||
NULL, XP_FALSE,
|
||||
#endif
|
||||
server->vol.gi->players[turn].robotIQ,
|
||||
&canMove, &newMove );
|
||||
if ( searchComplete ) {
|
||||
server->vol.gi->players[turn].robotIQ,
|
||||
&canMove, &newMove );
|
||||
}
|
||||
if ( forceTrade || searchComplete ) {
|
||||
const XP_UCHAR* str;
|
||||
XWStreamCtxt* stream = NULL;
|
||||
|
||||
XP_Bool trade = (newMove.nTiles == 0) && canMove &&
|
||||
(server_countTilesInPool( server ) >= MAX_TRAY_TILES);
|
||||
XP_Bool trade = forceTrade ||
|
||||
((newMove.nTiles == 0) && canMove &&
|
||||
(server_countTilesInPool( server ) >= MAX_TRAY_TILES));
|
||||
|
||||
server->vol.showPrevMove = XP_TRUE;
|
||||
if ( server->nv.showRobotScores ) {
|
||||
|
@ -1891,6 +1905,14 @@ sendMoveTo( ServerCtxt* server, XP_U16 devIndex, XP_U16 turn,
|
|||
|
||||
stream = messageStreamWithHeader( server, devIndex, code );
|
||||
|
||||
#ifdef STREAM_VERS_BIGBOARD
|
||||
if ( STREAM_VERS_BIGBOARD <= stream_getVersion( stream ) ) {
|
||||
XP_U32 hash = model_getHash( server->vol.model );
|
||||
// XP_LOGF( "%s: adding hash %x", __func__, (unsigned int)hash );
|
||||
stream_putU32( stream, hash );
|
||||
}
|
||||
#endif
|
||||
|
||||
stream_putBits( stream, PLAYERNUM_NBITS, turn ); /* who made the move */
|
||||
|
||||
traySetToStream( stream, newTiles );
|
||||
|
@ -1923,34 +1945,53 @@ sendMoveTo( ServerCtxt* server, XP_U16 devIndex, XP_U16 turn,
|
|||
stream_destroy( stream );
|
||||
} /* sendMoveTo */
|
||||
|
||||
static void
|
||||
static XP_Bool
|
||||
readMoveInfo( ServerCtxt* server, XWStreamCtxt* stream,
|
||||
XP_U16* whoMovedP, XP_Bool* isTradeP,
|
||||
TrayTileSet* newTiles, TrayTileSet* tradedTiles,
|
||||
XP_Bool* legalP )
|
||||
{
|
||||
XP_U16 whoMoved = stream_getBits( stream, PLAYERNUM_NBITS );
|
||||
XP_Bool success = XP_TRUE;
|
||||
XP_Bool legalMove = XP_TRUE;
|
||||
XP_Bool isTrade;
|
||||
|
||||
traySetFromStream( stream, newTiles );
|
||||
isTrade = stream_getBits( stream, 1 );
|
||||
|
||||
if ( isTrade ) {
|
||||
traySetFromStream( stream, tradedTiles );
|
||||
XP_LOGF( "%s: got trade of %d tiles", __func__, tradedTiles->nTiles );
|
||||
} else {
|
||||
legalMove = stream_getBits( stream, 1 );
|
||||
model_makeTurnFromStream( server->vol.model, whoMoved, stream );
|
||||
|
||||
getPlayerTime( server, stream, whoMoved );
|
||||
#ifdef STREAM_VERS_BIGBOARD
|
||||
if ( STREAM_VERS_BIGBOARD <= stream_getVersion( stream ) ) {
|
||||
XP_U32 hashReceived = stream_getU32( stream );
|
||||
success = hashReceived == model_getHash( server->vol.model );
|
||||
if ( !success ) {
|
||||
XP_LOGF( "%s: hash mismatch: dropping move", __func__ );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if ( success ) {
|
||||
XP_U16 whoMoved = stream_getBits( stream, PLAYERNUM_NBITS );
|
||||
traySetFromStream( stream, newTiles );
|
||||
success = pool_containsTiles( server->pool, newTiles );
|
||||
if ( success ) {
|
||||
isTrade = stream_getBits( stream, 1 );
|
||||
|
||||
pool_removeTiles( server->pool, newTiles );
|
||||
if ( isTrade ) {
|
||||
traySetFromStream( stream, tradedTiles );
|
||||
XP_LOGF( "%s: got trade of %d tiles", __func__,
|
||||
tradedTiles->nTiles );
|
||||
} else {
|
||||
legalMove = stream_getBits( stream, 1 );
|
||||
success = model_makeTurnFromStream( server->vol.model,
|
||||
whoMoved, stream );
|
||||
getPlayerTime( server, stream, whoMoved );
|
||||
}
|
||||
|
||||
*whoMovedP = whoMoved;
|
||||
*isTradeP = isTrade;
|
||||
*legalP = legalMove;
|
||||
if ( success ) {
|
||||
pool_removeTiles( server->pool, newTiles );
|
||||
|
||||
*whoMovedP = whoMoved;
|
||||
*isTradeP = isTrade;
|
||||
*legalP = legalMove;
|
||||
}
|
||||
}
|
||||
}
|
||||
return success;
|
||||
} /* readMoveInfo */
|
||||
|
||||
static void
|
||||
|
@ -2006,6 +2047,7 @@ makeMoveReportIf( ServerCtxt* server, XWStreamCtxt** wordsStream )
|
|||
static XP_Bool
|
||||
reflectMoveAndInform( ServerCtxt* server, XWStreamCtxt* stream )
|
||||
{
|
||||
XP_Bool success;
|
||||
ModelCtxt* model = server->vol.model;
|
||||
XP_U16 whoMoved;
|
||||
XP_U16 nTilesMoved = 0; /* trade case */
|
||||
|
@ -2022,76 +2064,77 @@ reflectMoveAndInform( ServerCtxt* server, XWStreamCtxt* stream )
|
|||
|
||||
XP_ASSERT( gi->serverRole == SERVER_ISSERVER );
|
||||
|
||||
readMoveInfo( server, stream, &whoMoved, &isTrade, &newTiles,
|
||||
&tradedTiles, &isLegalMove ); /* modifies model */
|
||||
XP_ASSERT( isLegalMove ); /* client should always report as true */
|
||||
success = readMoveInfo( server, stream, &whoMoved, &isTrade, &newTiles,
|
||||
&tradedTiles, &isLegalMove ); /* modifies model */
|
||||
XP_ASSERT( !success || isLegalMove ); /* client should always report as true */
|
||||
isLegalMove = XP_TRUE;
|
||||
|
||||
if ( isTrade ) {
|
||||
if ( success ) {
|
||||
if ( isTrade ) {
|
||||
|
||||
sendMoveToClientsExcept( server, whoMoved, XP_TRUE, &newTiles,
|
||||
&tradedTiles, sourceClientIndex );
|
||||
sendMoveToClientsExcept( server, whoMoved, XP_TRUE, &newTiles,
|
||||
&tradedTiles, sourceClientIndex );
|
||||
|
||||
model_makeTileTrade( model, whoMoved,
|
||||
&tradedTiles, &newTiles );
|
||||
pool_replaceTiles( server->pool, &tradedTiles );
|
||||
model_makeTileTrade( model, whoMoved,
|
||||
&tradedTiles, &newTiles );
|
||||
pool_replaceTiles( server->pool, &tradedTiles );
|
||||
|
||||
server->vol.showPrevMove = XP_TRUE;
|
||||
mvStream = makeTradeReportIf( server, &tradedTiles );
|
||||
server->vol.showPrevMove = XP_TRUE;
|
||||
mvStream = makeTradeReportIf( server, &tradedTiles );
|
||||
|
||||
} else {
|
||||
nTilesMoved = model_getCurrentMoveCount( model, whoMoved );
|
||||
isLegalMove = (nTilesMoved == 0)
|
||||
|| checkMoveAllowed( server, whoMoved );
|
||||
|
||||
/* I don't think this will work if there are more than two devices in
|
||||
a palm game; need to change state and get out of here before
|
||||
returning to send additional messages. PENDING(ehouse) */
|
||||
sendMoveToClientsExcept( server, whoMoved, isLegalMove, &newTiles,
|
||||
(TrayTileSet*)NULL, sourceClientIndex );
|
||||
|
||||
server->vol.showPrevMove = XP_TRUE;
|
||||
mvStream = makeMoveReportIf( server, &wordsStream );
|
||||
|
||||
model_commitTurn( model, whoMoved, &newTiles );
|
||||
resetEngines( server );
|
||||
}
|
||||
|
||||
if ( isLegalMove ) {
|
||||
XP_U16 nTilesLeft = model_getNumTilesTotal( model, whoMoved );
|
||||
|
||||
if ( (gi->phoniesAction == PHONIES_DISALLOW) && (nTilesMoved > 0) ) {
|
||||
server->lastMoveSource = sourceClientIndex;
|
||||
SETSTATE( server, XWSTATE_MOVE_CONFIRM_MUSTSEND );
|
||||
doRequest = XP_TRUE;
|
||||
} else if ( nTilesLeft > 0 ) {
|
||||
nextTurn( server, PICK_NEXT );
|
||||
} else {
|
||||
SETSTATE(server, XWSTATE_NEEDSEND_ENDGAME );
|
||||
nTilesMoved = model_getCurrentMoveCount( model, whoMoved );
|
||||
isLegalMove = (nTilesMoved == 0)
|
||||
|| checkMoveAllowed( server, whoMoved );
|
||||
|
||||
/* I don't think this will work if there are more than two devices in
|
||||
a palm game; need to change state and get out of here before
|
||||
returning to send additional messages. PENDING(ehouse) */
|
||||
sendMoveToClientsExcept( server, whoMoved, isLegalMove, &newTiles,
|
||||
(TrayTileSet*)NULL, sourceClientIndex );
|
||||
|
||||
server->vol.showPrevMove = XP_TRUE;
|
||||
mvStream = makeMoveReportIf( server, &wordsStream );
|
||||
|
||||
success = model_commitTurn( model, whoMoved, &newTiles );
|
||||
resetEngines( server );
|
||||
}
|
||||
|
||||
if ( success && isLegalMove ) {
|
||||
XP_U16 nTilesLeft = model_getNumTilesTotal( model, whoMoved );
|
||||
|
||||
if ( (gi->phoniesAction == PHONIES_DISALLOW) && (nTilesMoved > 0) ) {
|
||||
server->lastMoveSource = sourceClientIndex;
|
||||
SETSTATE( server, XWSTATE_MOVE_CONFIRM_MUSTSEND );
|
||||
doRequest = XP_TRUE;
|
||||
} else if ( nTilesLeft > 0 ) {
|
||||
nextTurn( server, PICK_NEXT );
|
||||
} else {
|
||||
SETSTATE(server, XWSTATE_NEEDSEND_ENDGAME );
|
||||
doRequest = XP_TRUE;
|
||||
}
|
||||
|
||||
if ( !!mvStream ) {
|
||||
XP_ASSERT( !server->nv.prevMoveStream );
|
||||
server->nv.prevMoveStream = mvStream;
|
||||
XP_ASSERT( !server->nv.prevWordsStream );
|
||||
server->nv.prevWordsStream = wordsStream;
|
||||
}
|
||||
} else {
|
||||
/* The client from which the move came still needs to be told. But we
|
||||
can't send a message now since we're burried in a message handler.
|
||||
(Palm, at least, won't manage.) So set up state to tell that
|
||||
client again in a minute. */
|
||||
SETSTATE( server, XWSTATE_NEEDSEND_BADWORD_INFO );
|
||||
server->lastMoveSource = sourceClientIndex;
|
||||
doRequest = XP_TRUE;
|
||||
}
|
||||
|
||||
if ( !!mvStream ) {
|
||||
XP_ASSERT( !server->nv.prevMoveStream );
|
||||
server->nv.prevMoveStream = mvStream;
|
||||
XP_ASSERT( !server->nv.prevWordsStream );
|
||||
server->nv.prevWordsStream = wordsStream;
|
||||
if ( doRequest ) {
|
||||
util_requestTime( server->vol.util );
|
||||
}
|
||||
} else {
|
||||
/* The client from which the move came still needs to be told. But we
|
||||
can't send a message now since we're burried in a message handler.
|
||||
(Palm, at least, won't manage.) So set up state to tell that
|
||||
client again in a minute. */
|
||||
SETSTATE( server, XWSTATE_NEEDSEND_BADWORD_INFO );
|
||||
server->lastMoveSource = sourceClientIndex;
|
||||
doRequest = XP_TRUE;
|
||||
}
|
||||
|
||||
if ( doRequest ) {
|
||||
util_requestTime( server->vol.util );
|
||||
}
|
||||
|
||||
return XP_TRUE;
|
||||
return success;
|
||||
} /* reflectMoveAndInform */
|
||||
|
||||
static XP_Bool
|
||||
|
@ -2110,9 +2153,10 @@ reflectMove( ServerCtxt* server, XWStreamCtxt* stream )
|
|||
moveOk = XWSTATE_INTURN == server->nv.gameState;
|
||||
XP_ASSERT( moveOk ); /* message permanently lost if dropped here! */
|
||||
if ( moveOk ) {
|
||||
readMoveInfo( server, stream, &whoMoved, &isTrade, &newTiles,
|
||||
&tradedTiles, &isLegal ); /* modifies model */
|
||||
|
||||
moveOk = readMoveInfo( server, stream, &whoMoved, &isTrade, &newTiles,
|
||||
&tradedTiles, &isLegal ); /* modifies model */
|
||||
}
|
||||
if ( moveOk ) {
|
||||
if ( isTrade ) {
|
||||
model_makeTileTrade( model, whoMoved, &tradedTiles, &newTiles );
|
||||
pool_replaceTiles( server->pool, &tradedTiles );
|
||||
|
@ -2466,7 +2510,8 @@ sendUndoToClientsExcept( ServerCtxt* server, XP_U16 skip,
|
|||
static XP_Bool
|
||||
reflectUndos( ServerCtxt* server, XWStreamCtxt* stream, XW_Proto code )
|
||||
{
|
||||
XP_U16 nUndone, lastUndone;
|
||||
XP_U16 nUndone;
|
||||
XP_S16 lastUndone;
|
||||
XP_U16 turn;
|
||||
ModelCtxt* model = server->vol.model;
|
||||
XP_Bool success = XP_TRUE;
|
||||
|
@ -2475,7 +2520,7 @@ reflectUndos( ServerCtxt* server, XWStreamCtxt* stream, XW_Proto code )
|
|||
lastUndone = stream_getU16( stream );
|
||||
|
||||
success = model_undoLatestMoves( model, server->pool, nUndone, &turn,
|
||||
NULL );
|
||||
&lastUndone );
|
||||
if ( success ) {
|
||||
|
||||
if ( code == XWPROTO_UNDO_INFO_CLIENT ) { /* need to inform */
|
||||
|
|
|
@ -94,7 +94,8 @@ DEFINES += -DTEXT_MODEL
|
|||
DEFINES += -DXWFEATURE_WALKDICT
|
||||
DEFINES += -DXWFEATURE_WALKDICT_FILTER
|
||||
DEFINES += -DXWFEATURE_DICTSANITY
|
||||
#DEFINES += -DMAX_ROWS=32
|
||||
# MAX_ROWS controls STREAM_VERS_BIGBOARD and with it move hashing
|
||||
DEFINES += -DMAX_ROWS=32
|
||||
|
||||
ifdef CURSES_CELL_HT
|
||||
DEFINES += -DCURSES_CELL_HT=$(CURSES_CELL_HT)
|
||||
|
|
|
@ -1709,6 +1709,7 @@ cursesmain( XP_Bool isServer, LaunchParams* params )
|
|||
#ifdef XWFEATURE_SLOW_ROBOT
|
||||
g_globals.cGlobals.cp.robotThinkMin = params->robotThinkMin;
|
||||
g_globals.cGlobals.cp.robotThinkMax = params->robotThinkMax;
|
||||
g_globals.cGlobals.cp.robotTradePct = params->robotTradePct;
|
||||
#endif
|
||||
|
||||
setupCursesUtilCallbacks( &g_globals, params->util );
|
||||
|
|
|
@ -2284,6 +2284,7 @@ gtkmain( LaunchParams* params, int argc, char *argv[] )
|
|||
#ifdef XWFEATURE_SLOW_ROBOT
|
||||
globals.cGlobals.cp.robotThinkMin = params->robotThinkMin;
|
||||
globals.cGlobals.cp.robotThinkMax = params->robotThinkMax;
|
||||
globals.cGlobals.cp.robotTradePct = params->robotTradePct;
|
||||
#endif
|
||||
#ifdef XWFEATURE_CROSSHAIRS
|
||||
globals.cGlobals.cp.hideCrosshairs = params->hideCrosshairs;
|
||||
|
|
|
@ -433,6 +433,7 @@ typedef enum {
|
|||
#endif
|
||||
#ifdef XWFEATURE_SLOW_ROBOT
|
||||
,CMD_SLOWROBOT
|
||||
,CMD_TRADEPCT
|
||||
#endif
|
||||
#if defined PLATFORM_GTK && defined PLATFORM_NCURSES
|
||||
,CMD_GTK
|
||||
|
@ -517,6 +518,7 @@ static CmdInfoRec CmdInfoRecs[] = {
|
|||
#endif
|
||||
#ifdef XWFEATURE_SLOW_ROBOT
|
||||
,{ CMD_SLOWROBOT, true, "slow-robot", "make robot slower to test network" }
|
||||
,{ CMD_TRADEPCT, true, "trade-pct", "what pct of the time should robot trade" }
|
||||
#endif
|
||||
#if defined PLATFORM_GTK && defined PLATFORM_NCURSES
|
||||
,{ CMD_GTK, false, "gtk", "use GTK for display" }
|
||||
|
@ -1581,6 +1583,12 @@ main( int argc, char** argv )
|
|||
usage(argv[0], "bad param" );
|
||||
}
|
||||
break;
|
||||
case CMD_TRADEPCT:
|
||||
mainParams.robotTradePct = atoi( optarg );
|
||||
if ( mainParams.robotTradePct < 0 || mainParams.robotTradePct > 100 ) {
|
||||
usage(argv[0], "must be 0 <= n <= 100" );
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined PLATFORM_GTK && defined PLATFORM_NCURSES
|
||||
|
|
|
@ -84,9 +84,9 @@ typedef struct LaunchParams {
|
|||
XP_Bool hideCrosshairs;
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef XWFEATURE_SLOW_ROBOT
|
||||
XP_U16 robotThinkMin, robotThinkMax;
|
||||
XP_U16 robotTradePct;
|
||||
#endif
|
||||
|
||||
DeviceRole serverRole;
|
||||
|
|
|
@ -159,7 +159,7 @@ build_cmds() {
|
|||
fi
|
||||
|
||||
PARAMS="$(player_params $NLOCALS $NPLAYERS $DEV)"
|
||||
PARAMS="$PARAMS $BOARD_SIZE --room $ROOM"
|
||||
PARAMS="$PARAMS $BOARD_SIZE --room $ROOM --trade-pct 20"
|
||||
PARAMS="$PARAMS --game-dict $DICT --port $PORT --host $HOST "
|
||||
PARAMS="$PARAMS --file $FILE --slow-robot 1:3 --skip-confirm"
|
||||
PARAMS="$PARAMS --drop-nth-packet $DROP_N $PLAT_PARMS"
|
||||
|
|
Loading…
Reference in a new issue