From 210c59ef9bdaf1487aece09c8461fe744e31e64a Mon Sep 17 00:00:00 2001 From: Andy2 Date: Wed, 16 Nov 2011 19:01:11 -0800 Subject: [PATCH] move bonus square values into model: add API to set an array, and API to query model for values. Now everybody else queries new model API rather than client via util_getSquareBonus(), model uses its internal values if present otherwise falls back to util_getSquareBonus(), and internalizes the array as part of the game. Now it should be easier to have different bonus patterns and to have them exchanged as part of network game init. --- xwords4/common/board.c | 3 +- xwords4/common/boarddrw.c | 8 +-- xwords4/common/comtypes.h | 10 ++++ xwords4/common/dictnry.h | 10 ---- xwords4/common/model.c | 120 ++++++++++++++++++++++++++++++++++--- xwords4/common/model.h | 5 ++ xwords4/common/modelp.h | 2 + xwords4/common/mscore.c | 5 +- xwords4/common/util.h | 7 +-- xwords4/linux/cursesmain.c | 2 +- xwords4/linux/gtkmain.c | 1 + xwords4/linux/linuxutl.c | 84 +++++++++++++++++++------- xwords4/linux/linuxutl.h | 11 +++- 13 files changed, 213 insertions(+), 55 deletions(-) diff --git a/xwords4/common/board.c b/xwords4/common/board.c index 1615beb3d..0d381cab6 100644 --- a/xwords4/common/board.c +++ b/xwords4/common/board.c @@ -1002,8 +1002,7 @@ timerFiredForPen( BoardCtxt* board ) #endif if ( !listWords ) { XWBonusType bonus; - bonus = util_getSquareBonus( board->util, board->model, - col, row ); + bonus = model_getSquareBonus( board->model, col, row ); if ( bonus != BONUS_NONE ) { #ifdef XWFEATURE_MINIWIN text = draw_getMiniWText( board->draw, diff --git a/xwords4/common/boarddrw.c b/xwords4/common/boarddrw.c index 123c5616b..88570fa13 100644 --- a/xwords4/common/boarddrw.c +++ b/xwords4/common/boarddrw.c @@ -1,6 +1,6 @@ -/* -*-mode: C; fill-column: 78; compile-command: "cd ../linux && make MEMDEBUG=TRUE"; -*- */ +/* -*- compile-command: "cd ../linux && make MEMDEBUG=TRUE -j3"; -*- */ /* - * Copyright 1997 - 2010 by Eric House (xwords@eehouse.org). All rights + * Copyright 1997 - 2011 by Eric House (xwords@eehouse.org). All rights * reserved. * * This program is free software; you can redistribute it and/or @@ -331,7 +331,7 @@ drawBoard( BoardCtxt* board ) XWBonusType bonus; HintAtts hintAtts; CellFlags flags = CELL_NONE; - bonus = util_getSquareBonus( board->util, model, col, row ); + bonus = model_getSquareBonus( model, col, row ); hintAtts = figureHintAtts( board, col, row ); #ifdef KEYBOARD_NAV if ( cellFocused( board, col, row ) ) { @@ -436,7 +436,7 @@ drawCell( BoardCtxt* board, XP_U16 col, XP_U16 row, XP_Bool skipBlanks ) textP = dict_getTileString( dict, tile ); } } - bonus = util_getSquareBonus( board->util, model, col, row ); + bonus = model_getSquareBonus( model, col, row ); hintAtts = figureHintAtts( board, col, row ); if ( (col==board->star_row) && (row==board->star_row) ) { diff --git a/xwords4/common/comtypes.h b/xwords4/common/comtypes.h index c95cecdba..dd8313f22 100644 --- a/xwords4/common/comtypes.h +++ b/xwords4/common/comtypes.h @@ -137,6 +137,16 @@ typedef XP_U32 RowFlags; error #endif +typedef enum { + BONUS_NONE, + BONUS_DOUBLE_LETTER, + BONUS_DOUBLE_WORD, + BONUS_TRIPLE_LETTER, + BONUS_TRIPLE_WORD, + + BONUS_LAST +} XWBonusType; + /* I need a way to communiate prefs to common/ code. For now, though, I'll * leave storage of these values up to the platforms. First, because I don't * want to deal with versioning in the common code. Second, becuase they diff --git a/xwords4/common/dictnry.h b/xwords4/common/dictnry.h index 16efe36e6..53788e77a 100644 --- a/xwords4/common/dictnry.h +++ b/xwords4/common/dictnry.h @@ -39,16 +39,6 @@ extern "C" { typedef XP_U8 XP_LangCode; -typedef enum { - BONUS_NONE, - BONUS_DOUBLE_LETTER, - BONUS_DOUBLE_WORD, - BONUS_TRIPLE_LETTER, - BONUS_TRIPLE_WORD, - - BONUS_LAST -} XWBonusType; - typedef enum { INTRADE_MW_TEXT = BONUS_LAST } XWMiniTextType; diff --git a/xwords4/common/model.c b/xwords4/common/model.c index 13bebf0ab..4745f414d 100644 --- a/xwords4/common/model.c +++ b/xwords4/common/model.c @@ -115,7 +115,7 @@ model_makeFromStream( MPFORMAL XWStreamCtxt* stream, DictionaryCtxt* dict, { ModelCtxt* model; XP_U16 nCols, nRows; - short i; + XP_U16 ii; XP_Bool hasDict; XP_U16 nPlayers; XP_U16 nColsNBits; @@ -144,6 +144,20 @@ model_makeFromStream( MPFORMAL XWStreamCtxt* stream, DictionaryCtxt* dict, model = model_make( MPPARM(mpool) dict, dicts, util, nCols, nRows ); model->nPlayers = nPlayers; +#ifdef STREAM_VERS_BIGBOARD + if ( STREAM_VERS_BIGBOARD <= version ) { + model->nBonuses = stream_getBits( stream, 7 ); + if ( 0 < model->nBonuses ) { + model->bonuses = + XP_MALLOC( model->vol.mpool, + model->nBonuses * sizeof( model->bonuses[0] ) ); + for ( ii = 0; ii < model->nBonuses; ++ii ) { + model->bonuses[ii] = stream_getBits( stream, 4 ); + } + } + } +#endif + stack_loadFromStream( model->vol.stack, stream ); buildModelFromStack( model, model->vol.stack, XP_FALSE, 0, @@ -151,10 +165,10 @@ model_makeFromStream( MPFORMAL XWStreamCtxt* stream, DictionaryCtxt* dict, (MovePrintFuncPre)NULL, (MovePrintFuncPost)NULL, NULL ); - for ( i = 0; i < model->nPlayers; ++i ) { - loadPlayerCtxt( stream, version, &model->players[i] ); - setPendingCounts( model, i ); - invalidateScore( model, i ); + for ( ii = 0; ii < model->nPlayers; ++ii ) { + loadPlayerCtxt( stream, version, &model->players[ii] ); + setPendingCounts( model, ii ); + invalidateScore( model, ii ); } return model; @@ -163,7 +177,7 @@ model_makeFromStream( MPFORMAL XWStreamCtxt* stream, DictionaryCtxt* dict, void model_writeToStream( ModelCtxt* model, XWStreamCtxt* stream ) { - short i; + XP_U16 ii; stream_putBits( stream, NUMCOLS_NBITS, model->nCols ); stream_putBits( stream, NUMCOLS_NBITS, model->nRows ); @@ -171,10 +185,17 @@ model_writeToStream( ModelCtxt* model, XWStreamCtxt* stream ) /* we have two bits for nPlayers, so range must be 0..3, not 1..4 */ stream_putBits( stream, NPLAYERS_NBITS, model->nPlayers ); +#ifdef STREAM_VERS_BIGBOARD + stream_putBits( stream, 7, model->nBonuses ); + for ( ii = 0; ii < model->nBonuses; ++ii ) { + stream_putBits( stream, 4, model->bonuses[ii] ); + } +#endif + stack_writeToStream( model->vol.stack, stream ); - for ( i = 0; i < model->nPlayers; ++i ) { - writePlayerCtxt( stream, &model->players[i] ); + for ( ii = 0; ii < model->nPlayers; ++ii ) { + writePlayerCtxt( stream, &model->players[ii] ); } } /* model_writeToStream */ @@ -246,9 +267,90 @@ model_destroy( ModelCtxt* model ) { stack_destroy( model->vol.stack ); /* is this it!? */ + if ( !!model->bonuses ) { + XP_FREE( model->vol.mpool, model->bonuses ); + } XP_FREE( model->vol.mpool, model ); } /* model_destroy */ +#ifdef STREAM_VERS_BIGBOARD +void +model_setSquareBonuses( ModelCtxt* model, XWBonusType* bonuses, XP_U16 nBonuses ) +{ +#ifdef DEBUG + XP_U16 nCols = (1 + model_numCols( model )) / 2; + XP_ASSERT( 0 < nCols ); + XP_U16 wantLen = 0; + while ( nCols > 0 ) { + wantLen += nCols--; + } + XP_ASSERT( wantLen == nBonuses ); +#endif + + if ( !!model->bonuses ) { + XP_FREE( model->vol.mpool, model->bonuses ); + } + model->bonuses = XP_MALLOC( model->vol.mpool, + nBonuses * sizeof(model->bonuses[0]) ); + XP_MEMCPY( model->bonuses, bonuses, nBonuses * sizeof(model->bonuses[0]) ); + model->nBonuses = nBonuses; +} + +static void +borrowSquareBonuses( ModelCtxt* dest, const ModelCtxt* src ) +{ + XP_ASSERT( !dest->bonuses ); + dest->bonuses = src->bonuses; + dest->nBonuses = src->nBonuses; +} + +static void +returnSquareBonuses( ModelCtxt* dest ) +{ + dest->bonuses = NULL; + dest->nBonuses = 0; +} +#else +# define borrowSquareBonuses(d,s) +# define returnSquareBonuses(d) +#endif + +XWBonusType +model_getSquareBonus( const ModelCtxt* model, XP_U16 col, XP_U16 row ) +{ + XWBonusType result = BONUS_NONE; + + if ( 0 ) { +#ifdef STREAM_VERS_BIGBOARD + } else if ( !!model->bonuses ) { + XP_U16 nCols = model_numCols( model ); + XP_U16 ii; + if ( col > (nCols/2) ) { + col = nCols - 1 - col; + } + if ( row > (nCols/2) ) { + row = nCols - 1 - row; + } + if ( col > row ) { + XP_U16 tmp = col; + col = row; + row = tmp; + } + for ( ii = 1; ii <= row; ++ii ) { + col += ii; + } + + if ( col < model->nBonuses ) { + result = model->bonuses[col]; + } +#endif + } else { + result = util_getSquareBonus( model->vol.util, model_numRows(model), + col, row ); + } + return result; +} + static void modelAddEntry( ModelCtxt* model, XP_U16 indx, const StackEntry* entry, XP_Bool useStack, XWStreamCtxt* stream, @@ -1950,6 +2052,7 @@ makeTmpModel( ModelCtxt* model, XWStreamCtxt* stream, model->vol.util, model_numCols(model), model_numRows(model)); model_setNPlayers( tmpModel, model->nPlayers ); + borrowSquareBonuses( tmpModel, model ); buildModelFromStack( tmpModel, model->vol.stack, XP_FALSE, 0, stream, (WordNotifierInfo*)NULL, mpf_pre, mpf_post, closure ); @@ -1971,6 +2074,7 @@ model_writeGameHistory( ModelCtxt* model, XWStreamCtxt* stream, tmpModel = makeTmpModel( model, stream, printMovePre, printMovePost, &closure ); + returnSquareBonuses( tmpModel ); model_destroy( tmpModel ); if ( gameOver ) { diff --git a/xwords4/common/model.h b/xwords4/common/model.h index 5bcf20685..ab01af9fd 100644 --- a/xwords4/common/model.h +++ b/xwords4/common/model.h @@ -269,6 +269,11 @@ void model_listWordsThrough( ModelCtxt* model, XP_U16 col, XP_U16 row, /* Have there been too many passes (so game should end)? */ XP_Bool model_recentPassCountOk( ModelCtxt* model ); +XWBonusType model_getSquareBonus( const ModelCtxt* model, + XP_U16 col, XP_U16 row ); +void model_setSquareBonuses( ModelCtxt* model, XWBonusType* bonuses, + XP_U16 nBonuses ); + XP_Bool model_checkMoveLegal( ModelCtxt* model, XP_S16 player, XWStreamCtxt* stream, WordNotifierInfo* notifyInfo ); diff --git a/xwords4/common/modelp.h b/xwords4/common/modelp.h index f9b15db7d..2d52f4c11 100644 --- a/xwords4/common/modelp.h +++ b/xwords4/common/modelp.h @@ -76,6 +76,8 @@ struct ModelCtxt { XP_U16 nPlayers; XP_U16 nCols; XP_U16 nRows; + XP_U16 nBonuses; + XWBonusType* bonuses; }; void invalidateScore( ModelCtxt* model, XP_S16 player ); diff --git a/xwords4/common/mscore.c b/xwords4/common/mscore.c index 80426c21d..4077f613c 100644 --- a/xwords4/common/mscore.c +++ b/xwords4/common/mscore.c @@ -526,7 +526,7 @@ figureMoveScore( const ModelCtxt* model, XP_U16 turn, MoveInfo* moveInfo, static XP_U16 word_multiplier( const ModelCtxt* model, XP_U16 col, XP_U16 row ) { - XWBonusType bonus = util_getSquareBonus( model->vol.util, model, col, row ); + XWBonusType bonus = model_getSquareBonus( model, col, row ); switch ( bonus ) { case BONUS_DOUBLE_WORD: return 2; @@ -540,8 +540,7 @@ word_multiplier( const ModelCtxt* model, XP_U16 col, XP_U16 row ) static XP_U16 tile_multiplier( const ModelCtxt* model, XP_U16 col, XP_U16 row ) { - XWBonusType bonus = util_getSquareBonus( model->vol.util, model, - col, row ); + XWBonusType bonus = model_getSquareBonus( model, col, row ); switch ( bonus ) { case BONUS_DOUBLE_LETTER: return 2; diff --git a/xwords4/common/util.h b/xwords4/common/util.h index dc25d28da..6815ebb46 100644 --- a/xwords4/common/util.h +++ b/xwords4/common/util.h @@ -99,8 +99,7 @@ typedef struct UtilVtable { XP_PlayerAddr channelNo ); #endif - XWBonusType (*m_util_getSquareBonus)( XW_UtilCtxt* uc, - const ModelCtxt* model, + XWBonusType (*m_util_getSquareBonus)( XW_UtilCtxt* uc, XP_U16 boardSize, XP_U16 col, XP_U16 row ); void (*m_util_userError)( XW_UtilCtxt* uc, UtilErrID id ); @@ -201,8 +200,8 @@ struct XW_UtilCtxt { #define util_makeStreamFromAddr(uc,a) \ (uc)->vtable->m_util_makeStreamFromAddr((uc),(a)) -#define util_getSquareBonus(uc,m,c,r) \ - (uc)->vtable->m_util_getSquareBonus((uc),(m),(c),(r)) +#define util_getSquareBonus(uc,b,c,r) \ + (uc)->vtable->m_util_getSquareBonus((uc),(b),(c),(r)) #define util_userError(uc,err) \ (uc)->vtable->m_util_userError((uc),(err)) diff --git a/xwords4/linux/cursesmain.c b/xwords4/linux/cursesmain.c index 11af9250b..7ef2e211d 100644 --- a/xwords4/linux/cursesmain.c +++ b/xwords4/linux/cursesmain.c @@ -1807,7 +1807,7 @@ cursesmain( XP_Bool isServer, LaunchParams* params ) #endif model_setDictionary( g_globals.cGlobals.game.model, params->dict ); - + setSquareBonuses( &g_globals.cGlobals ); positionSizeStuff( &g_globals, width, height ); #ifndef XWFEATURE_STANDALONE_ONLY diff --git a/xwords4/linux/gtkmain.c b/xwords4/linux/gtkmain.c index ebaccce8e..092d5740c 100644 --- a/xwords4/linux/gtkmain.c +++ b/xwords4/linux/gtkmain.c @@ -486,6 +486,7 @@ createOrLoadObjects( GtkAppGlobals* globals ) } #endif model_setDictionary( globals->cGlobals.game.model, params->dict ); + setSquareBonuses( &globals->cGlobals ); model_setPlayerDicts( globals->cGlobals.game.model, ¶ms->dicts ); #ifdef XWFEATURE_SEARCHLIMIT diff --git a/xwords4/linux/linuxutl.c b/xwords4/linux/linuxutl.c index b1df9cd12..886231376 100644 --- a/xwords4/linux/linuxutl.c +++ b/xwords4/linux/linuxutl.c @@ -80,6 +80,63 @@ linux_util_makeEmptyDict( XW_UtilCtxt* XP_UNUSED_DBG(uctx) ) #define TL BONUS_TRIPLE_LETTER #define TW BONUS_TRIPLE_WORD +static XWBonusType* +bonusesFor( XP_U16 boardSize, XP_U16* len ) +{ + static XWBonusType scrabbleBoard[] = { + TW,//EM,EM,DL,EM,EM,EM,TW, + EM,DW,//EM,EM,EM,TL,EM,EM, + + EM,EM,DW,//EM,EM,EM,DL,EM, + DL,EM,EM,DW,//EM,EM,EM,DL, + + EM,EM,EM,EM,DW,//EM,EM,EM, + EM,TL,EM,EM,EM,TL,//EM,EM, + + EM,EM,DL,EM,EM,EM,DL,//EM, + TW,EM,EM,DL,EM,EM,EM,DW, + }; /* scrabbleBoard */ + + static XWBonusType seventeen[] = { + TW,//EM,EM,DL,EM,EM,EM,TW, + EM,DW,//EM,EM,EM,TL,EM,EM, + + EM,EM,DW,//EM,EM,EM,DL,EM, + DL,EM,EM,DW,//EM,EM,EM,DL, + + EM,EM,EM,EM,DW,//EM,EM,EM, + EM,TL,EM,EM,EM,TL,//EM,EM, + + EM,EM,DL,EM,EM,EM,DL,//EM, + TW,EM,EM,DL,EM,EM,EM,DW, + TW,EM,EM,DL,EM,EM,EM,DW,DW, + }; /* scrabbleBoard */ + + XWBonusType* result = NULL; + if ( boardSize == 15 ) { + result = scrabbleBoard; + *len = VSIZE(scrabbleBoard); + } else if ( boardSize == 17 ) { + result = seventeen; + *len = VSIZE(seventeen); + } + + return result; +} + +#ifdef STREAM_VERS_BIGBOARD +void +setSquareBonuses( const CommonGlobals* cGlobals ) +{ + XP_U16 nBonuses; + XWBonusType* bonuses = + bonusesFor( cGlobals->params->gi.boardSize, &nBonuses ); + if ( !!bonuses ) { + model_setSquareBonuses( cGlobals->game.model, bonuses, nBonuses ); + } +} +#endif + static XWBonusType* parseBonusFile( XP_U16 nCols, const char* bonusFile ) { @@ -146,14 +203,13 @@ parseBonusFile( XP_U16 nCols, const char* bonusFile ) } static XWBonusType -linux_util_getSquareBonus( XW_UtilCtxt* uc, const ModelCtxt* model, +linux_util_getSquareBonus( XW_UtilCtxt* uc, XP_U16 nCols, XP_U16 col, XP_U16 row ) { static XWBonusType* parsedFile = NULL; XWBonusType result = EM; CommonGlobals* cGlobals = (CommonGlobals*)uc->closure; - XP_U16 nCols = model_numCols( model ); if ( NULL == parsedFile && NULL != cGlobals->params->bonusFile ) { if ( !parsedFile ) { parsedFile = parseBonusFile( nCols, cGlobals->params->bonusFile ); @@ -162,24 +218,10 @@ linux_util_getSquareBonus( XW_UtilCtxt* uc, const ModelCtxt* model, if ( NULL != parsedFile ) { result = parsedFile[(row*nCols) + col]; } else { + XP_U16 nEntries; + XWBonusType* scrabbleBoard = bonusesFor( 15, &nEntries ); + XP_U16 index, ii; - /* This must be static or won't compile under multilink (for Palm). - Fix! */ - static char scrabbleBoard[8*8] = { - TW,//EM,EM,DL,EM,EM,EM,TW, - EM,DW,//EM,EM,EM,TL,EM,EM, - - EM,EM,DW,//EM,EM,EM,DL,EM, - DL,EM,EM,DW,//EM,EM,EM,DL, - - EM,EM,EM,EM,DW,//EM,EM,EM, - EM,TL,EM,EM,EM,TL,//EM,EM, - - EM,EM,DL,EM,EM,EM,DL,//EM, - TW,EM,EM,DL,EM,EM,EM,DW, - }; /* scrabbleBoard */ - - XP_U16 nCols = model_numCols( model ); if ( col > (nCols/2) ) col = nCols - 1 - col; if ( row > (nCols/2) ) row = nCols - 1 - row; if ( col > row ) { @@ -192,8 +234,8 @@ linux_util_getSquareBonus( XW_UtilCtxt* uc, const ModelCtxt* model, index += ii; } - if ( index < VSIZE(scrabbleBoard) ) { - result = (XWBonusType)scrabbleBoard[index]; + if ( index < nEntries) { + result = scrabbleBoard[index]; } } return result; diff --git a/xwords4/linux/linuxutl.h b/xwords4/linux/linuxutl.h index 198d466fc..59e61d83b 100644 --- a/xwords4/linux/linuxutl.h +++ b/xwords4/linux/linuxutl.h @@ -1,6 +1,6 @@ -/* -*-mode: C; fill-column: 78; c-basic-offset: 4; compile-command: "make MEMDEBUG=TRUE"; -*- */ +/* -*- compile-command: "make MEMDEBUG=TRUE -j3"; -*- */ /* - * Copyright 2000-2008 by Eric House (xwords@eehouse.org). All rights + * Copyright 2000 - 2011 by Eric House (xwords@eehouse.org). All rights * reserved. * * This program is free software; you can redistribute it and/or @@ -25,6 +25,7 @@ #include "xptypes.h" #include "dictnry.h" #include "util.h" +#include "main.h" #ifdef DEBUG void linux_debugf(const char*, ...) @@ -41,4 +42,10 @@ const XP_UCHAR* linux_getErrString( UtilErrID id, XP_Bool* silent ); void formatConfirmTrade( const XP_UCHAR** tiles, XP_U16 nTiles, char* buf, XP_U16 buflen ); +#ifdef STREAM_VERS_BIGBOARD +void setSquareBonuses( const CommonGlobals* cGlobals ); +#else +# define setSquareBonuses( cg ) +#endif + #endif