bring in changes to make larger boards work for linux

Includes making tile sets vary with board size, calculated from 15x15
unless present in the wordlist. Likely breaks android.
This commit is contained in:
Eric House 2022-04-04 10:39:29 +02:00
commit 5d6d8c7499
24 changed files with 342 additions and 398 deletions

View file

@ -210,7 +210,6 @@ board_makeFromStream( MPFORMAL XWEnv xwe, XWStreamCtxt* stream, ModelCtxt* model
XP_U16 nPlayers )
{
BoardCtxt* board;
XP_U16 ii;
XP_U16 version = stream_getVersion( stream );
XP_U16 nColsNBits;
#ifdef STREAM_VERS_BIGBOARD
@ -223,11 +222,11 @@ board_makeFromStream( MPFORMAL XWEnv xwe, XWStreamCtxt* stream, ModelCtxt* model
board_setCallbacks( board, xwe );
if ( version >= STREAM_VERS_4YOFFSET) {
board->sd[SCROLL_H].offset = (XP_U16)stream_getBits( stream, 4 );
board->zoomCount = (XP_U16)stream_getBits( stream, 4 );
board->sd[SCROLL_H].offset = (XP_U16)stream_getBits( stream, nColsNBits );
board->zoomCount = (XP_U16)stream_getBits( stream, nColsNBits );
}
board->sd[SCROLL_V].offset = (XP_U16)
stream_getBits( stream, (version < STREAM_VERS_4YOFFSET) ? 2 : 4 );
stream_getBits( stream, (version < STREAM_VERS_4YOFFSET) ? 2 : nColsNBits );
board->isFlipped = (XP_Bool)stream_getBits( stream, 1 );
board->gameOver = (XP_Bool)stream_getBits( stream, 1 );
board->showColors = (XP_Bool)stream_getBits( stream, 1 );
@ -249,7 +248,7 @@ board_makeFromStream( MPFORMAL XWEnv xwe, XWStreamCtxt* stream, ModelCtxt* model
XP_ASSERT( !!server );
for ( ii = 0; ii < nPlayers; ++ii ) {
for ( int ii = 0; ii < nPlayers; ++ii ) {
PerTurnInfo* pti = &board->pti[ii];
BoardArrow* arrow = &pti->boardArrow;
arrow->col = (XP_U8)stream_getBits( stream, nColsNBits );
@ -324,10 +323,9 @@ board_writeToStream( const BoardCtxt* board, XWStreamCtxt* stream )
nColsNBits = NUMCOLS_NBITS_4;
#endif
stream_putBits( stream, 4, board->sd[SCROLL_H].offset );
stream_putBits( stream, 4, board->zoomCount );
stream_putBits( stream, 4, board->sd[SCROLL_V].offset );
stream_putBits( stream, nColsNBits, board->sd[SCROLL_H].offset );
stream_putBits( stream, nColsNBits, board->zoomCount );
stream_putBits( stream, nColsNBits, board->sd[SCROLL_V].offset );
stream_putBits( stream, 1, board->isFlipped );
stream_putBits( stream, 1, board->gameOver );
stream_putBits( stream, 1, board->showColors );
@ -1371,7 +1369,7 @@ timerFiredForPen( BoardCtxt* board, XWEnv xwe )
#endif
if ( !listWords ) {
XWBonusType bonus;
bonus = model_getSquareBonus( board->model, xwe, col, row );
bonus = model_getSquareBonus( board->model, col, row );
if ( bonus != BONUS_NONE ) {
#ifdef XWFEATURE_MINIWIN
text = draw_getMiniWText( board->draw,

View file

@ -339,7 +339,7 @@ drawBoard( BoardCtxt* board, XWEnv xwe )
XWBonusType bonus;
HintAtts hintAtts;
CellFlags flags = CELL_NONE;
bonus = model_getSquareBonus( model, xwe, col, row );
bonus = model_getSquareBonus( model, col, row );
hintAtts = figureHintAtts( board, col, row );
#ifdef KEYBOARD_NAV
if ( cellFocused( board, col, row ) ) {
@ -438,7 +438,7 @@ drawCell( BoardCtxt* board, XWEnv xwe, const XP_U16 col,
}
textP = dict_getTileString( dict, tile );
}
bonus = model_getSquareBonus( model, xwe, col, row );
bonus = model_getSquareBonus( model, col, row );
hintAtts = figureHintAtts( board, col, row );
if ( (col==board->star_row) && (row==board->star_row) ) {

View file

@ -46,6 +46,7 @@
# define MAX_ROWS 16
#endif
#define MAX_COLS MAX_ROWS
#define MIN_COLS 11
#define STREAM_VERS_SMALLCOMMS 0x1F
#define STREAM_VERS_NINETILES 0x1E
@ -212,6 +213,8 @@ typedef enum {
BONUS_DOUBLE_WORD,
BONUS_TRIPLE_LETTER,
BONUS_TRIPLE_WORD,
BONUS_QUAD_LETTER,
BONUS_QUAD_WORD,
BONUS_LAST
} XWBonusType;

View file

@ -1,6 +1,6 @@
/* -*- compile-command: "cd ../linux && make MEMDEBUG=TRUE -j3"; -*- */
/*
* Copyright 1997-2011 by Eric House (xwords@eehouse.org). All rights
* Copyright 1997 - 2022 by Eric House (xwords@eehouse.org). All rights
* reserved.
*
* This program is free software; you can redistribute it and/or
@ -41,6 +41,7 @@ extern "C" {
****************************************************************************/
static XP_Bool makeBitmap( XP_U8 const** ptrp, const XP_U8* end );
static XP_U8* getCountsFor( const DictionaryCtxt* dict, XP_U16 nCols );
const DictionaryCtxt*
p_dict_ref( const DictionaryCtxt* dict, XWEnv XP_UNUSED(xwe)
@ -99,14 +100,12 @@ dict_unref_all( PlayerDicts* pd, XWEnv xwe )
}
static XP_UCHAR*
getNullTermParam( DictionaryCtxt* XP_UNUSED_DBG(dctx), const XP_U8** ptr,
XP_U16* headerLen )
getNullTermParam( DictionaryCtxt* XP_UNUSED_DBG(dctx), const XP_U8** ptr )
{
XP_U16 len = 1 + XP_STRLEN( (XP_UCHAR*)*ptr );
XP_UCHAR* result = XP_MALLOC( dctx->mpool, len );
XP_MEMCPY( result, *ptr, len );
*ptr += len;
*headerLen -= len;
return result;
}
@ -234,44 +233,78 @@ parseCommon( DictionaryCtxt* dctx, XWEnv xwe, const XP_U8** ptrp, const XP_U8* e
XP_U8 numFaceBytes, numFaces;
if ( hasHeader ) {
XP_U16 headerLen;
const XP_U8* headerEnd;
{
XP_U16 headerLen;
XP_MEMCPY( &headerLen, ptr, sizeof(headerLen) );
ptr += sizeof(headerLen);
headerLen = XP_NTOHS( headerLen );
headerEnd = ptr + headerLen;
}
XP_U32 wordCount;
XP_MEMCPY( &headerLen, ptr, sizeof(headerLen) );
ptr += sizeof(headerLen);
headerLen = XP_NTOHS( headerLen );
XP_MEMCPY( &wordCount, ptr, sizeof(wordCount) );
ptr += sizeof(wordCount);
headerLen -= sizeof(wordCount);
dctx->nWords = XP_NTOHL( wordCount );
XP_DEBUGF( "dict contains %d words", dctx->nWords );
if ( 0 < headerLen ) {
dctx->desc = getNullTermParam( dctx, &ptr, &headerLen );
} else {
XP_LOGF( "%s: no note", __func__ );
if ( ptr == headerEnd ) {
XP_LOGFF( "no note" );
goto done;
}
if ( 0 < headerLen ) {
dctx->md5Sum = getNullTermParam( dctx, &ptr, &headerLen );
} else {
XP_LOGF( "%s: no md5Sum", __func__ );
XP_ASSERT( ptr < headerEnd );
dctx->desc = getNullTermParam( dctx, &ptr );
if ( ptr == headerEnd ) {
XP_LOGFF( "no md5Sum" );
goto done;
}
XP_ASSERT( ptr < headerEnd );
dctx->md5Sum = getNullTermParam( dctx, &ptr );
XP_U16 headerFlags = 0;
if ( sizeof(headerFlags) <= headerLen ) {
XP_MEMCPY( &headerFlags, ptr, sizeof(headerFlags) );
headerFlags = XP_NTOHS( headerFlags );
ptr += sizeof(headerFlags);
headerLen -= sizeof(headerFlags);
if ( ptr + sizeof(headerFlags) > headerEnd ) {
goto done;
}
XP_MEMCPY( &headerFlags, ptr, sizeof(headerFlags) );
headerFlags = XP_NTOHS( headerFlags );
ptr += sizeof(headerFlags);
XP_LOGFF( "setting headerFlags: 0x%x", headerFlags );
dctx->headerFlags = headerFlags;
if ( 0 < headerLen ) {
XP_LOGFF( "skipping %d bytes of header", headerLen );
if ( ptr == headerEnd ) {
goto done;
}
ptr += headerLen;
XP_UCHAR* langName = getNullTermParam( dctx, &ptr );
if ( ptr == headerEnd ) {
goto done;
}
XP_UCHAR* langCode = getNullTermParam( dctx, &ptr );
XP_LOGFF( "got langName: %s; langCode: %s", langName, langCode );
XP_FREE( dctx->mpool, langName );
XP_FREE( dctx->mpool, langCode );
if ( ptr == headerEnd ) {
goto done;
}
XP_U8 otherLen = *ptr++;
XP_LOGFF( "otherLen: %d", otherLen );
if ( 0 < otherLen ) {
XP_ASSERT( ptr + otherLen <= headerEnd );
if ( ptr + otherLen <= headerEnd ) {
dctx->otherCounts = XP_MALLOC( dctx->mpool, otherLen );
dctx->otherCountsEnd = dctx->otherCounts + otherLen;
XP_MEMCPY( dctx->otherCounts, ptr, otherLen );
ptr += otherLen;
}
}
done:
if ( ptr < headerEnd ) {
XP_LOGFF( "skipping %zu bytes of header", headerEnd - ptr );
}
ptr = headerEnd;
}
if ( isUTF8 ) {
@ -301,7 +334,10 @@ parseCommon( DictionaryCtxt* dctx, XWEnv xwe, const XP_U8** ptrp, const XP_U8* e
dctx->nFaces = numFaces;
dctx->countsAndValues = XP_MALLOC( dctx->mpool, numFaces * 2 );
dctx->values = XP_MALLOC( dctx->mpool, numFaces);
XP_U8* counts15 = XP_MALLOC( dctx->mpool, numFaces); /* leaking */
dctx->counts[15>>1] = counts15;
XP_U16 facesSize = numFaceBytes;
if ( !isUTF8 ) {
facesSize /= 2;
@ -316,8 +352,11 @@ parseCommon( DictionaryCtxt* dctx, XWEnv xwe, const XP_U8** ptrp, const XP_U8* e
unsigned short xloc;
XP_MEMCPY( &xloc, ptr, sizeof(xloc) );
ptr += sizeof(xloc);
XP_MEMCPY( dctx->countsAndValues, ptr, numFaces*2 );
ptr += numFaces*2;
for ( int ii = 0; ii < numFaces; ++ii ) {
counts15[ii] = *ptr++;
dctx->values[ii] = *ptr++;
}
dctx->langCode = xloc & 0x7F;
}
@ -413,7 +452,7 @@ dict_getBlankTile( const DictionaryCtxt* dict )
} /* dict_getBlankTile */
XP_U16
dict_getTileValue( const DictionaryCtxt* dict, Tile tile )
dict_getTileValue( const DictionaryCtxt* dict, const Tile tile )
{
XP_ASSERT( !!dict );
if ( (tile & TILE_VALUE_MASK) != tile ) {
@ -421,9 +460,8 @@ dict_getTileValue( const DictionaryCtxt* dict, Tile tile )
tile == dict_getBlankTile( dict ) );
}
XP_ASSERT( tile < dict->nFaces );
tile *= 2;
XP_ASSERT( !!dict->countsAndValues );
return dict->countsAndValues[tile+1];
XP_ASSERT( !!dict->values );
return dict->values[tile];
} /* dict_getTileValue */
static const XP_UCHAR*
@ -477,11 +515,57 @@ dict_getNextTileString( const DictionaryCtxt* dict, Tile tile,
}
XP_U16
dict_numTiles( const DictionaryCtxt* dict, Tile tile )
dict_numTilesForSize( const DictionaryCtxt* dict, Tile tile, XP_U16 nCols )
{
tile *= 2;
return dict->countsAndValues[tile];
} /* dict_numTiles */
XP_U8* counts = getCountsFor( dict, nCols );
return counts[tile];
}
/* Older wordlists are built assuming 15x15 boards. Different sized boards
need different numbers of tiles. The wordlist might provide for the size we
have, in which case we use it. Otherwise we extrapolate.
*/
static XP_U8*
getCountsFor( const DictionaryCtxt* dict, XP_U16 nCols )
{
int offset = nCols >> 1;
XP_U8* counts = dict->counts[offset];
if ( !counts ) {
counts = XP_MALLOC( dict->mpool, dict->nFaces );
((DictionaryCtxt*)dict)->counts[offset] = counts;
XP_U8* ptr = dict->otherCounts;
XP_Bool found = XP_FALSE;
while ( !found && !!ptr && ptr < dict->otherCountsEnd ) {
XP_U8 siz = *ptr++;
found = siz == nCols;
if ( found ) {
XP_MEMCPY( counts, ptr, dict->nFaces );
} else {
ptr += dict->nFaces;
}
}
/* don't have it in the wordlist? Extrapolate */
if ( !found ) {
XP_U16 pct = (nCols * nCols * 100) / (15 * 15);
XP_U8* src15 = dict->counts[15>>1];
XP_ASSERT( !!src15 );
for ( int ii = 0; ii < dict->nFaces; ++ii ) {
XP_U16 count = src15[ii];
XP_U16 newCount = count * pct / 100;
if ( 50 < (count * pct) % 100 ) {
++newCount;
}
counts[ii] = newCount;
}
}
}
// XP_LOGFF( "(tile=%d, ncols=%d) => %d", tile, nCols, count );
return counts;
} /* getCountsFor */
XP_U16
dict_numTileFaces( const DictionaryCtxt* dict )
@ -631,7 +715,7 @@ dict_tilesAreSame( const DictionaryCtxt* dict1, const DictionaryCtxt* dict2 )
} else if ( 0 != XP_STRCMP( face1, face2 ) ) {
break;
}
if ( dict_numTiles( dict1, ii ) != dict_numTiles( dict2, ii ) ) {
if ( dict_numTilesForSize( dict1, ii, 15 ) != dict_numTilesForSize( dict2, ii, 15 ) ) {
break;
}
}
@ -641,33 +725,14 @@ dict_tilesAreSame( const DictionaryCtxt* dict1, const DictionaryCtxt* dict2 )
} /* dict_tilesAreSame */
#ifndef XWFEATURE_STANDALONE_ONLY
static void
ucharsToNarrow( const DictionaryCtxt* dict, XP_UCHAR* buf, XP_U16* bufsizep )
{
XP_U16 ii;
XP_U16 nUsed = 0;
XP_U16 bufsize = *bufsizep;
for ( ii = 0; ii < dict->nFaces; ++ii ) {
const XP_UCHAR* facep = dict_getTileStringRaw( dict, ii );
if ( IS_SPECIAL(*facep) ) {
buf[nUsed++] = *facep;
} else {
nUsed += XP_SNPRINTF( &buf[nUsed], bufsize - nUsed, "%s", facep );
}
XP_ASSERT( nUsed < bufsize );
}
buf[nUsed] = 0;
*bufsizep = nUsed;
}
/* Summarize tile info in a way it can be presented to users */
void
dict_writeTilesInfo( const DictionaryCtxt* dict, XWStreamCtxt* stream )
dict_writeTilesInfo( const DictionaryCtxt* dict, XP_U16 boardSize, XWStreamCtxt* stream )
{
XP_U16 nFaces = dict_numTileFaces( dict );
for ( Tile tile = 0; tile < nFaces; ++tile ) {
XP_U16 val = dict_getTileValue( dict, tile );
XP_U16 count = dict_numTiles( dict, tile );
XP_U16 count = dict_numTilesForSize( dict, tile, boardSize );
const XP_UCHAR* face = dict_getTileString( dict, tile );
XP_UCHAR buf[32];
XP_SNPRINTF( buf, VSIZE(buf), "%s\t%d\t%d\n", face, count, val );
@ -676,60 +741,63 @@ dict_writeTilesInfo( const DictionaryCtxt* dict, XWStreamCtxt* stream )
}
void
dict_writeToStream( const DictionaryCtxt* dict, XWStreamCtxt* stream )
dict_writeToStream( const DictionaryCtxt* XP_UNUSED(dict),
XWStreamCtxt* XP_UNUSED(stream) )
{
XP_U16 maxCount = 0;
XP_U16 maxValue = 0;
XP_U16 ii, nSpecials;
XP_U16 maxCountBits, maxValueBits;
XP_UCHAR buf[64];
XP_U16 nBytes;
XP_ASSERT(0);
/* XP_U16 maxCount = 0; */
/* XP_U16 maxValue = 0; */
/* XP_U16 ii, nSpecials; */
/* XP_U16 maxCountBits, maxValueBits; */
/* XP_UCHAR buf[64]; */
/* XP_U16 nBytes; */
stream_putBits( stream, 6, dict->nFaces );
/* stream_putBits( stream, 6, dict->nFaces ); */
for ( ii = 0; ii < dict->nFaces*2; ii+=2 ) {
XP_U16 count, value;
/* XP_ASSERT(0); /\* if this fires, need to fix for per-boardSize counts *\/ */
/* for ( ii = 0; ii < dict->nFaces*2; ii+=2 ) { */
/* XP_U16 count, value; */
count = dict->countsAndValues[ii];
if ( maxCount < count ) {
maxCount = count;
}
/* count = dict->countsAndValues[ii]; */
/* if ( maxCount < count ) { */
/* maxCount = count; */
/* } */
value = dict->countsAndValues[ii+1];
if ( maxValue < value ) {
maxValue = value;
}
}
/* value = dict->countsAndValues[ii+1]; */
/* if ( maxValue < value ) { */
/* maxValue = value; */
/* } */
/* } */
maxCountBits = bitsForMax( maxCount );
maxValueBits = bitsForMax( maxValue );
/* maxCountBits = bitsForMax( maxCount ); */
/* maxValueBits = bitsForMax( maxValue ); */
stream_putBits( stream, 3, maxCountBits ); /* won't be bigger than 5 */
stream_putBits( stream, 3, maxValueBits );
/* stream_putBits( stream, 3, maxCountBits ); /\* won't be bigger than 5 *\/ */
/* stream_putBits( stream, 3, maxValueBits ); */
for ( ii = 0; ii < dict->nFaces*2; ii+=2 ) {
stream_putBits( stream, maxCountBits, dict->countsAndValues[ii] );
stream_putBits( stream, maxValueBits, dict->countsAndValues[ii+1] );
}
/* for ( ii = 0; ii < dict->nFaces; ++ii ) { */
/* stream_putBits( stream, maxCountBits, counts[ii] ); */
/* stream_putBits( stream, maxValueBits, dict->values[ii] ); */
/* } */
/* Stream format of the faces is unchanged: chars run together, which
* happens to equal utf-8 for ascii. But now there may be more than one
* byte per face. Old code assumes that, but compatibility is ensured by
* the caller which will not accept an incoming message if the version's
* too new. And utf-8 dicts are flagged as newer by the sender.
*/
/* /\* Stream format of the faces is unchanged: chars run together, which */
/* * happens to equal utf-8 for ascii. But now there may be more than one */
/* * byte per face. Old code assumes that, but compatibility is ensured by */
/* * the caller which will not accept an incoming message if the version's */
/* * too new. And utf-8 dicts are flagged as newer by the sender. */
/* *\/ */
nBytes = sizeof(buf);
ucharsToNarrow( dict, buf, &nBytes );
stream_putU8( stream, nBytes );
stream_putBytes( stream, buf, nBytes );
/* nBytes = sizeof(buf); */
/* ucharsToNarrow( dict, buf, &nBytes ); */
/* stream_putU8( stream, nBytes ); */
/* stream_putBytes( stream, buf, nBytes ); */
for ( nSpecials = ii = 0; ii < dict->nFaces; ++ii ) {
const XP_UCHAR* facep = dict_getTileStringRaw( dict, (Tile)ii );
if ( IS_SPECIAL( *facep ) ) {
stringToStream( stream, dict->chars[nSpecials++] );
}
}
/* for ( nSpecials = ii = 0; ii < dict->nFaces; ++ii ) { */
/* const XP_UCHAR* facep = dict_getTileStringRaw( dict, (Tile)ii ); */
/* if ( IS_SPECIAL( *facep ) ) { */
/* stringToStream( stream, dict->chars[nSpecials++] ); */
/* } */
/* } */
} /* dict_writeToStream */
#endif
@ -763,7 +831,11 @@ common_destructor( DictionaryCtxt* dict, XWEnv XP_UNUSED(xwe) )
{
freeSpecials( dict );
XP_FREE( dict->mpool, dict->countsAndValues );
XP_FREE( dict->mpool, dict->values );
for ( int ii = 0; ii < VSIZE(dict->counts); ++ii ) {
XP_FREEP( dict->mpool, &dict->counts[ii] );
}
XP_FREE( dict->mpool, dict->otherCounts );
XP_FREE( dict->mpool, dict->faces );
XP_FREE( dict->mpool, dict->facePtrs );
@ -774,6 +846,7 @@ common_destructor( DictionaryCtxt* dict, XWEnv XP_UNUSED(xwe) )
void
dict_loadFromStream( DictionaryCtxt* dict, XWEnv xwe, XWStreamCtxt* stream )
{
XP_ASSERT(0); /* if this fires, need to fix for per-boardSize counts */
XP_U8 nFaces, nFaceBytes;
XP_U16 maxCountBits, maxValueBits;
XP_U16 ii, nSpecials;
@ -792,15 +865,14 @@ dict_loadFromStream( DictionaryCtxt* dict, XWEnv xwe, XWStreamCtxt* stream )
dict->nFaces = nFaces;
dict->countsAndValues =
(XP_U8*)XP_MALLOC( dict->mpool,
sizeof(dict->countsAndValues[0]) * nFaces * 2 );
dict->values = (XP_U8*)XP_MALLOC( dict->mpool,
sizeof(dict->values[0]) * nFaces );
XP_U8* counts = dict->counts[15>>1]
= (XP_U8*)XP_MALLOC( dict->mpool, sizeof(dict->values[0]) * nFaces );
for ( ii = 0; ii < dict->nFaces*2; ii+=2 ) {
dict->countsAndValues[ii] = (XP_U8)stream_getBits( stream,
maxCountBits );
dict->countsAndValues[ii+1] = (XP_U8)stream_getBits( stream,
maxValueBits );
for ( ii = 0; ii < dict->nFaces; ++ii ) {
counts[ii] = (XP_U8)stream_getBits( stream, maxCountBits );
dict->values[ii] = (XP_U8)stream_getBits( stream, maxValueBits );
}
nFaceBytes = (XP_U8)stream_getU8( stream );
@ -1028,7 +1100,7 @@ make_stubbed_dict( MPFORMAL_NOCOMMA )
setBlankTile( dict );
return dict;
} /* make_subbed_dict */
} /* make_stubbed_dict */
#endif /* STUBBED_DICT */
@ -1123,6 +1195,21 @@ dict_super_init( MPFORMAL DictionaryCtxt* dict )
pthread_mutex_init( &dict->mutex, NULL );
} /* dict_super_init */
void
dict_super_destroy( DictionaryCtxt* dict )
{
XP_FREEP( dict->mpool, &dict->desc );
XP_FREEP( dict->mpool, &dict->md5Sum );
XP_FREEP( dict->mpool, &dict->values );
for ( int ii = 0; ii < VSIZE(dict->counts); ++ii ) {
XP_FREEP( dict->mpool, &dict->counts[ii] );
}
XP_FREEP( dict->mpool, &dict->otherCounts );
XP_FREEP( dict->mpool, &dict->faces );
XP_FREEP( dict->mpool, &dict->facePtrs );
XP_FREEP( dict->mpool, &dict->name );
}
const XP_UCHAR*
dict_getLangName( const DictionaryCtxt* ctxt )
{

View file

@ -86,7 +86,11 @@ struct DictionaryCtxt {
XP_UCHAR* desc;
XP_UCHAR* md5Sum;
const XP_UCHAR** facePtrs; /* elems point into faces, above */
XP_U8* countsAndValues;
XP_U8* counts[(MAX_COLS>>1) + 1];
XP_U8* values;
XP_U8* otherCounts;
XP_U8* otherCountsEnd;
SpecialBitmaps* bitmaps;
XP_UCHAR** chars;
@ -177,7 +181,7 @@ XP_Bool dict_tilesAreSame( const DictionaryCtxt* dict1,
XP_Bool dict_hasBlankTile( const DictionaryCtxt* dict );
Tile dict_getBlankTile( const DictionaryCtxt* dict );
XP_U16 dict_getTileValue( const DictionaryCtxt* ctxt, Tile tile );
XP_U16 dict_numTiles( const DictionaryCtxt* ctxt, Tile tile );
XP_U16 dict_numTilesForSize( const DictionaryCtxt* ctxt, Tile tile, XP_U16 nCols );
XP_U16 dict_numTileFaces( const DictionaryCtxt* ctxt );
XP_U16 dict_getMaxTileChars( const DictionaryCtxt* ctxt );
@ -207,7 +211,8 @@ const XP_UCHAR* dict_getDesc( const DictionaryCtxt* dict );
const XP_UCHAR* dict_getMd5Sum( const DictionaryCtxt* dict );
XP_Bool dict_hasDuplicates( const DictionaryCtxt* dict );
void dict_writeTilesInfo( const DictionaryCtxt* ctxt, XWStreamCtxt* stream );
void dict_writeTilesInfo( const DictionaryCtxt* ctxt, XP_U16 boardSize,
XWStreamCtxt* stream );
void dict_writeToStream( const DictionaryCtxt* ctxt, XWStreamCtxt* stream );
void dict_loadFromStream( DictionaryCtxt* dict, XWEnv xwe, XWStreamCtxt* stream );
@ -232,6 +237,8 @@ XP_Bool checkSanity( DictionaryCtxt* dict, XP_U32 numEdges );
/* To be called only by subclasses!!! */
void dict_super_init( MPFORMAL DictionaryCtxt* ctxt );
void dict_super_destroy( DictionaryCtxt* ctxt );
/* Must be implemented by subclasses */
void dict_splitFaces( DictionaryCtxt* dict, XWEnv xwe, const XP_U8* bytes,
XP_U16 nBytes, XP_U16 nFaceos );

View file

@ -1,6 +1,7 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
/* -*- compile-command: "cd ../linux && make -j5 MEMDEBUG=TRUE"; -*- */
/*
* Copyright 1997 - 2003 by Eric House (xwords@eehouse.org). All rights reserved.
* Copyright 1997 - 2022 by Eric House (xwords@eehouse.org). All rights
* reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -296,6 +297,7 @@ default_draw_score_pendingScore( DrawCtx* dctx,
draw_setClip( dctx, &oldClip, NULL );
} /* default_draw_score_pendingScore */
#ifdef XWFEATURE_MINIWIN
static const XP_UCHAR*
default_draw_getMiniWText( DrawCtx* XP_UNUSED(dctx), XWMiniTextType textHint )
{
@ -310,6 +312,10 @@ default_draw_getMiniWText( DrawCtx* XP_UNUSED(dctx), XWMiniTextType textHint )
str = "Triple letter"; break;
case BONUS_TRIPLE_WORD:
str = "Triple word"; break;
case BONUS_QUAD_LETTER:
str = "Quad letter"; break;
case BONUS_QUAD_WORD:
str = "Quad word"; break;
case INTRADE_MW_TEXT:
str = "Trading tiles;\nclick D when done"; break;
default:
@ -343,6 +349,7 @@ default_draw_drawMiniWindow( DrawCtx* dctx, const XP_UCHAR* text,
draw_setClip( dctx, &oldClip, NULL );
} /* default_draw_drawMiniWindow */
#endif
void
InitDrawDefaults( DrawCtxVTable* vtable )

View file

@ -375,31 +375,69 @@ model_popToHash( ModelCtxt* model, XWEnv xwe, const XP_U32 hash, PoolContext* po
#ifdef STREAM_VERS_BIGBOARD
void
model_setSquareBonuses( ModelCtxt* model, XWBonusType* bonuses, XP_U16 nBonuses )
model_setSquareBonuses( ModelCtxt* XP_UNUSED(model), XWBonusType* XP_UNUSED(bonuses),
XP_U16 XP_UNUSED(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->vol.bonuses ) {
XP_FREE( model->vol.mpool, model->vol.bonuses );
}
model->vol.bonuses = XP_MALLOC( model->vol.mpool,
nBonuses * sizeof(model->vol.bonuses[0]) );
XP_MEMCPY( model->vol.bonuses, bonuses,
nBonuses * sizeof(model->vol.bonuses[0]) );
model->vol.nBonuses = nBonuses;
XP_LOGFF( "doing nothing" );
}
#endif
#define EM BONUS_NONE
#define DL BONUS_DOUBLE_LETTER
#define DW BONUS_DOUBLE_WORD
#define TL BONUS_TRIPLE_LETTER
#define TW BONUS_TRIPLE_WORD
#define QL BONUS_QUAD_LETTER
#define QW BONUS_QUAD_WORD
static XWBonusType sTwentyOne[] = {
QW,
EM, DW,
EM, EM, DW,
DL, EM, EM, TW,
EM, TL, EM, EM, DW,
EM, EM, QL, EM, EM, DW,
EM, EM, EM, DL, EM, EM, DW,
TW, EM, EM, EM, EM, EM, EM, DW,
EM, DW, EM, EM, TL, EM, EM, EM, TL,
EM, EM, DW, EM, EM, DL, EM, EM, EM, DL,
DL, EM, EM, TW, EM, EM, DL, EM, EM, EM, DW,
}; /* sTwentyOne */
static XWBonusType
getSquareBonus( XP_U16 nCols, XP_U16 col, XP_U16 row )
{
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 a smaller board, skip the outer "rings" */
XP_U16 adj = (21 - nCols) / 2;
col += adj;
row += adj;
XP_U16 index = col;
for ( XP_U16 ii = 1; ii <= row; ++ii ) {
index += ii;
}
XWBonusType result = BONUS_NONE;
if ( index < VSIZE(sTwentyOne)) {
result = sTwentyOne[index];
}
return result;
}
XWBonusType
model_getSquareBonus( const ModelCtxt* model, XWEnv xwe, XP_U16 col, XP_U16 row )
model_getSquareBonus( const ModelCtxt* model, XP_U16 col, XP_U16 row )
{
XWBonusType result = BONUS_NONE;
#ifdef STREAM_VERS_BIGBOARD
@ -431,9 +469,7 @@ model_getSquareBonus( const ModelCtxt* model, XWEnv xwe, XP_U16 col, XP_U16 row
}
#endif
} else {
result = util_getSquareBonus( model->vol.util, xwe,
model_numRows(model),
col, row );
result = getSquareBonus( model_numRows(model), col, row );
}
return result;
}

View file

@ -288,7 +288,7 @@ XP_Bool model_listWordsThrough( ModelCtxt* model, XWEnv xwe, XP_U16 col,
XP_Bool model_recentPassCountOk( ModelCtxt* model );
XWBonusType model_getSquareBonus( const ModelCtxt* model,
XWEnv xwe, XP_U16 col, XP_U16 row );
XP_U16 col, XP_U16 row );
#ifdef STREAM_VERS_BIGBOARD
void model_setSquareBonuses( ModelCtxt* model, XWBonusType* bonuses,
XP_U16 nBonuses );

View file

@ -34,8 +34,7 @@ extern "C" {
/****************************** prototypes ******************************/
static XP_Bool isLegalMove( ModelCtxt* model, XWEnv xwe, MoveInfo* moves,
XP_Bool silent );
static XP_U16 word_multiplier( const ModelCtxt* model, XWEnv xwe,
XP_U16 col, XP_U16 row );
static XP_U16 word_multiplier( const ModelCtxt* model, XP_U16 col, XP_U16 row );
static XP_U16 find_end( const ModelCtxt* model, XP_U16 col, XP_U16 row,
XP_Bool isHorizontal );
static XP_U16 find_start( const ModelCtxt* model, XP_U16 col, XP_U16 row,
@ -43,7 +42,7 @@ static XP_U16 find_start( const ModelCtxt* model, XP_U16 col, XP_U16 row,
static XP_S16 checkScoreMove( ModelCtxt* model, XWEnv xwe, XP_S16 turn,
EngineCtxt* engine, XWStreamCtxt* stream,
XP_Bool silent, WordNotifierInfo* notifyInfo );
static XP_U16 scoreWord( const ModelCtxt* model, XWEnv xwe, XP_U16 turn,
static XP_U16 scoreWord( const ModelCtxt* model, XP_U16 turn,
const MoveInfo* movei, EngineCtxt* engine,
XWStreamCtxt* stream, WordNotifierInfo* notifyInfo );
@ -555,10 +554,10 @@ figureMoveScore( const ModelCtxt* model, XWEnv xwe, XP_U16 turn,
for ( ii = 0; ii < nTiles; ++ii ) {
*incr = moveInfo->tiles[ii].varCoord;
moveMultiplier *= multipliers[ii] =
word_multiplier( model, xwe, col, row );
word_multiplier( model, col, row );
}
oneScore = scoreWord( model, xwe, turn, moveInfo, (EngineCtxt*)NULL,
oneScore = scoreWord( model, turn, moveInfo, (EngineCtxt*)NULL,
stream, notifyInfo );
if ( !!stream ) {
formatWordScore( stream, oneScore, moveMultiplier );
@ -576,7 +575,7 @@ figureMoveScore( const ModelCtxt* model, XWEnv xwe, XP_U16 turn,
tmpMI.commonCoord = tiles->varCoord;
tmpMI.tiles[0].tile = tiles->tile;
oneScore = scoreWord( model, xwe, turn, &tmpMI, engine, stream, notifyInfo );
oneScore = scoreWord( model, turn, &tmpMI, engine, stream, notifyInfo );
if ( !!stream ) {
formatWordScore( stream, oneScore, multipliers[ii] );
}
@ -612,35 +611,39 @@ figureMoveScore( const ModelCtxt* model, XWEnv xwe, XP_U16 turn,
} /* figureMoveScore */
static XP_U16
word_multiplier( const ModelCtxt* model, XWEnv xwe, XP_U16 col, XP_U16 row )
word_multiplier( const ModelCtxt* model, XP_U16 col, XP_U16 row )
{
XWBonusType bonus = model_getSquareBonus( model, xwe, col, row );
XWBonusType bonus = model_getSquareBonus( model, col, row );
switch ( bonus ) {
case BONUS_DOUBLE_WORD:
return 2;
case BONUS_TRIPLE_WORD:
return 3;
case BONUS_QUAD_WORD:
return 4;
default:
return 1;
}
} /* word_multiplier */
static XP_U16
tile_multiplier( const ModelCtxt* model, XWEnv xwe, XP_U16 col, XP_U16 row )
tile_multiplier( const ModelCtxt* model, XP_U16 col, XP_U16 row )
{
XWBonusType bonus = model_getSquareBonus( model, xwe, col, row );
XWBonusType bonus = model_getSquareBonus( model, col, row );
switch ( bonus ) {
case BONUS_DOUBLE_LETTER:
return 2;
case BONUS_TRIPLE_LETTER:
return 3;
case BONUS_QUAD_LETTER:
return 4;
default:
return 1;
}
} /* tile_multiplier */
static XP_U16
scoreWord( const ModelCtxt* model, XWEnv xwe, XP_U16 turn,
scoreWord( const ModelCtxt* model, XP_U16 turn,
const MoveInfo* movei, /* new tiles */
EngineCtxt* engine,/* for crosswise caching */
XWStreamCtxt* stream,
@ -689,7 +692,7 @@ scoreWord( const ModelCtxt* model, XWEnv xwe, XP_U16 turn,
thisTileValue = dict_getTileValue( dict, tile );
XP_ASSERT( *incr == tiles[0].varCoord );
thisTileValue *= tile_multiplier( model, xwe, col, row );
thisTileValue *= tile_multiplier( model, col, row );
XP_ASSERT( engine == NULL || nTiles == 1 );
@ -725,7 +728,7 @@ scoreWord( const ModelCtxt* model, XWEnv xwe, XP_U16 turn,
* mode, as the blank won't be known there. (Assert will
* fail.) */
tileMultiplier = tile_multiplier( model, xwe, col, row );
tileMultiplier = tile_multiplier( model, col, row );
++tiles;
--nTiles;
} else { /* placed on the board before this move */

View file

@ -242,7 +242,7 @@ pool_getNTilesLeftFor( const PoolContext* pool, Tile tile )
} /* pool_remainingTileCount */
void
pool_initFromDict( PoolContext* pool, const DictionaryCtxt* dict )
pool_initFromDict( PoolContext* pool, const DictionaryCtxt* dict, XP_U16 nCols )
{
const XP_U16 numFaces = dict_numTileFaces( dict );
@ -253,9 +253,9 @@ pool_initFromDict( PoolContext* pool, const DictionaryCtxt* dict )
numFaces * sizeof(pool->lettersLeft[0]) );
pool->numTilesLeft = 0;
for ( Tile ii = 0; ii < numFaces; ++ii ) {
XP_U16 numTiles = dict_numTiles( dict, ii );
pool->lettersLeft[ii] = (XP_U8)numTiles;
for ( Tile tile = 0; tile < numFaces; ++tile ) {
XP_U16 numTiles = dict_numTilesForSize( dict, tile, nCols );
pool->lettersLeft[tile] = (XP_U8)numTiles;
pool->numTilesLeft += numTiles;
}

View file

@ -39,7 +39,8 @@ XP_U16 pool_getNTilesLeftFor( const PoolContext* pool, Tile tile );
PoolContext* pool_make( MPFORMAL_NOCOMMA );
void pool_destroy( PoolContext* pool );
void pool_initFromDict( PoolContext* pool, const DictionaryCtxt* dict );
void pool_initFromDict( PoolContext* pool, const DictionaryCtxt* dict,
XP_U16 nCols );
void pool_writeToStream( PoolContext* pool, XWStreamCtxt* stream );
PoolContext* pool_makeFromStream( MPFORMAL XWStreamCtxt* stream );

View file

@ -2573,7 +2573,8 @@ makePoolOnce( ServerCtxt* server )
if ( server->pool == NULL ) {
server->pool = pool_make( MPPARM_NOCOMMA(server->mpool) );
XP_STATUSF( "%s(): initing pool", __func__ );
pool_initFromDict( server->pool, model_getDictionary(model));
pool_initFromDict( server->pool, model_getDictionary(model),
server->vol.gi->boardSize );
}
}
@ -4330,12 +4331,12 @@ server_formatDictCounts( ServerCtxt* server, XWEnv xwe, XWStreamCtxt* stream,
stream_catString( stream, buf );
nChars = dict_numTileFaces( dict );
XP_U16 boardSize = server->vol.gi->boardSize;
for ( tile = 0, nPrinted = 0; ; ) {
XP_UCHAR buf[128];
XP_U16 count, value;
count = dict_numTiles( dict, tile );
count = dict_numTilesForSize( dict, tile, boardSize );
if ( count > 0 ) {
const XP_UCHAR* face = NULL;

View file

@ -89,9 +89,6 @@ typedef struct UtilVtable {
XWStreamCtxt* (*m_util_makeStreamFromAddr)(XW_UtilCtxt* uc, XWEnv xwe,
XP_PlayerAddr channelNo );
#endif
XWBonusType (*m_util_getSquareBonus)( XW_UtilCtxt* uc, XWEnv xwe, XP_U16 boardSize,
XP_U16 col, XP_U16 row );
void (*m_util_userError)( XW_UtilCtxt* uc, XWEnv xwe, UtilErrID id );
void (*m_util_notifyMove)( XW_UtilCtxt* uc, XWEnv xwe, XWStreamCtxt* stream );
@ -221,9 +218,6 @@ struct XW_UtilCtxt {
#define util_makeStreamFromAddr(uc,e,a) \
(uc)->vtable->m_util_makeStreamFromAddr((uc), (e),(a))
#define util_getSquareBonus(uc,e,b,c,r) \
(uc)->vtable->m_util_getSquareBonus((uc), (e),(b),(c),(r))
#define util_userError(uc,e,err) \
(uc)->vtable->m_util_userError((uc),(e),(err))

View file

@ -16,7 +16,7 @@
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
XWLANG=BasEnglish
LANGCODE=en_US
LANGCODE=en
DICT2DAWGARGS = -r -nosort
DICTNOTE = "Wordlist created in the 1930s for language learners"

View file

@ -24,7 +24,7 @@ DICTNOTE = "Words on a list at www.wordfrequency.info"
include ../Makefile.langcommon
ENGLISH = $(XWDICTPATH)/English
SOURCEDICT ?= $(ENGLISH)/CSW.dict.gz
SOURCEDICT ?= $(ENGLISH)/CSW19.dict
# I have permission to download the "top 5000" wordlist but not
# necessarily to distribute it. And it contains words, especially
@ -35,7 +35,7 @@ $(XWLANG)Main.dict.gz: $(SOURCEDICT) $(ENGLISH)/Top_5000.dict.gz
zcat $(ENGLISH)/Top_5000.dict.gz | \
sed 's/[[:lower:]]*/\U&/' | \
sort > /tmp/Top_5000.dict
zcat $< | tr -d '\r' | \
cat $< | tr -d '\r' | \
sed 's/[[:lower:]]*/\U&/' | \
grep -e "^[A-Z]\{2,15\}$$" | \
sort > /tmp/$$(basename $<)

View file

@ -137,7 +137,7 @@ DEFINES += -DNLI_VERSION=1
# DEFINES += -DRELAY_VIA_HTTP
# MAX_ROWS controls STREAM_VERS_BIGBOARD and with it move hashing
DEFINES += -DMAX_ROWS=32
DEFINES += -DMAX_ROWS=23
ifdef CURSES_CELL_HT
DEFINES += -DCURSES_CELL_HT=$(CURSES_CELL_HT)

View file

@ -418,6 +418,10 @@ curses_draw_drawCell( DrawCtx* p_dctx, XWEnv XP_UNUSED(xwe), const XP_Rect* rect
ch = '^'; break;
case BONUS_TRIPLE_WORD:
ch = '#'; break;
case BONUS_QUAD_LETTER:
ch = '%'; break;
case BONUS_QUAD_WORD:
ch = '&'; break;
default:
break;
} /* switch */

View file

@ -1326,7 +1326,6 @@ gtk_draw_getMiniWText( DrawCtx* XP_UNUSED(p_dctx), XWEnv XP_UNUSED(xwe),
{
/* GtkDrawCtx* dctx = (GtkDrawCtx*)p_dctx; */
XP_UCHAR* str;
switch( textHint ) {
case BONUS_DOUBLE_LETTER:
str = "Double letter"; break;
@ -1334,6 +1333,10 @@ gtk_draw_getMiniWText( DrawCtx* XP_UNUSED(p_dctx), XWEnv XP_UNUSED(xwe),
str = "Double word"; break;
case BONUS_TRIPLE_LETTER:
str = "Triple letter"; break;
case BONUS_QUAD_WORD:
str = "Quad word"; break;
case BONUS_QUAD_LETTER:
str = "Quad letter"; break;
case BONUS_TRIPLE_WORD:
str = "Triple word"; break;
case INTRADE_MW_TEXT:

View file

@ -30,8 +30,6 @@
#include "gtkutils.h"
#include "gtkask.h"
#define MAX_SIZE_CHOICES 32
#define BINGO_THRESHOLD "Bingo threshold"
#define TRAY_SIZE "Tray size"
@ -168,7 +166,7 @@ size_combo_changed( GtkComboBox* combo, gpointer gp )
GtkNewGameState* state = (GtkNewGameState*)gp;
gint index = gtk_combo_box_get_active( GTK_COMBO_BOX(combo) );
if ( index >= 0 ) {
state->nCols = MAX_COLS - index;
state->nCols = MIN_COLS + (index * 2);
XP_LOGF( "set nCols = %d", state->nCols );
}
} /* size_combo_changed */
@ -348,14 +346,16 @@ addSizesRow( GtkNewGameState* state, GtkWidget* parent )
gtk_widget_set_sensitive( boardSizeCombo, FALSE );
}
for ( int ii = 0; ii < MAX_SIZE_CHOICES; ++ii ) {
int curEntry = 0;
for ( int siz = MIN_COLS; siz <= MAX_COLS; siz += 2 ) {
char buf[10];
XP_U16 siz = MAX_COLS - ii;
// XP_U16 siz = MAX_COLS - ii;
snprintf( buf, sizeof(buf), "%dx%d", siz, siz );
gtk_combo_box_text_append_text( GTK_COMBO_BOX_TEXT(boardSizeCombo), buf );
if ( siz == state->nCols ) {
gtk_combo_box_set_active( GTK_COMBO_BOX(boardSizeCombo), ii );
gtk_combo_box_set_active( GTK_COMBO_BOX(boardSizeCombo), curEntry );
}
++curEntry;
}
g_signal_connect( boardSizeCombo, "changed",

View file

@ -48,7 +48,6 @@ typedef struct LinuxDictionaryCtxt {
XP_Bool useMMap;
} LinuxDictionaryCtxt;
/************************ Prototypes ***********************/
static XP_Bool initFromDictFile( LinuxDictionaryCtxt* dctx,
const LaunchParams* params,
@ -279,13 +278,8 @@ linux_dictionary_destroy( DictionaryCtxt* dict, XWEnv XP_UNUSED(xwe) )
}
}
/* super's destructor should do this!!!! */
XP_FREEP( dict->mpool, &ctxt->super.desc );
XP_FREEP( dict->mpool, &ctxt->super.md5Sum );
XP_FREEP( dict->mpool, &ctxt->super.countsAndValues );
XP_FREEP( dict->mpool, &ctxt->super.faces );
XP_FREEP( dict->mpool, &ctxt->super.facePtrs );
XP_FREEP( dict->mpool, &ctxt->super.name );
dict_super_destroy( &ctxt->super );
XP_FREE( dict->mpool, ctxt );
} /* linux_dictionary_destroy */

View file

@ -249,8 +249,6 @@ linuxOpenGame( CommonGlobals* cGlobals, const TransportProcs* procs,
}
}
setSquareBonuses( cGlobals );
/* Need to save in order to have a valid selRow for the first send */
linuxSaveGame( cGlobals );
savedGame = true;

View file

@ -110,173 +110,6 @@ linux_util_makeEmptyDict( XW_UtilCtxt* XP_UNUSED_DBG(uctx), XWEnv xwe )
return linux_dictionary_make( MPPARM(uctx->mpool) xwe, NULL, NULL, XP_FALSE );
} /* linux_util_makeEmptyDict */
#define EM BONUS_NONE
#define DL BONUS_DOUBLE_LETTER
#define DW BONUS_DOUBLE_WORD
#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->gi->boardSize, &nBonuses );
if ( !!bonuses ) {
model_setSquareBonuses( cGlobals->game.model, bonuses, nBonuses );
}
}
#endif
static XWBonusType*
parseBonusFile( XP_U16 nCols, const char* bonusFile )
{
XWBonusType* result = NULL;
FILE* file = fopen( bonusFile, "r" );
if ( !!file ) {
XP_U16 row = 0;
XP_U16 col;
result = malloc( nCols * nCols * sizeof(*result) );
char line[1024];
while ( line == fgets( line, sizeof(line), file ) && row < nCols ) {
bool inComment = false;
char* ch;
XWBonusType bonus;
col = 0;
for ( ch = line; '\0' != *ch; ++ch ) {
switch( *ch ) {
case '#': /* comment; line is done */
inComment = true;
break;
case '+':
bonus = BONUS_DOUBLE_LETTER;
break;
case '*':
bonus = BONUS_DOUBLE_WORD;
break;
case '^':
bonus = BONUS_TRIPLE_LETTER;
break;
case '!':
bonus = BONUS_TRIPLE_WORD;
break;
case '.':
case ' ':
bonus = BONUS_NONE;
break;
case '\n':
case '\a':
break;
default:
if ( !inComment ) {
fprintf( stderr, "unexpected char '%c' in %s\n", *ch, bonusFile );
exit( 1 );
}
break;
}
if ( !inComment && col < nCols ) {
result[(row * nCols) + col] = bonus;
++col;
/* Let's just allow anything to follow the 15 letters we
care about, e.g. comments */
if ( col >= nCols ) {
inComment = true;
}
}
}
if ( col > 0 && row < nCols - 1) {
++row;
}
}
fclose( file );
}
return result;
}
static XWBonusType
linux_util_getSquareBonus( XW_UtilCtxt* uc, XWEnv XP_UNUSED(xwe), XP_U16 nCols,
XP_U16 col, XP_U16 row )
{
static XWBonusType* parsedFile = NULL;
XWBonusType result = EM;
CommonGlobals* cGlobals = (CommonGlobals*)uc->closure;
if ( NULL == parsedFile && NULL != cGlobals->params->bonusFile ) {
if ( !parsedFile ) {
parsedFile = parseBonusFile( nCols, cGlobals->params->bonusFile );
}
}
if ( NULL != parsedFile ) {
result = parsedFile[(row*nCols) + col];
} else {
XP_U16 nEntries;
XWBonusType* scrabbleBoard = bonusesFor( 15, &nEntries );
XP_U16 index, 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;
}
index = col;
for ( ii = 1; ii <= row; ++ii ) {
index += ii;
}
if ( index < nEntries) {
result = scrabbleBoard[index];
}
}
return result;
} /* linux_util_getSquareBonus */
static const DictionaryCtxt*
linux_util_getDict( XW_UtilCtxt* uc, XWEnv xwe,
XP_LangCode XP_UNUSED(lang), const XP_UCHAR* dictName )
@ -316,7 +149,6 @@ linux_util_vt_init( MPFORMAL XW_UtilCtxt* util )
util->vtable = XP_MALLOC( mpool, sizeof(UtilVtable) );
util->vtable->m_util_makeEmptyDict = linux_util_makeEmptyDict;
util->vtable->m_util_getSquareBonus = linux_util_getSquareBonus;
util->vtable->m_util_getDict = linux_util_getDict;
util->vtable->m_util_getInviteeName = linux_util_getInviteeName;

View file

@ -1,7 +1,10 @@
I installed emcc via
# git clone https://github.com/emscripten-core/emsdk.git
then
# cd emsdk
# git checkout 3.1.0
But I have no particular reason to believe that tag's better than a
later one when it comes along.
# ./emsdk install latest
# ./emsdk activate latest

View file

@ -45,32 +45,6 @@ wasm_util_makeStreamFromAddr( XW_UtilCtxt* uc, XWEnv xwe, XP_PlayerAddr channelN
return stream;
}
static XWBonusType
wasm_util_getSquareBonus( XW_UtilCtxt* uc, XWEnv xwe, XP_U16 boardSize,
XP_U16 col, XP_U16 row )
{
#define BONUS_DIM 8
static const int s_buttsBoard[BONUS_DIM][BONUS_DIM] = {
{ BONUS_TRIPLE_WORD, BONUS_NONE, BONUS_NONE,BONUS_DOUBLE_LETTER,BONUS_NONE,BONUS_NONE,BONUS_NONE,BONUS_TRIPLE_WORD },
{ BONUS_NONE, BONUS_DOUBLE_WORD, BONUS_NONE,BONUS_NONE,BONUS_NONE,BONUS_TRIPLE_LETTER,BONUS_NONE,BONUS_NONE },
{ BONUS_NONE, BONUS_NONE, BONUS_DOUBLE_WORD,BONUS_NONE,BONUS_NONE,BONUS_NONE,BONUS_DOUBLE_LETTER,BONUS_NONE },
{ BONUS_DOUBLE_LETTER,BONUS_NONE, BONUS_NONE,BONUS_DOUBLE_WORD,BONUS_NONE,BONUS_NONE,BONUS_NONE,BONUS_DOUBLE_LETTER },
{ BONUS_NONE, BONUS_NONE, BONUS_NONE,BONUS_NONE,BONUS_DOUBLE_WORD,BONUS_NONE,BONUS_NONE,BONUS_NONE },
{ BONUS_NONE, BONUS_TRIPLE_LETTER,BONUS_NONE,BONUS_NONE,BONUS_NONE,BONUS_TRIPLE_LETTER,BONUS_NONE,BONUS_NONE },
{ BONUS_NONE, BONUS_NONE, BONUS_DOUBLE_LETTER,BONUS_NONE,BONUS_NONE,BONUS_NONE,BONUS_DOUBLE_LETTER,BONUS_NONE },
{ BONUS_TRIPLE_WORD, BONUS_NONE, BONUS_NONE,BONUS_DOUBLE_LETTER,BONUS_NONE,BONUS_NONE,BONUS_NONE,BONUS_DOUBLE_WORD },
}; /* buttsBoard */
int half = boardSize / 2;
if ( col > half ) { col = (half*2) - col; }
if ( row > half ) { row = (half*2) - row; }
XP_ASSERT( col < BONUS_DIM && row < BONUS_DIM );
return s_buttsBoard[row][col];
}
static const XP_UCHAR*
wasm_getErrString( UtilErrID id, XP_Bool* silent )
{
@ -628,7 +602,6 @@ wasm_util_make( MPFORMAL CurGameInfo* gi, XW_DUtilCtxt* dctxt, GameState* closur
SET_VTABLE_ENTRY( wuctxt->super.vtable, util_userError, wasm );
SET_VTABLE_ENTRY( wuctxt->super.vtable, util_makeStreamFromAddr, wasm );
SET_VTABLE_ENTRY( wuctxt->super.vtable, util_getSquareBonus, wasm );
SET_VTABLE_ENTRY( wuctxt->super.vtable, util_notifyMove, wasm );
SET_VTABLE_ENTRY( wuctxt->super.vtable, util_notifyTrade, wasm );