mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2024-12-30 10:26:58 +01:00
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:
parent
7c0c6461cd
commit
c41b211735
2 changed files with 59 additions and 32 deletions
|
@ -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 );
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Loading…
Reference in a new issue