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.
This commit is contained in:
Andy2 2011-11-16 19:01:11 -08:00
parent fab39a5f87
commit 210c59ef9b
13 changed files with 213 additions and 55 deletions

View file

@ -1002,8 +1002,7 @@ timerFiredForPen( BoardCtxt* board )
#endif #endif
if ( !listWords ) { if ( !listWords ) {
XWBonusType bonus; XWBonusType bonus;
bonus = util_getSquareBonus( board->util, board->model, bonus = model_getSquareBonus( board->model, col, row );
col, row );
if ( bonus != BONUS_NONE ) { if ( bonus != BONUS_NONE ) {
#ifdef XWFEATURE_MINIWIN #ifdef XWFEATURE_MINIWIN
text = draw_getMiniWText( board->draw, text = draw_getMiniWText( board->draw,

View file

@ -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. * reserved.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
@ -331,7 +331,7 @@ drawBoard( BoardCtxt* board )
XWBonusType bonus; XWBonusType bonus;
HintAtts hintAtts; HintAtts hintAtts;
CellFlags flags = CELL_NONE; CellFlags flags = CELL_NONE;
bonus = util_getSquareBonus( board->util, model, col, row ); bonus = model_getSquareBonus( model, col, row );
hintAtts = figureHintAtts( board, col, row ); hintAtts = figureHintAtts( board, col, row );
#ifdef KEYBOARD_NAV #ifdef KEYBOARD_NAV
if ( cellFocused( board, col, row ) ) { 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 ); textP = dict_getTileString( dict, tile );
} }
} }
bonus = util_getSquareBonus( board->util, model, col, row ); bonus = model_getSquareBonus( model, col, row );
hintAtts = figureHintAtts( board, col, row ); hintAtts = figureHintAtts( board, col, row );
if ( (col==board->star_row) && (row==board->star_row) ) { if ( (col==board->star_row) && (row==board->star_row) ) {

View file

@ -137,6 +137,16 @@ typedef XP_U32 RowFlags;
error error
#endif #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 /* 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 * 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 * want to deal with versioning in the common code. Second, becuase they

View file

@ -39,16 +39,6 @@ extern "C" {
typedef XP_U8 XP_LangCode; 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 { typedef enum {
INTRADE_MW_TEXT = BONUS_LAST INTRADE_MW_TEXT = BONUS_LAST
} XWMiniTextType; } XWMiniTextType;

View file

@ -115,7 +115,7 @@ model_makeFromStream( MPFORMAL XWStreamCtxt* stream, DictionaryCtxt* dict,
{ {
ModelCtxt* model; ModelCtxt* model;
XP_U16 nCols, nRows; XP_U16 nCols, nRows;
short i; XP_U16 ii;
XP_Bool hasDict; XP_Bool hasDict;
XP_U16 nPlayers; XP_U16 nPlayers;
XP_U16 nColsNBits; 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 = model_make( MPPARM(mpool) dict, dicts, util, nCols, nRows );
model->nPlayers = nPlayers; 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 ); stack_loadFromStream( model->vol.stack, stream );
buildModelFromStack( model, model->vol.stack, XP_FALSE, 0, buildModelFromStack( model, model->vol.stack, XP_FALSE, 0,
@ -151,10 +165,10 @@ model_makeFromStream( MPFORMAL XWStreamCtxt* stream, DictionaryCtxt* dict,
(MovePrintFuncPre)NULL, (MovePrintFuncPost)NULL, (MovePrintFuncPre)NULL, (MovePrintFuncPost)NULL,
NULL ); NULL );
for ( i = 0; i < model->nPlayers; ++i ) { for ( ii = 0; ii < model->nPlayers; ++ii ) {
loadPlayerCtxt( stream, version, &model->players[i] ); loadPlayerCtxt( stream, version, &model->players[ii] );
setPendingCounts( model, i ); setPendingCounts( model, ii );
invalidateScore( model, i ); invalidateScore( model, ii );
} }
return model; return model;
@ -163,7 +177,7 @@ model_makeFromStream( MPFORMAL XWStreamCtxt* stream, DictionaryCtxt* dict,
void void
model_writeToStream( ModelCtxt* model, XWStreamCtxt* stream ) model_writeToStream( ModelCtxt* model, XWStreamCtxt* stream )
{ {
short i; XP_U16 ii;
stream_putBits( stream, NUMCOLS_NBITS, model->nCols ); stream_putBits( stream, NUMCOLS_NBITS, model->nCols );
stream_putBits( stream, NUMCOLS_NBITS, model->nRows ); 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 */ /* we have two bits for nPlayers, so range must be 0..3, not 1..4 */
stream_putBits( stream, NPLAYERS_NBITS, model->nPlayers ); 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 ); stack_writeToStream( model->vol.stack, stream );
for ( i = 0; i < model->nPlayers; ++i ) { for ( ii = 0; ii < model->nPlayers; ++ii ) {
writePlayerCtxt( stream, &model->players[i] ); writePlayerCtxt( stream, &model->players[ii] );
} }
} /* model_writeToStream */ } /* model_writeToStream */
@ -246,9 +267,90 @@ model_destroy( ModelCtxt* model )
{ {
stack_destroy( model->vol.stack ); stack_destroy( model->vol.stack );
/* is this it!? */ /* is this it!? */
if ( !!model->bonuses ) {
XP_FREE( model->vol.mpool, model->bonuses );
}
XP_FREE( model->vol.mpool, model ); XP_FREE( model->vol.mpool, model );
} /* model_destroy */ } /* 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 static void
modelAddEntry( ModelCtxt* model, XP_U16 indx, const StackEntry* entry, modelAddEntry( ModelCtxt* model, XP_U16 indx, const StackEntry* entry,
XP_Bool useStack, XWStreamCtxt* stream, XP_Bool useStack, XWStreamCtxt* stream,
@ -1950,6 +2052,7 @@ makeTmpModel( ModelCtxt* model, XWStreamCtxt* stream,
model->vol.util, model_numCols(model), model->vol.util, model_numCols(model),
model_numRows(model)); model_numRows(model));
model_setNPlayers( tmpModel, model->nPlayers ); model_setNPlayers( tmpModel, model->nPlayers );
borrowSquareBonuses( tmpModel, model );
buildModelFromStack( tmpModel, model->vol.stack, XP_FALSE, 0, stream, buildModelFromStack( tmpModel, model->vol.stack, XP_FALSE, 0, stream,
(WordNotifierInfo*)NULL, mpf_pre, mpf_post, closure ); (WordNotifierInfo*)NULL, mpf_pre, mpf_post, closure );
@ -1971,6 +2074,7 @@ model_writeGameHistory( ModelCtxt* model, XWStreamCtxt* stream,
tmpModel = makeTmpModel( model, stream, printMovePre, printMovePost, tmpModel = makeTmpModel( model, stream, printMovePre, printMovePost,
&closure ); &closure );
returnSquareBonuses( tmpModel );
model_destroy( tmpModel ); model_destroy( tmpModel );
if ( gameOver ) { if ( gameOver ) {

View file

@ -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)? */ /* Have there been too many passes (so game should end)? */
XP_Bool model_recentPassCountOk( ModelCtxt* model ); 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, XP_Bool model_checkMoveLegal( ModelCtxt* model, XP_S16 player,
XWStreamCtxt* stream, XWStreamCtxt* stream,
WordNotifierInfo* notifyInfo ); WordNotifierInfo* notifyInfo );

View file

@ -76,6 +76,8 @@ struct ModelCtxt {
XP_U16 nPlayers; XP_U16 nPlayers;
XP_U16 nCols; XP_U16 nCols;
XP_U16 nRows; XP_U16 nRows;
XP_U16 nBonuses;
XWBonusType* bonuses;
}; };
void invalidateScore( ModelCtxt* model, XP_S16 player ); void invalidateScore( ModelCtxt* model, XP_S16 player );

View file

@ -526,7 +526,7 @@ figureMoveScore( const ModelCtxt* model, XP_U16 turn, MoveInfo* moveInfo,
static XP_U16 static XP_U16
word_multiplier( const ModelCtxt* model, XP_U16 col, XP_U16 row ) 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 ) { switch ( bonus ) {
case BONUS_DOUBLE_WORD: case BONUS_DOUBLE_WORD:
return 2; return 2;
@ -540,8 +540,7 @@ word_multiplier( const ModelCtxt* model, XP_U16 col, XP_U16 row )
static XP_U16 static XP_U16
tile_multiplier( const ModelCtxt* model, XP_U16 col, XP_U16 row ) tile_multiplier( const ModelCtxt* model, XP_U16 col, XP_U16 row )
{ {
XWBonusType bonus = util_getSquareBonus( model->vol.util, model, XWBonusType bonus = model_getSquareBonus( model, col, row );
col, row );
switch ( bonus ) { switch ( bonus ) {
case BONUS_DOUBLE_LETTER: case BONUS_DOUBLE_LETTER:
return 2; return 2;

View file

@ -99,8 +99,7 @@ typedef struct UtilVtable {
XP_PlayerAddr channelNo ); XP_PlayerAddr channelNo );
#endif #endif
XWBonusType (*m_util_getSquareBonus)( XW_UtilCtxt* uc, XWBonusType (*m_util_getSquareBonus)( XW_UtilCtxt* uc, XP_U16 boardSize,
const ModelCtxt* model,
XP_U16 col, XP_U16 row ); XP_U16 col, XP_U16 row );
void (*m_util_userError)( XW_UtilCtxt* uc, UtilErrID id ); void (*m_util_userError)( XW_UtilCtxt* uc, UtilErrID id );
@ -201,8 +200,8 @@ struct XW_UtilCtxt {
#define util_makeStreamFromAddr(uc,a) \ #define util_makeStreamFromAddr(uc,a) \
(uc)->vtable->m_util_makeStreamFromAddr((uc),(a)) (uc)->vtable->m_util_makeStreamFromAddr((uc),(a))
#define util_getSquareBonus(uc,m,c,r) \ #define util_getSquareBonus(uc,b,c,r) \
(uc)->vtable->m_util_getSquareBonus((uc),(m),(c),(r)) (uc)->vtable->m_util_getSquareBonus((uc),(b),(c),(r))
#define util_userError(uc,err) \ #define util_userError(uc,err) \
(uc)->vtable->m_util_userError((uc),(err)) (uc)->vtable->m_util_userError((uc),(err))

View file

@ -1807,7 +1807,7 @@ cursesmain( XP_Bool isServer, LaunchParams* params )
#endif #endif
model_setDictionary( g_globals.cGlobals.game.model, params->dict ); model_setDictionary( g_globals.cGlobals.game.model, params->dict );
setSquareBonuses( &g_globals.cGlobals );
positionSizeStuff( &g_globals, width, height ); positionSizeStuff( &g_globals, width, height );
#ifndef XWFEATURE_STANDALONE_ONLY #ifndef XWFEATURE_STANDALONE_ONLY

View file

@ -486,6 +486,7 @@ createOrLoadObjects( GtkAppGlobals* globals )
} }
#endif #endif
model_setDictionary( globals->cGlobals.game.model, params->dict ); model_setDictionary( globals->cGlobals.game.model, params->dict );
setSquareBonuses( &globals->cGlobals );
model_setPlayerDicts( globals->cGlobals.game.model, &params->dicts ); model_setPlayerDicts( globals->cGlobals.game.model, &params->dicts );
#ifdef XWFEATURE_SEARCHLIMIT #ifdef XWFEATURE_SEARCHLIMIT

View file

@ -80,6 +80,63 @@ linux_util_makeEmptyDict( XW_UtilCtxt* XP_UNUSED_DBG(uctx) )
#define TL BONUS_TRIPLE_LETTER #define TL BONUS_TRIPLE_LETTER
#define TW BONUS_TRIPLE_WORD #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* static XWBonusType*
parseBonusFile( XP_U16 nCols, const char* bonusFile ) parseBonusFile( XP_U16 nCols, const char* bonusFile )
{ {
@ -146,14 +203,13 @@ parseBonusFile( XP_U16 nCols, const char* bonusFile )
} }
static XWBonusType 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 ) XP_U16 col, XP_U16 row )
{ {
static XWBonusType* parsedFile = NULL; static XWBonusType* parsedFile = NULL;
XWBonusType result = EM; XWBonusType result = EM;
CommonGlobals* cGlobals = (CommonGlobals*)uc->closure; CommonGlobals* cGlobals = (CommonGlobals*)uc->closure;
XP_U16 nCols = model_numCols( model );
if ( NULL == parsedFile && NULL != cGlobals->params->bonusFile ) { if ( NULL == parsedFile && NULL != cGlobals->params->bonusFile ) {
if ( !parsedFile ) { if ( !parsedFile ) {
parsedFile = parseBonusFile( nCols, cGlobals->params->bonusFile ); parsedFile = parseBonusFile( nCols, cGlobals->params->bonusFile );
@ -162,24 +218,10 @@ linux_util_getSquareBonus( XW_UtilCtxt* uc, const ModelCtxt* model,
if ( NULL != parsedFile ) { if ( NULL != parsedFile ) {
result = parsedFile[(row*nCols) + col]; result = parsedFile[(row*nCols) + col];
} else { } else {
XP_U16 nEntries;
XWBonusType* scrabbleBoard = bonusesFor( 15, &nEntries );
XP_U16 index, ii; 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 ( col > (nCols/2) ) col = nCols - 1 - col;
if ( row > (nCols/2) ) row = nCols - 1 - row; if ( row > (nCols/2) ) row = nCols - 1 - row;
if ( col > row ) { if ( col > row ) {
@ -192,8 +234,8 @@ linux_util_getSquareBonus( XW_UtilCtxt* uc, const ModelCtxt* model,
index += ii; index += ii;
} }
if ( index < VSIZE(scrabbleBoard) ) { if ( index < nEntries) {
result = (XWBonusType)scrabbleBoard[index]; result = scrabbleBoard[index];
} }
} }
return result; return result;

View file

@ -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. * reserved.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
@ -25,6 +25,7 @@
#include "xptypes.h" #include "xptypes.h"
#include "dictnry.h" #include "dictnry.h"
#include "util.h" #include "util.h"
#include "main.h"
#ifdef DEBUG #ifdef DEBUG
void linux_debugf(const char*, ...) 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, void formatConfirmTrade( const XP_UCHAR** tiles, XP_U16 nTiles, char* buf,
XP_U16 buflen ); XP_U16 buflen );
#ifdef STREAM_VERS_BIGBOARD
void setSquareBonuses( const CommonGlobals* cGlobals );
#else
# define setSquareBonuses( cg )
#endif
#endif #endif