From d430e158baccfb0b0237e06ad3808cf37cdba560 Mon Sep 17 00:00:00 2001 From: Andy2 Date: Fri, 1 Apr 2011 17:36:04 -0700 Subject: [PATCH 1/3] add commandline flag for phonies --- xwords4/linux/linuxmain.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/xwords4/linux/linuxmain.c b/xwords4/linux/linuxmain.c index 87c867b24..49a653da3 100644 --- a/xwords4/linux/linuxmain.c +++ b/xwords4/linux/linuxmain.c @@ -283,6 +283,7 @@ typedef enum { ,CMD_ROOMNAME ,CMD_ADVERTISEROOM ,CMD_JOINADVERTISED + ,CMD_PHONIES #endif #ifdef XWFEATURE_BLUETOOTH ,CMD_BTADDR @@ -352,6 +353,7 @@ static CmdInfoRec CmdInfoRecs[] = { ,{ CMD_ROOMNAME, true, "room", "name of room on relay" } ,{ CMD_ADVERTISEROOM, false, "make-public", "make room public on relay" } ,{ CMD_JOINADVERTISED, false, "join-public", "look for a public room" } + ,{ CMD_PHONIES, true, "phonies", "ignore (0, default), warn (1) or lose turn (2)" } #endif #ifdef XWFEATURE_BLUETOOTH ,{ CMD_BTADDR, true, "btaddr", "bluetooth address of host" } @@ -1092,6 +1094,20 @@ main( int argc, char** argv ) case CMD_JOINADVERTISED: mainParams.connInfo.relay.seeksPublicRoom = true; break; + case CMD_PHONIES: + switch( atoi(optarg) ) { + case 0: + mainParams.gi.phoniesAction = PHONIES_IGNORE; + break; + case 1: + mainParams.gi.phoniesAction = PHONIES_WARN; + break; + case 2: + mainParams.gi.phoniesAction = PHONIES_DISALLOW; + break; + default: + usage( argv[0], "phonies takes 0 or 1 or 2" ); + } #endif case CMD_CLOSESTDIN: closeStdin = XP_TRUE; From 3b7b4802a937dbf53256124f78fdf4ebcc43887b Mon Sep 17 00:00:00 2001 From: Andy2 Date: Fri, 1 Apr 2011 19:57:10 -0700 Subject: [PATCH 2/3] add ability to specify, track and use separate dictionaries for each player. Works for gtk client. Compiles for Android but there's no UI yet to specify more than one dict. Management of dupicate dicts without duplicating memory -- refcounting -- will be up to the platforms. --- xwords4/android/XWords4/jni/xwjni.c | 6 +- xwords4/common/board.c | 19 ++--- xwords4/common/comtypes.h | 4 + xwords4/common/draw.h | 4 +- xwords4/common/engine.c | 14 ++-- xwords4/common/engine.h | 2 +- xwords4/common/game.c | 33 ++++---- xwords4/common/game.h | 8 +- xwords4/common/model.c | 117 +++++++++++++++++++++------- xwords4/common/model.h | 16 ++-- xwords4/common/modelp.h | 1 + xwords4/common/mscore.c | 17 ++-- xwords4/common/server.c | 4 +- xwords4/linux/cursesdraw.c | 3 +- xwords4/linux/cursesmain.c | 6 +- xwords4/linux/gtkdraw.c | 1 + xwords4/linux/gtkmain.c | 4 +- xwords4/linux/linuxmain.c | 25 +++++- xwords4/linux/main.h | 1 + 19 files changed, 195 insertions(+), 90 deletions(-) diff --git a/xwords4/android/XWords4/jni/xwjni.c b/xwords4/android/XWords4/jni/xwjni.c index cb4ac5651..28f3a5f4c 100644 --- a/xwords4/android/XWords4/jni/xwjni.c +++ b/xwords4/android/XWords4/jni/xwjni.c @@ -230,8 +230,8 @@ Java_org_eehouse_android_xw4_jni_XwJNI_gi_1from_1stream CurGameInfo gi; XP_MEMSET( &gi, 0, sizeof(gi) ); - if ( game_makeFromStream( MPPARM(mpool) stream, NULL, - &gi, NULL, NULL, NULL, NULL, NULL ) ) { + if ( game_makeFromStream( MPPARM(mpool) stream, NULL, + &gi, NULL, NULL, NULL, NULL, NULL, NULL ) ) { setJGI( env, jgi, &gi ); } else { XP_LOGF( "%s: game_makeFromStream failed", __func__ ); @@ -458,7 +458,7 @@ Java_org_eehouse_android_xw4_jni_XwJNI_game_1makeFromStream CommonPrefs cp; loadCommonPrefs( env, &cp, jcp ); result = game_makeFromStream( MPPARM(mpool) stream, &state->game, - globals->gi, dict, + globals->gi, dict, NULL, globals->util, globals->dctx, &cp, globals->xportProcs ); stream_destroy( stream ); diff --git a/xwords4/common/board.c b/xwords4/common/board.c index 9e3c6efb3..396afc37c 100644 --- a/xwords4/common/board.c +++ b/xwords4/common/board.c @@ -84,7 +84,8 @@ static void boardCellChanged( void* board, XP_U16 turn, XP_U16 col, XP_U16 row, XP_Bool added ); static void boardTilesChanged( void* board, XP_U16 turn, XP_S16 index1, XP_S16 index2 ); -static void dictChanged( void* p_board, const DictionaryCtxt* oldDict, +static void dictChanged( void* p_board, XP_S16 playerNum, + const DictionaryCtxt* oldDict, const DictionaryCtxt* newDict ); static void boardTurnChanged( void* board ); @@ -1708,14 +1709,14 @@ board_requestHint( BoardCtxt* board, } } #endif - searchComplete = engine_findMove(engine, model, - model_getDictionary(model), - tiles, nTiles, usePrev, + searchComplete = + engine_findMove( engine, model, selPlayer, + tiles, nTiles, usePrev, #ifdef XWFEATURE_SEARCHLIMIT - lp, useTileLimits, + lp, useTileLimits, #endif - 0, /* 0: not a robot */ - &canMove, &newMove ); + 0, /* 0: not a robot */ + &canMove, &newMove ); board_popTimerSave( board ); if ( searchComplete && canMove ) { @@ -3324,13 +3325,13 @@ boardTilesChanged( void* p_board, XP_U16 turn, XP_S16 index1, XP_S16 index2 ) } /* boardTilesChanged */ static void -dictChanged( void* p_board, const DictionaryCtxt* oldDict, +dictChanged( void* p_board, XP_S16 playerNum, const DictionaryCtxt* oldDict, const DictionaryCtxt* newDict ) { BoardCtxt* board = (BoardCtxt*)p_board; if ( !!board->draw ) { if ( (NULL == oldDict) || (oldDict != newDict) ) { - draw_dictChanged( board->draw, newDict ); + draw_dictChanged( board->draw, playerNum, newDict ); } } } diff --git a/xwords4/common/comtypes.h b/xwords4/common/comtypes.h index 855bc1651..0828b8147 100644 --- a/xwords4/common/comtypes.h +++ b/xwords4/common/comtypes.h @@ -138,6 +138,10 @@ typedef struct CommonPrefs { XP_Bool allowPeek; /* applies to all games */ } CommonPrefs; +typedef struct _PlayerDicts { + DictionaryCtxt* dicts[MAX_NUM_PLAYERS]; +} PlayerDicts; + #ifdef XWFEATURE_BLUETOOTH /* temporary debugging hack */ diff --git a/xwords4/common/draw.h b/xwords4/common/draw.h index 10774614a..45e712553 100644 --- a/xwords4/common/draw.h +++ b/xwords4/common/draw.h @@ -113,7 +113,7 @@ typedef struct DrawCtxVTable { void DRAW_VTABLE_NAME(destroyCtxt) ( DrawCtx* dctx ); - void DRAW_VTABLE_NAME(dictChanged)( DrawCtx* dctx, + void DRAW_VTABLE_NAME(dictChanged)( DrawCtx* dctx, XP_S16 playerNum, const DictionaryCtxt* dict ); XP_Bool DRAW_VTABLE_NAME(boardBegin) ( DrawCtx* dctx, @@ -252,7 +252,7 @@ struct DrawCtx { #endif #define draw_destroyCtxt(dc) CALL_DRAW_NAME0(destroyCtxt, dc) -#define draw_dictChanged( dc, d ) CALL_DRAW_NAME1(dictChanged, (dc), (d)) +#define draw_dictChanged( dc, n, d ) CALL_DRAW_NAME2(dictChanged, (dc), (n), (d)) #define draw_boardBegin( dc,r,h,v,f ) CALL_DRAW_NAME4(boardBegin, (dc),\ (r),(h),(v),(f)) #define draw_objFinished( dc, t, r, d ) CALL_DRAW_NAME3(objFinished, (dc), (t), (r), (d)) diff --git a/xwords4/common/engine.c b/xwords4/common/engine.c index 112a98069..d564f2231 100644 --- a/xwords4/common/engine.c +++ b/xwords4/common/engine.c @@ -84,6 +84,7 @@ struct EngineCtxt { const ModelCtxt* model; const DictionaryCtxt* dict; XW_UtilCtxt* util; + XP_U16 turn; Engine_rack rack; Tile blankTile; @@ -407,7 +408,7 @@ normalizeIQ( EngineCtxt* engine, XP_U16 iq ) */ XP_Bool engine_findMove( EngineCtxt* engine, const ModelCtxt* model, - const DictionaryCtxt* dict, const Tile* tiles, + XP_U16 turn, const Tile* tiles, XP_U16 nTiles, XP_Bool usePrev, #ifdef XWFEATURE_SEARCHLIMIT const BdHintLimits* searchLimits, @@ -448,9 +449,10 @@ engine_findMove( EngineCtxt* engine, const ModelCtxt* model, #endif engine->model = model; - engine->dict = dict; + engine->dict = model_getPlayerDict( model, turn ); + engine->turn = turn; engine->usePrev = usePrev; - engine->blankTile = dict_getBlankTile( dict ); + engine->blankTile = dict_getBlankTile( engine->dict ); engine->returnNOW = XP_FALSE; #ifdef XWFEATURE_SEARCHLIMIT engine->searchLimits = searchLimits; @@ -465,8 +467,8 @@ engine_findMove( EngineCtxt* engine, const 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, - nTiles ); + *canMoveP = NULL != dict_getTopEdge(engine->dict) + && initTray( engine, tiles, nTiles ); if ( *canMoveP ) { util_engineStarting( engine->util, @@ -1116,7 +1118,7 @@ considerScoreWordHasBlanks( EngineCtxt* engine, XP_U16 blanksLeft, if ( blanksLeft == 0 ) { XP_U16 score; - score = figureMoveScore( engine->model, + score = figureMoveScore( engine->model, engine->turn, &posmove->moveInfo, engine, (XWStreamCtxt*)NULL, (WordNotifierInfo*)NULL, NULL, 0 ); diff --git a/xwords4/common/engine.h b/xwords4/common/engine.h index 33a447c97..f6e42e75a 100644 --- a/xwords4/common/engine.h +++ b/xwords4/common/engine.h @@ -49,7 +49,7 @@ void engine_reset( EngineCtxt* ctxt ); void engine_destroy( EngineCtxt* ctxt ); XP_Bool engine_findMove( EngineCtxt* ctxt, const ModelCtxt* model, - const DictionaryCtxt* dict, const Tile* tiles, + XP_U16 turn, const Tile* tiles, XP_U16 nTiles, XP_Bool usePrev, #ifdef XWFEATURE_SEARCHLIMIT const BdHintLimits* boardLimits, diff --git a/xwords4/common/game.c b/xwords4/common/game.c index c2c7af1a1..290ef0bf1 100644 --- a/xwords4/common/game.c +++ b/xwords4/common/game.c @@ -85,7 +85,7 @@ game_makeNewGame( MPFORMAL XWGame* game, CurGameInfo* gi, } gi->gameID = gameID; - game->model = model_make( MPPARM(mpool) (DictionaryCtxt*)NULL, util, + game->model = model_make( MPPARM(mpool) (DictionaryCtxt*)NULL, NULL, util, gi->boardSize, gi->boardSize ); #ifndef XWFEATURE_STANDALONE_ONLY @@ -170,6 +170,7 @@ game_reset( MPFORMAL XWGame* game, CurGameInfo* gi, XP_Bool game_makeFromStream( MPFORMAL XWStreamCtxt* stream, XWGame* game, CurGameInfo* gi, DictionaryCtxt* dict, + const PlayerDicts* dicts, XW_UtilCtxt* util, DrawCtx* draw, CommonPrefs* cp, const TransportProcs* procs ) { @@ -217,8 +218,8 @@ game_makeFromStream( MPFORMAL XWStreamCtxt* stream, XWGame* game, game->comms = NULL; } - XP_ASSERT( !!dict ); - game->model = model_makeFromStream( MPPARM(mpool) stream, dict, util ); + game->model = model_makeFromStream( MPPARM(mpool) stream, dict, + dicts, util ); game->server = server_makeFromStream( MPPARM(mpool) stream, game->model, game->comms, @@ -230,7 +231,7 @@ game_makeFromStream( MPFORMAL XWStreamCtxt* stream, XWGame* game, server_prefsChanged( game->server, cp ); board_prefsChanged( game->board, cp ); if ( !!draw ) { - draw_dictChanged( draw, dict ); + draw_dictChanged( draw, -1, dict ); } success = XP_TRUE; } while( XP_FALSE ); @@ -288,10 +289,7 @@ game_dispose( XWGame* game ) } #endif if ( !!game->model ) { - DictionaryCtxt* dict = model_getDictionary( game->model ); - if ( !!dict ) { - dict_destroy( dict ); - } + model_destroyDicts( game->model ); model_destroy( game->model ); game->model = NULL; } @@ -417,7 +415,7 @@ void gi_readFromStream( MPFORMAL XWStreamCtxt* stream, CurGameInfo* gi ) { LocalPlayer* pl; - XP_U16 i; + XP_U16 ii; XP_UCHAR* str; XP_U16 strVersion = stream_getVersion( stream ); @@ -458,7 +456,7 @@ gi_readFromStream( MPFORMAL XWStreamCtxt* stream, CurGameInfo* gi ) gi->gameSeconds = stream_getU16( stream ); } - for ( pl = gi->players, i = 0; i < gi->nPlayers; ++pl, ++i ) { + for ( pl = gi->players, ii = 0; ii < gi->nPlayers; ++pl, ++ii ) { str = stringFromStream( mpool, stream ); replaceStringIfDifferent( mpool, &pl->name, str ); if ( !!str ) { @@ -471,6 +469,14 @@ gi_readFromStream( MPFORMAL XWStreamCtxt* stream, CurGameInfo* gi ) XP_FREE( mpool, str ); } + if ( strVersion >= STREAM_VERS_PLAYERDICTS ) { + str = stringFromStream( mpool, stream ); + replaceStringIfDifferent( mpool, &pl->dictName, str ); + if ( !!str ) { + XP_FREE( mpool, str ); + } + } + pl->secondsUsed = stream_getU16( stream ); pl->robotIQ = ( strVersion < STREAM_VERS_ROBOTIQ ) ? (XP_U8)stream_getBits( stream, 1 ) @@ -483,7 +489,7 @@ void gi_writeToStream( XWStreamCtxt* stream, const CurGameInfo* gi ) { const LocalPlayer* pl; - XP_U16 i; + XP_U16 ii; stringToStream( stream, gi->dictName ); @@ -500,10 +506,11 @@ gi_writeToStream( XWStreamCtxt* stream, const CurGameInfo* gi ) stream_putU16( stream, gi->gameID ); stream_putU8( stream, gi->dictLang ); stream_putU16( stream, gi->gameSeconds ); - - for ( pl = gi->players, i = 0; i < gi->nPlayers; ++pl, ++i ) { + + for ( pl = gi->players, ii = 0; ii < gi->nPlayers; ++pl, ++ii ) { stringToStream( stream, pl->name ); stringToStream( stream, pl->password ); + stringToStream( stream, pl->dictName ); stream_putU16( stream, pl->secondsUsed ); stream_putU8( stream, pl->robotIQ ); stream_putBits( stream, 1, pl->isLocal ); diff --git a/xwords4/common/game.h b/xwords4/common/game.h index 9e8547b77..440eb2fe7 100644 --- a/xwords4/common/game.h +++ b/xwords4/common/game.h @@ -31,6 +31,7 @@ extern "C" { #endif +#define STREAM_VERS_PLAYERDICTS 0x0F #define STREAM_SAVE_PREVMOVE 0x0E /* server saves prev move explanation */ #define STREAM_VERS_ROBOTIQ STREAM_SAVE_PREVMOVE /* robots have different smarts */ #define STREAM_VERS_DICTLANG 0x0D /* save dict lang code in CurGameInfo */ @@ -50,11 +51,12 @@ extern "C" { #define STREAM_VERS_41B4 0x02 #define STREAM_VERS_405 0x01 -#define CUR_STREAM_VERS STREAM_SAVE_PREVMOVE +#define CUR_STREAM_VERS STREAM_VERS_PLAYERDICTS typedef struct LocalPlayer { XP_UCHAR* name; XP_UCHAR* password; + XP_UCHAR* dictName; XP_U16 secondsUsed; XP_Bool isLocal; XP_U8 robotIQ; /* 0 means not a robot; 1-100 means how @@ -110,8 +112,8 @@ void game_reset( MPFORMAL XWGame* game, CurGameInfo* gi, XW_UtilCtxt* util, CommonPrefs* cp, const TransportProcs* procs ); XP_Bool game_makeFromStream( MPFORMAL XWStreamCtxt* stream, XWGame* game, - CurGameInfo* gi, - DictionaryCtxt* dict, XW_UtilCtxt* util, + CurGameInfo* gi, DictionaryCtxt* dict, + const PlayerDicts* dicts, XW_UtilCtxt* util, DrawCtx* draw, CommonPrefs* cp, const TransportProcs* procs ); diff --git a/xwords4/common/model.c b/xwords4/common/model.c index a199e4200..6f119bbd6 100644 --- a/xwords4/common/model.c +++ b/xwords4/common/model.c @@ -1,4 +1,4 @@ -/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */ +/* -*- compile-command: "cd ../linux && make -j3 MEMDEBUG=TRUE"; -*- */ /* * Copyright 2000-2009 by Eric House (xwords@eehouse.org). All rights reserved. * @@ -50,7 +50,8 @@ static void notifyBoardListeners( ModelCtxt* model, XP_U16 turn, XP_U16 col, XP_U16 row, XP_Bool added ); static void notifyTrayListeners( ModelCtxt* model, XP_U16 turn, XP_S16 index1, XP_S16 index2 ); -static void notifyDictListeners( ModelCtxt* model, DictionaryCtxt* oldDict, +static void notifyDictListeners( ModelCtxt* model, XP_S16 playerNum, + DictionaryCtxt* oldDict, DictionaryCtxt* newDict ); static CellTile getModelTileRaw( const ModelCtxt* model, XP_U16 col, @@ -80,7 +81,8 @@ static XP_U16 model_getRecentPassCount( ModelCtxt* model ); * ****************************************************************************/ ModelCtxt* -model_make( MPFORMAL DictionaryCtxt* dict, XW_UtilCtxt* util, XP_U16 nCols, +model_make( MPFORMAL DictionaryCtxt* dict, + const PlayerDicts* dicts, XW_UtilCtxt* util, XP_U16 nCols, XP_U16 nRows ) { ModelCtxt* result = (ModelCtxt*)XP_MALLOC( mpool, sizeof( *result ) ); @@ -96,6 +98,7 @@ model_make( MPFORMAL DictionaryCtxt* dict, XW_UtilCtxt* util, XP_U16 nCols, result->vol.gi = util->gameInfo; model_setDictionary( result, dict ); + model_setPlayerDicts( result, dicts ); } return result; @@ -103,7 +106,7 @@ model_make( MPFORMAL DictionaryCtxt* dict, XW_UtilCtxt* util, XP_U16 nCols, ModelCtxt* model_makeFromStream( MPFORMAL XWStreamCtxt* stream, DictionaryCtxt* dict, - XW_UtilCtxt* util ) + const PlayerDicts* dicts, XW_UtilCtxt* util ) { ModelCtxt* model; XP_U16 nCols, nRows; @@ -112,7 +115,7 @@ model_makeFromStream( MPFORMAL XWStreamCtxt* stream, DictionaryCtxt* dict, XP_U16 nPlayers; XP_U16 version = stream_getVersion( stream ); - XP_ASSERT( !!dict ); + XP_ASSERT( !!dict || !!dicts ); nCols = (XP_U16)stream_getBits( stream, NUMCOLS_NBITS ); nRows = (XP_U16)stream_getBits( stream, NUMCOLS_NBITS ); @@ -127,7 +130,7 @@ model_makeFromStream( MPFORMAL XWStreamCtxt* stream, DictionaryCtxt* dict, dict_destroy( savedDict ); } - model = model_make( MPPARM(mpool) dict, util, nCols, nRows ); + model = model_make( MPPARM(mpool) dict, dicts, util, nCols, nRows ); model->nPlayers = nPlayers; stack_loadFromStream( model->vol.stack, stream ); @@ -263,6 +266,16 @@ model_getNPlayers( const ModelCtxt* model ) return model->nPlayers; } +static void +setStackBits( ModelCtxt* model, const DictionaryCtxt* dict ) +{ + if ( NULL != dict ) { + XP_U16 nFaces = dict_numTileFaces( dict ); + XP_ASSERT( !!model->vol.stack ); + stack_setBitsPerTile( model->vol.stack, nFaces <= 32? 5 : 6 ); + } +} + void model_setDictionary( ModelCtxt* model, DictionaryCtxt* dict ) { @@ -270,21 +283,72 @@ model_setDictionary( ModelCtxt* model, DictionaryCtxt* dict ) model->vol.dict = dict; if ( !!dict ) { - XP_U16 nFaces = dict_numTileFaces( dict ); - XP_ASSERT( !!model->vol.stack ); - stack_setBitsPerTile( model->vol.stack, nFaces <= 32? 5 : 6 ); - - notifyDictListeners( model, oldDict, dict ); + setStackBits( model, dict ); + notifyDictListeners( model, -1, oldDict, dict ); } } /* model_setDictionary */ +void +model_setPlayerDicts( ModelCtxt* model, const PlayerDicts* dicts ) +{ + if ( !!dicts ) { + XP_U16 ii; + DictionaryCtxt* gameDict = model_getDictionary( model ); + for ( ii = 0; ii < VSIZE(dicts->dicts); ++ii ) { + DictionaryCtxt* oldDict = model->vol.dicts.dicts[ii]; + DictionaryCtxt* newDict = dicts->dicts[ii]; + if ( oldDict != newDict ) { + XP_ASSERT( NULL == newDict || NULL == gameDict + || dict_tilesAreSame( gameDict, newDict ) ); + model->vol.dicts.dicts[ii] = newDict; + notifyDictListeners( model, ii, oldDict, newDict ); + setStackBits( model, newDict ); + } + } + } +} + DictionaryCtxt* model_getDictionary( const ModelCtxt* model ) { -/* XP_ASSERT( !!model->vol.dict ); */ - return model->vol.dict; + XP_U16 ii; + DictionaryCtxt* result = model->vol.dict; + for ( ii = 0; !result && ii < VSIZE(model->vol.dicts.dicts); ++ii ) { + result = model->vol.dicts.dicts[ii]; + } + return result; } /* model_getDictionary */ +DictionaryCtxt* +model_getPlayerDict( const ModelCtxt* model, XP_U16 playerNum ) +{ + DictionaryCtxt* dict = model->vol.dicts.dicts[playerNum]; + if ( NULL == dict ) { + dict = model->vol.dict; + } + XP_ASSERT( !!dict ); + return dict; +} + +static void +destroyNotNull( DictionaryCtxt** dictp ) +{ + if ( !!*dictp ) { + dict_destroy( *dictp ); + *dictp = NULL; + } +} + +void +model_destroyDicts( ModelCtxt* model ) +{ + XP_U16 ii; + for ( ii = 0; ii < VSIZE(model->vol.dicts.dicts); ++ii ) { + destroyNotNull( &model->vol.dicts.dicts[ii] ); + } + destroyNotNull( &model->vol.dict ); +} + static XP_Bool getPendingTileFor( const ModelCtxt* model, XP_U16 turn, XP_U16 col, XP_U16 row, CellTile* cellTile ) @@ -717,7 +781,7 @@ model_makeTurnFromStream( ModelCtxt* model, XP_U16 playerNum, XWStreamCtxt* stream ) { XP_U16 numTiles; - Tile blank = dict_getBlankTile( model->vol.dict ); + Tile blank = dict_getBlankTile( model_getDictionary(model) ); model_resetCurrentTurn( model, playerNum ); @@ -766,7 +830,7 @@ model_makeTurnFromMoveInfo( ModelCtxt* model, XP_U16 playerNum, Tile blank; XP_U16 numTiles; - blank = dict_getBlankTile( model->vol.dict ); + blank = dict_getBlankTile( model_getDictionary( model ) ); numTiles = newMove->nTiles; col = row = newMove->commonCoord; /* just assign both */ @@ -799,8 +863,7 @@ model_countAllTrayTiles( ModelCtxt* model, XP_U16* counts, XP_S16 i; Tile blank; - XP_ASSERT( !!model->vol.dict ); - blank = dict_getBlankTile( model->vol.dict ); + blank = dict_getBlankTile( model_getDictionary(model) ); for ( i = 0, player = model->players; i < nPlayers; ++i, ++player ) { if ( i != excludePlayer ) { @@ -925,7 +988,7 @@ model_packTilesUtil( ModelCtxt* model, PoolContext* pool, XP_U16* nUsed, const XP_UCHAR** texts, Tile* tiles ) { - DictionaryCtxt* dict = model->vol.dict; + DictionaryCtxt* dict = model_getDictionary(model); XP_U16 nFaces = dict_numTileFaces( dict ); Tile blankFace = dict_getBlankTile( dict ); Tile tile; @@ -986,7 +1049,7 @@ model_moveTrayToBoard( ModelCtxt* model, XP_S16 turn, XP_U16 col, XP_U16 row, Tile tile = model_removePlayerTile( model, turn, tileIndex ); - if ( tile == dict_getBlankTile(model->vol.dict) ) { + if ( tile == dict_getBlankTile(model_getDictionary(model)) ) { if ( blankFace != EMPTY_TILE ) { tile = blankFace; } else { @@ -1038,7 +1101,7 @@ model_redoPendingTiles( ModelCtxt* model, XP_S16 turn ) XP_S16 foundAt; if ( isBlank ) { - tile = dict_getBlankTile( model->vol.dict ); + tile = dict_getBlankTile( model_getDictionary(model) ); } foundAt = model_trayContains( model, turn, tile ); XP_ASSERT( foundAt >= 0 ); @@ -1082,7 +1145,7 @@ model_moveBoardToTray( ModelCtxt* model, XP_S16 turn, tile = pt->tile; if ( (tile & TILE_BLANK_BIT) != 0 ) { - tile = dict_getBlankTile( model->vol.dict ); + tile = dict_getBlankTile( model_getDictionary(model) ); } model_addPlayerTile( model, turn, trayOffset, tile ); @@ -1551,13 +1614,13 @@ notifyTrayListeners( ModelCtxt* model, XP_U16 turn, XP_S16 index1, } /* notifyTrayListeners */ static void -notifyDictListeners( ModelCtxt* model, DictionaryCtxt* oldDict, - DictionaryCtxt* newDict ) +notifyDictListeners( ModelCtxt* model, XP_S16 playerNum, + DictionaryCtxt* oldDict, DictionaryCtxt* newDict ) { XP_ASSERT( !!newDict ); if ( model->vol.dictListenerFunc != NULL ) { - (*model->vol.dictListenerFunc)( model->vol.dictListenerData, oldDict, - newDict ); + (*model->vol.dictListenerFunc)( model->vol.dictListenerData, playerNum, + oldDict, newDict ); } } /* notifyDictListeners */ @@ -1751,7 +1814,7 @@ makeTmpModel( ModelCtxt* model, XWStreamCtxt* stream, void* closure ) { ModelCtxt* tmpModel = model_make( MPPARM(model->vol.mpool) - model_getDictionary(model), + model_getDictionary(model), NULL, model->vol.util, model_numCols(model), model_numRows(model)); model_setNPlayers( tmpModel, model->nPlayers ); @@ -1811,7 +1874,7 @@ scoreLastMove( ModelCtxt* model, MoveInfo* moveInfo, XP_U16 howMany, XP_ASSERT( 0 ); } - score = figureMoveScore( tmpModel, moveInfo, (EngineCtxt*)NULL, + score = figureMoveScore( tmpModel, turn, moveInfo, (EngineCtxt*)NULL, (XWStreamCtxt*)NULL, (WordNotifierInfo*)NULL, wordBuf, VSIZE(wordBuf) ); diff --git a/xwords4/common/model.h b/xwords4/common/model.h index 5218d964e..1c39629ed 100644 --- a/xwords4/common/model.h +++ b/xwords4/common/model.h @@ -100,11 +100,12 @@ typedef XP_U8 TileBit; /* bits indicating selection of tiles in tray */ only */ -ModelCtxt* model_make( MPFORMAL DictionaryCtxt* dict, XW_UtilCtxt* util, - XP_U16 nCols, XP_U16 nRows ); +ModelCtxt* model_make( MPFORMAL DictionaryCtxt* dict, const PlayerDicts* dicts, + XW_UtilCtxt* util, XP_U16 nCols, XP_U16 nRows ); ModelCtxt* model_makeFromStream( MPFORMAL XWStreamCtxt* stream, - DictionaryCtxt* dict, XW_UtilCtxt* util ); + DictionaryCtxt* dict, const PlayerDicts* dicts, + XW_UtilCtxt* util ); void model_writeToStream( ModelCtxt* model, XWStreamCtxt* stream ); @@ -116,6 +117,10 @@ XP_U16 model_getNPlayers( const ModelCtxt* model ); void model_setDictionary( ModelCtxt* model, DictionaryCtxt* dict ); DictionaryCtxt* model_getDictionary( const ModelCtxt* model ); +void model_setPlayerDicts( ModelCtxt* model, const PlayerDicts* dicts ); +DictionaryCtxt* model_getPlayerDict( const ModelCtxt* model, XP_U16 playerNum ); +void model_destroyDicts( ModelCtxt* model ); + XP_Bool model_getTile( const ModelCtxt* model, XP_U16 col, XP_U16 row, XP_Bool getPending, XP_S16 turn, Tile* tile, XP_Bool* isBlank, @@ -209,7 +214,8 @@ typedef void (*TrayListener)( void* data, XP_U16 turn, XP_S16 index1, XP_S16 index2 ); void model_setTrayListener( ModelCtxt* model, TrayListener bl, void* data ); -typedef void (*DictListener)( void* data, const DictionaryCtxt* oldDict, +typedef void (*DictListener)( void* data, XP_S16 playerNum, + const DictionaryCtxt* oldDict, const DictionaryCtxt* newDict ); void model_setDictListener( ModelCtxt* model, DictListener dl, void* data ); @@ -253,7 +259,7 @@ void model_figureFinalScores( ModelCtxt* model, ScoresArray* scores, ScoresArray* tilePenalties ); /* figureMoveScore is meant only for the engine's use */ -XP_U16 figureMoveScore( const ModelCtxt* model, MoveInfo* moveInfo, +XP_U16 figureMoveScore( const ModelCtxt* model, XP_U16 turn, MoveInfo* mvInfo, EngineCtxt* engine, XWStreamCtxt* stream, WordNotifierInfo* notifyInfo, XP_UCHAR* mainWord, XP_U16 mainWordLen ); diff --git a/xwords4/common/modelp.h b/xwords4/common/modelp.h index 9330fca86..c3f812158 100644 --- a/xwords4/common/modelp.h +++ b/xwords4/common/modelp.h @@ -47,6 +47,7 @@ typedef struct ModelVolatiles { XW_UtilCtxt* util; struct CurGameInfo* gi; DictionaryCtxt* dict; + PlayerDicts dicts; BoardListener boardListenerFunc; StackCtxt* stack; void* boardListenerData; diff --git a/xwords4/common/mscore.c b/xwords4/common/mscore.c index e8b3279c4..517fdaca2 100644 --- a/xwords4/common/mscore.c +++ b/xwords4/common/mscore.c @@ -40,7 +40,7 @@ static XP_U16 find_start( const ModelCtxt* model, XP_U16 col, XP_U16 row, static XP_S16 checkScoreMove( ModelCtxt* model, XP_S16 turn, EngineCtxt* engine, XWStreamCtxt* stream, XP_Bool silent, WordNotifierInfo* notifyInfo ); -static XP_U16 scoreWord( const ModelCtxt* model, MoveInfo* movei, +static XP_U16 scoreWord( const ModelCtxt* model, XP_U16 turn, MoveInfo* movei, EngineCtxt* engine, XWStreamCtxt* stream, WordNotifierInfo* notifyInfo, XP_UCHAR* mainWord, XP_U16 mainWordLen ); @@ -102,7 +102,7 @@ adjustScoreForUndone( ModelCtxt* model, MoveInfo* mi, XP_U16 turn ) if ( mi->nTiles == 0 ) { moveScore = 0; } else { - moveScore = figureMoveScore( model, mi, (EngineCtxt*)NULL, + moveScore = figureMoveScore( model, turn, mi, (EngineCtxt*)NULL, (XWStreamCtxt*)NULL, (WordNotifierInfo*)NULL, NULL, 0 ); } @@ -240,7 +240,7 @@ checkScoreMove( ModelCtxt* model, XP_S16 turn, EngineCtxt* engine, normalizeMoves( model, turn, isHorizontal, &moveInfo ); if ( isLegalMove( model, &moveInfo, silent ) ) { - score = figureMoveScore( model, &moveInfo, engine, stream, + score = figureMoveScore( model, turn, &moveInfo, engine, stream, notifyInfo, NULL, 0 ); } } else if ( !silent ) { /* tiles out of line */ @@ -443,7 +443,7 @@ isLegalMove( ModelCtxt* model, MoveInfo* mInfo, XP_Bool silent ) } /* isLegalMove */ XP_U16 -figureMoveScore( const ModelCtxt* model, MoveInfo* moveInfo, +figureMoveScore( const ModelCtxt* model, XP_U16 turn, MoveInfo* moveInfo, EngineCtxt* engine, XWStreamCtxt* stream, WordNotifierInfo* notifyInfo, XP_UCHAR* mainWord, XP_U16 mainWordLen ) @@ -474,7 +474,7 @@ figureMoveScore( const ModelCtxt* model, MoveInfo* moveInfo, moveMultiplier *= multipliers[i] = word_multiplier( model, col, row ); } - oneScore = scoreWord( model, moveInfo, (EngineCtxt*)NULL, stream, + oneScore = scoreWord( model, turn, moveInfo, (EngineCtxt*)NULL, stream, notifyInfo, mainWord, mainWordLen ); if ( !!stream ) { formatWordScore( stream, oneScore, moveMultiplier ); @@ -500,7 +500,7 @@ figureMoveScore( const ModelCtxt* model, MoveInfo* moveInfo, tmpMI.commonCoord = tiles->varCoord; tmpMI.tiles[0].tile = tiles->tile; - oneScore = scoreWord( model, &tmpMI, engine, stream, + oneScore = scoreWord( model, turn, &tmpMI, engine, stream, notifyInfo, mainWord, mainWordLen ); if ( !!stream ) { formatWordScore( stream, oneScore, multipliers[i] ); @@ -557,7 +557,8 @@ tile_multiplier( const ModelCtxt* model, XP_U16 col, XP_U16 row ) } /* tile_multiplier */ static XP_U16 -scoreWord( const ModelCtxt* model, MoveInfo* movei, /* new tiles */ +scoreWord( const ModelCtxt* model, XP_U16 turn, + MoveInfo* movei, /* new tiles */ EngineCtxt* engine,/* for crosswise caching */ XWStreamCtxt* stream, WordNotifierInfo* notifyInfo, @@ -574,7 +575,7 @@ scoreWord( const ModelCtxt* model, MoveInfo* movei, /* new tiles */ XP_U16 col, row; MoveInfoTile* tiles = movei->tiles; XP_U16 firstCoord = tiles->varCoord; - DictionaryCtxt* dict = model->vol.dict; + DictionaryCtxt* dict = model_getPlayerDict( model, turn ); if ( movei->isHorizontal ) { row = movei->commonCoord; diff --git a/xwords4/common/server.c b/xwords4/common/server.c index d22be358b..e665867c9 100644 --- a/xwords4/common/server.c +++ b/xwords4/common/server.c @@ -692,8 +692,8 @@ makeRobotMove( ServerCtxt* server ) XP_ASSERT( !!server_getEngineFor( server, turn ) ); searchComplete = engine_findMove( server_getEngineFor( server, turn ), - model, model_getDictionary( model ), - tileSet->tiles, tileSet->nTiles, XP_FALSE, + model, turn, tileSet->tiles, + tileSet->nTiles, XP_FALSE, #ifdef XWFEATURE_SEARCHLIMIT NULL, XP_FALSE, #endif diff --git a/xwords4/linux/cursesdraw.c b/xwords4/linux/cursesdraw.c index 91a37da1e..334de9067 100644 --- a/xwords4/linux/cursesdraw.c +++ b/xwords4/linux/cursesdraw.c @@ -86,7 +86,8 @@ curses_draw_destroyCtxt( DrawCtx* XP_UNUSED(p_dctx) ) } /* draw_setup */ static void -curses_draw_dictChanged( DrawCtx* XP_UNUSED(p_dctx), +curses_draw_dictChanged( DrawCtx* XP_UNUSED(p_dctx), + XP_S16 XP_UNUSED(playerNum), const DictionaryCtxt* XP_UNUSED(dict) ) { } diff --git a/xwords4/linux/cursesmain.c b/xwords4/linux/cursesmain.c index 673692333..f8c469820 100644 --- a/xwords4/linux/cursesmain.c +++ b/xwords4/linux/cursesmain.c @@ -1443,7 +1443,6 @@ void cursesmain( XP_Bool isServer, LaunchParams* params ) { int piperesult; - DictionaryCtxt* dict; int width, height; memset( &g_globals, 0, sizeof(g_globals) ); @@ -1466,8 +1465,6 @@ cursesmain( XP_Bool isServer, LaunchParams* params ) g_globals.cGlobals.cp.robotThinkMax = params->robotThinkMax; #endif - dict = params->dict; - setupCursesUtilCallbacks( &g_globals, params->util ); #ifdef XWFEATURE_RELAY @@ -1519,7 +1516,8 @@ cursesmain( XP_Bool isServer, LaunchParams* params ) &g_globals ); (void)game_makeFromStream( MEMPOOL stream, &g_globals.cGlobals.game, - ¶ms->gi, dict, params->util, + ¶ms->gi, params->dict, ¶ms->dicts, + params->util, (DrawCtx*)g_globals.draw, &g_globals.cGlobals.cp, &procs ); diff --git a/xwords4/linux/gtkdraw.c b/xwords4/linux/gtkdraw.c index b8da011da..af87a27e9 100644 --- a/xwords4/linux/gtkdraw.c +++ b/xwords4/linux/gtkdraw.c @@ -369,6 +369,7 @@ gtk_draw_destroyCtxt( DrawCtx* p_dctx ) static void gtk_draw_dictChanged( DrawCtx* XP_UNUSED(p_dctx), + XP_S16 XP_UNUSED(playerNum), const DictionaryCtxt* XP_UNUSED(dict) ) { } diff --git a/xwords4/linux/gtkmain.c b/xwords4/linux/gtkmain.c index be411ecbb..3285b5e2e 100644 --- a/xwords4/linux/gtkmain.c +++ b/xwords4/linux/gtkmain.c @@ -419,7 +419,7 @@ createOrLoadObjects( GtkAppGlobals* globals ) opened = game_makeFromStream( MEMPOOL stream, &globals->cGlobals.game, &globals->cGlobals.params->gi, - params->dict, params->util, + params->dict, ¶ms->dicts, params->util, (DrawCtx*)globals->draw, &globals->cGlobals.cp, &procs ); @@ -485,8 +485,8 @@ createOrLoadObjects( GtkAppGlobals* globals ) } #endif model_setDictionary( globals->cGlobals.game.model, params->dict ); + model_setPlayerDicts( globals->cGlobals.game.model, ¶ms->dicts ); - /* params->gi.phoniesAction = PHONIES_DISALLOW; */ #ifdef XWFEATURE_SEARCHLIMIT params->gi.allowHintRect = params->allowHintRect; #endif diff --git a/xwords4/linux/linuxmain.c b/xwords4/linux/linuxmain.c index 49a653da3..c8a5dc014 100644 --- a/xwords4/linux/linuxmain.c +++ b/xwords4/linux/linuxmain.c @@ -198,8 +198,8 @@ read_pipe_then_close( CommonGlobals* cGlobals ) XP_Bool opened = game_makeFromStream( MPPARM(cGlobals->params->util->mpool) stream, &cGlobals->game, - ¶ms->gi, - params->dict, params->util, + ¶ms->gi, params->dict, + ¶ms->dicts, params->util, NULL /*draw*/, &cGlobals->cp, NULL ); XP_ASSERT( opened ); @@ -245,6 +245,7 @@ typedef enum { ,CMD_SHOW_OTHERSCORES ,CMD_HOSTIP ,CMD_DICT + ,CMD_PLAYERDICT ,CMD_SEED ,CMD_GAMEFILE ,CMD_PRINTHISORY @@ -314,7 +315,8 @@ static CmdInfoRec CmdInfoRecs[] = { ,{ CMD_SHOW_OTHERSCORES, false, "no-show-other", "do not show robot and remote scores" } ,{ CMD_HOSTIP, true, "hostip", "remote host ip address (for direct connect)" } - ,{ CMD_DICT, true, "dict", "dictionary name" } + ,{ CMD_DICT, true, "game-dict", "dictionary name for game" } + ,{ CMD_PLAYERDICT, true, "player-dict", "dictionary name for player (in sequence)" } ,{ CMD_SEED, true, "seed", "random seed" } ,{ CMD_GAMEFILE, true, "file", "file to save to/read from" } ,{ CMD_PRINTHISORY, false, "print-history", "print history on game over" } @@ -876,7 +878,9 @@ main( int argc, char** argv ) XP_Bool closeStdin = XP_FALSE; unsigned int seed = defaultRandomSeed(); LaunchParams mainParams; + XP_U16 nPlayerDicts = 0; XP_U16 robotCount = 0; + XP_U16 ii; /* install a no-op signal handler. Later curses- or gtk-specific code will install one that does the right thing in that context */ @@ -992,6 +996,9 @@ main( int argc, char** argv ) mainParams.gi.dictName = copyString( mainParams.util->mpool, (XP_UCHAR*)optarg ); break; + case CMD_PLAYERDICT: + mainParams.gi.players[nPlayerDicts++].dictName = optarg; + break; case CMD_SEED: seed = atoi(optarg); break; @@ -1206,7 +1213,9 @@ main( int argc, char** argv ) XP_WARNF( "no dictionary provided: using English stub dict\n" ); mainParams.gi.dictLang = dict_getLangCode( mainParams.dict ); #else - mainParams.needsNewGame = XP_TRUE; + if ( 0 == nPlayerDicts ) { + mainParams.needsNewGame = XP_TRUE; + } #endif } else if ( robotCount > 0 ) { mainParams.needsNewGame = XP_TRUE; @@ -1217,6 +1226,14 @@ main( int argc, char** argv ) mainParams.needsNewGame = XP_TRUE; } + for ( ii = 0; ii < nPlayerDicts; ++ii ) { + XP_UCHAR* name = mainParams.gi.players[ii].dictName; + if ( !!name ) { + mainParams.dicts.dicts[ii] = + linux_dictionary_make( MPPARM(mainParams.util->mpool) name ); + } + } + /* if ( !isServer ) { */ /* if ( mainParams.info.serverInfo.nRemotePlayers > 0 ) { */ /* mainParams.needsNewGame = XP_TRUE; */ diff --git a/xwords4/linux/main.h b/xwords4/linux/main.h index fcef37a60..cfd5b1d2a 100644 --- a/xwords4/linux/main.h +++ b/xwords4/linux/main.h @@ -47,6 +47,7 @@ typedef struct LaunchParams { XW_UtilCtxt* util; DictionaryCtxt* dict; CurGameInfo gi; + PlayerDicts dicts; char* fileName; char* pipe; VTableMgr* vtMgr; From 55221c70b00c687bf9b70606c9de450081a908d9 Mon Sep 17 00:00:00 2001 From: Andy2 Date: Sun, 3 Apr 2011 21:51:51 -0700 Subject: [PATCH 3/3] fix for new API --- xwords4/android/XWords4/jni/drawwrapper.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/xwords4/android/XWords4/jni/drawwrapper.c b/xwords4/android/XWords4/jni/drawwrapper.c index 9aa55eaab..e006d8a2d 100644 --- a/xwords4/android/XWords4/jni/drawwrapper.c +++ b/xwords4/android/XWords4/jni/drawwrapper.c @@ -382,7 +382,8 @@ and_draw_objFinished( DrawCtx* dctx, BoardObjectType typ, } static void -and_draw_dictChanged( DrawCtx* dctx, const DictionaryCtxt* dict ) +and_draw_dictChanged( DrawCtx* dctx, XP_S16 playerNum, + const DictionaryCtxt* dict ) { AndDraw* draw = (AndDraw*)dctx; if ( NULL != draw->jdraw ) {