/* -*- fill-column: 78; compile-command: "cd ../linux && make -j3 MEMDEBUG=TRUE"; -*- */ /* * Copyright 1997 - 2009 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 * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _MODEL_H_ #define _MODEL_H_ #include "comtypes.h" #include "dictnry.h" #include "mempool.h" #ifdef CPLUS extern "C" { #endif #define NUMCOLS_NBITS_4 4 #if 16 < MAX_COLS && MAX_COLS <= 32 # define NUMCOLS_NBITS_5 5 #endif #ifdef EIGHT_TILES # define NTILES_NBITS 4 #else # define NTILES_NBITS 3 #endif /* Try making this 0, as some local rules, e.g. Spanish, allow. Will need to * add UI to limit the number of tiles selected to that remaining in the pool. */ #define MIN_TRADE_TILES MAX_TRAY_TILES /* apply to CellTile */ #define TILE_VALUE_MASK 0x003F #define TILE_BLANK_BIT 0x0040 #define IS_BLANK(t) (((t)&TILE_BLANK_BIT)!= 0) #define TILE_EMPTY_BIT 0x0080 #define TILE_PENDING_BIT 0x0100 #define PREV_MOVE_BIT 0x200 #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 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; /* 6 bits will do */ } MoveInfoTile; typedef struct MoveInfo { XP_U8 nTiles; /* 4 bits: 0-7 */ XP_U8 commonCoord; /* 5 bits: 0-16 if 17x17 possible */ XP_Bool isHorizontal; /* 1 bit */ /* If this is to go on an undo stack, we need player num here, or the code has to keep track of it *and* there must be exactly one entry per player per turn. */ MoveInfoTile tiles[MAX_TRAY_TILES]; } MoveInfo; typedef struct _LastMoveInfo { const XP_UCHAR* name; XP_U8 moveType; XP_U16 score; XP_U16 nTiles; XP_UCHAR word[MAX_COLS+1]; } LastMoveInfo; typedef XP_U8 TrayTile; typedef struct TrayTileSet { XP_U8 nTiles; TrayTile tiles[MAX_TRAY_TILES]; } TrayTileSet; typedef struct BlankQueue { XP_U16 nBlanks; XP_U8 col[MAX_NUM_BLANKS]; XP_U8 row[MAX_NUM_BLANKS]; } BlankQueue; typedef XP_U8 TileBit; /* bits indicating selection of tiles in tray */ #define ALLTILES ((TileBit)~(0xFF<<(MAX_TRAY_TILES))) #define ILLEGAL_MOVE_SCORE (-1) #define EMPTY_TILE TILE_EMPTY_BIT #define TILE_IS_EMPTY(t) (((t)&TILE_EMPTY_BIT)!=0) #define REVERSED_TILE TILE_PENDING_BIT /* reuse that bit for tile drawing only */ ModelCtxt* model_make( MPFORMAL DictionaryCtxt* dict, const PlayerDicts* dicts, XW_UtilCtxt* util, XP_U16 nCols ); ModelCtxt* model_makeFromStream( MPFORMAL XWStreamCtxt* stream, DictionaryCtxt* dict, const PlayerDicts* dicts, XW_UtilCtxt* util ); void model_writeToStream( const ModelCtxt* model, XWStreamCtxt* stream ); #ifdef TEXT_MODEL void model_writeToTextStream( const ModelCtxt* model, XWStreamCtxt* stream ); #endif void model_setSize( ModelCtxt* model, XP_U16 boardSize ); void model_destroy( ModelCtxt* model ); XP_U32 model_getHash( const ModelCtxt* model, XP_U16 version ); XP_Bool model_hashMatches( const ModelCtxt* model, XP_U32 hash ); void model_setNPlayers( ModelCtxt* model, XP_U16 numPlayers ); XP_U16 model_getNPlayers( const ModelCtxt* model ); void model_setDictionary( ModelCtxt* model, DictionaryCtxt* dict ); DictionaryCtxt* model_getDictionary( const ModelCtxt* model ); void model_setPlayerDicts( ModelCtxt* model, const PlayerDicts* dicts ); DictionaryCtxt* model_getPlayerDict( const ModelCtxt* model, XP_U16 playerNum ); XP_Bool model_getTile( const ModelCtxt* model, XP_U16 col, XP_U16 row, XP_Bool getPending, XP_S16 turn, Tile* tile, XP_Bool* isBlank, XP_Bool* isPending, XP_Bool* isRecent ); void model_listPlacedBlanks( ModelCtxt* model, XP_U16 turn, XP_Bool includePending, BlankQueue* bcp ); XP_U16 model_getCellOwner( ModelCtxt* model, XP_U16 col, XP_U16 row ); void model_assignPlayerTiles( ModelCtxt* model, XP_S16 turn, const TrayTileSet* tiles ); Tile model_getPlayerTile( const ModelCtxt* model, XP_S16 turn, XP_S16 index ); Tile model_removePlayerTile( ModelCtxt* model, XP_S16 turn, XP_S16 index ); void model_addPlayerTile( ModelCtxt* model, XP_S16 turn, XP_S16 index, Tile tile ); void model_moveTileOnTray( ModelCtxt* model, XP_S16 turn, XP_S16 indexCur, XP_S16 indexNew ); XP_U16 model_getDividerLoc( const ModelCtxt* model, XP_S16 turn ); void model_setDividerLoc( ModelCtxt* model, XP_S16 turn, XP_U16 loc ); /* As an optimization, return a pointer to the model's array of tiles for a player. Don't even think about modifying the array!!!! */ const TrayTileSet* model_getPlayerTiles( const ModelCtxt* model, XP_S16 turn ); #ifdef DEBUG XP_UCHAR* formatTileSet( const TrayTileSet* tiles, XP_UCHAR* buf, XP_U16 len ); #endif void model_sortTiles( ModelCtxt* model, XP_S16 turn ); XP_U16 model_getNumTilesInTray( ModelCtxt* model, XP_S16 turn ); XP_U16 model_getNumTilesTotal( ModelCtxt* model, XP_S16 turn ); void model_moveBoardToTray( ModelCtxt* model, XP_S16 turn, XP_U16 col, XP_U16 row, XP_U16 trayOffset ); void model_moveTrayToBoard( ModelCtxt* model, XP_S16 turn, XP_U16 col, XP_U16 row, XP_S16 tileIndex, Tile blankFace ); XP_Bool model_moveTileOnBoard( ModelCtxt* model, XP_S16 turn, XP_U16 colCur, XP_U16 rowCur, XP_U16 colNew, XP_U16 rowNew ); XP_Bool model_redoPendingTiles( ModelCtxt* model, XP_S16 turn ); XP_S16 model_trayContains( ModelCtxt* model, XP_S16 turn, Tile tile ); XP_U16 model_numRows( const ModelCtxt* model ); XP_U16 model_numCols( const ModelCtxt* model ); /* XP_U16 model_numTilesCurrentTray( ModelCtxt* model ); */ /* Tile model_currentTrayTile( ModelCtxt* model, XP_U16 index ); */ void model_addToCurrentMove( ModelCtxt* model, XP_S16 turn, XP_U16 col, XP_U16 row, Tile tile, XP_Bool isBlank ); XP_U16 model_getCurrentMoveCount( const ModelCtxt* model, XP_S16 turn ); XP_Bool model_getCurrentMoveIsVertical( const ModelCtxt* model, XP_S16 turn, XP_Bool* isHorizontal ); void model_getCurrentMoveTile( ModelCtxt* model, XP_S16 turn, XP_S16* index, Tile* tile, XP_U16* col, XP_U16* row, XP_Bool* isBlank ); XP_Bool model_commitTurn( ModelCtxt* model, XP_S16 player, TrayTileSet* newTiles ); void model_commitRejectedPhony( ModelCtxt* model, XP_S16 player ); void model_makeTileTrade( ModelCtxt* model, XP_S16 player, const TrayTileSet* oldTiles, const TrayTileSet* newTiles ); XP_Bool model_canUndo( const ModelCtxt* model ); XP_Bool model_undoLatestMoves( ModelCtxt* model, PoolContext* pool, XP_U16 nMovesSought, XP_U16* turn, XP_S16* moveNum ); void model_rejectPreviousMove( ModelCtxt* model, PoolContext* pool, XP_U16* turn ); void model_trayToStream( ModelCtxt* model, XP_S16 turn, XWStreamCtxt* stream ); void model_currentMoveToStream( ModelCtxt* model, XP_S16 turn, XWStreamCtxt* stream); XP_Bool model_makeTurnFromStream( ModelCtxt* model, XP_U16 playerNum, XWStreamCtxt* stream ); void model_makeTurnFromMoveInfo( ModelCtxt* model, XP_U16 playerNum, const MoveInfo* newMove ); void model_resetCurrentTurn( ModelCtxt* model, XP_S16 turn ); XP_S16 model_getNMoves( const ModelCtxt* model ); /* Are there two or more tiles visible */ XP_U16 model_visTileCount( const ModelCtxt* model, XP_U16 turn, XP_Bool trayVisible ); XP_Bool model_canShuffle( const ModelCtxt* model, XP_U16 turn, XP_Bool trayVisible ); XP_Bool model_canTogglePending( const ModelCtxt* model, XP_U16 turn ); /********************* notification ********************/ typedef void (*BoardListener)(void* data, XP_U16 turn, XP_U16 col, XP_U16 row, XP_Bool added ); void model_setBoardListener( ModelCtxt* model, BoardListener bl, void* data ); typedef void (*TrayListener)( void* data, XP_U16 turn, XP_S16 index1, XP_S16 index2 ); void model_setTrayListener( ModelCtxt* model, TrayListener bl, void* data ); typedef void (*DictListener)( void* data, XP_S16 playerNum, const DictionaryCtxt* oldDict, const DictionaryCtxt* newDict ); void model_setDictListener( ModelCtxt* model, DictListener dl, void* data ); void model_foreachPendingCell( ModelCtxt* model, XP_S16 turn, BoardListener bl, void* data ); void model_foreachPrevCell( ModelCtxt* model, BoardListener bl, void* data ); void model_writeGameHistory( ModelCtxt* model, XWStreamCtxt* stream, ServerCtxt* server, /* for player names */ XP_Bool gameOver ); /* for the tile values dialog: total all the tiles in players trays and tentatively placed on the board. */ void model_countAllTrayTiles( ModelCtxt* model, XP_U16* counts, XP_S16 excludePlayer ); /********************* scoring ********************/ typedef XP_Bool (*WordNotifierProc)( const XP_UCHAR* word, XP_Bool isLegal, const DictionaryCtxt* dict, #ifdef XWFEATURE_BOARDWORDS const MoveInfo* movei, XP_U16 start, XP_U16 end, #endif void* closure ); typedef struct WordNotifierInfo { WordNotifierProc proc; void* closure; } WordNotifierInfo; XP_Bool getCurrentMoveScoreIfLegal( ModelCtxt* model, XP_S16 turn, XWStreamCtxt* stream, WordNotifierInfo* wni, XP_S16* score ); XP_S16 model_getPlayerScore( ModelCtxt* model, XP_S16 player ); XP_Bool model_getPlayersLastScore( ModelCtxt* model, XP_S16 player, LastMoveInfo* info ); #ifdef XWFEATURE_BOARDWORDS void model_listWordsThrough( ModelCtxt* model, XP_U16 col, XP_U16 row, XWStreamCtxt* stream ); #endif /* 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 ); #ifdef STREAM_VERS_BIGBOARD void model_setSquareBonuses( ModelCtxt* model, XWBonusType* bonuses, XP_U16 nBonuses ); #endif XP_Bool model_checkMoveLegal( ModelCtxt* model, XP_S16 player, XWStreamCtxt* stream, WordNotifierInfo* notifyInfo ); typedef struct _ScoresArray { XP_S16 arr[MAX_NUM_PLAYERS]; } ScoresArray; void model_figureFinalScores( ModelCtxt* model, ScoresArray* scores, ScoresArray* tilePenalties ); /* figureMoveScore is meant only for the engine's use */ XP_U16 figureMoveScore( const ModelCtxt* model, XP_U16 turn, MoveInfo* mvInfo, EngineCtxt* engine, XWStreamCtxt* stream, WordNotifierInfo* notifyInfo ); /* tap into internal WordNotifierInfo */ WordNotifierInfo* model_initWordCounter( ModelCtxt* model, XWStreamCtxt* stream ); /********************* persistence ********************/ #ifdef INCLUDE_IO_SUPPORT void model_load( ModelCtxt* model, XP_Stream* inStream ); void model_store( ModelCtxt* model, XP_Stream* outStream ); #endif /* a utility function needed by server too. Not a clean design, this. */ void model_packTilesUtil( ModelCtxt* model, PoolContext* pool, XP_Bool includeBlank, XP_U16* nUsed, const XP_UCHAR** texts, Tile* tiles ); #ifdef CPLUS } #endif #endif