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
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,

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.
*
* 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) ) {

View file

@ -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

View file

@ -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;

View file

@ -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 ) {

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)? */
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 );

View file

@ -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 );

View file

@ -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;

View file

@ -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))

View file

@ -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

View file

@ -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, &params->dicts );
#ifdef XWFEATURE_SEARCHLIMIT

View file

@ -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;

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.
*
* 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