increase possible number of unique tiles from 32 to 64 in order to

support Slovak which has 40.  This change is preliminary: it seems to
work for both existing and dicts with >32 chars, but it breaks backwards
compatibility: existing saved games will crash this code.  I think the
fix is to deduce the number of bits per tile from the number in the
dictionary being used, but that's not in yet.
This commit is contained in:
ehouse 2006-08-09 04:56:34 +00:00
parent 7c0c6461cd
commit c41b211735
2 changed files with 59 additions and 32 deletions

View file

@ -1,6 +1,7 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */ /* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
/* /*
* Copyright 1997 - 2002 by Eric House (xwords@eehouse.org). All rights reserved. * Copyright 1997 - 2006 by Eric House (xwords@eehouse.org). All rights
* reserved.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -54,7 +55,8 @@ typedef struct MoveIterationData {
XP_U16 leftInMoveCache; XP_U16 leftInMoveCache;
} MoveIterationData; } MoveIterationData;
typedef XP_U32 Crosscheck; /* one bit per tile that's possible here */ /* one bit per tile that's possible here *\/ */
typedef struct Crosscheck { XP_U32 bits[2]; } Crosscheck;
struct EngineCtxt { struct EngineCtxt {
ModelCtxt* model; ModelCtxt* model;
@ -100,8 +102,9 @@ static array_edge* edge_with_tile( DictionaryCtxt* dict, array_edge* from, Tile
static XP_Bool scoreQualifies( EngineCtxt* engine, XP_U16 score ); static XP_Bool scoreQualifies( EngineCtxt* engine, XP_U16 score );
static void findMovesForAnchor( EngineCtxt* engine, XP_S16* prevAnchor, static void findMovesForAnchor( EngineCtxt* engine, XP_S16* prevAnchor,
XP_U16 col, XP_U16 row ) ; XP_U16 col, XP_U16 row ) ;
static Crosscheck figureCrosschecks( EngineCtxt* engine, XP_U16 col, static void figureCrosschecks( EngineCtxt* engine, XP_U16 col,
XP_U16 row, XP_U16* scoreP ); XP_U16 row, XP_U16* scoreP,
Crosscheck* check );
static XP_Bool isAnchorSquare( EngineCtxt* engine, XP_U16 col, XP_U16 row ); static XP_Bool isAnchorSquare( EngineCtxt* engine, XP_U16 col, XP_U16 row );
static array_edge* follow( DictionaryCtxt* dict, array_edge* in ); static array_edge* follow( DictionaryCtxt* dict, array_edge* in );
static array_edge* edge_from_tile( DictionaryCtxt* dict, array_edge* from, static array_edge* edge_from_tile( DictionaryCtxt* dict, array_edge* from,
@ -153,7 +156,8 @@ static XP_S16 cmpMoves( PossibleMove* m1, PossibleMove* m2 );
((Tile)(((array_edge_old*)(edge))->bits & LETTERMASK_OLD)) ((Tile)(((array_edge_old*)(edge))->bits & LETTERMASK_OLD))
#endif #endif
#define CROSSCHECK_CONTAINS(chk,tile) (((chk) & (1L<<(tile))) != 0) /* #define CROSSCHECK_CONTAINS(chk,tile) (((chk) & (1L<<(tile))) != 0) */
#define CROSSCHECK_CONTAINS(chk,tile) checkIsSet( (chk), (tile) )
#define HILITE_CELL( engine, col, row ) \ #define HILITE_CELL( engine, col, row ) \
util_hiliteCell( (engine)->util, (col), (row) ) util_hiliteCell( (engine)->util, (col), (row) )
@ -242,7 +246,7 @@ initTray( EngineCtxt* engine, const Tile* tiles, XP_U16 numTiles )
XP_MEMSET( engine->rack, 0, sizeof(engine->rack) ); XP_MEMSET( engine->rack, 0, sizeof(engine->rack) );
for ( i = 0; i < numTiles; ++i ) { for ( i = 0; i < numTiles; ++i ) {
Tile tile = *tiles++; Tile tile = *tiles++;
XP_ASSERT( tile <= MAX_UNIQUE_TILES+1 ); XP_ASSERT( tile < MAX_UNIQUE_TILES );
++engine->rack[tile]; ++engine->rack[tile];
} }
} }
@ -542,16 +546,15 @@ findMovesOneRow( EngineCtxt* engine )
lastSearchCol = lastCol; lastSearchCol = lastCol;
} }
XP_MEMSET( &engine->rowChecks, 0, sizeof(engine->rowChecks) ); /* clear */
for ( col = 0; col <= lastCol; ++col ) { for ( col = 0; col <= lastCol; ++col ) {
Crosscheck check;
if ( col < firstSearchCol || col > lastSearchCol ) { if ( col < firstSearchCol || col > lastSearchCol ) {
check = 0x00000000;
engine->scoreCache[col] = 0; engine->scoreCache[col] = 0;
} else { } else {
check = figureCrosschecks( engine, col, row, figureCrosschecks( engine, col, row,
&engine->scoreCache[col] ); &engine->scoreCache[col],
&engine->rowChecks[col]);
} }
engine->rowChecks[col] = check;
/* XP_DEBUGF( "row %d: set scoreCache[%d] to %d\n", row, col, */ /* XP_DEBUGF( "row %d: set scoreCache[%d] to %d\n", row, col, */
/* engine->scoreCache[col] ); */ /* engine->scoreCache[col] ); */
@ -587,10 +590,36 @@ lookup( DictionaryCtxt* dict, array_edge* edge, Tile* buf, XP_U16 tileIndex,
return XP_FALSE; return XP_FALSE;
} /* lookup */ } /* lookup */
static Crosscheck static void
figureCrosschecks( EngineCtxt* engine, XP_U16 x, XP_U16 y, XP_U16* scoreP ) setCheck( Crosscheck* check, Tile tile )
{
XP_U32* ptr = &check->bits[0];
XP_ASSERT( tile < MAX_UNIQUE_TILES );
while ( tile > 31 ) {
++ptr;
tile -= 32;
XP_ASSERT( tile <= 31 ); /* only iterate once!!! */
}
*ptr |= 1L << tile;
} /* setCheck */
static XP_Bool
checkIsSet( const Crosscheck* check, Tile tile )
{
const XP_U32* ptr = &check->bits[0];
XP_ASSERT( tile < MAX_UNIQUE_TILES );
while ( tile > 31 ) {
++ptr;
tile -= 32;
XP_ASSERT( tile <= 31 ); /* only iterate once!!! */
}
return (*ptr & (1L<<tile)) != 0;
} /* checkIsSet */
static void
figureCrosschecks( EngineCtxt* engine, XP_U16 x, XP_U16 y, XP_U16* scoreP,
Crosscheck* check )
{ {
Crosscheck result = 0L; /* nothing's possible */
XP_S16 startY, maybeY; XP_S16 startY, maybeY;
XP_U16 numRows = engine->numRows; XP_U16 numRows = engine->numRows;
Tile tile; Tile tile;
@ -622,8 +651,9 @@ figureCrosschecks( EngineCtxt* engine, XP_U16 x, XP_U16 y, XP_U16* scoreP )
if ( (y == startY) && if ( (y == startY) &&
((y == numRows-1) || ((y == numRows-1) ||
(localGetBoardTile( engine, x, y+1, XP_FALSE ) == EMPTY_TILE))){ (localGetBoardTile( engine, x, y+1, XP_FALSE ) == EMPTY_TILE))){
result = 0xFFFFFFFF; /* all tiles legal and checkScore remains 0, /* all tiles legal and checkScore remains 0, as there are no
as there are no neighbors */ neighbors */
XP_MEMSET( check, 0xFF, sizeof(*check) );
goto outer; goto outer;
} }
@ -653,7 +683,7 @@ figureCrosschecks( EngineCtxt* engine, XP_U16 x, XP_U16 y, XP_U16* scoreP )
if ( in_edge == NULL ) { if ( in_edge == NULL ) {
/* Only way to have gotten here is if a user's played a word /* Only way to have gotten here is if a user's played a word
not in this dict. We'll not be able to build on it! */ not in this dict. We'll not be able to build on it! */
result = 0L; XP_ASSERT( check->bits[0] == 0L && check->bits[1] == 0L );
goto outer; goto outer;
} }
++startY; ++startY;
@ -683,9 +713,7 @@ figureCrosschecks( EngineCtxt* engine, XP_U16 x, XP_U16 y, XP_U16* scoreP )
XP_ASSERT( tile < MAX_UNIQUE_TILES ); XP_ASSERT( tile < MAX_UNIQUE_TILES );
tiles[0] = tile; tiles[0] = tile;
if ( lookup( dict, in_edge, tiles, 0, tilesAfter ) ) { if ( lookup( dict, in_edge, tiles, 0, tilesAfter ) ) {
Crosscheck tmp = (1L << tile); setCheck( check, tile );
XP_ASSERT( tmp != 0 );
result |= tmp;
} }
if ( IS_LAST_EDGE(dict,candidateEdge ) ) { if ( IS_LAST_EDGE(dict,candidateEdge ) ) {
@ -702,7 +730,6 @@ figureCrosschecks( EngineCtxt* engine, XP_U16 x, XP_U16 y, XP_U16* scoreP )
if ( scoreP != NULL ) { if ( scoreP != NULL ) {
*scoreP = checkScore; *scoreP = checkScore;
} }
return result;
} /* figureCrosschecks */ } /* figureCrosschecks */
XP_Bool XP_Bool
@ -914,7 +941,7 @@ extendRight( EngineCtxt* engine, Tile* tiles, XP_U16 tileLength,
goto no_check; // don't check at the end goto no_check; // don't check at the end
} }
} else if ( tile == EMPTY_TILE ) { } else if ( tile == EMPTY_TILE ) {
Crosscheck check = engine->rowChecks[col]; /* make a local copy */ const Crosscheck* check = &engine->rowChecks[col];
if ( engine->nTilesMax > 0 ) { if ( engine->nTilesMax > 0 ) {
for ( ; ; ) { for ( ; ; ) {
@ -970,7 +997,7 @@ rack_remove( EngineCtxt* engine, Tile tile, XP_Bool* isBlank )
{ {
Tile blankIndex = engine->blankTile; Tile blankIndex = engine->blankTile;
XP_ASSERT( tile < 32 ); XP_ASSERT( tile < MAX_UNIQUE_TILES );
XP_ASSERT( tile != blankIndex ); XP_ASSERT( tile != blankIndex );
XP_ASSERT( engine->nTilesMax > 0 ); XP_ASSERT( engine->nTilesMax > 0 );

View file

@ -42,24 +42,24 @@ extern "C" {
#define MIN_TRADE_TILES MAX_TRAY_TILES #define MIN_TRADE_TILES MAX_TRAY_TILES
/* apply to CellTile */ /* apply to CellTile */
#define TILE_VALUE_MASK 0x001F #define TILE_VALUE_MASK 0x003F
#define TILE_BLANK_BIT 0x0020 #define TILE_BLANK_BIT 0x0040
#define IS_BLANK(t) (((t)&TILE_BLANK_BIT)!= 0) #define IS_BLANK(t) (((t)&TILE_BLANK_BIT)!= 0)
#define TILE_EMPTY_BIT 0x0040 #define TILE_EMPTY_BIT 0x0080
#define TILE_PENDING_BIT 0x0080 #define TILE_PENDING_BIT 0x0100
#define PREV_MOVE_BIT 0x100 #define PREV_MOVE_BIT 0x200
#define CELL_OWNER_MASK 0x0600 #define CELL_OWNER_MASK 0x0C00
#define CELL_OWNER_OFFSET 9 #define CELL_OWNER_OFFSET 10
#define CELL_OWNER(t) (((t)&CELL_OWNER_MASK) >> CELL_OWNER_OFFSET) #define CELL_OWNER(t) (((t)&CELL_OWNER_MASK) >> CELL_OWNER_OFFSET)
#define MAX_UNIQUE_TILES 32 /* max tile non-blank faces */ #define MAX_UNIQUE_TILES 64 /* max tile non-blank faces */
#define MAX_NUM_BLANKS 4 #define MAX_NUM_BLANKS 4
/* Used by scoring code and engine as fast representation of moves. */ /* Used by scoring code and engine as fast representation of moves. */
typedef struct MoveInfoTile { typedef struct MoveInfoTile {
XP_U8 varCoord; /* 5 bits ok (0-16 for 17x17 board) */ XP_U8 varCoord; /* 5 bits ok (0-16 for 17x17 board) */
Tile tile; /* 5 bits will do */ Tile tile; /* 6 bits will do */
} MoveInfoTile; } MoveInfoTile;
typedef struct MoveInfo { typedef struct MoveInfo {