From c41b211735e5225657441ba5ba06359070f3ad6d Mon Sep 17 00:00:00 2001 From: ehouse Date: Wed, 9 Aug 2006 04:56:34 +0000 Subject: [PATCH] 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. --- xwords4/common/engine.c | 73 ++++++++++++++++++++++++++++------------- xwords4/common/model.h | 18 +++++----- 2 files changed, 59 insertions(+), 32 deletions(-) diff --git a/xwords4/common/engine.c b/xwords4/common/engine.c index cf23dba41..f1f5152d7 100644 --- a/xwords4/common/engine.c +++ b/xwords4/common/engine.c @@ -1,6 +1,7 @@ /* -*-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 * modify it under the terms of the GNU General Public License @@ -54,7 +55,8 @@ typedef struct MoveIterationData { XP_U16 leftInMoveCache; } 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 { 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 void findMovesForAnchor( EngineCtxt* engine, XP_S16* prevAnchor, XP_U16 col, XP_U16 row ) ; -static Crosscheck figureCrosschecks( EngineCtxt* engine, XP_U16 col, - XP_U16 row, XP_U16* scoreP ); +static void figureCrosschecks( EngineCtxt* engine, XP_U16 col, + XP_U16 row, XP_U16* scoreP, + Crosscheck* check ); static XP_Bool isAnchorSquare( EngineCtxt* engine, XP_U16 col, XP_U16 row ); static array_edge* follow( DictionaryCtxt* dict, array_edge* in ); 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)) #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 ) \ 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) ); for ( i = 0; i < numTiles; ++i ) { Tile tile = *tiles++; - XP_ASSERT( tile <= MAX_UNIQUE_TILES+1 ); + XP_ASSERT( tile < MAX_UNIQUE_TILES ); ++engine->rack[tile]; } } @@ -542,16 +546,15 @@ findMovesOneRow( EngineCtxt* engine ) lastSearchCol = lastCol; } + XP_MEMSET( &engine->rowChecks, 0, sizeof(engine->rowChecks) ); /* clear */ for ( col = 0; col <= lastCol; ++col ) { - Crosscheck check; if ( col < firstSearchCol || col > lastSearchCol ) { - check = 0x00000000; engine->scoreCache[col] = 0; } else { - check = figureCrosschecks( engine, col, row, - &engine->scoreCache[col] ); + figureCrosschecks( engine, col, row, + &engine->scoreCache[col], + &engine->rowChecks[col]); } - engine->rowChecks[col] = check; /* XP_DEBUGF( "row %d: set scoreCache[%d] to %d\n", row, col, */ /* engine->scoreCache[col] ); */ @@ -587,10 +590,36 @@ lookup( DictionaryCtxt* dict, array_edge* edge, Tile* buf, XP_U16 tileIndex, return XP_FALSE; } /* lookup */ -static Crosscheck -figureCrosschecks( EngineCtxt* engine, XP_U16 x, XP_U16 y, XP_U16* scoreP ) +static void +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<numRows; Tile tile; @@ -622,8 +651,9 @@ figureCrosschecks( EngineCtxt* engine, XP_U16 x, XP_U16 y, XP_U16* scoreP ) if ( (y == startY) && ((y == numRows-1) || (localGetBoardTile( engine, x, y+1, XP_FALSE ) == EMPTY_TILE))){ - result = 0xFFFFFFFF; /* all tiles legal and checkScore remains 0, - as there are no neighbors */ + /* all tiles legal and checkScore remains 0, as there are no + neighbors */ + XP_MEMSET( check, 0xFF, sizeof(*check) ); goto outer; } @@ -653,7 +683,7 @@ figureCrosschecks( EngineCtxt* engine, XP_U16 x, XP_U16 y, XP_U16* scoreP ) if ( in_edge == NULL ) { /* 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! */ - result = 0L; + XP_ASSERT( check->bits[0] == 0L && check->bits[1] == 0L ); goto outer; } ++startY; @@ -683,9 +713,7 @@ figureCrosschecks( EngineCtxt* engine, XP_U16 x, XP_U16 y, XP_U16* scoreP ) XP_ASSERT( tile < MAX_UNIQUE_TILES ); tiles[0] = tile; if ( lookup( dict, in_edge, tiles, 0, tilesAfter ) ) { - Crosscheck tmp = (1L << tile); - XP_ASSERT( tmp != 0 ); - result |= tmp; + setCheck( check, tile ); } 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 ) { *scoreP = checkScore; } - return result; } /* figureCrosschecks */ XP_Bool @@ -914,7 +941,7 @@ extendRight( EngineCtxt* engine, Tile* tiles, XP_U16 tileLength, goto no_check; // don't check at the end } } else if ( tile == EMPTY_TILE ) { - Crosscheck check = engine->rowChecks[col]; /* make a local copy */ + const Crosscheck* check = &engine->rowChecks[col]; if ( engine->nTilesMax > 0 ) { for ( ; ; ) { @@ -970,7 +997,7 @@ rack_remove( EngineCtxt* engine, Tile tile, XP_Bool* isBlank ) { Tile blankIndex = engine->blankTile; - XP_ASSERT( tile < 32 ); + XP_ASSERT( tile < MAX_UNIQUE_TILES ); XP_ASSERT( tile != blankIndex ); XP_ASSERT( engine->nTilesMax > 0 ); diff --git a/xwords4/common/model.h b/xwords4/common/model.h index 7f01cccc4..f45b54967 100644 --- a/xwords4/common/model.h +++ b/xwords4/common/model.h @@ -42,24 +42,24 @@ extern "C" { #define MIN_TRADE_TILES MAX_TRAY_TILES /* apply to CellTile */ -#define TILE_VALUE_MASK 0x001F -#define TILE_BLANK_BIT 0x0020 +#define TILE_VALUE_MASK 0x003F +#define TILE_BLANK_BIT 0x0040 #define IS_BLANK(t) (((t)&TILE_BLANK_BIT)!= 0) -#define TILE_EMPTY_BIT 0x0040 -#define TILE_PENDING_BIT 0x0080 -#define PREV_MOVE_BIT 0x100 +#define TILE_EMPTY_BIT 0x0080 +#define TILE_PENDING_BIT 0x0100 +#define PREV_MOVE_BIT 0x200 -#define CELL_OWNER_MASK 0x0600 -#define CELL_OWNER_OFFSET 9 +#define CELL_OWNER_MASK 0x0C00 +#define CELL_OWNER_OFFSET 10 #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 /* Used by scoring code and engine as fast representation of moves. */ typedef struct MoveInfoTile { XP_U8 varCoord; /* 5 bits ok (0-16 for 17x17 board) */ - Tile tile; /* 5 bits will do */ + Tile tile; /* 6 bits will do */ } MoveInfoTile; typedef struct MoveInfo {