branch for smartphone release

This commit is contained in:
ehouse 2008-12-18 13:23:12 +00:00
parent 4d0122816b
commit 144ecb3934
450 changed files with 95959 additions and 0 deletions

5
xwords4/Makefile Normal file
View file

@ -0,0 +1,5 @@
tags:
etags $$(find . -name '*.c' -print \
-o -name '*.h' -print \
-o -name '*.cpp' -print)

11
xwords4/common/.cvsignore Normal file
View file

@ -0,0 +1,11 @@
franklin
palm
ARMV4Rel
emulatorDbg
PALM_PNO
obj_linux_memdbg
obj_linux_rel
obj_win32_dbg
obj_win32_rel
obj_wince_dbg
obj_wince_rel

5
xwords4/common/Makefile Normal file
View file

@ -0,0 +1,5 @@
# -*- mode: Makefile; -*-
clean:
rm -rf $(PLATFORM)

3051
xwords4/common/board.c Normal file

File diff suppressed because it is too large Load diff

167
xwords4/common/board.h Normal file
View file

@ -0,0 +1,167 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
/*
* Copyright 1997 - 2000 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 __BOARD_H__
#define __BOARD_H__
#include "comtypes.h"
#include "model.h"
#include "server.h"
#include "draw.h"
#include "xwstream.h"
/* typedef struct BoardVTable { */
/* } BoardVTable; */
#ifdef CPLUS
extern "C" {
#endif
typedef enum {
/* keep these three together: for the cursor */
XP_KEY_NONE = 0,
XP_CURSOR_KEY_DOWN,
XP_CURSOR_KEY_ALTDOWN,
XP_CURSOR_KEY_RIGHT,
XP_CURSOR_KEY_ALTRIGHT,
XP_CURSOR_KEY_UP,
XP_CURSOR_KEY_ALTUP,
XP_CURSOR_KEY_LEFT,
XP_CURSOR_KEY_ALTLEFT,
XP_CURSOR_KEY_DEL,
XP_RAISEFOCUS_KEY,
XP_RETURN_KEY,
XP_KEY_LAST
} XP_Key;
#define BONUS_HINT_INTERVAL 15 /* stolen from xwords.c */
/* typedef struct BoardCtxt BoardCtxt; */
BoardCtxt* board_make( MPFORMAL ModelCtxt* model, ServerCtxt* server,
DrawCtx* draw, XW_UtilCtxt* util );
BoardCtxt* board_makeFromStream( MPFORMAL XWStreamCtxt* stream,
ModelCtxt* model, ServerCtxt* server,
DrawCtx* draw, XW_UtilCtxt* util,
XP_U16 nPlayers );
void board_destroy( BoardCtxt* board );
void board_writeToStream( BoardCtxt* board, XWStreamCtxt* stream );
void board_setPos( BoardCtxt* board, XP_U16 left, XP_U16 top,
XP_Bool leftHanded );
void board_reset( BoardCtxt* board );
/* Vertical scroll support; offset is in rows, not pixels */
XP_Bool board_setYOffset( BoardCtxt* board, XP_U16 newOffset );
XP_U16 board_getYOffset( const BoardCtxt* board );
void board_setScoreboardLoc( BoardCtxt* board,
XP_U16 scoreLeft, XP_U16 scoreTop,
XP_U16 scoreWidth, XP_U16 scoreHeight,
XP_Bool divideHorizontally );
void board_setTimerLoc( BoardCtxt* board,
XP_U16 timerLeft, XP_U16 timerTop,
XP_U16 timerWidth, XP_U16 timerHeight );
void board_invalAll( BoardCtxt* board );
void board_invalRect( BoardCtxt* board, XP_Rect* rect );
XP_Bool board_draw( BoardCtxt* board );
XP_Bool board_get_flipped( const BoardCtxt* board );
XP_Bool board_flip( BoardCtxt* board );
XP_Bool board_get_showValues( const BoardCtxt* board );
XP_Bool board_toggle_showValues( BoardCtxt* board );
XP_Bool board_getShowColors( BoardCtxt* board );
XP_Bool board_setShowColors( BoardCtxt* board, XP_Bool showColors );
XP_Bool board_replaceTiles( BoardCtxt* board );
XP_Bool board_requestHint( BoardCtxt* board,
#ifdef XWFEATURE_SEARCHLIMIT
XP_Bool useTileLimits,
#endif
XP_Bool* workRemainsP );
void board_setScale( BoardCtxt* board, XP_U16 hScale, XP_U16 vScale );
void board_getScale( BoardCtxt* board, XP_U16* hScale, XP_U16* vScale );
XP_Bool board_prefsChanged( BoardCtxt* board, CommonPrefs* cp );
BoardObjectType board_getFocusOwner( BoardCtxt* board );
void board_hiliteCellAt( BoardCtxt* board, XP_U16 col, XP_U16 row );
void board_resetEngine( BoardCtxt* board );
XP_Bool board_commitTurn( BoardCtxt* board );
void board_pushTimerSave( BoardCtxt* board );
void board_popTimerSave( BoardCtxt* board );
void board_formatRemainingTiles( BoardCtxt* board, XWStreamCtxt* stream );
#ifdef POINTER_SUPPORT
XP_Bool board_handlePenDown( BoardCtxt* board, XP_U16 x, XP_U16 y,
XP_Bool* handled );
XP_Bool board_handlePenMove( BoardCtxt* board, XP_U16 x, XP_U16 y );
XP_Bool board_handlePenUp( BoardCtxt* board, XP_U16 x, XP_U16 y );
#endif
#ifdef KEY_SUPPORT
XP_Bool board_handleKey( BoardCtxt* board, XP_Key key, XP_Bool* handled );
# ifdef KEYBOARD_NAV
XP_Bool board_handleKeyUp( BoardCtxt* board, XP_Key key, XP_Bool* handled );
XP_Bool board_handleKeyDown( BoardCtxt* board, XP_Key key, XP_Bool* handled );
XP_Bool board_handleKeyRepeat( BoardCtxt* board, XP_Key key, XP_Bool* handled );
XP_Bool board_focusChanged( BoardCtxt* board, BoardObjectType typ,
XP_Bool gained );
XP_Bool board_toggle_arrowDir( BoardCtxt* board );
# endif
#endif
/******************** Tray methods ********************/
#define NO_TILES ((TileBit)0)
void board_setTrayLoc( BoardCtxt* board, XP_U16 trayLeft, XP_U16 trayTop,
XP_U16 trayWidth, XP_U16 trayHeight,
XP_U16 minDividerWidth );
XP_Bool board_hideTray( BoardCtxt* board );
XP_Bool board_showTray( BoardCtxt* board );
XW_TrayVisState board_getTrayVisState( const BoardCtxt* board );
void board_invalTrayTiles( BoardCtxt* board, TileBit what );
XP_Bool board_juggleTray( BoardCtxt* board );
XP_Bool board_beginTrade( BoardCtxt* board );
#if defined FOR_GREMLINS
XP_Bool board_moveDivider( BoardCtxt* board, XP_Bool right );
#endif
#ifdef CPLUS
}
#endif
#endif

568
xwords4/common/boarddrw.c Normal file
View file

@ -0,0 +1,568 @@
/* -*-mode: C; fill-column: 78; compile-command: "cd ../linux && make MEMDEBUG=TRUE"; -*- */
/*
* Copyright 1997 - 2008 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.
*/
/* Re: boards that can't fit on the screen. Let's have an assumption, that
* the tray is always either below the board or overlapping its bottom. There
* is never any board visible below the tray. But it's possible to have a
* board small enough that scrolling is necessary even with the tray hidden.
*
* Currently we don't specify the board bounds. We give top,left and the size
* of cells, and the board figures out the bounds. That's probably a mistake.
* Better to give bounds, and maybe a min scale, and let it figure out how
* many cells can be visible. Could it also decide if the tray should overlap
* or be below? Some platforms have to own that decision since the tray is
* narrower than the board. So give them separate bounds-setting functions,
* and let the board code figure out if they overlap.
*
* Problem: the board size must always be a multiple of the scale. The
* platform-specific code has an easy time doing that math. The board can't:
* it'd have to take bounds, then spit them back out slightly modified. It'd
* also have to refuse to work (maybe just assert) if asked to take bounds
* before it had a min_scale.
*
* Another way of looking at it closer to the current: the board's position
* and the tray's bounds determine the board's bounds. If the board's vScale
* times the number of rows places its would-be bottom at or above the bottom
* of the tray, then it's potentially visible. If its would-be bottom is
* above the top of the tray, no scrolling is needed. But if it's below the
* tray entirely then scrolling will happen even with the tray hidden. As
* above, we assume the board never appears below the tray.
*/
#include "comtypes.h"
#include "board.h"
#include "scorebdp.h"
#include "game.h"
#include "server.h"
#include "comms.h" /* for CHANNEL_NONE */
#include "dictnry.h"
#include "draw.h"
#include "engine.h"
#include "util.h"
#include "mempool.h" /* debug only */
#include "memstream.h"
#include "strutils.h"
#include "LocalizedStrIncludes.h"
#include "boardp.h"
#include "dragdrpp.h"
#include "dbgutil.h"
#ifdef CPLUS
extern "C" {
#endif
static XP_Bool drawCell( BoardCtxt* board, XP_U16 col, XP_U16 row,
XP_Bool skipBlanks );
static void drawBoard( BoardCtxt* board );
static void scrollIfCan( BoardCtxt* board );
static XP_Bool cellFocused( const BoardCtxt* board, XP_U16 col, XP_U16 row );
static void drawTradeWindowIf( BoardCtxt* board );
#ifdef XWFEATURE_SEARCHLIMIT
static HintAtts figureHintAtts( BoardCtxt* board, XP_U16 col, XP_U16 row );
#else
# define figureHintAtts(b,c,r) HINT_BORDER_NONE
#endif
#ifdef POINTER_SUPPORT
static void drawDragTileIf( BoardCtxt* board );
#endif
#ifdef KEYBOARD_NAV
#ifdef PERIMETER_FOCUS
static void
invalOldPerimeter( BoardCtxt* board )
{
/* We need to inval the center of the row that's moving into the center
from a border (at which point it got borders drawn on it.) */
XP_S16 diff = board->yOffset - board->prevYScrollOffset;
XP_U16 firstRow, lastRow;
XP_ASSERT( diff != 0 );
if ( diff < 0 ) {
/* moving up; inval row previously on bottom */
firstRow = board->yOffset + 1;
lastRow = board->prevYScrollOffset;
} else {
XP_U16 nVisible = board->lastVisibleRow - board->yOffset + 1;
lastRow = board->prevYScrollOffset + nVisible - 1;
firstRow = lastRow - diff + 1;
}
XP_ASSERT( firstRow <= lastRow );
while ( firstRow <= lastRow ) {
board->redrawFlags[firstRow] |= ~0;
++firstRow;
}
} /* invalOldPerimeter */
#endif
#endif
/* if any of a blank's neighbors is invalid, so must the blank become (since
* they share a border and drawing the neighbor will redraw the blank's border
* too) We'll want to redraw only those blanks that are themselves already
* invalid *OR* that become invalid this way, and so we'll build a new
* BlankQueue of them and replace the old.
*
* I'm not sure what happens if two blanks are neighbors.
*/
#define INVAL_BIT_SET(b,c,r) (((b)->redrawFlags[(r)] & (1 <<(c))) != 0)
static void
invalBlanksWithNeighbors( BoardCtxt* board, BlankQueue* bqp )
{
XP_U16 i;
XP_U16 lastCol, lastRow;
BlankQueue invalBlanks;
XP_U16 nInvalBlanks = 0;
lastCol = model_numCols(board->model) - 1;
lastRow = model_numRows(board->model) - 1;
for ( i = 0; i < bqp->nBlanks; ++i ) {
XP_U16 modelCol = bqp->col[i];
XP_U16 modelRow = bqp->row[i];
XP_U16 col, row;
flipIf( board, modelCol, modelRow, &col, &row );
if ( INVAL_BIT_SET( board, col, row )
|| (col > 0 && INVAL_BIT_SET( board, col-1, row ))
|| (col < lastCol && INVAL_BIT_SET( board, col+1, row ))
|| (row > 0 && INVAL_BIT_SET( board, col, row-1 ))
|| (row < lastRow && INVAL_BIT_SET( board, col, row+1 )) ) {
invalCell( board, col, row );
invalBlanks.col[nInvalBlanks] = (XP_U8)col;
invalBlanks.row[nInvalBlanks] = (XP_U8)row;
++nInvalBlanks;
}
}
invalBlanks.nBlanks = nInvalBlanks;
XP_MEMCPY( bqp, &invalBlanks, sizeof(*bqp) );
} /* invalBlanksWithNeighbors */
#ifdef XWFEATURE_SEARCHLIMIT
static HintAtts
figureHintAtts( BoardCtxt* board, XP_U16 col, XP_U16 row )
{
HintAtts result = HINT_BORDER_NONE;
/* while lets us break to exit... */
while ( board->trayVisState == TRAY_REVEALED
&& !board->gi->hintsNotAllowed
&& board->gi->allowHintRect ) {
BdHintLimits limits;
if ( dragDropGetHintLimits( board, &limits ) ) {
/* do nothing */
} else if ( board->selInfo->hasHintRect ) {
limits = board->selInfo->limits;
} else {
break;
}
if ( col < limits.left ) break;
if ( row < limits.top ) break;
if ( col > limits.right ) break;
if ( row > limits.bottom ) break;
if ( col == limits.left ) {
result |= HINT_BORDER_LEFT;
}
if ( col == limits.right ) {
result |= HINT_BORDER_RIGHT;
}
if ( row == limits.top) {
result |= HINT_BORDER_TOP;
}
if ( row == limits.bottom ) {
result |= HINT_BORDER_BOTTOM;
}
#ifndef XWFEATURE_SEARCHLIMIT_DOCENTERS
if ( result == HINT_BORDER_NONE ) {
result = HINT_BORDER_CENTER;
}
#endif
break;
}
return result;
} /* figureHintAtts */
#endif
static XP_Bool
rectContainsRect( XP_Rect* rect1, XP_Rect* rect2 )
{
return ( rect1->top <= rect2->top
&& rect1->left <= rect2->left
&& rect1->top + rect1->height >= rect2->top + rect2->height
&& rect1->left + rect1->width >= rect2->left + rect2->width );
} /* rectContainsRect */
static void
makeMiniWindowForTrade( BoardCtxt* board )
{
const XP_UCHAR* text;
text = draw_getMiniWText( board->draw, INTRADE_MW_TEXT );
makeMiniWindowForText( board, text, MINIWINDOW_TRADING );
} /* makeMiniWindowForTrade */
static void
drawBoard( BoardCtxt* board )
{
if ( board->needsDrawing
&& draw_boardBegin( board->draw,
&board->boardBounds,
dfsFor( board, OBJ_BOARD ) ) ) {
XP_Bool allDrawn = XP_TRUE;
XP_S16 lastCol, i;
XP_S16 row;
ModelCtxt* model = board->model;
BlankQueue bq;
XP_Rect arrowRect;
scrollIfCan( board ); /* this must happen before we count blanks
since it invalidates squares */
/* This is freaking expensive!!!! PENDING FIXME Can't we start from
what's invalid rather than scanning the entire model every time
somebody dirties a single cell? */
model_listPlacedBlanks( model, board->selPlayer,
board->trayVisState == TRAY_REVEALED, &bq );
invalBlanksWithNeighbors( board, &bq );
for ( row = board->yOffset; row <= board->lastVisibleRow; ++row ) {
XP_U16 rowFlags = board->redrawFlags[row];
if ( rowFlags != 0 ) {
XP_U16 colMask;
XP_U16 failedBits = 0;
lastCol = model_numCols( model );
for ( colMask = 1<<(lastCol-1); lastCol--; colMask >>= 1 ) {
if ( (rowFlags & colMask) != 0 ) {
if ( !drawCell( board, lastCol, row, XP_TRUE )) {
failedBits |= colMask;
allDrawn = XP_FALSE;
}
}
}
board->redrawFlags[row] = failedBits;
}
}
/* draw the blanks we skipped before */
for ( i = 0; i < bq.nBlanks; ++i ) {
if ( !drawCell( board, bq.col[i], bq.row[i], XP_FALSE ) ) {
allDrawn = XP_FALSE;
}
}
if ( board->trayVisState == TRAY_REVEALED ) {
BoardArrow* arrow = &board->selInfo->boardArrow;
if ( arrow->visible ) {
XP_U16 col = arrow->col;
XP_U16 row = arrow->row;
if ( getCellRect( board, col, row, &arrowRect ) ) {
XWBonusType bonus;
HintAtts hintAtts;
CellFlags flags = CELL_NONE;
bonus = util_getSquareBonus( board->util, model,
col, row );
hintAtts = figureHintAtts( board, col, row );
#ifdef KEYBOARD_NAV
if ( cellFocused( board, col, row ) ) {
flags |= CELL_ISCURSOR;
}
#endif
draw_drawBoardArrow( board->draw, &arrowRect, bonus,
arrow->vert, hintAtts, flags );
}
}
}
/* I doubt the two of these can happen at the same time */
drawTradeWindowIf( board );
#ifdef POINTER_SUPPORT
drawDragTileIf( board );
#endif
draw_objFinished( board->draw, OBJ_BOARD, &board->boardBounds,
dfsFor( board, OBJ_BOARD ) );
board->needsDrawing = !allDrawn;
}
} /* drawBoard */
static XP_Bool
drawCell( BoardCtxt* board, XP_U16 col, XP_U16 row, XP_Bool skipBlanks )
{
XP_Bool success = XP_TRUE;
XP_Rect cellRect;
Tile tile;
XP_Bool isBlank, isEmpty, recent, pending = XP_FALSE;
XWBonusType bonus;
ModelCtxt* model = board->model;
DictionaryCtxt* dict = model_getDictionary( model );
XP_U16 modelCol, modelRow;
if ( dict != NULL && getCellRect( board, col, row, &cellRect ) ) {
/* We want to invert EITHER the current pending tiles OR the most recent
* move. So if the tray is visible AND there are tiles missing from it,
* show them. Otherwise show the most recent move.
*/
XP_U16 selPlayer = board->selPlayer;
XP_U16 curCount = model_getCurrentMoveCount( model, selPlayer );
XP_Bool showPending = board->trayVisState == TRAY_REVEALED
&& curCount > 0;
flipIf( board, col, row, &modelCol, &modelRow );
/* This 'while' is only here so I can 'break' below */
while ( board->trayVisState == TRAY_HIDDEN ||
!rectContainsRect( &board->trayBounds, &cellRect ) ) {
XP_UCHAR ch[4] = {'\0'};
XP_S16 owner = -1;
XP_Bool invert = XP_FALSE;
XP_Bitmap bitmap = NULL;
XP_UCHAR* textP = NULL;
HintAtts hintAtts;
CellFlags flags = CELL_NONE;
XP_Bool isOrigin;
isEmpty = !model_getTile( model, modelCol, modelRow, showPending,
selPlayer, &tile, &isBlank,
&pending, &recent );
if ( dragDropIsBeingDragged( board, col, row, &isOrigin ) ) {
flags |= isOrigin? CELL_DRAGSRC : CELL_DRAGCUR;
if ( isEmpty && !isOrigin ) {
dragDropTileInfo( board, &tile, &isBlank );
pending = XP_TRUE;
recent = XP_FALSE;
isEmpty = XP_FALSE;
}
}
if ( isEmpty ) {
isBlank = XP_FALSE;
flags |= CELL_ISEMPTY;
} else if ( isBlank && skipBlanks ) {
break;
} else {
if ( board->showColors ) {
owner = (XP_S16)model_getCellOwner( model, modelCol,
modelRow );
}
invert = showPending? pending : recent;
if ( board->showCellValues ) {
Tile valTile = isBlank? dict_getBlankTile( dict ) : tile;
XP_U16 val = dict_getTileValue( dict, valTile );
XP_SNPRINTF( ch, sizeof(ch), (XP_UCHAR*)"%d", val );
textP = ch;
} else {
if ( dict_faceIsBitmap( dict, tile ) ) {
bitmap = dict_getFaceBitmap( dict, tile, XP_FALSE );
XP_ASSERT( !!bitmap );
}
(void)dict_tilesToString( dict, &tile, 1, ch, sizeof(ch) );
textP = ch;
}
}
bonus = util_getSquareBonus( board->util, model, col, row );
hintAtts = figureHintAtts( board, col, row );
if ( (col==board->star_row) && (row==board->star_row) ) {
flags |= CELL_ISSTAR;
}
if ( invert ) {
flags |= CELL_HIGHLIGHT;
}
if ( isBlank ) {
flags |= CELL_ISBLANK;
}
#ifdef KEYBOARD_NAV
if ( cellFocused( board, col, row ) ) {
flags |= CELL_ISCURSOR;
}
#endif
success = draw_drawCell( board->draw, &cellRect, textP, bitmap,
tile, owner, bonus, hintAtts, flags );
break;
}
}
return success;
} /* drawCell */
#ifdef KEYBOARD_NAV
DrawFocusState
dfsFor( BoardCtxt* board, BoardObjectType obj )
{
DrawFocusState dfs;
if ( (board->focussed == obj) && !board->hideFocus ) {
if ( board->focusHasDived ) {
dfs = DFS_DIVED;
} else {
dfs = DFS_TOP;
}
} else {
dfs = DFS_NONE;
}
return dfs;
} /* dfsFor */
static XP_Bool
cellFocused( const BoardCtxt* board, XP_U16 col, XP_U16 row )
{
XP_Bool focussed = XP_FALSE;
if ( (board->focussed == OBJ_BOARD) && !board->hideFocus ) {
if ( board->focusHasDived ) {
if ( (col == board->selInfo->bdCursor.col)
&& (row == board->selInfo->bdCursor.row) ) {
focussed = XP_TRUE;
}
} else {
#ifdef PERIMETER_FOCUS
focussed = (col == 0)
|| (col == model_numCols(board->model) - 1)
|| (row == board->yOffset)
|| (row == board->lastVisibleRow);
#else
focussed = XP_TRUE;
#endif
}
}
return focussed;
} /* cellFocused */
#endif
#ifdef POINTER_SUPPORT
static void
drawDragTileIf( BoardCtxt* board )
{
if ( dragDropInProgress( board ) ) {
XP_U16 col, row;
if ( dragDropGetBoardTile( board, &col, &row ) ) {
XP_Rect rect;
Tile tile;
XP_Bool isBlank;
XP_UCHAR buf[4];
XP_UCHAR* face;
XP_Bitmap bitmap = NULL;
XP_S16 value;
CellFlags flags;
getDragCellRect( board, col, row, &rect );
dragDropTileInfo( board, &tile, &isBlank );
face = getTileDrawInfo( board, tile, isBlank, &bitmap,
&value, buf, sizeof(buf) );
flags = CELL_DRAGCUR;
if ( isBlank ) {
flags |= CELL_ISBLANK;
}
if ( board->hideValsInTray && !board->showCellValues ) {
flags |= CELL_VALHIDDEN;
}
draw_drawTileMidDrag( board->draw, &rect, face, bitmap, value,
board->selPlayer, flags );
}
}
} /* drawDragTileIf */
#endif
static void
scrollIfCan( BoardCtxt* board )
{
if ( board->yOffset != board->prevYScrollOffset ) {
XP_Rect scrollR = board->boardBounds;
XP_Bool scrolled;
XP_S16 dist;
#ifdef PERIMETER_FOCUS
if ( (board->focussed == OBJ_BOARD)
&& !board->focusHasDived
&& !board->hideFocus ) {
invalOldPerimeter( board );
}
#endif
invalSelTradeWindow( board );
dist = (board->yOffset - board->prevYScrollOffset)
* board->boardVScale;
scrolled = draw_vertScrollBoard( board->draw, &scrollR, dist,
dfsFor( board, OBJ_BOARD ) );
if ( scrolled ) {
/* inval the rows that have been scrolled into view. I'm cheating
making the client figure the inval rect, but Palm's the first
client and it does it so well.... */
invalCellsUnderRect( board, &scrollR );
} else {
board_invalAll( board );
}
board->prevYScrollOffset = board->yOffset;
}
} /* scrollIfCan */
static void
drawTradeWindowIf( BoardCtxt* board )
{
if ( board->tradingMiniWindowInvalid &&
TRADE_IN_PROGRESS(board) && board->trayVisState == TRAY_REVEALED ) {
MiniWindowStuff* stuff;
makeMiniWindowForTrade( board );
stuff = &board->miniWindowStuff[MINIWINDOW_TRADING];
draw_drawMiniWindow( board->draw, stuff->text,
&stuff->rect, (void**)NULL );
board->tradingMiniWindowInvalid = XP_FALSE;
}
} /* drawTradeWindowIf */
XP_Bool
board_draw( BoardCtxt* board )
{
if ( board->boardBounds.width > 0 ) {
drawScoreBoard( board );
drawTray( board );
drawBoard( board );
}
return !board->needsDrawing;
} /* board_draw */
#ifdef CPLUS
}
#endif

300
xwords4/common/boardp.h Normal file
View file

@ -0,0 +1,300 @@
/* -*-mode: C; fill-column: 78; -*- */
/*
* Copyright 1997 - 2007 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 _BOARDP_H_
#define _BOARDP_H_
#include "comtypes.h"
#include "model.h"
#include "board.h"
#include "engine.h"
#include "mempool.h" /* debug only */
#ifdef CPLUS
extern "C" {
#endif
typedef struct _DragObjInfo {
BoardObjectType obj;
union {
struct {
XP_U16 col;
XP_U16 row;
} board;
struct {
XP_U16 index;
} tray;
} u;
} DragObjInfo;
typedef enum {
DT_NONE
,DT_DIVIDER
,DT_TILE
#ifdef XWFEATURE_SEARCHLIMIT
,DT_HINTRGN
#endif
,DT_BOARD
} DragType;
typedef struct _DragState {
DragType dtype;
XP_Bool didMove; /* there was change during the drag; not a
tap */
XP_Bool scrollTimerSet;
XP_Bool isBlank; /* cache rather than lookup in model */
Tile tile; /* cache rather than lookup in model */
DragObjInfo start;
DragObjInfo cur;
} DragState;
typedef struct _BoardArrow { /* gets flipped along with board */
XP_U8 col;
XP_U8 row;
XP_Bool vert;
XP_Bool visible;
} BoardArrow;
#ifdef KEYBOARD_NAV
typedef struct _BdCursorLoc {
XP_U8 col;
XP_U8 row;
} BdCursorLoc;
#endif
/* We only need two of these, one for the value hint and the other for the
trading window. There's never more than of the former since it lives only
as long as the pen is down. There are, in theory, as many trading windows
as there are (local) players, but they can all use the same window. */
typedef struct _MiniWindowStuff {
void* closure;
const XP_UCHAR* text;
XP_Rect rect;
} MiniWindowStuff;
enum { MINIWINDOW_VALHINT, MINIWINDOW_TRADING };
typedef XP_U16 MiniWindowType; /* one of the two above */
typedef struct _PerTurnInfo {
#ifdef KEYBOARD_NAV
XP_Rect scoreRects;
BdCursorLoc bdCursor;
#endif
BoardArrow boardArrow;
XP_U16 scoreDims;
XP_U8 dividerLoc; /* 0 means left of 0th tile, etc. */
TileBit traySelBits;
#ifdef XWFEATURE_SEARCHLIMIT
BdHintLimits limits;
#endif
#ifdef KEYBOARD_NAV
XP_U8 trayCursorLoc; /* includes divider!!! */
#endif
XP_Bool dividerSelected; /* probably need to save this */
XP_Bool tradeInProgress;
#ifdef XWFEATURE_SEARCHLIMIT
XP_Bool hasHintRect;
#endif
} PerTurnInfo;
struct BoardCtxt {
/* BoardVTable* vtable; */
ModelCtxt* model;
ServerCtxt* server;
DrawCtx* draw;
XW_UtilCtxt* util;
struct CurGameInfo* gi;
XP_U16 boardHScale;
XP_U16 boardVScale;
XP_U16 yOffset;
XP_U16 lastVisibleRow;
XP_U16 preHideYOffset;
XP_U16 prevYScrollOffset; /* represents where the last draw took place;
used to see if bit scrolling can be used */
XP_U16 penDownX;
XP_U16 penDownY;
XP_U32 timerStoppedTime;
XP_U16 timerSaveCount;
#ifdef DEBUG
XP_S16 timerStoppedTurn;
#endif
XP_U16 redrawFlags[MAX_ROWS];
XP_Rect boardBounds;
BoardObjectType penDownObject;
XP_Bool needsDrawing;
XP_Bool isFlipped;
XP_Bool showGrid;
XP_Bool gameOver;
XP_Bool leftHanded;
XP_Bool badWordRejected;
XP_Bool timerPending;
XP_Bool disableArrow;
XP_Bool hideValsInTray;
XP_Bool eraseTray;
XP_Bool boardObscuresTray;
XP_Bool boardHidesTray;
XP_Bool scoreSplitHor;/* how to divide the scoreboard? */
XP_Bool srcIsPen; /* We're processing a pen event, not a key event */
XP_U16 star_row;
/* Unless KEYBOARD_NAV is defined, this does not change */
BoardObjectType focussed;
#ifdef KEYBOARD_NAV
XP_Bool focusHasDived;
XP_Bool hideFocus; /* not saved */
XP_Bool trayHiddenPreFocus; /* not saved */
XP_Rect remRect; /* on scoreboard */
#endif
/* scoreboard state */
XP_Rect scoreBdBounds;
XP_Rect timerBounds;
XP_U8 selPlayer; /* which player is selected (!= turn) */
PerTurnInfo pti[MAX_NUM_PLAYERS];
PerTurnInfo* selInfo;
/* tray state */
XP_U8 trayScaleH;
XP_U8 trayScaleV;
XP_Rect trayBounds;
XP_U16 remDim; /* width (or ht) of the "rem:" string in scoreboard */
XP_U8 dividerWidth; /* 0 would mean invisible */
XP_Bool dividerInvalid;
XP_Bool scoreBoardInvalid;
DragState dragState;
MiniWindowStuff miniWindowStuff[2];
XP_Bool tradingMiniWindowInvalid;
TileBit trayInvalBits;
#ifdef KEYBOARD_NAV
XP_U8 scoreCursorLoc;
#endif
XW_TrayVisState trayVisState;
XP_Bool penTimerFired;
XP_Bool showCellValues;
XP_Bool showColors;
MPSLOT
};
#define CURSOR_LOC_REM 0
#define valHintMiniWindowActive( board ) \
((XP_Bool)((board)->miniWindowStuff[MINIWINDOW_VALHINT].text != NULL))
#define MY_TURN(b) ((b)->selPlayer == server_getCurrentTurn( (b)->server ))
#define TRADE_IN_PROGRESS(b) ((b)->selInfo->tradeInProgress==XP_TRUE)
/* tray-related functions */
XP_Bool handlePenUpTray( BoardCtxt* board, XP_U16 x, XP_U16 y );
void drawTray( BoardCtxt* board );
XP_Bool moveTileToArrowLoc( BoardCtxt* board, XP_U8 index );
XP_U16 indexForBits( XP_U8 bits );
XP_Bool rectContainsPt( const XP_Rect* rect1, XP_S16 x, XP_S16 y );
XP_Bool checkRevealTray( BoardCtxt* board );
void figureTrayTileRect( BoardCtxt* board, XP_U16 index, XP_Rect* rect );
XP_Bool rectsIntersect( const XP_Rect* rect1, const XP_Rect* rect2 );
XP_S16 pointToTileIndex( BoardCtxt* board, XP_U16 x, XP_U16 y,
XP_Bool* onDividerP );
void board_selectPlayer( BoardCtxt* board, XP_U16 newPlayer );
void flipIf( const BoardCtxt* board, XP_U16 col, XP_U16 row,
XP_U16* fCol, XP_U16* fRow );
XP_Bool pointOnSomething( BoardCtxt* board, XP_U16 x, XP_U16 y,
BoardObjectType* wp );
XP_Bool coordToCell( BoardCtxt* board, XP_S16 xx, XP_S16 yy, XP_U16* colP,
XP_U16* rowP );
XP_Bool cellOccupied( const BoardCtxt* board, XP_U16 col, XP_U16 row,
XP_Bool inclPending );
XP_Bool holdsPendingTile( BoardCtxt* board, XP_U16 pencol, XP_U16 penrow );
XP_Bool moveTileToBoard( BoardCtxt* board, XP_U16 col, XP_U16 row,
XP_U16 tileIndex, Tile blankFace );
void invalTilesUnderRect( BoardCtxt* board, const XP_Rect* rect );
void invalCellRegion( BoardCtxt* board, XP_U16 colA, XP_U16 rowA, XP_U16 colB,
XP_U16 rowB );
void invalCell( BoardCtxt* board, XP_U16 col, XP_U16 row );
void invalDragObj( BoardCtxt* board, const DragObjInfo* di );
void invalTrayTilesAbove( BoardCtxt* board, XP_U16 tileIndex );
void invalTrayTilesBetween( BoardCtxt* board, XP_U16 tileIndex1,
XP_U16 tileIndex2 );
void makeMiniWindowForText( BoardCtxt* board, const XP_UCHAR* text,
MiniWindowType winType );
XP_Bool getCellRect( const BoardCtxt* board, XP_U16 col, XP_U16 row,
XP_Rect* rect);
void getDragCellRect( BoardCtxt* board, XP_U16 col, XP_U16 row,
XP_Rect* rectP );
void invalSelTradeWindow( BoardCtxt* board );
void invalCellsUnderRect( BoardCtxt* board, const XP_Rect* rect );
#ifdef XWFEATURE_SEARCHLIMIT
void invalCurHintRect( BoardCtxt* board, XP_U16 player );
#endif
void hideMiniWindow( BoardCtxt* board, XP_Bool destroy,
MiniWindowType winType );
void moveTileInTray( BoardCtxt* board, XP_U16 moveTo, XP_U16 moveFrom );
XP_Bool handleTrayDuringTrade( BoardCtxt* board, XP_S16 index );
XP_UCHAR* getTileDrawInfo( const BoardCtxt* board, Tile tile, XP_Bool isBlank,
XP_Bitmap* bitmap, XP_S16* value,
XP_UCHAR* buf, XP_U16 len );
XP_Bool dividerMoved( BoardCtxt* board, XP_U8 newLoc );
XP_Bool checkScrollCell( BoardCtxt* board, XP_U16 col, XP_U16 row );
XP_Bool onBorderCanScroll( const BoardCtxt* board, XP_U16 row, XP_S16* change );
XP_Bool adjustYOffset( BoardCtxt* board, XP_S16 moveBy );
#ifdef KEYBOARD_NAV
XP_Bool tray_moveCursor( BoardCtxt* board, XP_Key cursorKey,
XP_Bool preflightOnly, XP_Bool* up );
void adjustForDivider( const BoardCtxt* board, XP_S16* index );
XP_Bool tray_keyAction( BoardCtxt* board );
DrawFocusState dfsFor( BoardCtxt* board, BoardObjectType obj );
void shiftFocusUp( BoardCtxt* board, XP_Key key );
void getFocussedTileCenter( BoardCtxt* board, XP_U16* xp, XP_U16* yp );
void getRectCenter( const XP_Rect* rect, XP_U16* xp, XP_U16* yp );
#else
# define dfsFor( board, obj ) DFS_NONE
#endif
#ifdef CPLUS
}
#endif
#endif

54
xwords4/common/commmgr.h Normal file
View file

@ -0,0 +1,54 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
/*
* Copyright 2000 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.
*/
/* The Communications manager brokers messages between controllers It
* maps players to devices.
*
* Messages for players go through it. If the player is remote, then the
* message is queued. If local, it's a simple function call executed
* immediately. When the caller is finished, it calls comms_okToSend()
* or somesuch, and all the queued messages are combined into a single
* message for each device represented, and sent.
*
* The problem of duplicate messages: Say there are two players A and B on
* remote device D. A has just made a move {{7,6,'A'},{7,7,'T'}}. The
* server wants to tell each player about A's move. It will want to send the
* same message to every player but A, yet there's no point in sending to B's
* device since the information is already there.
*
* There are three possiblities: put message codes into classes -- e.g.
*/
#ifndef _COMMMGR_H_
#define _COMMMGR_H_
#include "comtypes.h" /* that's *common* types */
#include "xwstream.h"
#include "server.h"
/* typedef struct CommMgrCtxt CommMgrCtxt; */
CommMgrCtxt* commmgr_make( XWStreamCtxt* serverStream );
void commmgr_setServer( CommMgrCtxt* commMgr, ServerCtxt* server );
XWStreamCtxt* commmgr_getServerStream( CommMgrCtxt* commmgr );
void commmgr_receiveMessage( CommMgrCtxt* commmgr, XWStreamCtxt* incomming );
#endif

1643
xwords4/common/comms.c Normal file

File diff suppressed because it is too large Load diff

138
xwords4/common/comms.h Normal file
View file

@ -0,0 +1,138 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
/*
* Copyright 2001 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 _COMMS_H_
#define _COMMS_H_
#include "comtypes.h"
#include "mempool.h"
#include "xwrelay.h"
#include "server.h"
EXTERN_C_START
#define CHANNEL_NONE ((XP_PlayerAddr)0)
#define CONN_ID_NONE 0L
typedef XP_U32 MsgID; /* this is too big!!! PENDING */
typedef XP_U8 XWHostID;
typedef enum {
COMMS_CONN_NONE /* I want errors on uninited case */
,COMMS_CONN_IR
,COMMS_CONN_IP_DIRECT
,COMMS_CONN_RELAY
,COMMS_CONN_BT
} CommsConnType;
/* WHAT SHOULD THIS BE? Copied from Whiteboard.... PENDING */
#define XW_BT_UUID \
{ 0x83, 0xe0, 0x87, 0xae, 0x4e, 0x18, 0x46, 0xbe, \
0x83, 0xe0, 0x7b, 0x3d, 0xe6, 0xa1, 0xc3, 0x3b }
#define XW_BT_NAME "Crosswords"
/* on Palm BtLibDeviceAddressType is a 48-bit quantity. Linux's typeis the
same size. Goal is something all platforms support */
typedef struct XP_BtAddr { XP_U8 bits[6]; } XP_BtAddr;
typedef struct XP_BtAddrStr { XP_UCHAR chars[18]; } XP_BtAddrStr;
#ifdef COMMS_HEARTBEAT
# define IF_CH(a) a,
#else
# define IF_CH(a)
#endif
#define MAX_HOSTNAME_LEN 63
typedef struct CommsAddrRec {
CommsConnType conType;
union {
struct {
XP_UCHAR hostName_ip[MAX_HOSTNAME_LEN + 1];
XP_U32 ipAddr_ip; /* looked up from above */
XP_U16 port_ip;
} ip;
struct {
XP_UCHAR cookie[MAX_COOKIE_LEN + 1];
XP_UCHAR hostName[MAX_HOSTNAME_LEN + 1];
XP_U32 ipAddr; /* looked up from above */
XP_U16 port;
} ip_relay;
struct {
/* nothing? */
XP_UCHAR foo; /* wince doesn't like nothing here */
} ir;
struct {
/* guests can browse for the host to connect to */
XP_UCHAR hostName[MAX_HOSTNAME_LEN + 1];
XP_BtAddr btAddr;
} bt;
} u;
} CommsAddrRec;
typedef XP_S16 (*TransportSend)( const XP_U8* buf, XP_U16 len,
const CommsAddrRec* addr,
void* closure );
typedef void (*TransportReset)( void* closure );
CommsCtxt* comms_make( MPFORMAL XW_UtilCtxt* util,
XP_Bool isServer,
XP_U16 nPlayersHere, XP_U16 nPlayersTotal,
TransportSend sendproc, IF_CH(TransportReset resetproc)
void* closure );
void comms_reset( CommsCtxt* comms, XP_Bool isServer,
XP_U16 nPlayersHere, XP_U16 nPlayersTotal );
void comms_destroy( CommsCtxt* comms );
void comms_setConnID( CommsCtxt* comms, XP_U32 connID );
/* "static" methods work when no comms present */
void comms_getInitialAddr( CommsAddrRec* addr );
XP_Bool comms_checkAddr( DeviceRole role, const CommsAddrRec* addr,
XW_UtilCtxt* util );
void comms_getAddr( const CommsCtxt* comms, CommsAddrRec* addr );
void comms_setAddr( CommsCtxt* comms, const CommsAddrRec* addr );
CommsConnType comms_getConType( const CommsCtxt* comms );
XP_Bool comms_getIsServer( const CommsCtxt* comms );
CommsCtxt* comms_makeFromStream( MPFORMAL XWStreamCtxt* stream,
XW_UtilCtxt* util, TransportSend sendproc,
IF_CH(TransportReset resetproc)
void* closure );
void comms_start( CommsCtxt* comms );
void comms_writeToStream( const CommsCtxt* comms, XWStreamCtxt* stream );
XP_S16 comms_send( CommsCtxt* comms, XWStreamCtxt* stream );
XP_S16 comms_resendAll( CommsCtxt* comms );
XP_Bool comms_checkIncomingStream( CommsCtxt* comms, XWStreamCtxt* stream,
const CommsAddrRec* addr );
# ifdef DEBUG
void comms_getStats( CommsCtxt* comms, XWStreamCtxt* stream );
# endif
EXTERN_C_END
#endif /* _COMMS_H_ */

241
xwords4/common/comtypes.h Normal file
View file

@ -0,0 +1,241 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
/*
* Copyright 1997 - 2000 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 _COMTYPES_H_
#define _COMTYPES_H_
#include "xptypes.h"
#ifndef EXTERN_C_START
# ifdef CPLUS
# define EXTERN_C_START extern "C" {
# else
# define EXTERN_C_START
# endif
#endif
#ifndef EXTERN_C_END
# ifdef CPLUS
# define EXTERN_C_END }
# else
# define EXTERN_C_END
# endif
#endif
#define VSIZE(arr) (sizeof(arr)/sizeof(arr[0]))
typedef struct XP_Rect {
XP_S16 left;
XP_S16 top;
XP_S16 width;
XP_S16 height;
} XP_Rect;
typedef XP_U16 CellTile;
typedef XP_U8 Tile;
typedef void* XP_Bitmap;
typedef XP_UCHAR XP_UCHAR4[4];
typedef enum {
TRI_ENAB_NONE
,TRI_ENAB_HIDDEN
,TRI_ENAB_DISABLED
,TRI_ENAB_ENABLED
} XP_TriEnable;
typedef enum {
DFS_NONE
,DFS_TOP /* focus is on the object */
,DFS_DIVED /* focus is inside the object */
} DrawFocusState;
typedef enum {
TRAY_HIDDEN, /* doesn't happen unless tray overlaps board */
TRAY_REVERSED,
TRAY_REVEALED
} XW_TrayVisState;
typedef enum {
OBJ_NONE,
OBJ_BOARD,
OBJ_SCORE,
OBJ_TRAY
} BoardObjectType;
/* I'm going to try putting all forward "class" decls in the same file */
typedef struct BoardCtxt BoardCtxt;
typedef struct CommMgrCtxt CommMgrCtxt;
typedef struct DictionaryCtxt DictionaryCtxt;
typedef struct DrawCtx DrawCtx;
typedef struct EngineCtxt EngineCtxt;
typedef struct ModelCtxt ModelCtxt;
typedef struct CommsCtxt CommsCtxt;
typedef struct PlayerSocket PlayerSocket;
typedef struct ScoreBdContext ScoreBdContext;
typedef struct ServerCtxt ServerCtxt;
typedef struct XWStreamCtxt XWStreamCtxt;
typedef struct TrayContext TrayContext;
typedef struct PoolContext PoolContext;
typedef struct XW_UtilCtxt XW_UtilCtxt;
typedef XP_S16 XP_PlayerAddr;
typedef enum {
TIMER_PENDOWN = 1, /* ARM doesn't like ids of 0... */
TIMER_TIMERTICK,
#if defined RELAY_HEARTBEAT || defined COMMS_HEARTBEAT
TIMER_HEARTBEAT,
#endif
NUM_TIMERS_PLUS_ONE /* must be last */
} XWTimerReason;
#define MAX_NUM_PLAYERS 4
#define PLAYERNUM_NBITS 2
#define NDEVICES_NBITS 2 /* 1-4, but reduced by 1 fits in 2 bits */
#define NPLAYERS_NBITS 3
#define EMPTIED_TRAY_BONUS 50
/* I need a way to communiate prefs to common/ code. For now, though, I'll
* leave storage of these values up to the platforms. First, because I don't
* want to deal with versioning in the common code. Second, becuase they
* already have the notion of per-game and all-game prefs.
*/
typedef struct CommonPrefs {
XP_Bool showBoardArrow; /* applies to all games */
XP_Bool showRobotScores; /* applies to all games */
XP_Bool hideTileValues;
XP_Bool reserved2; /* get to 32-bit for ARM... */
} CommonPrefs;
#ifdef XWFEATURE_BLUETOOTH
/* temporary debugging hack */
/* From BtLibTypes.h: Pre-assigned assigned PSM values are permitted; however,
* they must be odd, within the range of 0x1001 to 0xFFFF, and have the 9th
* bit (0x0100) set to zero. Passing in BT_L2CAP_RANDOM_PSM will automatically
* create a usable PSM for the channel. In this case the actual PSM value will
* be filled in by the call. */
# define XW_PSM 0x3031
#endif
/* used for all vtables */
#define SET_VTABLE_ENTRY( vt, name, prefix ) \
(vt)->m_##name = prefix##_##name
#ifdef DRAW_LINK_DIRECT
# define DLSTATIC
#else
# define DLSTATIC static
#endif
#ifdef DEBUG
# define DEBUG_ASSIGN(a,b) (a) = (b)
#else
# define DEBUG_ASSIGN(a,b)
#endif
#define OFFSET_OF(typ,var) ((XP_U16)&(((typ*) 0)->var))
#ifdef MEM_DEBUG
# define XP_MALLOC(pool,nbytes) \
mpool_alloc((pool),(nbytes),__FILE__,__LINE__)
# define XP_REALLOC(pool,p,s) mpool_realloc((pool),(p),(s),__FILE__,__LINE__)
# define XP_FREE(pool,p) mpool_free((pool), (p),__FILE__,__LINE__)
# define MPFORMAL_NOCOMMA MemPoolCtx* mpool
# define MPFORMAL MPFORMAL_NOCOMMA,
# define MPSLOT MPFORMAL_NOCOMMA;
# define MPPARM_NOCOMMA(p) (p)
# define MPPARM(p) MPPARM_NOCOMMA(p),
# define MPASSIGN(slot,val) (slot)=(val)
#else
# define MPFORMAL_NOCOMMA
# define MPFORMAL
# define MPSLOT
# define MPPARM_NOCOMMA(p)
# define MPPARM(p)
# define MPASSIGN(slot,val)
#endif
#define LOG_FUNC() XP_LOGF( "IN: %s", __func__ )
#define LOG_RETURNF(fmt, ...) XP_LOGF( "%s => " fmt, __func__, __VA_ARGS__ )
#define LOG_RETURN_VOID() LOG_RETURNF("%s","void")
#define XP_LOGLOC() XP_LOGF( "%s(), line %d", __func__, __LINE__ )
#ifndef XP_UNUSED
# if defined __GNUC__
# define XP_UNUSED(x) UNUSED__ ## x __attribute__((unused))
# else
# define XP_UNUSED(x) x
# endif
#endif
#ifdef DEBUG
# define XP_UNUSED_DBG(x) x
#else
# define XP_UNUSED_DBG(x) XP_UNUSED(x)
#endif
#ifdef ENABLE_LOGGING
# define XP_UNUSED_LOG(x) x
#else
# define XP_UNUSED_LOG(x) XP_UNUSED(x)
#endif
#ifdef XWFEATURE_RELAY
# define XP_UNUSED_RELAY(x) x
#else
# define XP_UNUSED_RELAY(x) UNUSED__ ## x __attribute__((unused))
#endif
#ifdef XWFEATURE_BLUETOOTH
# define XP_UNUSED_BT(x) x
#else
# define XP_UNUSED_BT(x) UNUSED__ ## x __attribute__((unused))
#endif
#if BT_USE_RFCOMM
# define XP_UNUSED_RFCOMM(x) x
#else
# define XP_UNUSED_RFCOMM(x) UNUSED__ ## x __attribute__((unused))
#endif
#ifdef KEYBOARD_NAV
# define XP_UNUSED_KEYBOARD_NAV(x) x
#else
# define XP_UNUSED_KEYBOARD_NAV(x) UNUSED__ ## x __attribute__((unused))
#endif
#ifndef XWFEATURE_STANDALONE_ONLY
# define XP_UNUSED_STANDALONE(x) x
#else
# define XP_UNUSED_STANDALONE(x) UNUSED__ ## x __attribute__((unused))
#endif
#endif

81
xwords4/common/config.mk Normal file
View file

@ -0,0 +1,81 @@
# -*- mode: makefile -*-
# Copyright 2002 by Eric House
#
# 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.
COMMON_INCS = -I ./$(PLATFORM) -I../common -I../relay
INCLUDES += $(COMMON_INCS) -I./
COMMONDIR ?= ../common
COMMONOBJDIR = ../common/$(PLATFORM)
COMMONSRC = \
$(COMMONDIR)/board.c \
$(COMMONDIR)/boarddrw.c \
$(COMMONDIR)/dragdrpp.c \
$(COMMONDIR)/scorebdp.c \
$(COMMONDIR)/tray.c \
$(COMMONDIR)/draw.c \
$(COMMONDIR)/model.c \
$(COMMONDIR)/mscore.c \
$(COMMONDIR)/server.c \
$(COMMONDIR)/pool.c \
$(COMMONDIR)/game.c \
$(COMMONDIR)/nwgamest.c \
$(COMMONDIR)/dictnry.c \
$(COMMONDIR)/engine.c \
$(COMMONDIR)/memstream.c \
$(COMMONDIR)/comms.c \
$(COMMONDIR)/mempool.c \
$(COMMONDIR)/movestak.c \
$(COMMONDIR)/strutils.c \
$(COMMONDIR)/vtabmgr.c \
$(COMMONDIR)/dbgutil.c \
# PENDING: define this in terms of above!!!
COMMON1 = \
$(COMMONOBJDIR)/board.o \
$(COMMONOBJDIR)/boarddrw.o \
$(COMMONOBJDIR)/tray.o \
$(COMMONOBJDIR)/scorebdp.o \
$(COMMONOBJDIR)/draw.o \
COMMON2 = \
$(COMMONOBJDIR)/model.o \
$(COMMONOBJDIR)/mscore.o \
$(COMMONOBJDIR)/server.o \
$(COMMONOBJDIR)/pool.o \
COMMON3 = \
$(COMMONOBJDIR)/game.o \
$(COMMONOBJDIR)/nwgamest.o \
$(COMMONOBJDIR)/dictnry.o \
$(COMMONOBJDIR)/engine.o \
COMMON4 = \
$(COMMONOBJDIR)/dragdrpp.o \
$(COMMONOBJDIR)/memstream.o \
$(COMMONOBJDIR)/comms.o \
$(COMMONOBJDIR)/mempool.o \
COMMON5 = \
$(COMMONOBJDIR)/movestak.o \
$(COMMONOBJDIR)/strutils.o \
$(COMMONOBJDIR)/vtabmgr.o \
$(COMMONOBJDIR)/dbgutil.o \
COMMONOBJ = $(COMMON1) $(COMMON2) $(COMMON3) $(COMMON4) $(COMMON5)

88
xwords4/common/dawg.h Normal file
View file

@ -0,0 +1,88 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4;-*- */
/*
* Copyright 1998-2001 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 _DAWG_H_
#define _DAWG_H_
#include "xptypes.h"
/*
* the bits field has five bits for the character (0-based rather than
* 'a'-based, of course; one bit each indicating whether the edge may
* be terminal and whether it's the last edge of a sub-array; and a final
* bit that's overflow from the highByte field allowing indices to be in
* the range 0-(2^^17)-1
*/
#define LETTERMASK_OLD 0x1f
#define ACCEPTINGMASK_OLD 0x20
#define LASTEDGEMASK_OLD 0x40
#define EXTRABITMASK_OLD 0x80
#define LETTERMASK_NEW_4 0x3f
#define LETTERMASK_NEW_3 0x1f
#define ACCEPTINGMASK_NEW 0x80
#define LASTEDGEMASK_NEW 0x40
/* This guy doesn't exist in 4-byte case */
#define EXTRABITMASK_NEW 0x20
#define OLD_THREE_FIELDS \
XP_U8 highByte; \
XP_U8 lowByte; \
XP_U8 bits
typedef struct array_edge_old {
OLD_THREE_FIELDS;
} array_edge_old;
typedef struct array_edge_new {
OLD_THREE_FIELDS;
XP_U8 moreBits;
} array_edge_new;
typedef XP_U8 array_edge;
/* This thing exists only in current xwords dicts (on PalmOS); not sure if I
* should do away with it.
*/
typedef struct dawg_header {
unsigned long numWords;
unsigned char firstEdgeRecNum;
unsigned char charTableRecNum;
unsigned char valTableRecNum;
unsigned char reserved[3]; /* worst case this points to a new resource */
#ifdef NODE_CAN_4
unsigned short flags;
#endif
} dawg_header;
/* Part of xwords3 dictionaries on PalmOS */
typedef struct Xloc_header {
unsigned char langCodeFlags; /* can't do bitfields; gcc for pilot and x86
seem to generate different code */
unsigned char padding; /* ptrs to the shorts in Xloc_specialEntry
will otherwise be odd */
} Xloc_header;
typedef struct Xloc_specialEntry {
unsigned char textVersion[4]; /* string can be up to 3 chars long */
short hasLarge;
short hasSmall;
} Xloc_specialEntry;
#endif /* _DAWG_H_ */

75
xwords4/common/dbgutil.c Normal file
View file

@ -0,0 +1,75 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
/*
* Copyright 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
* 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.
*/
#ifdef ENABLE_LOGGING
#include "dbgutil.h"
#define CASESTR(s) case s: return #s
#define FUNC(f) #f
const char*
XP_Key_2str( XP_Key key )
{
switch( key ) {
CASESTR(XP_KEY_NONE);
CASESTR(XP_CURSOR_KEY_DOWN);
CASESTR(XP_CURSOR_KEY_ALTDOWN);
CASESTR(XP_CURSOR_KEY_RIGHT);
CASESTR(XP_CURSOR_KEY_ALTRIGHT);
CASESTR(XP_CURSOR_KEY_UP);
CASESTR(XP_CURSOR_KEY_ALTUP);
CASESTR(XP_CURSOR_KEY_LEFT);
CASESTR(XP_CURSOR_KEY_ALTLEFT);
CASESTR(XP_CURSOR_KEY_DEL);
CASESTR(XP_RAISEFOCUS_KEY);
CASESTR(XP_RETURN_KEY);
CASESTR(XP_KEY_LAST );
default: return FUNC(__func__) " unknown";
}
}
const char*
DrawFocusState_2str( DrawFocusState dfs )
{
switch( dfs ) {
CASESTR(DFS_NONE);
CASESTR(DFS_TOP);
CASESTR(DFS_DIVED);
default: return FUNC(__func__) " unknown";
}
}
const char*
BoardObjectType_2str( BoardObjectType obj )
{
switch( obj ) {
CASESTR(OBJ_NONE);
CASESTR(OBJ_BOARD);
CASESTR(OBJ_SCORE);
CASESTR(OBJ_TRAY);
default: return FUNC(__func__) " unknown";
}
}
#undef CASESTR
#endif /* ENABLE_LOGGING */

29
xwords4/common/dbgutil.h Normal file
View file

@ -0,0 +1,29 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
/*
* Copyright 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
* 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 _DBGUTIL_H_
#define _DBGUTIL_H_
#include "board.h"
const char* XP_Key_2str( XP_Key key );
const char* DrawFocusState_2str( DrawFocusState dfs );
const char* BoardObjectType_2str( BoardObjectType dfs );
#endif

531
xwords4/common/dictnry.c Normal file
View file

@ -0,0 +1,531 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
/*
* Copyright 1997-2000 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.
*/
#ifdef USE_STDIO
# include <stdio.h>
# include <stdlib.h>
#endif
#include "comtypes.h"
#include "dictnryp.h"
#include "xwstream.h"
#include "strutils.h"
#ifdef CPLUS
extern "C" {
#endif
/*****************************************************************************
*
****************************************************************************/
void
setBlankTile( DictionaryCtxt* dctx )
{
XP_U16 i;
dctx->blankTile = -1; /* no known blank */
for ( i = 0; i < dctx->nFaces; ++i ) {
if ( dctx->faces16[i] == 0 ) {
XP_ASSERT( dctx->blankTile == -1 ); /* only one passes test? */
dctx->blankTile = (XP_S8)i;
#ifndef DEBUG
break;
#endif
}
}
} /* setBlankTile */
/* #if defined BLANKS_FIRST || defined DEBUG */
XP_Bool
dict_hasBlankTile( const DictionaryCtxt* dict )
{
return dict->blankTile >= 0;
} /* dict_hasBlankTile */
/* #endif */
Tile
dict_getBlankTile( const DictionaryCtxt* dict )
{
XP_ASSERT( dict_hasBlankTile(dict) );
return (Tile)dict->blankTile;
} /* dict_getBlankTile */
XP_U16
dict_getTileValue( const DictionaryCtxt* dict, Tile tile )
{
if ( (tile & TILE_VALUE_MASK) != tile ) {
XP_ASSERT( tile == 32 &&
tile == dict_getBlankTile( dict ) );
}
XP_ASSERT( tile < dict->nFaces );
tile *= 2;
return dict->countsAndValues[tile+1];
} /* dict_getTileValue */
static XP_UCHAR
dict_getTileChar( const DictionaryCtxt* dict, Tile tile )
{
XP_ASSERT( tile < dict->nFaces );
XP_ASSERT( (dict->faces16[tile] & 0xFF00) == 0 ); /* no unicode yet */
return (XP_UCHAR)dict->faces16[tile];
} /* dict_getTileValue */
XP_U16
dict_numTiles( const DictionaryCtxt* dict, Tile tile )
{
tile *= 2;
return dict->countsAndValues[tile];
} /* dict_numTiles */
XP_U16
dict_numTileFaces( const DictionaryCtxt* dict )
{
return dict->nFaces;
} /* dict_numTileFaces */
XP_U16
dict_tilesToString( const DictionaryCtxt* ctxt, const Tile* tiles,
XP_U16 nTiles, XP_UCHAR* buf, XP_U16 bufSize )
{
XP_UCHAR* bufp = buf;
XP_UCHAR* end = bufp + bufSize;
XP_U16 result = 0;
while ( nTiles-- ) {
Tile tile = *tiles++;
XP_UCHAR face = dict_getTileChar(ctxt, tile);
if ( IS_SPECIAL(face) ) {
XP_UCHAR* chars = ctxt->chars[(XP_U16)face];
XP_U16 len = XP_STRLEN( chars );
if ( bufp + len >= end ) {
bufp = NULL;
break;
}
XP_MEMCPY( bufp, chars, len );
bufp += len;
} else {
XP_ASSERT ( tile != ctxt->blankTile ); /* printing blank should be
handled by specials
mechanism */
if ( bufp + 1 >= end ) {
bufp = NULL;
break;
}
*bufp++ = face;
}
}
if ( bufp != NULL && bufp < end ) {
*bufp = '\0';
result = bufp - buf;
}
return result;
} /* dict_tilesToString */
Tile
dict_tileForString( const DictionaryCtxt* dict, const XP_UCHAR* key )
{
XP_U16 nFaces = dict_numTileFaces( dict );
Tile tile;
XP_Bool keyNotSpecial = XP_STRLEN((char*)key) == 1;
for ( tile = 0; tile < nFaces; ++tile ) {
XP_UCHAR face = dict_getTileChar( dict, tile );
if ( IS_SPECIAL(face) ) {
XP_UCHAR* chars = dict->chars[(XP_U16)face];
if ( 0 == XP_STRNCMP( chars, key, XP_STRLEN(chars) ) ) {
return tile;
}
} else if ( keyNotSpecial && (face == *key) ) {
return tile;
}
}
return EMPTY_TILE;
} /* dict_tileForChar */
XP_Bool
dict_tilesAreSame( const DictionaryCtxt* dict1, const DictionaryCtxt* dict2 )
{
XP_Bool result = XP_FALSE;
Tile i;
XP_U16 nTileFaces = dict_numTileFaces( dict1 );
if ( nTileFaces == dict_numTileFaces( dict2 ) ) {
for ( i = 0; i < nTileFaces; ++i ) {
XP_UCHAR face1, face2;
if ( dict_getTileValue( dict1, i )
!= dict_getTileValue( dict2, i ) ){
break;
}
#if 1
face1 = dict_getTileChar( dict1, i );
face2 = dict_getTileChar( dict2, i );
if ( face1 != face2 ) {
break;
}
#else
face1 = dict_getTileChar( dict1, i );
face2 = dict_getTileChar( dict2, i );
if ( IS_SPECIAL(face1) != IS_SPECIAL(face2) ) {
break;
}
if ( IS_SPECIAL(face1) ) {
XP_UCHAR* chars1 = dict1->chars[face1];
XP_UCHAR* chars2 = dict2->chars[face2];
XP_U16 len = XP_STRLEN(chars1);
if ( 0 != XP_STRNCMP( chars1, chars2, len ) ) {
break;
}
} else if ( face1 != face2 ) {
break;
}
#endif
if ( dict_numTiles( dict1, i ) != dict_numTiles( dict2, i ) ) {
break;
}
}
result = i == nTileFaces; /* did we get that far */
}
return result;
} /* dict_tilesAreSame */
void
dict_writeToStream( const DictionaryCtxt* dict, XWStreamCtxt* stream )
{
XP_U16 maxCount = 0;
XP_U16 maxValue = 0;
XP_U16 i, nSpecials;
XP_U16 maxCountBits, maxValueBits;
stream_putBits( stream, 6, dict->nFaces );
for ( i = 0; i < dict->nFaces*2; i+=2 ) {
XP_U16 count, value;
count = dict->countsAndValues[i];
if ( maxCount < count ) {
maxCount = count;
}
value = dict->countsAndValues[i+1];
if ( maxValue < value ) {
maxValue = value;
}
}
maxCountBits = bitsForMax( maxCount );
maxValueBits = bitsForMax( maxValue );
stream_putBits( stream, 3, maxCountBits ); /* won't be bigger than 5 */
stream_putBits( stream, 3, maxValueBits );
for ( i = 0; i < dict->nFaces*2; i+=2 ) {
stream_putBits( stream, maxCountBits, dict->countsAndValues[i] );
stream_putBits( stream, maxValueBits, dict->countsAndValues[i+1] );
}
for ( i = 0; i < dict->nFaces; ++i ) {
stream_putU8( stream, (XP_U8)dict->faces16[i] );
}
for ( nSpecials = i = 0; i < dict->nFaces; ++i ) {
XP_UCHAR face = dict_getTileChar( dict, (Tile)i );
if ( IS_SPECIAL( face ) ) {
stringToStream( stream, dict->chars[nSpecials++] );
}
}
} /* dict_writeToStream */
static void
freeSpecials( DictionaryCtxt* dict )
{
Tile t;
XP_U16 nSpecials;
for ( nSpecials = t = 0; t < dict->nFaces; ++t ) {
XP_UCHAR face = dict_getTileChar( dict, t );
if ( IS_SPECIAL( face ) ) {
XP_ASSERT( !!dict->chars[nSpecials] );
XP_FREE( dict->mpool, dict->chars[nSpecials] );
if ( !!dict->bitmaps[nSpecials].largeBM ) {
XP_FREE( dict->mpool, dict->bitmaps[nSpecials].largeBM );
}
if ( !!dict->bitmaps[nSpecials].smallBM ) {
XP_FREE( dict->mpool, dict->bitmaps[nSpecials].smallBM );
}
++nSpecials;
}
}
if ( nSpecials > 0 ) {
XP_FREE( dict->mpool, dict->chars );
XP_FREE( dict->mpool, dict->bitmaps );
}
} /* freeSpecials */
static void
common_destructor( DictionaryCtxt* dict )
{
freeSpecials( dict );
XP_FREE( dict->mpool, dict->countsAndValues );
XP_FREE( dict->mpool, dict->faces16 );
XP_FREE( dict->mpool, dict );
} /* dict */
void
dict_loadFromStream( DictionaryCtxt* dict, XWStreamCtxt* stream )
{
XP_U8 nFaces;
XP_U16 maxCountBits, maxValueBits;
XP_U16 i, nSpecials;
XP_UCHAR* localTexts[32];
XP_ASSERT( !dict->destructor );
dict->destructor = common_destructor;
dict->func_dict_getShortName = dict_getName; /* default */
nFaces = (XP_U8)stream_getBits( stream, 6 );
maxCountBits = (XP_U16)stream_getBits( stream, 3 );
maxValueBits = (XP_U16)stream_getBits( stream, 3 );
dict->nFaces = nFaces;
dict->countsAndValues =
(XP_U8*)XP_MALLOC( dict->mpool,
sizeof(dict->countsAndValues[0]) * nFaces * 2 );
for ( i = 0; i < dict->nFaces*2; i+=2 ) {
dict->countsAndValues[i] = (XP_U8)stream_getBits( stream,
maxCountBits );
dict->countsAndValues[i+1] = (XP_U8)stream_getBits( stream,
maxValueBits );
}
dict->faces16 = (XP_CHAR16*)XP_MALLOC( dict->mpool,
sizeof(dict->faces16[0]) * nFaces );
for ( i = 0; i < dict->nFaces; ++i ) {
dict->faces16[i] = (XP_CHAR16)stream_getU8( stream );
}
for ( nSpecials = i = 0; i < nFaces; ++i ) {
XP_UCHAR face = dict_getTileChar( dict, (Tile)i );
if ( IS_SPECIAL( face ) ) {
XP_UCHAR* txt = stringFromStream( dict->mpool, stream );
XP_ASSERT( !!txt );
localTexts[nSpecials] = txt;
++nSpecials;
}
}
if ( nSpecials > 0 ) {
dict->bitmaps =
(SpecialBitmaps*)XP_MALLOC( dict->mpool,
nSpecials * sizeof(*dict->bitmaps) );
XP_MEMSET( dict->bitmaps, 0, nSpecials * sizeof(*dict->bitmaps) );
dict->chars = (XP_UCHAR**)XP_MALLOC( dict->mpool,
nSpecials * sizeof(*dict->chars) );
XP_MEMCPY(dict->chars, localTexts, nSpecials * sizeof(*dict->chars));
}
setBlankTile( dict );
} /* dict_loadFromStream */
const XP_UCHAR*
dict_getName( const DictionaryCtxt* dict )
{
XP_ASSERT( !!dict );
XP_ASSERT( !!dict->name );
return dict->name;
} /* dict_getName */
XP_Bool
dict_faceIsBitmap( const DictionaryCtxt* dict, Tile tile )
{
XP_UCHAR face = dict_getTileChar( dict, tile );
return /* face != 0 && */IS_SPECIAL(face);
} /* dict_faceIsBitmap */
XP_Bitmap
dict_getFaceBitmap( const DictionaryCtxt* dict, Tile tile, XP_Bool isLarge )
{
SpecialBitmaps* bitmaps;
XP_UCHAR face = dict_getTileChar( dict, tile );
XP_ASSERT( dict_faceIsBitmap( dict, tile ) );
XP_ASSERT( !!dict->bitmaps );
bitmaps = &dict->bitmaps[(XP_U16)face];
return isLarge? bitmaps->largeBM:bitmaps->smallBM;
} /* dict_getFaceBitmap */
#ifdef TALL_FONTS
XP_LangCode
dict_getLangCode( const DictionaryCtxt* dict )
{
return dict->langCode;
}
#endif
#ifdef STUBBED_DICT
#define BLANK_FACE '\0'
static XP_U8 stub_english_data[] = {
/* count value face */
9, 1, 'A',
2, 3, 'B',
2, 3, 'C',
4, 2, 'D',
12, 1, 'E',
2, 4, 'F',
3, 2, 'G',
2, 4, 'H',
9, 1, 'I',
1, 8, 'J',
1, 5, 'K',
4, 1, 'L',
2, 3, 'M',
6, 1, 'N',
8, 1, 'O',
2, 3, 'P',
1, 10, 'Q',
6, 1, 'R',
4, 1, 'S',
6, 1, 'T',
4, 1, 'U',
2, 4, 'V',
2, 4, 'W',
1, 8, 'X',
2, 4, 'Y',
1, 10, 'Z',
2, 0, BLANK_FACE, /* BLANK1 */
};
void
setStubbedSpecials( DictionaryCtxt* dict )
{
dict->chars = (XP_UCHAR**)XP_MALLOC( dict->mpool, sizeof(char*) );
dict->chars[0] = "_";
} /* setStubbedSpecials */
void
destroy_stubbed_dict( DictionaryCtxt* dict )
{
XP_FREE( dict->mpool, dict->countsAndValues );
XP_FREE( dict->mpool, dict->faces16 );
XP_FREE( dict->mpool, dict->chars );
XP_FREE( dict->mpool, dict->name );
XP_FREE( dict->mpool, dict->bitmaps );
XP_FREE( dict->mpool, dict );
} /* destroy_stubbed_dict */
DictionaryCtxt*
make_stubbed_dict( MPFORMAL_NOCOMMA )
{
DictionaryCtxt* dict = (DictionaryCtxt*)XP_MALLOC( mpool, sizeof(*dict) );
XP_U8* data = stub_english_data;
XP_U16 datasize = sizeof(stub_english_data);
XP_U16 i;
XP_MEMSET( dict, 0, sizeof(*dict) );
MPASSIGN( dict->mpool, mpool );
dict->name = copyString( mpool, "Stub dictionary" );
dict->nFaces = datasize/3;
dict->destructor = destroy_stubbed_dict;
dict->faces16 = (XP_CHAR16*)
XP_MALLOC( mpool, dict->nFaces * sizeof(dict->faces16[0]) );
for ( i = 0; i < datasize/3; ++i ) {
dict->faces16[i] = (XP_CHAR16)data[(i*3)+2];
}
dict->countsAndValues = (XP_U8*)XP_MALLOC( mpool, dict->nFaces*2 );
for ( i = 0; i < datasize/3; ++i ) {
dict->countsAndValues[i*2] = data[(i*3)];
dict->countsAndValues[(i*2)+1] = data[(i*3)+1];
}
dict->bitmaps = (SpecialBitmaps*)XP_MALLOC( mpool, sizeof(SpecialBitmaps) );
dict->bitmaps->largeBM = dict->bitmaps->largeBM = NULL;
setStubbedSpecials( dict );
setBlankTile( dict );
return dict;
} /* make_subbed_dict */
#endif /* STUBBED_DICT */
static array_edge*
dict_super_edge_for_index( const DictionaryCtxt* dict, XP_U32 index )
{
array_edge* result;
if ( index == 0 ) {
result = NULL;
} else {
XP_ASSERT( index < dict->numEdges );
#ifdef NODE_CAN_4
/* avoid long-multiplication lib call on Palm... */
if ( dict->nodeSize == 3 ) {
index += (index << 1);
} else {
XP_ASSERT( dict->nodeSize == 4 );
index <<= 2;
}
#else
index += (index << 1);
#endif
result = &dict->base[index];
}
return result;
} /* dict_edge_for_index */
static array_edge*
dict_super_getTopEdge( const DictionaryCtxt* dict )
{
return dict->topEdge;
} /* dict_super_getTopEdge */
void
dict_super_init( DictionaryCtxt* ctxt )
{
/* subclass may change these later.... */
ctxt->func_edge_for_index = dict_super_edge_for_index;
ctxt->func_dict_getTopEdge = dict_super_getTopEdge;
ctxt->func_dict_getShortName = dict_getName;
} /* dict_super_init */
#ifdef CPLUS
}
#endif

168
xwords4/common/dictnry.h Normal file
View file

@ -0,0 +1,168 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
/*
* Copyright 1997 - 2000 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 __DICTNRY_H__
#define __DICTNRY_H__
#include "comtypes.h"
#include "dawg.h"
#include "model.h"
#include "mempool.h"
#ifdef CPLUS
extern "C" {
#endif
#define LETTER_NONE '\0'
#define IS_SPECIAL(face) (((XP_CHAR16)(face)) < 0x0020)
typedef XP_U8 XP_LangCode;
typedef XP_U16 XP_CHAR16;
typedef enum {
BONUS_NONE,
BONUS_DOUBLE_LETTER,
BONUS_DOUBLE_WORD,
BONUS_TRIPLE_LETTER,
BONUS_TRIPLE_WORD,
BONUS_LAST
} XWBonusType;
typedef enum {
INTRADE_MW_TEXT = BONUS_LAST
} XWMiniTextType;
typedef struct SpecialBitmaps {
XP_Bitmap largeBM;
XP_Bitmap smallBM;
} SpecialBitmaps;
struct DictionaryCtxt {
void (*destructor)( DictionaryCtxt* dict );
array_edge* (*func_edge_for_index)( const DictionaryCtxt* dict, XP_U32 index );
array_edge* (*func_dict_getTopEdge)( const DictionaryCtxt* dict );
const XP_UCHAR* (*func_dict_getShortName)( const DictionaryCtxt* dict );
array_edge* topEdge;
array_edge* base; /* the physical beginning of the dictionary; not
necessarily the entry point for search!! */
XP_UCHAR* name;
XP_CHAR16* faces16; /* 16 for unicode */
XP_U8* countsAndValues;
SpecialBitmaps* bitmaps;
XP_UCHAR** chars;
#ifdef TALL_FONTS
XP_LangCode langCode;
#endif
XP_U8 nFaces;
#ifdef NODE_CAN_4
XP_U8 nodeSize;
XP_Bool is_4_byte;
#endif
XP_S8 blankTile; /* negative means there's no known blank */
#ifdef DEBUG
XP_U32 numEdges;
#endif
MPSLOT
};
/* This is the datastructure that allows access to a DAWG in a
* platform-independent way.
*/
/* typedef struct DictionaryVtable { */
/* XP_U16 (*m_getTileValue)( DictionaryCtxt* ctxt, CellTile tile ); */
/* unsigned char (*m_getTileChar)( DictionaryCtxt* ctxt, CellTile tile, */
/* XP_FontCode* fontCode ); */
/* XP_U16 (*m_numTiles)( DictionaryCtxt* ctxt, Tile tile ); */
/* XP_U16 (*m_numTileFaces)( DictionaryCtxt* ctxt ); */
/* } DictionaryVtable; */
/* struct DictionaryCtxt { */
/* DictionaryVtable* vtable; */
/* }; */
/* #define dict_getTileValue(dc,t) \ */
/* (dc)->vtable->m_getTileValue((dc),(t)) */
/* #define dict_getTileChar(dc,t,fc) \ */
/* (dc)->vtable->m_getTileChar((dc),(t),(fc)) */
/* #define dict_numTiles(dc,t) (dc)->vtable->m_numTiles((dc),(t)) */
/* #define dict_numTileFaces(dc) (dc)->vtable->m_numTileFaces(dc) */
#define dict_destroy(d) (*((d)->destructor))(d)
#define dict_edge_for_index(d, i) (*((d)->func_edge_for_index))((d), (i))
#define dict_getTopEdge(d) (*((d)->func_dict_getTopEdge))(d)
#define dict_getShortName(d) (*((d)->func_dict_getShortName))(d)
XP_Bool dict_tilesAreSame( const DictionaryCtxt* dict1,
const DictionaryCtxt* dict2 );
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_numTileFaces( const DictionaryCtxt* ctxt );
XP_U16 dict_tilesToString( const DictionaryCtxt* ctxt, const Tile* tiles,
XP_U16 nTiles, XP_UCHAR* buf, XP_U16 bufSize );
const XP_UCHAR* dict_getName( const DictionaryCtxt* ctxt );
Tile dict_tileForString( const DictionaryCtxt* dict, const XP_UCHAR* key );
XP_Bool dict_faceIsBitmap( const DictionaryCtxt* dict, Tile tile );
XP_Bitmap dict_getFaceBitmap( const DictionaryCtxt* dict, Tile tile,
XP_Bool isLarge );
#ifdef TALL_FONTS
XP_LangCode dict_getLangCode( const DictionaryCtxt* dict );
#endif
void dict_writeToStream( const DictionaryCtxt* ctxt, XWStreamCtxt* stream );
void dict_loadFromStream( DictionaryCtxt* dict, XWStreamCtxt* stream );
/* These methods get "overridden" by subclasses. That is, they must be
implemented by each platform. */
#ifdef STUBBED_DICT
DictionaryCtxt* make_stubbed_dict( MPFORMAL_NOCOMMA );
#endif
/* To be called only by subclasses!!! */
void dict_super_init( DictionaryCtxt* ctxt );
#ifdef CPLUS
}
#endif
#endif

36
xwords4/common/dictnryp.h Normal file
View file

@ -0,0 +1,36 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4;-*- */
/*
* Copyright 1997-2000 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 _DICTNRYP_H_
#define _DICTNRYP_H_
#include "dictnry.h"
#ifdef CPLUS
extern "C" {
#endif
void setBlankTile( DictionaryCtxt* dctx );
#ifdef CPLUS
}
#endif
#endif

573
xwords4/common/dragdrpp.c Normal file
View file

@ -0,0 +1,573 @@
/* -*-mode: C; fill-column: 78; compile-command: "cd ../linux && make MEMDEBUG=TRUE"; -*- */
/*
* Copyright 1997 - 2008 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.
*/
#ifdef CPLUS
extern "C" {
#endif
#include "dragdrpp.h"
#include "game.h"
/* How many squares must scroll gesture take in to be recognized. */
#define SCROLL_DRAG_THRESHHOLD 3
static XP_Bool dragDropContinueImpl( BoardCtxt* board, XP_U16 xx, XP_U16 yy,
BoardObjectType* onWhichP );
static void invalDragObjRange( BoardCtxt* board, const DragObjInfo* from,
const DragObjInfo* to );
#ifdef XWFEATURE_SEARCHLIMIT
static void invalHintRectDiffs( BoardCtxt* board, const DragObjInfo* cur,
const DragObjInfo* nxt );
static void setLimitsFrom( const BoardCtxt* board, BdHintLimits* limits );
#endif
static void startScrollTimerIf( BoardCtxt* board );
XP_Bool
dragDropInProgress( const BoardCtxt* board )
{
const DragState* ds = &board->dragState;
/* LOG_RETURNF( "%d", ds->dragInProgress ); */
return ds->dtype != DT_NONE;
} /* dragDropInProgress */
XP_Bool
dragDropHasMoved( const BoardCtxt* board )
{
return dragDropInProgress(board) && board->dragState.didMove;
} /* dragDropHasMoved */
static XP_Bool
ddStartBoard( BoardCtxt* board, XP_U16 xx, XP_U16 yy )
{
DragState* ds = &board->dragState;
XP_Bool found;
XP_Bool trayVisible;
XP_U16 col, row;
found = coordToCell( board, xx, yy, &col, &row );
XP_ASSERT( found );
trayVisible = board->trayVisState == TRAY_REVEALED;
if ( trayVisible && holdsPendingTile( board, col, row ) ) {
XP_U16 modelc, modelr;
XP_Bool ignore;
ds->dtype = DT_TILE;
flipIf( board, col, row, &modelc, &modelr );
found = model_getTile( board->model, modelc, modelr, XP_TRUE,
board->selPlayer, &ds->tile, &ds->isBlank,
&ignore, &ignore );
XP_ASSERT( found );
} else {
/* If we're not dragging a tile, we can either drag the board (scroll)
or work on hint regions. Sometimes scrolling isn't possible.
Sometimes hint dragging is disabled. But if both are possible,
then the alt key determines it. I figure scrolling will be more
common than hint dragging when both are possible, but you can turn
hint dragging off, so if it's on that's probably what you want. */
XP_Bool canScroll = board->lastVisibleRow < model_numRows(board->model);
if ( 0 ) {
#ifdef XWFEATURE_SEARCHLIMIT
} else if ( !board->gi->hintsNotAllowed && board->gi->allowHintRect
&& trayVisible ) {
if ( !util_altKeyDown(board->util) ) {
ds->dtype = DT_HINTRGN;
} else if ( canScroll ) {
ds->dtype = DT_BOARD;
}
#endif
} else if ( canScroll ) {
ds->dtype = DT_BOARD;
}
}
ds->start.u.board.col = col;
ds->start.u.board.row = row;
return ds->dtype != DT_NONE;
} /* ddStartBoard */
static XP_Bool
ddStartTray( BoardCtxt* board, XP_U16 x, XP_U16 y )
{
XP_Bool canDrag;
DragState* ds = &board->dragState;
XP_Bool onDivider;
XP_S16 index = pointToTileIndex( board, x, y, &onDivider );
canDrag = onDivider || index >= 0;
if ( canDrag ) {
if ( onDivider ) {
board->dividerInvalid = XP_TRUE;
ds->start.u.tray.index = board->selInfo->dividerLoc;
ds->dtype = DT_DIVIDER;
} else {
Tile tile;
tile = model_getPlayerTile( board->model, board->selPlayer, index );
ds->isBlank =
tile == dict_getBlankTile( model_getDictionary(board->model) );
ds->tile = tile;
ds->start.u.tray.index = index;
/* during drag the moving tile is drawn as selected, so inval
currently selected tile. */
board_invalTrayTiles( board, board->selInfo->traySelBits );
ds->dtype = DT_TILE;
}
}
return canDrag;
} /* ddStartTray */
/* x and y, in board coordinates (not model, should the board be flipped), are
* already col,row (cells) in the board case, but real x/y (pixels) on the
* tray.
*/
XP_Bool
dragDropStart( BoardCtxt* board, BoardObjectType obj, XP_U16 x, XP_U16 y )
{
XP_Bool result = XP_FALSE;
DragState* ds = &board->dragState;
if ( dragDropInProgress(board) ) {
XP_LOGF( "warning: starting drag while dragDropInProgress() true" );
}
XP_MEMSET( ds, 0, sizeof(*ds) );
ds->start.obj = obj;
if ( OBJ_BOARD == obj ) {
result = ddStartBoard( board, x, y );
} else if ( OBJ_TRAY == obj ) {
result = ddStartTray( board, x, y );
} else {
XP_ASSERT(0);
}
if ( result ) {
ds->cur = ds->start;
invalDragObj( board, &ds->start );
startScrollTimerIf( board );
}
return result;
} /* dragDropStart */
/* We're potentially dragging. If we're leaving one object, inval it.
* If we're entering another, inval it. Track where we are so we don't inval
* again. If we didn't really move, don't inval anything!
*
* Our overriding concern must be to preserve data integrity in the face of
* buggy OSes that may drop events (esp. MouseUp). So never own a tile: keep
* it attached either to the tray or the board. If the state of the board is
* to change as dragging happens, that's for the board (view) to display, not
* the model. So drawing has to be aware of drag-and-drop, but we don't
* change the model until the pen's actually lifted. If we never get the
* pen-up event at the worst the board's drawn incorrectly for a bit.
*
* Exception: since divider location is in the board rather than the model
* just change it every time we can.
*/
XP_Bool
dragDropContinue( BoardCtxt* board, XP_U16 xx, XP_U16 yy )
{
BoardObjectType ignore;
XP_ASSERT( dragDropInProgress(board) );
return dragDropContinueImpl( board, xx, yy, &ignore );
}
XP_Bool
dragDropEnd( BoardCtxt* board, XP_U16 xx, XP_U16 yy, XP_Bool* dragged )
{
DragState* ds = &board->dragState;
BoardObjectType newObj;
XP_ASSERT( dragDropInProgress(board) );
(void)dragDropContinueImpl( board, xx, yy, &newObj );
*dragged = ds->didMove;
/* If we've dropped on something, put the tile there! Since we
don't remove it from its earlier location until it's dropped,
we need to specify where it's coming from. */
if ( ds->dtype == DT_DIVIDER ) {
board->dividerInvalid = XP_TRUE;
/* nothing to do */
#ifdef XWFEATURE_SEARCHLIMIT
} else if ( ds->dtype == DT_HINTRGN ) {
if ( OBJ_BOARD == newObj && ds->didMove ) {
XP_Bool makeActive = ds->start.u.board.row <= ds->cur.u.board.row;
board->selInfo->hasHintRect = makeActive;
if ( makeActive ) {
setLimitsFrom( board, &board->selInfo->limits );
} else {
invalHintRectDiffs( board, &ds->cur, NULL );
}
board_resetEngine( board );
} else {
/* return it to whatever it was */
invalHintRectDiffs( board, &ds->cur, NULL );
invalCurHintRect( board, board->selPlayer );
}
#endif
} else if ( ds->dtype == DT_BOARD ) {
/* do nothing */
} else {
XP_U16 mod_startc, mod_startr;
flipIf( board, ds->start.u.board.col, ds->start.u.board.row,
&mod_startc, &mod_startr );
if ( newObj == OBJ_TRAY ) {
if ( ds->start.obj == OBJ_BOARD ) { /* board->tray is pending */
model_moveBoardToTray( board->model, board->selPlayer,
mod_startc, mod_startr,
ds->cur.u.tray.index );
} else {
model_moveTileOnTray( board->model, board->selPlayer,
ds->start.u.tray.index,
ds->cur.u.tray.index );
}
} else if ( (newObj == OBJ_BOARD) &&
!cellOccupied( board, ds->cur.u.board.col,
ds->cur.u.board.row, XP_TRUE ) ) {
if ( ds->start.obj == OBJ_TRAY ) {
/* moveTileToBoard flips its inputs */
(void)moveTileToBoard( board, ds->cur.u.board.col,
ds->cur.u.board.row,
ds->start.u.tray.index, EMPTY_TILE );
} else if ( ds->start.obj == OBJ_BOARD ) {
XP_U16 mod_curc, mod_curr;
flipIf( board, ds->cur.u.board.col, ds->cur.u.board.row,
&mod_curc, &mod_curr );
if ( model_moveTileOnBoard( board->model, board->selPlayer,
mod_startc, mod_startr, mod_curc,
mod_curr ) ) {
/* inval points tile in case score changed */
board_invalTrayTiles( board, 1 << (MAX_TRAY_TILES-1) );
}
}
} else {
/* We're returning it to start, so will be re-inserted in tray */
if ( OBJ_TRAY == ds->start.obj ) {
invalTrayTilesAbove( board, ds->start.u.tray.index );
}
}
/* These may change appearance, e.g. from big tile to dropped cell. */
invalDragObj( board, &ds->cur );
invalDragObj( board, &ds->start );
}
ds->dtype = DT_NONE;
return XP_TRUE;
} /* dragDropEnd */
XP_Bool
dragDropGetBoardTile( const BoardCtxt* board, XP_U16* col, XP_U16* row )
{
const DragState* ds = &board->dragState;
XP_Bool found = ds->dtype == DT_TILE && ds->cur.obj == OBJ_BOARD;
if ( found ) {
*col = ds->cur.u.board.col;
*row = ds->cur.u.board.row;
}
return found;
}
XP_Bool
dragDropIsBeingDragged( const BoardCtxt* board, XP_U16 col, XP_U16 row,
XP_Bool* isOrigin )
{
const DragState* ds = &board->dragState;
XP_Bool result = ds->dtype == DT_TILE && ds->cur.obj == OBJ_BOARD;
if ( result ) {
const DragState* ds = &board->dragState;
if ( (ds->cur.obj == OBJ_BOARD) && (ds->cur.u.board.col == col)
&& (ds->cur.u.board.row == row) ) {
*isOrigin = XP_FALSE;
} else if ( (ds->start.obj == OBJ_BOARD)
&& (ds->start.u.board.col == col)
&& (ds->start.u.board.row == row) ) {
*isOrigin = XP_TRUE;
} else {
result = XP_FALSE;
}
}
return result;
}
void
dragDropGetTrayChanges( const BoardCtxt* board, XP_U16* rmvdIndx,
XP_U16* addedIndx )
{
const DragState* ds = &board->dragState;
*addedIndx = *rmvdIndx = MAX_TRAY_TILES; /* too big means ignore me */
if ( ds->dtype == DT_TILE ) {
if ( OBJ_TRAY == ds->start.obj ) {
*rmvdIndx = ds->start.u.tray.index;
}
if ( OBJ_TRAY == ds->cur.obj ) {
*addedIndx = ds->cur.u.tray.index;
}
}
}
#ifdef XWFEATURE_SEARCHLIMIT
XP_Bool
dragDropGetHintLimits( const BoardCtxt* board, BdHintLimits* limits )
{
XP_Bool result = board->dragState.dtype == DT_HINTRGN;
if ( result ) {
setLimitsFrom( board, limits );
}
return result;
}
#endif
XP_Bool
dragDropIsDividerDrag( const BoardCtxt* board )
{
return board->dragState.dtype == DT_DIVIDER;
}
void
dragDropTileInfo( const BoardCtxt* board, Tile* tile, XP_Bool* isBlank )
{
const DragState* ds = &board->dragState;
XP_ASSERT( dragDropInProgress( board ) );
XP_ASSERT( ds->dtype == DT_TILE );
XP_ASSERT ( OBJ_BOARD == ds->start.obj || OBJ_TRAY == ds->start.obj );
*tile = ds->tile;
*isBlank = ds->isBlank;
}
#ifdef XWFEATURE_SEARCHLIMIT
static void
invalHintRectDiffs( BoardCtxt* board, const DragObjInfo* cur,
const DragObjInfo* nxt )
{
XP_U16 startCol = board->dragState.start.u.board.col;
XP_U16 startRow = board->dragState.start.u.board.row;
/* These two regions will generally have close to 50% of their borders in
common. Try not to inval what needn't be inval'd. But at the moment
performance seems good enough without adding the complexity and new
bugs...
The challenge in doing a smarter diff is that some squares need to be
invalidated even if they're part of the borders of both limits rects,
in particular if one is a corner of one and just a side of another.
One simple but expensive way of accounting for this would be to call
figureHintAtts() on each square in the borders of both rects and
invalidate when the hintAttributes aren't the same for both. That
misses an opportunity to avoid doing any calculations on those border
squares that clearly haven't changed at all.
*/
invalCellRegion( board, startCol, startRow, cur->u.board.col,
cur->u.board.row );
if ( !!nxt ) {
BdHintLimits limits;
setLimitsFrom( board, &limits );
invalCellRegion( board, startCol, startRow, nxt->u.board.col,
nxt->u.board.row );
}
} /* invalHintRectDiffs */
#endif
static XP_Bool
dragDropContinueImpl( BoardCtxt* board, XP_U16 xx, XP_U16 yy,
BoardObjectType* onWhichP )
{
XP_Bool moving = XP_FALSE;
DragObjInfo newInfo;
DragState* ds = &board->dragState;
if ( !pointOnSomething( board, xx, yy, &newInfo.obj ) ) {
newInfo.obj = OBJ_NONE;
}
*onWhichP = newInfo.obj;
if ( newInfo.obj == OBJ_BOARD ) {
(void)coordToCell( board, xx, yy, &newInfo.u.board.col,
&newInfo.u.board.row );
}
if ( ds->dtype == DT_DIVIDER ) {
if ( OBJ_TRAY == newInfo.obj ) {
XP_U16 newloc;
XP_U16 scale = board->trayScaleH;
xx -= board->trayBounds.left;
newloc = xx / scale;
if ( (xx % scale) > ((scale+board->dividerWidth)/2)) {
++newloc;
}
moving = dividerMoved( board, newloc );
}
#ifdef XWFEATURE_SEARCHLIMIT
} else if ( ds->dtype == DT_HINTRGN && newInfo.obj != OBJ_BOARD ) {
/* do nothing */
#endif
} else if ( ds->dtype == DT_BOARD ) {
if ( newInfo.obj == OBJ_BOARD ) {
XP_S16 diff = newInfo.u.board.row - ds->cur.u.board.row;
diff /= SCROLL_DRAG_THRESHHOLD;
moving = adjustYOffset( board, diff );
}
} else {
if ( newInfo.obj == OBJ_BOARD ) {
moving = (newInfo.u.board.col != ds->cur.u.board.col)
|| (newInfo.u.board.row != ds->cur.u.board.row)
|| (OBJ_TRAY == ds->cur.obj);
} else if ( newInfo.obj == OBJ_TRAY ) {
XP_Bool onDivider;
XP_S16 index = pointToTileIndex( board, xx, yy, &onDivider );
if ( !onDivider ) {
if ( index < 0 ) { /* negative means onto empty part of
tray. Force left. */
index = model_getNumTilesInTray( board->model,
board->selPlayer );
if ( OBJ_TRAY == ds->start.obj ) {
--index; /* dragging right into space */
}
}
moving = (OBJ_BOARD == ds->cur.obj)
|| (index != ds->cur.u.tray.index);
if ( moving ) {
newInfo.u.tray.index = index;
}
}
}
if ( moving ) {
if ( ds->dtype == DT_TILE ) {
invalDragObjRange( board, &ds->cur, &newInfo );
#ifdef XWFEATURE_SEARCHLIMIT
} else if ( ds->dtype == DT_HINTRGN ) {
invalHintRectDiffs( board, &ds->cur, &newInfo );
if ( !ds->didMove ) { /* first time through */
invalCurHintRect( board, board->selPlayer );
}
#endif
}
XP_MEMCPY( &ds->cur, &newInfo, sizeof(ds->cur) );
startScrollTimerIf( board );
}
}
if ( moving ) {
if ( !ds->didMove ) {
/* This is the first time we've moved!!! Kill any future timers,
and if there's a window up kill it.*/
board->penTimerFired = XP_FALSE;
if ( valHintMiniWindowActive( board ) ) {
hideMiniWindow( board, XP_TRUE, MINIWINDOW_VALHINT );
}
}
ds->didMove = XP_TRUE;
}
return moving;
} /* dragDropContinueImpl */
static void
invalDragObjRange( BoardCtxt* board, const DragObjInfo* from,
const DragObjInfo* to )
{
invalDragObj( board, from );
if ( NULL != to ) {
invalDragObj( board, to );
if ( (OBJ_TRAY == from->obj) && (OBJ_TRAY == to->obj) ) {
invalTrayTilesBetween( board, from->u.tray.index,
to->u.tray.index );
} else if ( OBJ_TRAY == from->obj ) {
invalTrayTilesAbove( board, from->u.tray.index );
} else if ( OBJ_TRAY == to->obj ) {
invalTrayTilesAbove( board, to->u.tray.index );
}
}
}
#ifdef XWFEATURE_SEARCHLIMIT
static void
setLimitsFrom( const BoardCtxt* board, BdHintLimits* limits )
{
const DragState* ds = &board->dragState;
limits->left = XP_MIN( ds->start.u.board.col, ds->cur.u.board.col );
limits->right = XP_MAX( ds->start.u.board.col, ds->cur.u.board.col );
limits->top = XP_MIN( ds->start.u.board.row, ds->cur.u.board.row );
limits->bottom = XP_MAX( ds->start.u.board.row, ds->cur.u.board.row );
}
#endif
static XP_Bool
scrollTimerProc( void* closure, XWTimerReason XP_UNUSED_DBG(why) )
{
XP_Bool draw = XP_FALSE;
BoardCtxt* board = (BoardCtxt*)closure;
DragState* ds = &board->dragState;
XP_ASSERT( why == TIMER_PENDOWN );
if ( ds->scrollTimerSet ) {
XP_S16 change;
ds->scrollTimerSet = XP_FALSE;
if ( onBorderCanScroll( board, ds->cur.u.board.row, &change ) ) {
invalDragObj( board, &ds->cur );
ds->cur.u.board.row += (change >0 ? 1 : -1);
if ( checkScrollCell( board, ds->cur.u.board.col,
ds->cur.u.board.row ) ) {
board_draw( board ); /* may fail, e.g. on wince */
startScrollTimerIf( board );
draw = XP_TRUE;
}
}
}
return draw;
} /* scrollTimerProc */
static void
startScrollTimerIf( BoardCtxt* board )
{
DragState* ds = &board->dragState;
if ( (ds->dtype == DT_TILE) && (ds->cur.obj == OBJ_BOARD) ) {
XP_S16 ignore;
if ( onBorderCanScroll( board, ds->cur.u.board.row, &ignore ) ) {
util_setTimer( board->util, TIMER_PENDOWN, 0,
scrollTimerProc, (void*) board );
ds->scrollTimerSet = XP_TRUE;
} else {
/* ignore if we've moved off */
ds->scrollTimerSet = XP_FALSE;
}
}
} /* startScrollTimerIf */
#ifdef CPLUS
}
#endif

61
xwords4/common/dragdrpp.h Normal file
View file

@ -0,0 +1,61 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
/*
* Copyright 1997 - 2008 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 _DRAGDRPP_H_
#define _DRAGDRPP_H_
#include "boardp.h"
#ifdef CPLUS
extern "C" {
#endif
XP_Bool dragDropInProgress( const BoardCtxt* board );
XP_Bool dragDropHasMoved( const BoardCtxt* board );
XP_Bool dragDropStart( BoardCtxt* board, BoardObjectType obj,
XP_U16 xx, XP_U16 yy );
XP_Bool dragDropContinue( BoardCtxt* board, XP_U16 xx, XP_U16 yy );
XP_Bool dragDropEnd( BoardCtxt* board, XP_U16 xx, XP_U16 yy, XP_Bool* dragged );
XP_Bool dragDropGetBoardTile( const BoardCtxt* board, XP_U16* col, XP_U16* row );
XP_Bool dragDropIsBeingDragged( const BoardCtxt* board, XP_U16 col, XP_U16 row,
XP_Bool* isOrigin );
/* return locations (0-based indices from left) in tray where a drag has added
* and removed a tile. Index larger than MAX_TRAY_TILES means invalid: don't
* use.
*/
void dragDropGetTrayChanges( const BoardCtxt* board, XP_U16* rmvdIndx,
XP_U16* addedIndx );
XP_Bool dragDropIsDividerDrag( const BoardCtxt* board );
#ifdef XWFEATURE_SEARCHLIMIT
XP_Bool dragDropGetHintLimits( const BoardCtxt* board, BdHintLimits* limits );
#endif
void dragDropTileInfo( const BoardCtxt* board, Tile* tile, XP_Bool* isBlank );
#ifdef CPLUS
}
#endif
#endif /* __DRAGDRPP_H_ */

366
xwords4/common/draw.c Normal file
View file

@ -0,0 +1,366 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
/*
* Copyright 1997 - 2003 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.
*/
#ifdef DRAW_WITH_PRIMITIVES
#include "draw.h"
#include "xptypes.h"
static void
insetRect( XP_Rect* r, XP_S16 amt )
{
r->top += amt;
r->left += amt;
amt *= 2;
r->width -= amt;
r->height -= amt;
} /* insetRect */
static void
getRemText( XP_UCHAR* buf, XP_U16 bufSize, XP_S16 nTilesLeft )
{
if ( nTilesLeft > 0 ) {
XP_SNPRINTF( buf, bufSize, "rem: %d", nTilesLeft );
} else {
buf[0] = '\0';
}
} /* getRemText */
static void
default_draw_measureRemText( DrawCtx* dctx, const XP_Rect* XP_UNUSED(r),
XP_S16 nTilesLeft,
XP_U16* widthP, XP_U16* heightP )
{
XP_U16 width, height;
if ( nTilesLeft > 0 ) {
XP_UCHAR buf[20];
getRemText( buf, sizeof(buf), nTilesLeft );
draw_measureText( dctx, buf, &width, &height );
} else {
width = height = 0;
}
*widthP = width;
*heightP = height;
} /* default_draw_measureRemText */
static void
default_draw_drawRemText( DrawCtx* dctx, const XP_Rect* XP_UNUSED(rInner),
const XP_Rect* rOuter, XP_S16 nTilesLeft )
{
XP_Rect oldClip;
XP_UCHAR buf[10];
getRemText( buf, sizeof(buf), nTilesLeft );
draw_setClip( dctx, rOuter, &oldClip );
draw_drawString( dctx, buf, rOuter->left, rOuter->top );
draw_setClip( dctx, &oldClip, NULL );
} /* default_draw_drawRemText */
static void
formatScore( XP_UCHAR* buf, XP_U16 bufSize, const DrawScoreInfo* dsi )
{
XP_UCHAR remBuf[10];
XP_UCHAR* selStr;
if ( dsi->selected ) {
selStr = "*";
} else {
selStr = "";
}
if ( dsi->nTilesLeft >= 0 ) {
XP_SNPRINTF( remBuf, sizeof(remBuf), ":%d", dsi->nTilesLeft );
} else {
remBuf[0] = '\0';
}
XP_SNPRINTF( buf, bufSize, "%s%d%s%s", selStr, dsi->totalScore,
remBuf, selStr );
} /* formatScore */
static void
default_draw_measureScoreText( DrawCtx* dctx, const XP_Rect* XP_UNUSED(r),
const DrawScoreInfo* dsi,
XP_U16* widthP, XP_U16* heightP )
{
XP_UCHAR buf[20];
formatScore( buf, sizeof(buf), dsi );
draw_measureText( dctx, buf, widthP, heightP );
} /* default_draw_measureScoreText */
static void
default_draw_score_drawPlayer( DrawCtx* dctx,
const XP_Rect* rInner, const XP_Rect* rOuter,
const DrawScoreInfo* dsi )
{
XP_Rect oldClip;
XP_UCHAR buf[20];
draw_setClip( dctx, rInner, &oldClip );
draw_clearRect( dctx, rOuter );
formatScore( buf, sizeof(buf), dsi );
draw_drawString( dctx, buf, rInner->left, rInner->top );
draw_setClip( dctx, &oldClip, NULL );
} /* default_draw_score_drawPlayer */
static XP_Bool
default_draw_drawCell( DrawCtx* dctx, const XP_Rect* rect,
const XP_UCHAR* text,
const XP_Bitmap bitmap,
Tile XP_UNUSED(tile), XP_S16 XP_UNUSED(owner),
XWBonusType bonus, HintAtts XP_UNUSED(hintAtts),
CellFlags flags )
{
XP_Rect oldClip;
XP_Rect inset = *rect;
insetRect( &inset, 1 );
draw_setClip( dctx, rect, &oldClip );
draw_clearRect( dctx, rect );
if ( !!text && text[0] != 0 ) {
draw_drawString( dctx, text, inset.left, inset.top );
} else if ( !!bitmap ) {
draw_drawBitmap( dctx, bitmap, inset.left, inset.top );
} else if ( bonus != BONUS_NONE ) {
XP_UCHAR* bstr;
switch( bonus ) {
case BONUS_DOUBLE_LETTER:
bstr = "*";
break;
case BONUS_DOUBLE_WORD:
bstr = "%";
break;
case BONUS_TRIPLE_LETTER:
bstr = "#";
break;
case BONUS_TRIPLE_WORD:
bstr = "@";
break;
default:
XP_ASSERT(0);
break;
}
draw_drawString( dctx, bstr, inset.left, inset.top );
}
if ( 0 != (flags & CELL_HIGHLIGHT) ) {
draw_invertRect( dctx, &inset );
}
draw_frameRect( dctx, rect );
draw_setClip( dctx, &oldClip, NULL );
return XP_TRUE;
} /* default_draw_drawCell */
static void
default_draw_drawBoardArrow( DrawCtx* dctx, const XP_Rect* rect,
XWBonusType XP_UNUSED(bonus), XP_Bool vert,
HintAtts XP_UNUSED(hintAtts),
CellFlags XP_UNUSED(flags) )
{
XP_Rect oldClip;
XP_UCHAR* arrow;
if ( vert ) {
arrow = "|";
} else {
arrow = "-";
}
draw_setClip( dctx, rect, &oldClip );
draw_clearRect( dctx, rect );
draw_frameRect( dctx, rect );
draw_drawString( dctx, arrow, rect->left+1, rect->top+1 );
draw_setClip( dctx, &oldClip, NULL );
} /* default_draw_drawBoardArrow */
static void
default_draw_drawTile( DrawCtx* dctx, const XP_Rect* rect,
const XP_UCHAR* text,
const XP_Bitmap bitmap,
XP_S16 val, CellFlags flags )
{
XP_Rect oldClip;
XP_Rect inset = *rect;
draw_setClip( dctx, rect, &oldClip );
draw_clearRect( dctx, rect );
draw_frameRect( dctx, rect );
if ( 0 != (flags & CELL_HIGHLIGHT) ) {
insetRect( &inset, 1 );
draw_frameRect( dctx, &inset );
insetRect( &inset, 1 );
} else {
insetRect( &inset, 2 );
}
if ( !!text && text[0] != '\0' ) {
draw_drawString( dctx, text, inset.left, inset.top );
} else if ( !!bitmap ) {
draw_drawBitmap( dctx, bitmap, inset.left, inset.top );
}
if ( val >= 0 ) {
XP_UCHAR sbuf[4];
XP_U16 width, height;
XP_U16 x, y;
XP_SNPRINTF( sbuf, sizeof(sbuf), "%d", val );
draw_measureText( dctx, sbuf, &width, &height );
x = inset.left + inset.width - width;
y = inset.top + inset.height - height;
draw_drawString( dctx, sbuf, x, y );
}
draw_setClip( dctx, &oldClip, NULL );
} /* default_draw_drawTile */
static void
default_draw_drawTileBack( DrawCtx* dctx, const XP_Rect* rect,
CellFlags XP_UNUSED(flags) )
{
default_draw_drawTile( dctx, rect, "?", NULL, -1, XP_FALSE );
} /* default_draw_drawTileBack */
static void
default_draw_drawTrayDivider( DrawCtx* dctx, const XP_Rect* rect,
CellFlags XP_UNUSED(flags))
{
XP_Rect r = *rect;
draw_clearRect( dctx, rect );
if ( r.width > 2 ) {
r.width -= 2;
r.left += 1;
}
draw_frameRect( dctx, &r );
} /* default_draw_drawTrayDivider */
static void
default_draw_score_pendingScore( DrawCtx* dctx,
const XP_Rect* rect,
XP_S16 score,
XP_U16 XP_UNUSED(playerNum),
CellFlags XP_UNUSED(flags) )
{
XP_UCHAR buf[5];
XP_Rect oldClip;
XP_Rect r;
XP_U16 width, height;
XP_UCHAR* stxt;
draw_setClip( dctx, rect, &oldClip );
XP_MEMCPY( &r, rect, sizeof(r) );
++r.left; /* don't erase neighbor's border */
--r.width;
draw_clearRect( dctx, &r );
draw_drawString( dctx, "pts", r.left, r.top );
if ( score >= 0 ) {
XP_SNPRINTF( buf, sizeof(buf), "%d", score );
stxt = buf;
} else {
stxt = "???";
}
draw_measureText( dctx, stxt, &width, &height );
draw_drawString( dctx, stxt, r.left, r.top + r.height - height );
draw_setClip( dctx, &oldClip, NULL );
} /* default_draw_score_pendingScore */
static const XP_UCHAR*
default_draw_getMiniWText( DrawCtx* XP_UNUSED(dctx), XWMiniTextType textHint )
{
char* str;
switch( textHint ) {
case BONUS_DOUBLE_LETTER:
str = "Double letter"; break;
case BONUS_DOUBLE_WORD:
str = "Double word"; break;
case BONUS_TRIPLE_LETTER:
str = "Triple letter"; break;
case BONUS_TRIPLE_WORD:
str = "Triple word"; break;
case INTRADE_MW_TEXT:
str = "Trading tiles;\nclick D when done"; break;
default:
XP_ASSERT( XP_FALSE );
}
return str;
} /* default_draw_getMiniWText */
static void
default_draw_measureMiniWText( DrawCtx* dctx, const XP_UCHAR* textP,
XP_U16* widthP, XP_U16* heightP )
{
draw_measureText( dctx, textP, widthP, heightP );
/* increase for frame */
*widthP += 2;
*heightP += 2;
} /* default_draw_measureMiniWText */
static void
default_draw_drawMiniWindow( DrawCtx* dctx, const XP_UCHAR* text,
const XP_Rect* rect, void** XP_UNUSED(closure) )
{
XP_Rect oldClip;
draw_setClip( dctx, rect, &oldClip );
draw_clearRect( dctx, rect );
draw_frameRect( dctx, rect );
draw_drawString( dctx, text, rect->left+1, rect->top+1 );
draw_setClip( dctx, &oldClip, NULL );
} /* default_draw_drawMiniWindow */
void
InitDrawDefaults( DrawCtxVTable* vtable )
{
SET_VTABLE_ENTRY( vtable, draw_measureRemText, default );
SET_VTABLE_ENTRY( vtable, draw_drawRemText, default );
SET_VTABLE_ENTRY( vtable, draw_measureScoreText, default );
SET_VTABLE_ENTRY( vtable, draw_score_drawPlayer, default );
SET_VTABLE_ENTRY( vtable, draw_drawCell, default );
SET_VTABLE_ENTRY( vtable, draw_drawBoardArrow, default );
SET_VTABLE_ENTRY( vtable, draw_drawTile, default );
SET_VTABLE_ENTRY( vtable, draw_drawTileBack, default );
SET_VTABLE_ENTRY( vtable, draw_drawTrayDivider, default );
SET_VTABLE_ENTRY( vtable, draw_score_pendingScore, default );
SET_VTABLE_ENTRY( vtable, draw_getMiniWText, default );
SET_VTABLE_ENTRY( vtable, draw_measureMiniWText, default );
SET_VTABLE_ENTRY( vtable, draw_drawMiniWindow, default );
} /* InitDrawDefaults */
#endif

309
xwords4/common/draw.h Normal file
View file

@ -0,0 +1,309 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
/*
* Copyright 1997 - 2007 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 _DRAW_H_
#define _DRAW_H_
#include "comtypes.h"
#include "xptypes.h"
#include "model.h"
/* typedef struct DrawCtx DrawCtx; */
typedef XP_Bool (*LastScoreCallback)( void* closure, XP_S16 player,
XP_UCHAR* expl, XP_U16* explLen );
typedef enum {
CELL_NONE = 0x00
, CELL_ISBLANK = 0x01
, CELL_HIGHLIGHT = 0x02
, CELL_ISSTAR = 0x04
, CELL_ISCURSOR = 0x08
, CELL_ISEMPTY = 0x10 /* of a tray tile slot */
, CELL_VALHIDDEN = 0x20 /* show letter only, not value */
, CELL_DRAGSRC = 0x40 /* where drag originated */
, CELL_DRAGCUR = 0x80 /* where drag is now */
, CELL_ALL = 0xFF
} CellFlags;
typedef struct DrawScoreInfo {
LastScoreCallback lsc;
void* lscClosure;
XP_UCHAR* name;
XP_U16 playerNum;
XP_S16 totalScore;
XP_S16 nTilesLeft; /* < 0 means don't use */
CellFlags flags;
XP_Bool isTurn;
XP_Bool selected;
XP_Bool isRemote;
XP_Bool isRobot;
} DrawScoreInfo;
enum HINT_ATTS { HINT_BORDER_NONE = 0,
HINT_BORDER_LEFT = 1,
HINT_BORDER_RIGHT = 2,
HINT_BORDER_TOP = 4,
HINT_BORDER_BOTTOM = 8,
HINT_BORDER_CENTER = 0x10
};
typedef XP_UCHAR HintAtts;
#define HINT_BORDER_EDGE \
(HINT_BORDER_LEFT|HINT_BORDER_RIGHT|HINT_BORDER_TOP|HINT_BORDER_BOTTOM)
/* Platform-supplied draw functions are either staticly linked, or called via
* a vtable. If you want static linking, define DRAW_LINK_DIRECT via a -D
* option to your compiler, and use the DRAW_FUNC_NAME macro to make your
* names match what's declared here. Otherwise, if DRAW_LINK_DIRECT is not
* defined, you need to create and populate a vtable. See any of the existing
* platforms' draw implementations for examples.
*
* As to how to choose, static linking makes the binary a tiny bit smaller,
* but vtables give more flexibilty. For example, Palm uses them to support
* both black-and-white and color screens, while linux on linux separate
* vtable are created to allow a runtime choice between gtk and ncurses
* drawing.
*/
#ifdef DRAW_LINK_DIRECT
# define DRAW_FUNC_NAME(name) linked##_draw_##name
# define DRAW_VTABLE_NAME DRAW_FUNC_NAME
#else
# define DRAW_VTABLE_NAME(name) (*m_draw_ ## name)
#endif
#ifdef DRAW_LINK_DIRECT
typedef void DrawCtxVTable;
#else
typedef struct DrawCtxVTable {
#endif
#ifdef DRAW_WITH_PRIMITIVES
void DRAW_VTABLE_NAME(setClip)( DrawCtx* dctx, const XP_Rect* newClip,
const XP_Rect* oldClip );
void DRAW_VTABLE_NAME(frameRect)( DrawCtx* dctx, const XP_Rect* rect );
void DRAW_VTABLE_NAME(invertRect)( DrawCtx* dctx, const XP_Rect* rect );
void DRAW_VTABLE_NAME(drawString)( DrawCtx* dctx, const XP_UCHAR* str,
XP_U16 x, XP_U16 y );
void DRAW_VTABLE_NAME(drawBitmap)( DrawCtx* dctx, const XP_Bitmap bm,
XP_U16 x, XP_U16 y );
void DRAW_VTABLE_NAME(measureText)( DrawCtx* dctx, const XP_UCHAR* buf,
XP_U16* widthP, XP_U16* heightP );
#endif
void DRAW_VTABLE_NAME(destroyCtxt) ( DrawCtx* dctx );
void DRAW_VTABLE_NAME(dictChanged)( DrawCtx* dctx,
const DictionaryCtxt* dict );
XP_Bool DRAW_VTABLE_NAME(boardBegin) ( DrawCtx* dctx,
const XP_Rect* rect,
DrawFocusState dfs );
void DRAW_VTABLE_NAME(objFinished)( DrawCtx* dctx, BoardObjectType typ,
const XP_Rect* rect,
DrawFocusState dfs );
/* rect is not const: set by callee */
XP_Bool DRAW_VTABLE_NAME(vertScrollBoard) (DrawCtx* dctx, XP_Rect* rect,
XP_S16 dist, DrawFocusState dfs );
XP_Bool DRAW_VTABLE_NAME(trayBegin) ( DrawCtx* dctx, const XP_Rect* rect,
XP_U16 owner,
DrawFocusState dfs );
void DRAW_VTABLE_NAME(measureRemText) ( DrawCtx* dctx, const XP_Rect* r,
XP_S16 nTilesLeft,
XP_U16* width, XP_U16* height );
void DRAW_VTABLE_NAME(drawRemText) (DrawCtx* dctx, const XP_Rect* rInner,
const XP_Rect* rOuter,
XP_S16 nTilesLeft, XP_Bool focussed );
void DRAW_VTABLE_NAME(scoreBegin) ( DrawCtx* dctx, const XP_Rect* rect,
XP_U16 numPlayers, DrawFocusState dfs );
void DRAW_VTABLE_NAME(measureScoreText) ( DrawCtx* dctx,
const XP_Rect* r,
const DrawScoreInfo* dsi,
XP_U16* width, XP_U16* height );
void DRAW_VTABLE_NAME(score_drawPlayer) ( DrawCtx* dctx,
const XP_Rect* rInner,
const XP_Rect* rOuter,
const DrawScoreInfo* dsi );
void DRAW_VTABLE_NAME(score_pendingScore) ( DrawCtx* dctx,
const XP_Rect* rect,
XP_S16 score,
XP_U16 playerNum,
CellFlags flags );
void DRAW_VTABLE_NAME(drawTimer) ( DrawCtx* dctx, const XP_Rect* rInner,
const XP_Rect* rOuter,
XP_U16 player, XP_S16 secondsLeft );
XP_Bool DRAW_VTABLE_NAME(drawCell) ( DrawCtx* dctx, const XP_Rect* rect,
/* at least one of these two will be
null */
const XP_UCHAR* text,
const XP_Bitmap bitmap,
Tile tile,
XP_S16 owner, /* -1 means don't use */
XWBonusType bonus, HintAtts hintAtts,
CellFlags flags );
void DRAW_VTABLE_NAME(invertCell) ( DrawCtx* dctx, const XP_Rect* rect );
void DRAW_VTABLE_NAME(drawTile) ( DrawCtx* dctx, const XP_Rect* rect,
/* at least 1 of these two will be null*/
const XP_UCHAR* text,
const XP_Bitmap bitmap,
XP_S16 val, CellFlags flags );
#ifdef POINTER_SUPPORT
void DRAW_VTABLE_NAME(drawTileMidDrag) ( DrawCtx* dctx, const XP_Rect* rect,
/* at least 1 of these two will be null*/
const XP_UCHAR* text,
const XP_Bitmap bitmap,
XP_S16 val, XP_U16 owner,
CellFlags flags );
#endif
void DRAW_VTABLE_NAME(drawTileBack) ( DrawCtx* dctx, const XP_Rect* rect,
CellFlags flags );
void DRAW_VTABLE_NAME(drawTrayDivider) ( DrawCtx* dctx, const XP_Rect* rect,
CellFlags flags );
void DRAW_VTABLE_NAME(clearRect) ( DrawCtx* dctx, const XP_Rect* rect );
void DRAW_VTABLE_NAME(drawBoardArrow) ( DrawCtx* dctx,
const XP_Rect* rect,
XWBonusType bonus, XP_Bool vert,
HintAtts hintAtts,
CellFlags flags);
const XP_UCHAR* DRAW_VTABLE_NAME(getMiniWText) ( DrawCtx* dctx,
XWMiniTextType textHint );
void DRAW_VTABLE_NAME(measureMiniWText) ( DrawCtx* dctx, const XP_UCHAR* textP,
XP_U16* width, XP_U16* height );
void DRAW_VTABLE_NAME(drawMiniWindow)( DrawCtx* dctx, const XP_UCHAR* text,
const XP_Rect* rect, void** closure );
#ifndef DRAW_LINK_DIRECT
} DrawCtxVTable; /* */
#endif
struct DrawCtx {
DrawCtxVTable* vtable;
};
/* Franklin's compiler is too old to support __VA_ARGS__... */
#ifdef DRAW_LINK_DIRECT
# define CALL_DRAW_NAME0(name,dc) linked##_draw_##name(dc)
# define CALL_DRAW_NAME1(name,dc,p1) linked##_draw_##name(dc,(p1))
# define CALL_DRAW_NAME2(name,dc,p1,p2) \
linked##_draw_##name(dc,(p1),(p2))
# define CALL_DRAW_NAME3(name,dc,p1,p2,p3) \
linked##_draw_##name(dc,(p1),(p2),(p3))
# define CALL_DRAW_NAME4(name,dc,p1,p2,p3,p4) \
linked##_draw_##name(dc,(p1),(p2),(p3),(p4))
# define CALL_DRAW_NAME5(name,dc,p1,p2,p3,p4,p5) \
linked##_draw_##name(dc,(p1),(p2),(p3),(p4),(p5))
# define CALL_DRAW_NAME6(name,dc,p1,p2,p3,p4,p5,p6) \
linked##_draw_##name(dc,(p1),(p2),(p3),(p4),(p5),(p6))
# define CALL_DRAW_NAME8(name,dc,p1,p2,p3,p4,p5,p6,p7,p8) \
linked##_draw_##name(dc,(p1),(p2),(p3),(p4),(p5),(p6),(p7),(p8))
# define CALL_DRAW_NAME10(name,dc,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10) \
linked##_draw_##name(dc,(p1),(p2),(p3),(p4),(p5),(p6),(p7),\
(p8),(p9),(p10))
#else
# define CALL_DRAW_NAME0(name,dc) ((dc)->vtable->m_draw_##name)(dc)
# define CALL_DRAW_NAME1(name,dc,p1) ((dc)->vtable->m_draw_##name)(dc,(p1))
# define CALL_DRAW_NAME2(name,dc,p1,p2) \
((dc)->vtable->m_draw_##name)(dc,(p1),(p2))
# define CALL_DRAW_NAME3(name,dc,p1,p2,p3) \
((dc)->vtable->m_draw_##name)(dc,(p1),(p2),(p3))
# define CALL_DRAW_NAME4(name,dc,p1,p2,p3,p4) \
((dc)->vtable->m_draw_##name)(dc,(p1),(p2),(p3),(p4))
# define CALL_DRAW_NAME5(name,dc,p1,p2,p3,p4,p5) \
((dc)->vtable->m_draw_##name)(dc,(p1),(p2),(p3),(p4),(p5))
# define CALL_DRAW_NAME6(name,dc,p1,p2,p3,p4,p5,p6) \
((dc)->vtable->m_draw_##name)(dc,(p1),(p2),(p3),(p4),(p5),(p6))
# define CALL_DRAW_NAME8(name,dc,p1,p2,p3,p4,p5,p6,p7,p8) \
((dc)->vtable->m_draw_##name)(dc,(p1),(p2),(p3),(p4),(p5),(p6),(p7),\
(p8))
# define CALL_DRAW_NAME10(name,dc,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10) \
((dc)->vtable->m_draw_##name)(dc,(p1),(p2),(p3),(p4),(p5),(p6),(p7),\
(p8),(p9),(p10))
#endif
#define draw_destroyCtxt(dc) CALL_DRAW_NAME0(destroyCtxt, dc)
#define draw_dictChanged( dc, d ) CALL_DRAW_NAME1(dictChanged, (dc), (d))
#define draw_boardBegin( dc,r,f ) CALL_DRAW_NAME2(boardBegin, dc, r,f)
#define draw_objFinished( dc, t, r, d ) CALL_DRAW_NAME3(objFinished, (dc), (t), (r), (d))
#define draw_trayBegin( dc, r, o, f ) CALL_DRAW_NAME3(trayBegin,dc, r, o, f)
#define draw_vertScrollBoard( dc, r, d, f ) \
CALL_DRAW_NAME3(vertScrollBoard, (dc),(r),(d),(f))
#define draw_scoreBegin( dc, r, t, f ) \
CALL_DRAW_NAME3( scoreBegin,(dc), (r), (t), (f))
#define draw_measureRemText( dc, r, n, wp, hp ) \
CALL_DRAW_NAME4(measureRemText, (dc), (r), (n), (wp), (hp) )
#define draw_drawRemText( dc, ri, ro, n, f ) \
CALL_DRAW_NAME4(drawRemText, (dc), (ri), (ro), (n), (f) )
#define draw_measureScoreText(dc,r,dsi,wp,hp) \
CALL_DRAW_NAME4(measureScoreText,(dc),(r),(dsi),(wp),(hp))
#define draw_score_drawPlayer(dc, ri, ro, dsi) \
CALL_DRAW_NAME3(score_drawPlayer,(dc),(ri),(ro),(dsi))
#define draw_score_pendingScore(dc, r, s, p, f ) \
CALL_DRAW_NAME4(score_pendingScore,(dc), (r), (s), (p), (f))
#define draw_drawTimer( dc, ri, ro, plyr, sec ) \
CALL_DRAW_NAME4(drawTimer,(dc),(ri),(ro),(plyr),(sec))
#define draw_drawCell( dc, rect, txt, bmap, t, o, bon, hi, f ) \
CALL_DRAW_NAME8(drawCell,(dc),(rect),(txt),(bmap),(t),(o),(bon),(hi),\
(f))
#define draw_invertCell( dc, rect ) CALL_DRAW_NAME1(invertCell,(dc),(rect))
#define draw_drawTile( dc, rect, text, bmp, val, hil ) \
CALL_DRAW_NAME5(drawTile,(dc),(rect),(text),(bmp),(val),(hil))
#ifdef POINTER_SUPPORT
#define draw_drawTileMidDrag( dc, rect, text, bmp, val, ownr, hil ) \
CALL_DRAW_NAME6(drawTileMidDrag,(dc),(rect),(text),(bmp),(val),(ownr),(hil))
#endif /* POINTER_SUPPORT */
#define draw_drawTileBack( dc, rect, f ) \
CALL_DRAW_NAME2(drawTileBack, (dc), (rect), (f) )
#define draw_drawTrayDivider( dc, rect, s ) \
CALL_DRAW_NAME2(drawTrayDivider,(dc),(rect), (s))
#define draw_clearRect( dc, rect ) CALL_DRAW_NAME1(clearRect,(dc),(rect))
#define draw_drawBoardArrow( dc, r, b, v, h, f ) \
CALL_DRAW_NAME5(drawBoardArrow,(dc),(r),(b), (v), (h), (f))
#define draw_getMiniWText( dc, b ) CALL_DRAW_NAME1(getMiniWText, (dc),(b) )
#define draw_measureMiniWText( dc, t, wp, hp) \
CALL_DRAW_NAME3(measureMiniWText, (dc),(t), (wp), (hp) )
#define draw_drawMiniWindow( dc, t, r, c ) \
CALL_DRAW_NAME3(drawMiniWindow, (dc), (t), (r), (c) )
#ifdef DRAW_WITH_PRIMITIVES
# define draw_setClip( dc, rn, ro ) CALL_DRAW_NAME2(setClip, (dc), (rn), (ro))
# define draw_frameRect( dc, r ) CALL_DRAW_NAME1(frameRect, (dc), (r) )
# define draw_invertRect( dc, r ) CALL_DRAW_NAME1(invertCell, (dc), (r) )
# define draw_drawString( dc, s, x, y) \
CALL_DRAW_NAME3(drawString, (dc), (s), (x), (y) )
# define draw_drawBitmap( dc, bm, x, y ) \
CALL_DRAW_NAME3(drawBitmap, (dc), (bm), (x), (y) )
# define draw_measureText( dc, t, wp, hp ) \
CALL_DRAW_NAME3(measureText, (dc), (t), (wp), (hp) )
void InitDrawDefaults( DrawCtxVTable* vtable );
#endif /* DRAW_WITH_PRIMITIVES */
#endif

1245
xwords4/common/engine.c Normal file

File diff suppressed because it is too large Load diff

67
xwords4/common/engine.h Normal file
View file

@ -0,0 +1,67 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
/*
* Copyright 1997 - 2002 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 _ENGINE_H_
#define _ENGINE_H_
#include "comtypes.h"
#include "dictnry.h"
#ifdef CPLUS
extern "C" {
#endif
#ifdef XWFEATURE_SEARCHLIMIT
typedef struct BdHintLimits {
XP_U16 left;
XP_U16 top;
XP_U16 right;
XP_U16 bottom;
} BdHintLimits;
#endif
XP_U16 engine_getScoreCache( EngineCtxt* engine, XP_U16 row );
EngineCtxt* engine_make( MPFORMAL XW_UtilCtxt* util, XP_Bool isRobot );
void engine_writeToStream( EngineCtxt* ctxt, XWStreamCtxt* stream );
EngineCtxt* engine_makeFromStream( MPFORMAL XWStreamCtxt* stream,
XW_UtilCtxt* util, XP_Bool isRobot );
void engine_init( EngineCtxt* ctxt );
void engine_reset( EngineCtxt* ctxt );
void engine_destroy( EngineCtxt* ctxt );
#define NO_SCORE_LIMIT 10000 /* for targetScore */
XP_Bool engine_findMove( EngineCtxt* ctxt, const ModelCtxt* model,
const DictionaryCtxt* dict, const Tile* tiles,
XP_U16 nTiles,
#ifdef XWFEATURE_SEARCHLIMIT
const BdHintLimits* boardLimits,
XP_Bool useTileLimits,
#endif
XP_U16 targetScore, XP_Bool* canMove,
MoveInfo* result );
XP_Bool engine_check( DictionaryCtxt* dict, Tile* buf, XP_U16 buflen );
#ifdef CPLUS
}
#endif
#endif /* _ENGINE_H_ */

511
xwords4/common/game.c Normal file
View file

@ -0,0 +1,511 @@
/* -*-mode: C; fill-column: 76; c-basic-offset: 4; -*- */
/*
* Copyright 2001 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.
*/
#include "game.h"
#include "dictnry.h"
#include "strutils.h"
#ifdef CPLUS
extern "C" {
#endif
#ifdef DEBUG
static void
assertUtilOK( XW_UtilCtxt* util )
{
UtilVtable* vtable = util->vtable;
XP_U16 nSlots = sizeof(vtable) / 4;
while ( nSlots-- ) {
void* fptr = ((void**)vtable)[nSlots];
XP_ASSERT( !!fptr );
}
} /* assertUtilOK */
#else
# define assertUtilOK(u)
#endif
static void
checkServerRole( CurGameInfo* gi, XP_U16* nPlayersHere, XP_U16* nPlayersTotal )
{
if ( !!gi ) {
XP_Bool standAlone = gi->serverRole == SERVER_STANDALONE;
XP_U16 i, remoteCount = 0;
for ( i = 0; i < gi->nPlayers; ++i ) {
LocalPlayer* player = &gi->players[i];
if ( !player->isLocal ) {
++remoteCount;
if ( standAlone ) {
player->isLocal = XP_TRUE;
}
}
}
if ( remoteCount == 0 && gi->serverRole != SERVER_ISCLIENT ) {
gi->serverRole = SERVER_STANDALONE;
}
*nPlayersHere = gi->nPlayers - remoteCount;
if ( gi->serverRole == SERVER_ISCLIENT ) {
*nPlayersTotal = 0;
} else {
*nPlayersTotal = gi->nPlayers;
}
}
} /* checkServerRole */
void
game_makeNewGame( MPFORMAL XWGame* game, CurGameInfo* gi,
XW_UtilCtxt* util, DrawCtx* draw,
XP_U16 gameID, CommonPrefs* cp,
TransportSend XP_UNUSED_STANDALONE(sendproc),
IF_CH( TransportReset resetproc )
void* XP_UNUSED_STANDALONE(closure) )
{
XP_U16 nPlayersHere, nPlayersTotal;
assertUtilOK( util );
checkServerRole( gi, &nPlayersHere, &nPlayersTotal );
gi->gameID = gameID;
game->model = model_make( MPPARM(mpool) (DictionaryCtxt*)NULL, util,
gi->boardSize, gi->boardSize );
#ifndef XWFEATURE_STANDALONE_ONLY
if ( !!sendproc && gi->serverRole != SERVER_STANDALONE ) {
game->comms = comms_make( MPPARM(mpool) util,
gi->serverRole != SERVER_ISCLIENT,
nPlayersHere, nPlayersTotal,
sendproc, IF_CH(resetproc) closure );
} else {
game->comms = (CommsCtxt*)NULL;
}
#endif
game->server = server_make( MPPARM(mpool) game->model,
#ifndef XWFEATURE_STANDALONE_ONLY
game->comms,
#else
(CommsCtxt*)NULL,
#endif
util );
game->board = board_make( MPPARM(mpool) game->model, game->server,
draw, util );
server_prefsChanged( game->server, cp );
board_prefsChanged( game->board, cp );
} /* game_makeNewGame */
void
game_reset( MPFORMAL XWGame* game, CurGameInfo* gi,
XW_UtilCtxt* XP_UNUSED_STANDALONE(util),
XP_U16 gameID, CommonPrefs* cp,
TransportSend XP_UNUSED_STANDALONE(sendproc),
IF_CH(TransportReset resetproc)
void* XP_UNUSED_STANDALONE(closure) )
{
XP_U16 i;
XP_U16 nPlayersHere, nPlayersTotal;
XP_ASSERT( !!game->model );
XP_ASSERT( !!gi );
checkServerRole( gi, &nPlayersHere, &nPlayersTotal );
gi->gameID = gameID;
#ifndef XWFEATURE_STANDALONE_ONLY
if ( !!game->comms ) {
if ( gi->serverRole == SERVER_STANDALONE ) {
comms_destroy( game->comms );
game->comms = NULL;
} else {
comms_reset( game->comms, gi->serverRole != SERVER_ISCLIENT,
nPlayersHere, nPlayersTotal );
}
} else if ( gi->serverRole != SERVER_STANDALONE ) {
game->comms = comms_make( MPPARM(mpool) util,
gi->serverRole != SERVER_ISCLIENT,
nPlayersHere, nPlayersTotal,
sendproc, IF_CH(resetproc) closure );
}
#else
# ifdef DEBUG
mpool = mpool; /* quash unused formal warning */
# endif
#endif
model_init( game->model, gi->boardSize, gi->boardSize );
server_reset( game->server,
#ifndef XWFEATURE_STANDALONE_ONLY
game->comms
#else
NULL
#endif
);
board_reset( game->board );
for ( i = 0; i < gi->nPlayers; ++i ) {
gi->players[i].secondsUsed = 0;
}
server_prefsChanged( game->server, cp );
board_prefsChanged( game->board, cp );
} /* game_reset */
XP_Bool
game_makeFromStream( MPFORMAL XWStreamCtxt* stream, XWGame* game,
CurGameInfo* gi, DictionaryCtxt* dict,
XW_UtilCtxt* util, DrawCtx* draw, CommonPrefs* cp,
TransportSend XP_UNUSED_STANDALONE(sendProc),
IF_CH(TransportReset resetProc)
void* XP_UNUSED_STANDALONE(closure) )
{
XP_Bool success = XP_FALSE;
XP_U8 strVersion;
#ifndef XWFEATURE_STANDALONE_ONLY
XP_Bool hasComms;
#endif
strVersion = stream_getU8( stream );
XP_DEBUGF( "strVersion = %d", (XP_U16)strVersion );
if ( strVersion <= CUR_STREAM_VERS ) {
stream_setVersion( stream, strVersion );
gi_readFromStream( MPPARM(mpool) stream, gi );
#ifndef XWFEATURE_STANDALONE_ONLY
hasComms = stream_getU8( stream );
if ( hasComms ) {
game->comms = comms_makeFromStream( MPPARM(mpool) stream, util,
sendProc, IF_CH(resetProc) closure );
} else {
game->comms = NULL;
}
#endif
XP_ASSERT( !!dict );
game->model = model_makeFromStream( MPPARM(mpool) stream, dict, util );
game->server = server_makeFromStream( MPPARM(mpool) stream,
game->model,
#ifndef XWFEATURE_STANDALONE_ONLY
game->comms,
#else
(CommsCtxt*)NULL,
#endif
util, gi->nPlayers );
game->board = board_makeFromStream( MPPARM(mpool) stream, game->model,
game->server, draw, util,
gi->nPlayers );
server_prefsChanged( game->server, cp );
board_prefsChanged( game->board, cp );
draw_dictChanged( draw, dict );
success = XP_TRUE;
} else {
XP_LOGF( "%s: aborting; stream version too new!", __func__ );
}
return success;
} /* game_makeFromStream */
void
game_saveToStream( const XWGame* game, const CurGameInfo* gi,
XWStreamCtxt* stream )
{
stream_putU8( stream, CUR_STREAM_VERS );
gi_writeToStream( stream, gi );
#ifndef XWFEATURE_STANDALONE_ONLY
stream_putU8( stream, (XP_U8)!!game->comms );
if ( !!game->comms ) {
comms_writeToStream( game->comms, stream );
}
#endif
model_writeToStream( game->model, stream );
server_writeToStream( game->server, stream );
board_writeToStream( game->board, stream );
} /* game_saveToStream */
void
game_dispose( XWGame* game )
{
/* The board should be reused!!! PENDING(ehouse) */
if ( !!game->board ) {
board_destroy( game->board );
game->board = NULL;
}
#ifndef XWFEATURE_STANDALONE_ONLY
if ( !!game->comms ) {
comms_destroy( game->comms );
game->comms = NULL;
}
#endif
if ( !!game->model ) {
DictionaryCtxt* dict = model_getDictionary( game->model );
if ( !!dict ) {
dict_destroy( dict );
}
model_destroy( game->model );
game->model = NULL;
}
if ( !!game->server ) {
server_destroy( game->server );
game->server = NULL;
}
} /* game_dispose */
void
gi_initPlayerInfo( MPFORMAL CurGameInfo* gi, const XP_UCHAR* nameTemplate )
{
XP_U16 i;
XP_MEMSET( gi, 0, sizeof(*gi) );
gi->serverRole = SERVER_STANDALONE;
gi->nPlayers = 2;
gi->boardSize = 15;
gi->robotSmartness = SMART_ROBOT;
gi->gameSeconds = 25 * 60; /* 25 minute game is common? */
gi->confirmBTConnect = XP_TRUE;
for ( i = 0; i < MAX_NUM_PLAYERS; ++i ) {
XP_UCHAR buf[20];
LocalPlayer* fp = &gi->players[i];
if ( !!nameTemplate ) {
XP_SNPRINTF( buf, sizeof(buf), nameTemplate, i+1 );
XP_ASSERT( fp->name == NULL );
fp->name = copyString( mpool, buf );
}
fp->isRobot = (i == 0); /* one robot */
fp->isLocal = XP_TRUE;
fp->secondsUsed = 0;
}
} /* game_initPlayerInfo */
static void
disposePlayerInfoInt( MPFORMAL CurGameInfo* gi )
{
XP_U16 i;
LocalPlayer* lp;
for ( lp = gi->players, i = 0; i < MAX_NUM_PLAYERS; ++lp, ++i ) {
if ( !!lp->name ) {
XP_FREE( mpool, lp->name );
lp->name = (XP_UCHAR*)NULL;
}
if ( !!lp->password ) {
XP_FREE( mpool, lp->password );
lp->password = (XP_UCHAR*)NULL;
}
}
} /* disposePlayerInfoInt */
void
gi_disposePlayerInfo( MPFORMAL CurGameInfo* gi )
{
disposePlayerInfoInt( MPPARM(mpool) gi );
if ( !!gi->dictName ) {
XP_FREE( mpool, gi->dictName );
gi->dictName = (XP_UCHAR*)NULL;
}
} /* gi_disposePlayerInfo */
void
gi_copy( MPFORMAL CurGameInfo* destGI, const CurGameInfo* srcGI )
{
XP_U16 nPlayers, i;
const LocalPlayer* srcPl;
LocalPlayer* destPl;
replaceStringIfDifferent( mpool, &destGI->dictName,
srcGI->dictName );
destGI->gameID = srcGI->gameID;
destGI->gameSeconds = srcGI->gameSeconds;
destGI->nPlayers = (XP_U8)srcGI->nPlayers;
nPlayers = srcGI->nPlayers;
destGI->boardSize = (XP_U8)srcGI->boardSize;
destGI->serverRole = srcGI->serverRole;
destGI->hintsNotAllowed = srcGI->hintsNotAllowed;
destGI->timerEnabled = srcGI->timerEnabled;
destGI->robotSmartness = (XP_U8)srcGI->robotSmartness;
destGI->phoniesAction = srcGI->phoniesAction;
destGI->allowPickTiles = srcGI->allowPickTiles;
for ( srcPl = srcGI->players, destPl = destGI->players, i = 0;
i < nPlayers; ++srcPl, ++destPl, ++i ) {
replaceStringIfDifferent( mpool, &destPl->name, srcPl->name );
replaceStringIfDifferent( mpool, &destPl->password,
srcPl->password );
destPl->secondsUsed = srcPl->secondsUsed;
destPl->isRobot = srcPl->isRobot;
destPl->isLocal = srcPl->isLocal;
}
} /* gi_copy */
XP_U16
gi_countLocalHumans( const CurGameInfo* gi )
{
XP_U16 count = 0;
XP_U16 nPlayers = gi->nPlayers;
const LocalPlayer* lp = gi->players;
while ( nPlayers-- ) {
if ( lp->isLocal && !lp->isRobot ) {
++count;
}
++lp;
}
return count;
} /* gi_countLocalHumans */
void
gi_readFromStream( MPFORMAL XWStreamCtxt* stream, CurGameInfo* gi )
{
LocalPlayer* pl;
XP_U16 i;
XP_UCHAR* str;
XP_U16 strVersion = stream_getVersion( stream );
str = stringFromStream( mpool, stream );
replaceStringIfDifferent( mpool, &gi->dictName, str );
if ( !!str ) {
XP_FREE( mpool, str );
}
gi->nPlayers = (XP_U8)stream_getBits( stream, NPLAYERS_NBITS );
gi->boardSize = (XP_U8)stream_getBits( stream, 4 );
gi->serverRole = (DeviceRole)stream_getBits( stream, 2 );
gi->hintsNotAllowed = stream_getBits( stream, 1 );
gi->robotSmartness = (XP_U8)stream_getBits( stream, 2 );
gi->phoniesAction = (XWPhoniesChoice)stream_getBits( stream, 2 );
gi->timerEnabled = stream_getBits( stream, 1 );
if ( strVersion >= STREAM_VERS_41B4 ) {
gi->allowPickTiles = stream_getBits( stream, 1 );
gi->allowHintRect = stream_getBits( stream, 1 );
} else {
gi->allowPickTiles = XP_FALSE;
gi->allowHintRect = XP_FALSE;
}
if ( strVersion >= STREAM_VERS_BLUETOOTH ) {
gi->confirmBTConnect = stream_getBits( stream, 1 );
} else {
gi->confirmBTConnect = XP_TRUE; /* safe given all the 650s out there. */
}
gi->gameID = stream_getU16( stream );
if ( gi->timerEnabled ) {
gi->gameSeconds = stream_getU16( stream );
}
for ( pl = gi->players, i = 0; i < gi->nPlayers; ++pl, ++i ) {
str = stringFromStream( mpool, stream );
replaceStringIfDifferent( mpool, &pl->name, str );
if ( !!str ) {
XP_FREE( mpool, str );
}
str = stringFromStream( mpool, stream );
replaceStringIfDifferent( mpool, &pl->password, str );
if ( !!str ) {
XP_FREE( mpool, str );
}
pl->secondsUsed = stream_getU16( stream );
pl->isRobot = stream_getBits( stream, 1 );
pl->isLocal = stream_getBits( stream, 1 );
}
} /* gi_readFromStream */
void
gi_writeToStream( XWStreamCtxt* stream, const CurGameInfo* gi )
{
const LocalPlayer* pl;
XP_U16 i;
stringToStream( stream, gi->dictName );
stream_putBits( stream, NPLAYERS_NBITS, gi->nPlayers );
stream_putBits( stream, 4, gi->boardSize );
stream_putBits( stream, 2, gi->serverRole );
stream_putBits( stream, 1, gi->hintsNotAllowed );
stream_putBits( stream, 2, gi->robotSmartness );
stream_putBits( stream, 2, gi->phoniesAction );
stream_putBits( stream, 1, gi->timerEnabled );
stream_putBits( stream, 1, gi->allowPickTiles );
stream_putBits( stream, 1, gi->allowHintRect );
stream_putBits( stream, 1, gi->confirmBTConnect );
stream_putU16( stream, gi->gameID );
if ( gi->timerEnabled) {
stream_putU16( stream, gi->gameSeconds );
}
for ( pl = gi->players, i = 0; i < gi->nPlayers; ++pl, ++i ) {
stringToStream( stream, pl->name );
stringToStream( stream, pl->password );
stream_putU16( stream, pl->secondsUsed );
stream_putBits( stream, 1, pl->isRobot );
stream_putBits( stream, 1, pl->isLocal );
}
} /* gi_writeToStream */
XP_Bool
player_hasPasswd( LocalPlayer* player )
{
XP_UCHAR* password = player->password;
/* XP_ASSERT( player->isLocal ); */
return !!password && *password != '\0';
} /* player_hasPasswd */
XP_Bool
player_passwordMatches( LocalPlayer* player, XP_U8* buf, XP_U16 len )
{
XP_ASSERT( player->isLocal );
return (XP_STRLEN(player->password) == len)
&& (0 == XP_STRNCMP( player->password, (XP_UCHAR*)buf, len ));
} /* player_passwordMatches */
XP_U16
player_timePenalty( CurGameInfo* gi, XP_U16 playerNum )
{
XP_S16 seconds = (gi->gameSeconds / gi->nPlayers);
LocalPlayer* player = gi->players + playerNum;
XP_U16 result = 0;
seconds -= player->secondsUsed;
if ( seconds < 0 ) {
seconds = -seconds;
seconds += 59;
result = (seconds/60) * 10;
}
return result;
} /* player_timePenalty */
#ifdef CPLUS
}
#endif

114
xwords4/common/game.h Normal file
View file

@ -0,0 +1,114 @@
/* -*-mode: C; fill-column: 76; c-basic-offset: 4; -*- */
/*
* Copyright 2001 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 _GAME_H_
#define _GAME_H_
#include "model.h"
#include "board.h"
#include "comms.h"
#include "server.h"
#include "util.h"
#ifdef CPLUS
extern "C" {
#endif
#define STREAM_VERS_MODEL_NO_DICT 0x06
#define STREAM_VERS_BLUETOOTH 0x05
#define STREAM_VERS_KEYNAV 0x04
#define STREAM_VERS_RELAY 0x03
#define STREAM_VERS_41B4 0x02
#define STREAM_VERS_405 0x01
#define CUR_STREAM_VERS STREAM_VERS_MODEL_NO_DICT
typedef struct LocalPlayer {
XP_UCHAR* name;
XP_UCHAR* password;
XP_U16 secondsUsed;
XP_Bool isRobot;
XP_Bool isLocal;
} LocalPlayer;
#define DUMB_ROBOT 0
#define SMART_ROBOT 1
typedef struct CurGameInfo {
XP_UCHAR* dictName;
LocalPlayer players[MAX_NUM_PLAYERS];
XP_U16 gameID; /* uniquely identifies game */
XP_U16 gameSeconds; /* for timer */
XP_U8 nPlayers;
XP_U8 boardSize;
DeviceRole serverRole;
XP_Bool hintsNotAllowed;
XP_Bool timerEnabled;
XP_Bool allowPickTiles;
XP_Bool allowHintRect;
XP_U8 robotSmartness;
XWPhoniesChoice phoniesAction;
XP_Bool confirmBTConnect; /* only used for BT */
} CurGameInfo;
typedef struct XWGame {
BoardCtxt* board;
ModelCtxt* model;
ServerCtxt* server;
#ifndef XWFEATURE_STANDALONE_ONLY
CommsCtxt* comms;
#endif
} XWGame;
void game_makeNewGame( MPFORMAL XWGame* game, CurGameInfo* gi,
XW_UtilCtxt* util, DrawCtx* draw, XP_U16 gameID,
CommonPrefs* cp, TransportSend sendproc,
IF_CH(TransportReset resetproc) void* closure);
void game_reset( MPFORMAL XWGame* game, CurGameInfo* gi, XW_UtilCtxt* util,
XP_U16 gameID, CommonPrefs* cp, TransportSend sendproc,
IF_CH(TransportReset resetproc) void* closure );
XP_Bool game_makeFromStream( MPFORMAL XWStreamCtxt* stream, XWGame* game,
CurGameInfo* gi,
DictionaryCtxt* dict, XW_UtilCtxt* util,
DrawCtx* draw, CommonPrefs* cp,
TransportSend sendProc, IF_CH(TransportReset rp)
void* closure );
void game_saveToStream( const XWGame* game, const CurGameInfo* gi,
XWStreamCtxt* stream );
void game_dispose( XWGame* game );
void gi_initPlayerInfo( MPFORMAL CurGameInfo* gi,
const XP_UCHAR* nameTemplate );
void gi_disposePlayerInfo( MPFORMAL CurGameInfo* gi );
void gi_writeToStream( XWStreamCtxt* stream, const CurGameInfo* gi );
void gi_readFromStream( MPFORMAL XWStreamCtxt* stream, CurGameInfo* gi );
void gi_copy( MPFORMAL CurGameInfo* destGI, const CurGameInfo* srcGi );
XP_U16 gi_countLocalHumans( const CurGameInfo* gi );
XP_Bool player_hasPasswd( LocalPlayer* player );
XP_Bool player_passwordMatches( LocalPlayer* player, XP_U8* buf, XP_U16 len );
XP_U16 player_timePenalty( CurGameInfo* gi, XP_U16 playerNum );
#ifdef CPLUS
}
#endif
#endif

276
xwords4/common/mempool.c Normal file
View file

@ -0,0 +1,276 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
/*
* Copyright 2001 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.
*/
#ifdef MEM_DEBUG
#include "mempool.h"
#include "comtypes.h"
#include "xwstream.h"
/* #define MPOOL_DEBUG */
#ifdef CPLUS
extern "C" {
#endif
typedef struct MemPoolEntry {
struct MemPoolEntry* next;
const char* fileName;
XP_U32 lineNo;
XP_U32 size;
void* ptr;
} MemPoolEntry;
struct MemPoolCtx {
MemPoolEntry* freeList;
MemPoolEntry* usedList;
XP_U16 nFree;
XP_U16 nUsed;
XP_U16 nAllocs;
};
/*--------------------------------------------------------------------------*/
MemPoolCtx*
mpool_make( void )
{
MemPoolCtx* result = (MemPoolCtx*)XP_PLATMALLOC( sizeof(*result) );
XP_MEMSET( result, 0, sizeof(*result) );
return result;
} /* mpool_make */
static void
freeList( MemPoolEntry* entry )
{
while ( !!entry ) {
MemPoolEntry* next = entry->next;
XP_ASSERT( !entry->ptr );
XP_PLATFREE( entry );
entry = next;
}
} /* freeList */
#ifdef DEBUG
static char*
checkIsText( MemPoolEntry* entry )
{
unsigned char* txt = (unsigned char*)entry->ptr;
XP_U32 len = entry->size;
while ( len-- ) {
unsigned char c = *txt++;
if ( c < 32 || c > 127 ) {
if ( len == 0 && c == '\0' ) {
return (char*)entry->ptr;
} else {
return (char*)NULL;
}
}
}
return (char*)NULL;
} /* checkIsText */
#endif
void
mpool_destroy( MemPoolCtx* mpool )
{
if ( mpool->nUsed > 0 ) {
XP_WARNF( "leaking %d blocks", mpool->nUsed );
}
if ( !!mpool->usedList ) {
MemPoolEntry* entry;
for ( entry = mpool->usedList; !!entry; entry = entry->next ) {
#ifndef FOR_GREMLINS /* I don't want to hear about this right now */
XP_LOGF( "%s: " XP_P " from ln %ld of %s\n", __func__,
entry->ptr, entry->lineNo, entry->fileName );
#ifdef DEBUG
{
char* tryTxt;
tryTxt = checkIsText( entry );
if ( !!tryTxt ) {
XP_WARNF( "--- looks like text: %s\n", tryTxt );
}
}
#endif
#endif
}
}
#ifndef FOR_GREMLINS
XP_ASSERT( !mpool->usedList && mpool->nUsed == 0 );
#endif
freeList( mpool->freeList );
XP_PLATFREE( mpool );
} /* mpool_destroy */
void*
mpool_alloc( MemPoolCtx* mpool, XP_U32 size, const char* file, XP_U32 lineNo )
{
MemPoolEntry* entry;
if ( mpool->nFree > 0 ) {
entry = mpool->freeList;
mpool->freeList = entry->next;
--mpool->nFree;
} else {
entry = (MemPoolEntry*)XP_PLATMALLOC( sizeof(*entry) );
}
entry->next = mpool->usedList;
mpool->usedList = entry;
entry->fileName = file;
entry->lineNo = lineNo;
entry->size = size;
entry->ptr = XP_PLATMALLOC( size );
XP_ASSERT( !!entry->ptr );
++mpool->nUsed;
++mpool->nAllocs;
#ifdef MPOOL_DEBUG
XP_LOGF( "%s(size=%ld,file=%s,lineNo=%ld)=>%p",
__func__, size, file, lineNo, entry->ptr );
#endif
return entry->ptr;
} /* mpool_alloc */
static MemPoolEntry*
findEntryFor( MemPoolCtx* mpool, void* ptr, MemPoolEntry** prevP )
{
MemPoolEntry* entry;
MemPoolEntry* prev;
for ( prev = (MemPoolEntry*)NULL, entry = mpool->usedList; !!entry;
prev = entry, entry = prev->next ) {
if ( entry->ptr == ptr ) {
if ( !!prevP ) {
*prevP = prev;
}
return entry;
}
}
return (MemPoolEntry*)NULL;
} /* findEntryFor */
void*
mpool_realloc( MemPoolCtx* mpool, void* ptr, XP_U32 newsize, const char* file, XP_U32 lineNo )
{
MemPoolEntry* entry = findEntryFor( mpool, ptr, (MemPoolEntry**)NULL );
if ( !entry ) {
XP_LOGF( "findEntryFor failed; called from %s, line %ld",
file, lineNo );
} else {
entry->ptr = XP_PLATREALLOC( entry->ptr, newsize );
XP_ASSERT( !!entry->ptr );
entry->fileName = file;
entry->lineNo = lineNo;
}
return entry->ptr;
} /* mpool_realloc */
void
mpool_free( MemPoolCtx* mpool, void* ptr, const char* file, XP_U32 lineNo )
{
MemPoolEntry* entry;
MemPoolEntry* prev;
entry = findEntryFor( mpool, ptr, &prev );
if ( !entry ) {
XP_LOGF( "findEntryFor failed; called from %s, line %ld",
file, lineNo );
} else {
#ifdef MPOOL_DEBUG
XP_LOGF( "%s(ptr=%p):size=%ld,file=%s,lineNo=%ld)", __func__,
entry->ptr, entry->size, entry->fileName, entry->lineNo );
#endif
if ( !!prev ) {
prev->next = entry->next;
} else {
mpool->usedList = entry->next;
}
XP_MEMSET( entry->ptr, 0x00, entry->size );
XP_PLATFREE( entry->ptr );
entry->ptr = NULL;
entry->next = mpool->freeList;
mpool->freeList = entry;
++mpool->nFree;
--mpool->nUsed;
return;
}
XP_ASSERT( 0 );
} /* mpool_free */
void
mpool_stats( MemPoolCtx* mpool, XWStreamCtxt* stream )
{
XP_UCHAR buf[128];
MemPoolEntry* entry;
XP_SNPRINTF( buf, sizeof(buf), (XP_UCHAR*)"Number of blocks in use: %d\n"
"Number of free blocks: %d\n"
"Total number of blocks allocated: %d\n",
mpool->nUsed, mpool->nFree, mpool->nAllocs );
if ( !!stream ) {
stream_putString( stream, buf );
} else {
XP_LOGF( "%s", buf );
}
for ( entry = mpool->usedList; !!entry; entry = entry->next ) {
XP_SNPRINTF( buf, sizeof(buf),
(XP_UCHAR*)"%ld byte block allocated at %p, %s: line %ld\n",
entry->size, entry->ptr, entry->fileName, entry->lineNo );
if ( !!stream ) {
stream_putString( stream, buf );
} else {
XP_LOGF( "%s", buf );
}
}
} /* mpool_stats */
XP_U16
mpool_getNUsed( MemPoolCtx* mpool )
{
return mpool->nUsed;
} /* mpool_getNUsed */
#ifdef CPLUS
}
#endif
#endif /* MEM_DEBUG */

53
xwords4/common/mempool.h Normal file
View file

@ -0,0 +1,53 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
/*
* Copyright 2001 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 _MEMPOOL_H_
#define _MEMPOOL_H_
#ifdef MEM_DEBUG
#include "comtypes.h"
#ifdef CPLUS
extern "C" {
#endif
typedef struct MemPoolCtx MemPoolCtx;
MemPoolCtx* mpool_make(void);
void mpool_destroy( MemPoolCtx* mpool );
void* mpool_alloc( MemPoolCtx* mpool, XP_U32 size,
const char* file, XP_U32 lineNo );
void* mpool_realloc( MemPoolCtx* mpool, void* ptr, XP_U32 newsize,
const char* file, XP_U32 lineNo );
void mpool_free( MemPoolCtx* mpool, void* ptr, const char* file, XP_U32 lineNo );
void mpool_stats( MemPoolCtx* mpool, XWStreamCtxt* stream );
XP_U16 mpool_getNUsed( MemPoolCtx* mpool );
#ifdef CPLUS
}
#endif
#else
# define mpool_destroy(p)
#endif /* MEM_DEBUG */
#endif /* _MEMPOOL_H_ */

469
xwords4/common/memstream.c Normal file
View file

@ -0,0 +1,469 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
/*
* Copyright 2001 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.
*/
/* #include <PalmTypes.h> */
/* #include <SystemMgr.h> */
/* #include <IrLib.h> */
#include "xwstream.h"
#include "comtypes.h"
#include "memstream.h"
#include "vtabmgr.h"
#ifdef CPLUS
extern "C" {
#endif
#define BIT_PART(pos) ((pos)&0x00000007)
#define BYTE_PART(pos) ((pos)>>3)
#define MIN_PACKETBUF_SIZE (1<<6)
#define STREAM_INCR_SIZE 100
#define SOCKET_STREAM_SUPER_COMMON_SLOTS \
StreamCtxVTable* vtable; \
void* closure; \
XP_U32 curReadPos; \
XP_U32 curWritePos; \
XP_PlayerAddr channelNo; \
XP_U8* buf; \
MemStreamCloseCallback onClose; \
XP_U16 nBytesWritten; \
XP_U16 nBytesAllocated; \
XP_U16 version; \
XP_U8 nReadBits; \
XP_U8 nWriteBits; \
XP_Bool isOpen; \
MPSLOT
#define SOCKET_STREAM_SUPER_SLOTS \
SOCKET_STREAM_SUPER_COMMON_SLOTS
typedef struct MemStreamCtxt {
SOCKET_STREAM_SUPER_SLOTS
} MemStreamCtxt;
static StreamCtxVTable* make_vtable( MemStreamCtxt* stream );
/* Try to keep this the only entry point to this file, and to keep it at the
* top of the file (first executable code).
*/
XWStreamCtxt*
mem_stream_make( MPFORMAL VTableMgr* vtmgr, void* closure,
XP_PlayerAddr channelNo, MemStreamCloseCallback onClose )
{
StreamCtxVTable* vtable;
MemStreamCtxt* result = (MemStreamCtxt*)XP_MALLOC( mpool,
sizeof(*result) );
XP_MEMSET( result, 0, sizeof(*result) );
MPASSIGN(result->mpool, mpool);
vtable = (StreamCtxVTable*)vtmgr_getVTable( vtmgr, VTABLE_MEM_STREAM );
if ( !vtable ) {
vtable = make_vtable( result );
vtmgr_setVTable( vtmgr, VTABLE_MEM_STREAM, vtable );
}
result->vtable = vtable;
result->closure = closure;
result->channelNo = channelNo;
result->onClose = onClose;
result->isOpen = XP_TRUE;
return (XWStreamCtxt*)result;
} /* make_mem_stream */
static void
mem_stream_getBytes( XWStreamCtxt* p_sctx, void* where, XP_U16 count )
{
MemStreamCtxt* stream = (MemStreamCtxt*)p_sctx;
if ( stream->nReadBits != 0 ) {
stream->nReadBits = 0;
}
XP_ASSERT( stream->curReadPos + count <= stream->nBytesAllocated );
XP_ASSERT( stream->curReadPos + count <= stream->nBytesWritten );
XP_MEMCPY( where, stream->buf + stream->curReadPos, count );
stream->curReadPos += count;
XP_ASSERT( stream->curReadPos <= stream->nBytesWritten );
} /* mem_stream_getBytes */
static XP_U8
mem_stream_getU8( XWStreamCtxt* p_sctx )
{
XP_U8 result;
mem_stream_getBytes( p_sctx, &result, sizeof(result) );
return result;
} /* mem_stream_getU8 */
static XP_U16
mem_stream_getU16( XWStreamCtxt* p_sctx )
{
XP_U16 result;
mem_stream_getBytes( p_sctx, &result, sizeof(result) );
return XP_NTOHS(result);
} /* mem_stream_getU16 */
static XP_U32
mem_stream_getU32( XWStreamCtxt* p_sctx )
{
XP_U32 result;
mem_stream_getBytes( p_sctx, &result, sizeof(result) );
return XP_NTOHL( result );
} /* mem_stream_getU32 */
static XP_Bool
getOneBit( MemStreamCtxt* stream )
{
XP_U8 mask, rack;
XP_Bool result;
if ( stream->nReadBits == 0 ) {
++stream->curReadPos;
}
XP_ASSERT( stream->curReadPos <= stream->nBytesWritten );
rack = stream->buf[stream->curReadPos-1];
mask = 1 << stream->nReadBits++;
result = (rack & mask) != 0;
if ( stream->nReadBits == 8 ) {
stream->nReadBits = 0;
}
return result;
} /* getOneBit */
static XP_U32
mem_stream_getBits( XWStreamCtxt* p_sctx, XP_U16 nBits )
{
MemStreamCtxt* stream = (MemStreamCtxt*)p_sctx;
XP_U32 mask;
XP_U32 result = 0;
for ( mask = 1L; nBits--; mask <<= 1 ) {
if ( getOneBit( stream ) ) {
result |= mask;
}
}
return result;
} /* stream_getBits */
static void
mem_stream_putBytes( XWStreamCtxt* p_sctx, const void* whence,
XP_U16 count )
{
MemStreamCtxt* stream = (MemStreamCtxt*)p_sctx;
XP_U32 newSize;
if ( !stream->buf ) {
XP_ASSERT( stream->nBytesAllocated == 0 );
stream->buf = (XP_U8*)XP_MALLOC( stream->mpool, STREAM_INCR_SIZE );
stream->nBytesAllocated = STREAM_INCR_SIZE;
}
/* I don't yet deal with getting asked to get/put a byte when in the
middle of doing bitwise stuff. It's probably just a matter of skipping
to the next byte, though -- and curPos should already be there. */
if ( stream->nWriteBits != 0 ) {
stream->nWriteBits = 0;
}
/* Reallocation. We may be writing into the middle of an existing stream,
and doing so may still require expanding the stream. So figure out if
the new size is bigger than what we have, and if so expand to hold it
plus something. */
newSize = stream->nBytesWritten + count;
if ( stream->curWritePos < stream->nBytesWritten ) {
newSize -= stream->nBytesWritten - stream->curWritePos;
}
if ( newSize > stream->nBytesAllocated ) {
XP_ASSERT( newSize + STREAM_INCR_SIZE < 0xFFFF );
stream->nBytesAllocated = (XP_U16)newSize + STREAM_INCR_SIZE;
stream->buf =
(XP_U8*)XP_REALLOC( stream->mpool, stream->buf,
stream->nBytesAllocated );
}
XP_MEMCPY( stream->buf + stream->curWritePos, whence, count );
stream->nBytesWritten = (XP_U16)newSize;
stream->curWritePos += count;
} /* mem_stream_putBytes */
static void
mem_stream_putString( XWStreamCtxt* p_sctx, const char* whence )
{
XP_U16 len = XP_STRLEN( whence );
mem_stream_putBytes( p_sctx, (void*)whence, len );
}
static void
mem_stream_putU8( XWStreamCtxt* p_sctx, XP_U8 data )
{
mem_stream_putBytes( p_sctx, &data, sizeof(data) );
} /* mem_stream_putU8 */
static void
mem_stream_putU16( XWStreamCtxt* p_sctx, XP_U16 data )
{
data = XP_HTONS( data );
mem_stream_putBytes( p_sctx, &data, sizeof(data) );
} /* linux_common_stream_putU16 */
static void
mem_stream_putU32( XWStreamCtxt* p_sctx, XP_U32 data )
{
data = XP_HTONL( data );
mem_stream_putBytes( p_sctx, &data, sizeof(data) );
} /* mem_stream_putU32 */
static void
putOneBit( MemStreamCtxt* stream, XP_U16 bit )
{
XP_U8 mask, rack;
if ( stream->nWriteBits == 0 ) {
if ( stream->curWritePos == stream->nBytesWritten ) {
stream_putU8( (XWStreamCtxt*)stream, 0 ); /* increments curPos */
} else {
++stream->curWritePos;
}
}
XP_ASSERT( stream->curWritePos > 0 );
rack = stream->buf[stream->curWritePos-1];
mask = 1 << stream->nWriteBits++;
if ( bit ) {
rack |= mask;
} else {
rack &= ~mask;
}
stream->buf[stream->curWritePos-1] = rack;
stream->nWriteBits %= 8;
} /* putOneBit */
static void
mem_stream_putBits( XWStreamCtxt* p_sctx, XP_U16 nBits, XP_U32 data
DBG_LINE_FILE_FORMAL )
{
MemStreamCtxt* stream = (MemStreamCtxt*)p_sctx;
#ifdef DEBUG
XP_U16 origBits = nBits;
#endif
XP_ASSERT( nBits > 0 );
while ( nBits-- ) {
putOneBit( stream, (XP_U16)(((data & 1L) != 0)? 1:0) );
data >>= 1;
}
XP_ASSERT( data == 0 ); /* otherwise nBits was too small */
#ifdef DEBUG
if ( data != 0 ) {
XP_LOGF( "%s: nBits was %d from line %d, %s", __func__,
origBits, lin, fil );
}
#endif
} /* mem_stream_putBits */
static void
mem_stream_copyFromStream( XWStreamCtxt* p_sctx, XWStreamCtxt* src,
XP_U16 nBytes )
{
while ( nBytes > 0 ) {
XP_U8 buf[256];
XP_U16 len = sizeof(buf);
if ( nBytes < len ) {
len = nBytes;
}
stream_getBytes( src, buf, len );
stream_putBytes( p_sctx, buf, len );
nBytes -= len;
}
} /* mem_stream_copyFromStream */
static void
mem_stream_open( XWStreamCtxt* p_sctx )
{
MemStreamCtxt* stream = (MemStreamCtxt*)p_sctx;
stream->nBytesWritten = 0;
stream->curReadPos = START_OF_STREAM;
stream->curWritePos = START_OF_STREAM;
} /* mem_stream_open */
static void
mem_stream_close( XWStreamCtxt* p_sctx )
{
MemStreamCtxt* stream = (MemStreamCtxt*)p_sctx;
XP_ASSERT( stream->isOpen );
if ( !!stream->onClose ) {
(*stream->onClose)( p_sctx, stream->closure );
}
stream->isOpen = XP_FALSE;
} /* mem_stream_close */
static XP_U16
mem_stream_getSize( XWStreamCtxt* p_sctx )
{
MemStreamCtxt* stream = (MemStreamCtxt*)p_sctx;
XP_U16 size = stream->nBytesWritten - stream->curReadPos;
return size;
} /* mem_stream_getSize */
static XP_PlayerAddr
mem_stream_getAddress( XWStreamCtxt* p_sctx )
{
MemStreamCtxt* stream = (MemStreamCtxt*)p_sctx;
return stream->channelNo;
} /* mem_stream_getAddress */
static void
mem_stream_setAddress( XWStreamCtxt* p_sctx, XP_PlayerAddr channelNo )
{
MemStreamCtxt* stream = (MemStreamCtxt*)p_sctx;
stream->channelNo = channelNo;
} /* mem_stream_getAddress */
static void
mem_stream_setVersion( XWStreamCtxt* p_sctx, XP_U16 vers )
{
MemStreamCtxt* stream = (MemStreamCtxt*)p_sctx;
stream->version = vers;
} /* mem_stream_setVersion */
static XP_U16
mem_stream_getVersion( XWStreamCtxt* p_sctx )
{
MemStreamCtxt* stream = (MemStreamCtxt*)p_sctx;
return stream->version;
} /* mem_stream_getVersion */
static void
mem_stream_setOnCloseProc( XWStreamCtxt* p_sctx, MemStreamCloseCallback proc )
{
MemStreamCtxt* stream = (MemStreamCtxt*)p_sctx;
stream->onClose = proc;
}
static XWStreamPos
mem_stream_getPos( XWStreamCtxt* p_sctx, PosWhich which )
{
XWStreamPos result;
MemStreamCtxt* stream = (MemStreamCtxt*)p_sctx;
if ( which == POS_WRITE ) {
result = (stream->curWritePos << 3) | stream->nWriteBits;
} else {
result = (stream->curReadPos << 3) | stream->nReadBits;
}
return result;
} /* mem_stream_getPos */
static XWStreamPos
mem_stream_setPos( XWStreamCtxt* p_sctx, XWStreamPos newpos, PosWhich which )
{
MemStreamCtxt* stream = (MemStreamCtxt*)p_sctx;
XWStreamPos oldPos = mem_stream_getPos( p_sctx, which );
if ( which == POS_WRITE ) {
stream->nWriteBits = (XP_U8)BIT_PART(newpos);
stream->curWritePos = (XP_U32)BYTE_PART(newpos);
} else {
stream->nReadBits = (XP_U8)BIT_PART(newpos);
stream->curReadPos = (XP_U32)BYTE_PART(newpos);
}
return oldPos;
} /* mem_stream_setPos */
static void
mem_stream_destroy( XWStreamCtxt* p_sctx )
{
MemStreamCtxt* stream = (MemStreamCtxt*)p_sctx;
if ( stream->isOpen ) {
stream_close( p_sctx );
}
if ( !!stream->buf ) {
XP_FREE( stream->mpool, stream->buf );
}
XP_FREE( stream->mpool, stream );
} /* mem_stream_destroy */
static StreamCtxVTable*
make_vtable( MemStreamCtxt* stream )
{
StreamCtxVTable* vtable;
XP_ASSERT( !stream->vtable );
XP_ASSERT( sizeof(stream->vtable) == sizeof(vtable) );
vtable = (StreamCtxVTable*)XP_MALLOC( stream->mpool,
sizeof(*stream->vtable) );
SET_VTABLE_ENTRY( vtable, stream_getU8, mem );
SET_VTABLE_ENTRY( vtable, stream_getBytes, mem );
SET_VTABLE_ENTRY( vtable, stream_getU16, mem );
SET_VTABLE_ENTRY( vtable, stream_getU32, mem );
SET_VTABLE_ENTRY( vtable, stream_getBits, mem );
SET_VTABLE_ENTRY( vtable, stream_putU8, mem );
SET_VTABLE_ENTRY( vtable, stream_putBytes, mem );
SET_VTABLE_ENTRY( vtable, stream_putString, mem );
SET_VTABLE_ENTRY( vtable, stream_putU16, mem );
SET_VTABLE_ENTRY( vtable, stream_putU32, mem );
SET_VTABLE_ENTRY( vtable, stream_putBits, mem );
SET_VTABLE_ENTRY( vtable, stream_copyFromStream, mem );
SET_VTABLE_ENTRY( vtable, stream_setPos, mem );
SET_VTABLE_ENTRY( vtable, stream_getPos, mem );
SET_VTABLE_ENTRY( vtable, stream_destroy, mem );
SET_VTABLE_ENTRY( vtable, stream_open, mem );
SET_VTABLE_ENTRY( vtable, stream_close, mem );
SET_VTABLE_ENTRY( vtable, stream_getSize, mem );
SET_VTABLE_ENTRY( vtable, stream_getAddress, mem );
SET_VTABLE_ENTRY( vtable, stream_setAddress, mem );
SET_VTABLE_ENTRY( vtable, stream_setVersion, mem );
SET_VTABLE_ENTRY( vtable, stream_getVersion, mem );
SET_VTABLE_ENTRY( vtable, stream_setOnCloseProc, mem );
return vtable;
} /* make_vtable */
#ifdef CPLUS
}
#endif

View file

@ -0,0 +1,46 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
/*
* Copyright 2001 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 _MEMSTREAM_H_
#define _MEMSTREAM_H_
#include "comtypes.h"
#include "mempool.h"
#include "vtabmgr.h"
#ifdef CPLUS
extern "C" {
#endif
typedef void (*MemStreamCloseCallback)( XWStreamCtxt* stream,
void* closure );
XWStreamCtxt* mem_stream_make( MPFORMAL VTableMgr* vtmgr,
void* closure,
XP_PlayerAddr addr, /* should be in a
subclass */
MemStreamCloseCallback onCloseWritten );
#ifdef CPLUS
}
#endif
#endif

1837
xwords4/common/model.c Normal file

File diff suppressed because it is too large Load diff

261
xwords4/common/model.h Normal file
View file

@ -0,0 +1,261 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
/*
* Copyright 1997 - 2000 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 MAX_ROWS 16
#define MAX_COLS 16
#define NUMCOLS_NBITS 4
#ifdef EIGHT_TILES
#define MAX_TRAY_TILES 8
#define NTILES_NBITS 4
#else
#define MAX_TRAY_TILES 7
#define NTILES_NBITS 3
#endif
#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 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, XW_UtilCtxt* util,
XP_U16 nCols, XP_U16 nRows );
ModelCtxt* model_makeFromStream( MPFORMAL XWStreamCtxt* stream,
DictionaryCtxt* dict, XW_UtilCtxt* util );
void model_writeToStream( ModelCtxt* model, XWStreamCtxt* stream );
void model_init( ModelCtxt* model, XP_U16 nCols, XP_U16 nRows );
void model_destroy( ModelCtxt* model );
void model_setNPlayers( ModelCtxt* model, XP_U16 numPlayers );
void model_setDictionary( ModelCtxt* model, DictionaryCtxt* dict );
DictionaryCtxt* model_getDictionary( ModelCtxt* model );
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,
TrayTileSet* tiles );
Tile model_getPlayerTile( 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 );
/* 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( 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_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( ModelCtxt* model, XP_S16 turn );
void model_getCurrentMoveTile( ModelCtxt* model, XP_S16 turn, XP_S16* index,
Tile* tile, XP_U16* col, XP_U16* row,
XP_Bool* isBlank );
void 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,
TrayTileSet* oldTiles, TrayTileSet* newTiles );
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);
void model_makeTurnFromStream( ModelCtxt* model, XP_U16 playerNum,
XWStreamCtxt* stream );
void model_makeTurnFromMoveInfo( ModelCtxt* model, XP_U16 playerNum,
MoveInfo* newMove );
void model_resetCurrentTurn( ModelCtxt* model, XP_S16 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, 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)( XP_UCHAR* word, void* closure );
typedef struct WordNotifierInfo {
WordNotifierProc proc;
void* closure;
} WordNotifierInfo;
XP_Bool getCurrentMoveScoreIfLegal( ModelCtxt* model, XP_S16 turn,
XWStreamCtxt* stream, XP_S16* score );
XP_S16 model_getPlayerScore( ModelCtxt* model, XP_S16 player );
XP_Bool model_getPlayersLastScore( ModelCtxt* model, XP_S16 player,
XP_UCHAR* expl, XP_U16* explLen );
/* Have there been too many passes (so game should end)? */
XP_Bool model_recentPassCountOk( ModelCtxt* model );
XP_Bool model_checkMoveLegal( ModelCtxt* model, XP_S16 player,
XWStreamCtxt* stream,
WordNotifierInfo* notifyInfo );
void model_figureFinalScores( ModelCtxt* model, XP_S16* scores,
XP_S16* tilePenalties );
/* figureMoveScore is meant only for the engine's use */
XP_U16 figureMoveScore( const ModelCtxt* model, MoveInfo* moveInfo,
EngineCtxt* engine, XWStreamCtxt* stream,
WordNotifierInfo* notifyInfo, XP_UCHAR* mainWord );
/********************* 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, XP_UCHAR4* texts,
Tile* tiles );
#ifdef CPLUS
}
#endif
#endif

80
xwords4/common/modelp.h Normal file
View file

@ -0,0 +1,80 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
/*
* Copyright 2000 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 _MODELP_H_
#define _MODELP_H_
#include "model.h"
#include "movestak.h"
#ifdef CPLUS
extern "C" {
#endif
typedef struct PendingTile {
XP_U8 col;
XP_U8 row;
Tile tile; /* includes face and blank bit */
} PendingTile;
typedef struct PlayerCtxt {
XP_S16 score;
XP_S16 curMoveScore; /* negative means illegal */
XP_Bool curMoveValid;
TrayTileSet trayTiles;
XP_U8 nPending; /* still in tray but "on board" */
PendingTile pendingTiles[MAX_TRAY_TILES];
} PlayerCtxt;
typedef struct ModelVolatiles {
XW_UtilCtxt* util;
struct CurGameInfo* gi;
DictionaryCtxt* dict;
BoardListener boardListenerFunc;
StackCtxt* stack;
void* boardListenerData;
TrayListener trayListenerFunc;
void* trayListenerData;
DictListener dictListenerFunc;
void* dictListenerData;
MPSLOT
} ModelVolatiles;
struct ModelCtxt {
ModelVolatiles vol;
CellTile tiles[MAX_COLS][MAX_ROWS];
PlayerCtxt players[MAX_NUM_PLAYERS];
XP_U16 nPlayers;
XP_U16 nCols;
XP_U16 nRows;
};
void invalidateScore( ModelCtxt* model, XP_S16 player );
XP_Bool tilesInLine( ModelCtxt* model, XP_S16 turn, XP_Bool* isHorizontal );
void normalizeMoves( ModelCtxt* model, XP_S16 turn,
XP_Bool isHorizontal, MoveInfo* moveInfo );
void adjustScoreForUndone( ModelCtxt* model, MoveInfo* mi, XP_U16 turn );
#ifdef CPLUS
}
#endif
#endif

386
xwords4/common/movestak.c Normal file
View file

@ -0,0 +1,386 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
/*
* Copyright 2001, 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
* 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.
*/
//#include "modelp.h"
#include "mempool.h"
#include "xwstream.h"
#include "movestak.h"
#include "memstream.h"
#include "strutils.h"
#ifdef CPLUS
extern "C" {
#endif
struct StackCtxt {
VTableMgr* vtmgr;
XWStreamCtxt* data;
XWStreamPos top;
XWStreamPos cachedPos;
XP_U16 cacheNext;
XP_U16 nEntries;
XP_U16 bitsPerTile;
XP_U16 highWaterMark;
MPSLOT
};
void
stack_init( StackCtxt* stack )
{
stack->nEntries = stack->highWaterMark = 0;
stack->top = START_OF_STREAM;
/* I see little point in freeing or shrinking stack->data. It'll get
shrunk to fit as soon as we serialize/deserialize anyway. */
} /* stack_init */
void
stack_setBitsPerTile( StackCtxt* stack, XP_U16 bitsPerTile )
{
XP_ASSERT( !!stack );
stack->bitsPerTile = bitsPerTile;
}
StackCtxt*
stack_make( MPFORMAL VTableMgr* vtmgr )
{
StackCtxt* result = (StackCtxt*)XP_MALLOC( mpool, sizeof( *result ) );
if ( !!result ) {
XP_MEMSET( result, 0, sizeof(*result) );
MPASSIGN(result->mpool, mpool);
result->vtmgr = vtmgr;
}
return result;
} /* stack_make */
void
stack_destroy( StackCtxt* stack )
{
if ( !!stack->data ) {
stream_destroy( stack->data );
}
XP_FREE( stack->mpool, stack );
} /* stack_destroy */
void
stack_loadFromStream( StackCtxt* stack, XWStreamCtxt* stream )
{
XP_U16 nBytes = stream_getU16( stream );
if ( nBytes > 0 ) {
stack->highWaterMark = stream_getU16( stream );
stack->nEntries = stream_getU16( stream );
stack->top = stream_getU32( stream );
stack->data = mem_stream_make( MPPARM(stack->mpool) stack->vtmgr,
NULL, 0,
(MemStreamCloseCallback)NULL );
stream_copyFromStream( stack->data, stream, nBytes );
} else {
XP_ASSERT( stack->nEntries == 0 );
XP_ASSERT( stack->top == 0 );
}
} /* stack_makeFromStream */
void
stack_writeToStream( StackCtxt* stack, XWStreamCtxt* stream )
{
XP_U16 nBytes;
XWStreamCtxt* data = stack->data;
XWStreamPos oldPos = START_OF_STREAM;
if ( !!data ) {
oldPos = stream_setPos( data, START_OF_STREAM, POS_READ );
nBytes = stream_getSize( data );
} else {
nBytes = 0;
}
stream_putU16( stream, nBytes );
if ( nBytes > 0 ) {
stream_putU16( stream, stack->highWaterMark );
stream_putU16( stream, stack->nEntries );
stream_putU32( stream, stack->top );
stream_setPos( data, START_OF_STREAM, POS_READ );
stream_copyFromStream( stream, data, nBytes );
}
if ( !!data ) {
/* in case it'll be used further */
(void)stream_setPos( data, oldPos, POS_READ );
}
} /* stack_writeToStream */
static void
pushEntry( StackCtxt* stack, const StackEntry* entry )
{
XP_U16 i, bitsPerTile;
XWStreamPos oldLoc;
XP_U16 nTiles = entry->u.move.moveInfo.nTiles;
XWStreamCtxt* stream = stack->data;
if ( !stream ) {
stream = mem_stream_make( MPPARM(stack->mpool) stack->vtmgr, NULL, 0,
(MemStreamCloseCallback)NULL );
stack->data = stream;
}
oldLoc = stream_setPos( stream, stack->top, POS_WRITE );
stream_putBits( stream, 2, entry->moveType );
stream_putBits( stream, 2, entry->playerNum );
switch( entry->moveType ) {
case MOVE_TYPE:
case PHONY_TYPE:
stream_putBits( stream, NTILES_NBITS, nTiles );
stream_putBits( stream, 5, entry->u.move.moveInfo.commonCoord );
stream_putBits( stream, 1, entry->u.move.moveInfo.isHorizontal );
bitsPerTile = stack->bitsPerTile;
XP_ASSERT( bitsPerTile == 5 || bitsPerTile == 6 );
for ( i = 0; i < nTiles; ++i ) {
Tile tile;
stream_putBits( stream, 5,
entry->u.move.moveInfo.tiles[i].varCoord );
tile = entry->u.move.moveInfo.tiles[i].tile;
stream_putBits( stream, bitsPerTile, tile & TILE_VALUE_MASK );
stream_putBits( stream, 1, (tile & TILE_BLANK_BIT) != 0 );
}
if ( entry->moveType == MOVE_TYPE ) {
traySetToStream( stream, &entry->u.move.newTiles );
}
break;
case ASSIGN_TYPE:
traySetToStream( stream, &entry->u.assign.tiles );
break;
case TRADE_TYPE:
XP_ASSERT( entry->u.trade.newTiles.nTiles
== entry->u.trade.oldTiles.nTiles );
traySetToStream( stream, &entry->u.trade.oldTiles );
/* could save three bits per trade by just writing the tiles of the
second guy */
traySetToStream( stream, &entry->u.trade.newTiles );
break;
}
++stack->nEntries;
stack->highWaterMark = stack->nEntries;
stack->top = stream_setPos( stream, oldLoc, POS_WRITE );
} /* pushEntry */
static void
readEntry( StackCtxt* stack, StackEntry* entry )
{
XP_U16 nTiles, i, bitsPerTile;
XWStreamCtxt* stream = stack->data;
entry->moveType = (StackMoveType)stream_getBits( stream, 2 );
entry->playerNum = (XP_U8)stream_getBits( stream, 2 );
switch( entry->moveType ) {
case MOVE_TYPE:
case PHONY_TYPE:
nTiles = entry->u.move.moveInfo.nTiles =
(XP_U8)stream_getBits( stream, NTILES_NBITS );
XP_ASSERT( nTiles <= MAX_TRAY_TILES );
entry->u.move.moveInfo.commonCoord = (XP_U8)stream_getBits(stream, 5);
entry->u.move.moveInfo.isHorizontal = (XP_U8)stream_getBits(stream, 1);
bitsPerTile = stack->bitsPerTile;
XP_ASSERT( bitsPerTile == 5 || bitsPerTile == 6 );
for ( i = 0; i < nTiles; ++i ) {
Tile tile;
entry->u.move.moveInfo.tiles[i].varCoord =
(XP_U8)stream_getBits(stream, 5);
tile = (Tile)stream_getBits( stream, bitsPerTile );
if ( 0 != stream_getBits( stream, 1 ) ) {
tile |= TILE_BLANK_BIT;
}
entry->u.move.moveInfo.tiles[i].tile = tile;
}
if ( entry->moveType == MOVE_TYPE ) {
traySetFromStream( stream, &entry->u.move.newTiles );
}
break;
case ASSIGN_TYPE:
traySetFromStream( stream, &entry->u.assign.tiles );
break;
case TRADE_TYPE:
traySetFromStream( stream, &entry->u.trade.oldTiles );
traySetFromStream( stream, &entry->u.trade.newTiles );
XP_ASSERT( entry->u.trade.newTiles.nTiles
== entry->u.trade.oldTiles.nTiles );
break;
}
} /* readEntry */
void
stack_addMove( StackCtxt* stack, XP_U16 turn, MoveInfo* moveInfo,
TrayTileSet* newTiles )
{
StackEntry move;
move.playerNum = (XP_U8)turn;
move.moveType = MOVE_TYPE;
XP_MEMCPY( &move.u.move.moveInfo, moveInfo, sizeof(move.u.move.moveInfo));
move.u.move.newTiles = *newTiles;
pushEntry( stack, &move );
} /* stack_addMove */
void
stack_addPhony( StackCtxt* stack, XP_U16 turn, MoveInfo* moveInfo )
{
StackEntry move;
move.playerNum = (XP_U8)turn;
move.moveType = PHONY_TYPE;
XP_MEMCPY( &move.u.phony.moveInfo, moveInfo,
sizeof(move.u.phony.moveInfo));
pushEntry( stack, &move );
} /* stack_addPhony */
void
stack_addTrade( StackCtxt* stack, XP_U16 turn,
TrayTileSet* oldTiles, TrayTileSet* newTiles )
{
StackEntry move;
move.playerNum = (XP_U8)turn;
move.moveType = TRADE_TYPE;
move.u.trade.oldTiles = *oldTiles;
move.u.trade.newTiles = *newTiles;
pushEntry( stack, &move );
} /* stack_addTrade */
void
stack_addAssign( StackCtxt* stack, XP_U16 turn, TrayTileSet* tiles )
{
StackEntry move;
move.playerNum = (XP_U8)turn;
move.moveType = ASSIGN_TYPE;
move.u.assign.tiles = *tiles;
pushEntry( stack, &move );
} /* stack_addAssign */
static XP_Bool
setCacheReadyFor( StackCtxt* stack, XP_U16 n )
{
StackEntry dummy;
XP_U16 i;
stream_setPos( stack->data, START_OF_STREAM, POS_READ );
for ( i = 0; i < n; ++i ) {
readEntry( stack, &dummy );
}
stack->cacheNext = n;
stack->cachedPos = stream_getPos( stack->data, XP_FALSE );
return XP_TRUE;
} /* setCacheReadyFor */
XP_U16
stack_getNEntries( StackCtxt* stack )
{
return stack->nEntries;
} /* stack_getNEntries */
XP_Bool
stack_getNthEntry( StackCtxt* stack, XP_U16 n, StackEntry* entry )
{
XP_Bool found;
if ( n >= stack->nEntries ) {
found = XP_FALSE;
} else if ( stack->cacheNext != n ) {
XP_ASSERT( !!stack->data );
found = setCacheReadyFor( stack, n );
XP_ASSERT( stack->cacheNext == n );
} else {
found = XP_TRUE;
}
if ( found ) {
XWStreamPos oldPos = stream_setPos( stack->data, stack->cachedPos,
POS_READ );
readEntry( stack, entry );
entry->moveNum = (XP_U8)n;
stack->cachedPos = stream_setPos( stack->data, oldPos, POS_READ );
++stack->cacheNext;
}
return found;
} /* stack_getNthEntry */
XP_Bool
stack_popEntry( StackCtxt* stack, StackEntry* entry )
{
XP_U16 n = stack->nEntries - 1;
XP_Bool found = stack_getNthEntry( stack, n, entry );
if ( found ) {
stack->nEntries = n;
setCacheReadyFor( stack, n ); /* set cachedPos by side-effect */
stack->top = stack->cachedPos;
}
return found;
} /* stack_popEntry */
void
stack_redo( StackCtxt* stack )
{
if( (stack->nEntries + 1) <= stack->highWaterMark ) {
++stack->nEntries;
setCacheReadyFor( stack, stack->nEntries );
stack->top = stack->cachedPos;
}
} /* stack_redo */
#ifdef CPLUS
}
#endif

95
xwords4/common/movestak.h Normal file
View file

@ -0,0 +1,95 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
/*
* Copyright 2001 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 _MOVESTAK_H_
#define _MOVESTAK_H_
#include "comtypes.h"
#include "model.h"
#include "vtabmgr.h"
#ifdef CPLUS
extern "C" {
#endif
enum { ASSIGN_TYPE, MOVE_TYPE, TRADE_TYPE, PHONY_TYPE };
typedef XP_U8 StackMoveType;
typedef struct AssignRec {
TrayTileSet tiles;
} AssignRec;
typedef struct TradeRec {
TrayTileSet oldTiles;
TrayTileSet newTiles;
} TradeRec;
typedef struct MoveRec {
MoveInfo moveInfo;
TrayTileSet newTiles;
} MoveRec;
typedef struct PhonyRec {
MoveInfo moveInfo;
} PhonyRec;
typedef union EntryData {
AssignRec assign;
TradeRec trade;
MoveRec move;
PhonyRec phony;
} EntryData;
typedef struct StackEntry {
StackMoveType moveType;
XP_U8 playerNum;
XP_U8 moveNum;
EntryData u;
} StackEntry;
typedef struct StackCtxt StackCtxt;
StackCtxt* stack_make( MPFORMAL VTableMgr* vtmgr );
void stack_destroy( StackCtxt* stack );
void stack_init( StackCtxt* stack );
void stack_setBitsPerTile( StackCtxt* stack, XP_U16 bitsPerTile );
void stack_loadFromStream( StackCtxt* stack, XWStreamCtxt* stream );
void stack_writeToStream( StackCtxt* stack, XWStreamCtxt* stream );
void stack_addMove( StackCtxt* stack, XP_U16 turn, MoveInfo* moveInfo,
TrayTileSet* newTiles );
void stack_addPhony( StackCtxt* stack, XP_U16 turn, MoveInfo* moveInfo );
void stack_addTrade( StackCtxt* stack, XP_U16 turn,
TrayTileSet* oldTiles, TrayTileSet* newTiles );
void stack_addAssign( StackCtxt* stack, XP_U16 turn, TrayTileSet* tiles );
XP_U16 stack_getNEntries( StackCtxt* stack );
XP_Bool stack_getNthEntry( StackCtxt* stack, XP_U16 n, StackEntry* entry );
XP_Bool stack_popEntry( StackCtxt* stack, StackEntry* entry );
void stack_redo( StackCtxt* stack );
#ifdef CPLUS
}
#endif
#endif

850
xwords4/common/mscore.c Normal file
View file

@ -0,0 +1,850 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
/*
* Copyright 1998-2001 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.
*/
#include "modelp.h"
#include "util.h"
#include "engine.h"
#include "game.h"
#include "LocalizedStrIncludes.h"
#ifdef CPLUS
extern "C" {
#endif
#define IMPOSSIBLY_LOW_PENALTY (-20*MAX_TRAY_TILES)
/****************************** prototypes ******************************/
static XP_Bool isLegalMove( ModelCtxt* model, MoveInfo* moves, XP_Bool silent );
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,
XP_Bool isHorizontal );
static XP_S16 checkScoreMove( ModelCtxt* model, XP_S16 turn,
EngineCtxt* engine, XWStreamCtxt* stream,
XP_Bool silent, WordNotifierInfo* notifyInfo );
static XP_U16 scoreWord( const ModelCtxt* model, MoveInfo* movei,
EngineCtxt* engine, XWStreamCtxt* stream,
WordNotifierInfo* notifyInfo, XP_UCHAR* mainWord );
/* for formatting when caller wants an explanation of the score. These live
in separate function called only when stream != NULL so that they'll have
as little impact as possible on the speed when the robot's looking for FAST
scoring */
typedef struct WordScoreFormatter {
DictionaryCtxt* dict;
XP_UCHAR fullBuf[80];
XP_UCHAR wordBuf[MAX_ROWS+1];
XP_U16 bufLen, nTiles;
XP_Bool firstPass;
} WordScoreFormatter;
static void wordScoreFormatterInit( WordScoreFormatter* fmtr,
DictionaryCtxt* dict );
static void wordScoreFormatterAddTile( WordScoreFormatter* fmtr, Tile tile,
XP_U16 tileMultiplier,
XP_Bool isBlank );
static void wordScoreFormatterFinish( WordScoreFormatter* fmtr, Tile* word,
XWStreamCtxt* stream, XP_UCHAR* mainWord );
static void formatWordScore( XWStreamCtxt* stream, XP_U16 wordScore,
XP_U16 moveMultiplier );
static void formatSummary( XWStreamCtxt* stream, const ModelCtxt* model,
XP_U16 score );
/* Calculate the score of the current move as it stands. Flag the score
* current so we won't have to do this again until something changes to
* invalidate the score.
*/
static void
scoreCurrentMove( ModelCtxt* model, XP_S16 turn, XWStreamCtxt* stream )
{
PlayerCtxt* player = &model->players[turn];
XP_S16 score;
XP_ASSERT( !player->curMoveValid );
/* recalc goes here */
score = checkScoreMove( model, turn, (EngineCtxt*)NULL, stream,
XP_TRUE, (WordNotifierInfo*)NULL );
XP_ASSERT( score >= 0 || score == ILLEGAL_MOVE_SCORE );
player->curMoveScore = score;
player->curMoveValid = XP_TRUE;
} /* scoreCurrentMove */
void
adjustScoreForUndone( ModelCtxt* model, MoveInfo* mi, XP_U16 turn )
{
XP_U16 moveScore;
PlayerCtxt* player = &model->players[turn];
if ( mi->nTiles == 0 ) {
moveScore = 0;
} else {
moveScore = figureMoveScore( model, mi, (EngineCtxt*)NULL,
(XWStreamCtxt*)NULL,
(WordNotifierInfo*)NULL, NULL );
}
player->score -= moveScore;
player->curMoveScore = 0;
player->curMoveValid = XP_TRUE;
} /* adjustScoreForUndone */
XP_Bool
model_checkMoveLegal( ModelCtxt* model, XP_S16 turn, XWStreamCtxt* stream,
WordNotifierInfo* notifyInfo )
{
XP_S16 score;
score = checkScoreMove( model, turn, (EngineCtxt*)NULL, stream, XP_FALSE,
notifyInfo );
return score != ILLEGAL_MOVE_SCORE;
} /* model_checkMoveLegal */
void
invalidateScore( ModelCtxt* model, XP_S16 turn )
{
model->players[turn].curMoveValid = XP_FALSE;
} /* invalidateScore */
XP_Bool
getCurrentMoveScoreIfLegal( ModelCtxt* model, XP_S16 turn,
XWStreamCtxt* stream, XP_S16* score )
{
PlayerCtxt* player = &model->players[turn];
if ( !player->curMoveValid ) {
scoreCurrentMove( model, turn, stream );
}
*score = player->curMoveScore;
return player->curMoveScore != ILLEGAL_MOVE_SCORE;
} /* getCurrentMoveScoreIfLegal */
XP_S16
model_getPlayerScore( ModelCtxt* model, XP_S16 player )
{
return model->players[player].score;
} /* model_getPlayerScore */
/* Based on the current scores based on tiles played and the tiles left in the
* tray, return an array giving the left-over-tile-adjusted scores for each
* player.
*/
void
model_figureFinalScores( ModelCtxt* model, XP_S16* finalScoresP,
XP_S16* tilePenalties )
{
XP_S16 i, j;
XP_S16 penalties[MAX_NUM_PLAYERS];
XP_S16 totalPenalty;
XP_U16 nPlayers = model->nPlayers;
XP_S16 firstDoneIndex = -1; /* not set unless FIRST_DONE_BONUS is set */
const TrayTileSet* tray;
PlayerCtxt* player;
DictionaryCtxt* dict = model_getDictionary( model );
CurGameInfo* gi = model->vol.gi;
XP_MEMSET( finalScoresP, 0, sizeof(*finalScoresP) * MAX_NUM_PLAYERS );
totalPenalty = 0;
for ( player = model->players, i = 0; i < nPlayers; ++player, ++i ) {
tray = model_getPlayerTiles( model, i );
penalties[i] = 0;
/* if there are no tiles left and this guy's the first done, make a
note of it in case he's to get a bonus. Note that this assumes
only one player can be out of tiles. */
if ( (tray->nTiles == 0) && (firstDoneIndex == -1) ) {
firstDoneIndex = i;
} else {
for ( j = tray->nTiles-1; j >= 0; --j ) {
penalties[i] += dict_getTileValue( dict, tray->tiles[j] );
}
}
/* include tiles in pending move too for the player whose turn it
is. */
for ( j = player->nPending - 1; j >= 0; --j ) {
Tile tile = player->pendingTiles[j].tile;
penalties[i] += dict_getTileValue(dict, (Tile)(tile & TILE_VALUE_MASK));
}
totalPenalty += penalties[i];
}
/* now total everybody's scores */
for ( i = 0; i < nPlayers; ++i ) {
XP_S16 score = model_getPlayerScore( model, i );
XP_S16 penalty;
penalty = (i == firstDoneIndex)? totalPenalty: -penalties[i];
finalScoresP[i] = score + penalty;
if ( !!tilePenalties ) {
tilePenalties[i] = penalty;
}
if ( gi->timerEnabled ) {
penalty = player_timePenalty( gi, i );
finalScoresP[i] -= penalty;
}
}
} /* model_figureFinalScores */
/* checkScoreMove.
* Negative score means illegal.
*/
static XP_S16
checkScoreMove( ModelCtxt* model, XP_S16 turn, EngineCtxt* engine,
XWStreamCtxt* stream, XP_Bool silent,
WordNotifierInfo* notifyInfo )
{
XP_Bool isHorizontal;
XP_S16 score = ILLEGAL_MOVE_SCORE;
PlayerCtxt* player = &model->players[turn];
XP_ASSERT( player->nPending <= MAX_TRAY_TILES );
if ( player->nPending == 0 ) {
score = 0;
if ( !!stream ) {
formatSummary( stream, model, 0 );
}
} else if ( tilesInLine( model, turn, &isHorizontal ) ) {
MoveInfo moveInfo;
normalizeMoves( model, turn, isHorizontal, &moveInfo );
if ( isLegalMove( model, &moveInfo, silent ) ) {
score = figureMoveScore( model, &moveInfo, engine, stream,
notifyInfo, NULL );
}
} else if ( !silent ) { /* tiles out of line */
util_userError( model->vol.util, ERR_TILES_NOT_IN_LINE );
}
return score;
} /* checkScoreMove */
XP_Bool
tilesInLine( ModelCtxt* model, XP_S16 turn, XP_Bool* isHorizontal )
{
XP_Bool xIsCommon, yIsCommon;
PlayerCtxt* player = &model->players[turn];
PendingTile* pt = player->pendingTiles;
XP_U16 commonX = pt->col;
XP_U16 commonY = pt->row;
short i;
xIsCommon = yIsCommon = XP_TRUE;
for ( i = 1; ++pt, i < player->nPending; ++i ) {
// test the boolean first in case it's already been made false
// (to save time)
if ( xIsCommon && (pt->col != commonX) ) {
xIsCommon = XP_FALSE;
}
if ( yIsCommon && (pt->row != commonY) ) {
yIsCommon = XP_FALSE;
}
}
*isHorizontal = !xIsCommon; // so will be vertical if both true
return xIsCommon || yIsCommon;
} /* tilesInLine */
void
normalizeMoves( ModelCtxt* model, XP_S16 turn, XP_Bool isHorizontal,
MoveInfo* moveInfo )
{
XP_S16 lowCol, i, j, thisCol; /* unsigned is a problem on palm */
PlayerCtxt* player = &model->players[turn];
XP_U16 nTiles = player->nPending;
XP_S16 lastTaken;
short lowIndex = 0;
PendingTile* pt;
moveInfo->isHorizontal = isHorizontal;
moveInfo->nTiles = (XP_U8)nTiles;
lastTaken = -1;
for ( i = 0; i < nTiles; ++i ) {
lowCol = 100; /* high enough to always be changed */
for ( j = 0; j < nTiles; ++j ) {
pt = &player->pendingTiles[j];
thisCol = isHorizontal? pt->col:pt->row;
if (thisCol < lowCol && thisCol > lastTaken ) {
lowCol = thisCol;
lowIndex = j;
}
}
/* we've found the next to transfer (4 bytes smaller without a temp
local ptr. */
pt = &player->pendingTiles[lowIndex];
lastTaken = lowCol;
moveInfo->tiles[i].varCoord = (XP_U8)lastTaken;
moveInfo->tiles[i].tile = pt->tile;
}
pt = &player->pendingTiles[0];
moveInfo->commonCoord = isHorizontal? pt->row:pt->col;
} /* normalizeMoves */
static XP_Bool
modelIsEmptyAt( const ModelCtxt* model, XP_U16 col, XP_U16 row )
{
Tile tile;
XP_Bool ignore;
XP_Bool found;
found = model_getTile( model, col, row, XP_FALSE, -1, &tile,
&ignore, &ignore, (XP_Bool*)NULL );
return !found;
} /* modelIsEmptyAt */
/*****************************************************************************
* Called only after moves have been confirmed to be in the same row, this
* function works whether the word is horizontal or vertical.
*
* For a move to be legal, either of the following must be true: a)
* if there are squares between those added in this move they must be occupied
* by previously placed pieces; or b) if these pieces are contiguous then at
* least one must touch a previously played piece (unless this is the first
* move) NOTE: this function does not verify that a newly placed piece is on an
* empty square. It's assumed that the calling code, most likely that which
* handles dragging the tiles, will have taken care of that.
****************************************************************************/
static XP_Bool
isLegalMove( ModelCtxt* model, MoveInfo* mInfo, XP_Bool silent )
{
XP_S16 high, low;
XP_S16 col, row;
XP_S16* incr;
XP_S16* commonP;
XP_U16 star_row = model_numRows(model) / 2;
XP_S16 nTiles = mInfo->nTiles;
MoveInfoTile* moves = mInfo->tiles;
XP_U16 commonCoord = mInfo->commonCoord;
/* First figure out what the low and high coordinates are in the dimension
not in common */
low = moves[0].varCoord;
high = moves[nTiles-1].varCoord;
XP_ASSERT( (nTiles == 1) || (low < high) );
if ( mInfo->isHorizontal ) {
row = commonCoord;
incr = &col;
commonP = &row;
} else {
col = commonCoord;
incr = &row;
commonP = &col;
}
/* are we looking at 2a above? */
if ( (high - low + 1) > nTiles ) {
/* there should be no empty tiles between the ends */
MoveInfoTile* newTile = moves; /* the newly placed tile to be checked */
for ( *incr = low; *incr <= high; ++*incr ) {
if ( newTile->varCoord == *incr ) {
++newTile;
} else if ( modelIsEmptyAt( model, col, row ) ) {
if ( !silent ) {
util_userError( model->vol.util, ERR_NO_EMPTIES_IN_TURN );
}
return XP_FALSE;
}
}
XP_ASSERT( newTile == &moves[nTiles] );
return XP_TRUE;
/* else we're looking at 2b: make sure there's some contact UNLESS
this is the first move */
} else {
/* check the ends first */
if ( low != 0 ) {
*incr = low - 1;
if ( !modelIsEmptyAt( model, col, row ) ) {
return XP_TRUE;
}
}
if ( high != MAX_ROWS-1 ) {
*incr = high+1;
if ( !modelIsEmptyAt( model, col, row ) ) {
return XP_TRUE;
}
}
/* now the neighbors above... */
if ( commonCoord != 0 ) {
--*commonP; /* decrement whatever's not being looped over */
for ( *incr = low; *incr <= high; ++*incr ) {
if ( !modelIsEmptyAt( model, col, row ) ) {
return XP_TRUE;
}
}
++*commonP;/* undo the decrement */
}
/* ...and below */
if ( commonCoord <= MAX_ROWS - 1 ) {
++*commonP;
for ( *incr = low; *incr <= high; ++*incr ) {
if ( !modelIsEmptyAt( model, col, row ) ) {
return XP_TRUE;
}
}
--*commonP;
}
/* if we got here, it's illegal unless this is the first move -- i.e.
unless one of the tiles is on the STAR */
if ( ( commonCoord == star_row) &&
( low <= star_row) && ( high >= star_row ) ) {
if ( nTiles > 1 ) {
return XP_TRUE;
} else {
if ( !silent ) {
util_userError(model->vol.util, ERR_TWO_TILES_FIRST_MOVE);
}
return XP_FALSE;
}
} else {
if ( !silent ) {
util_userError( model->vol.util, ERR_TILES_MUST_CONTACT );
}
return XP_FALSE;
}
}
XP_ASSERT( XP_FALSE );
return XP_FALSE; /* keep compiler happy */
} /* isLegalMove */
XP_U16
figureMoveScore( const ModelCtxt* model, MoveInfo* moveInfo,
EngineCtxt* engine, XWStreamCtxt* stream,
WordNotifierInfo* notifyInfo, XP_UCHAR* mainWord )
{
XP_U16 col, row;
XP_U16* incr;
XP_U16 oneScore;
XP_U16 score = 0;
short i;
short moveMultiplier = 1;
short multipliers[MAX_TRAY_TILES];
MoveInfo tmpMI;
MoveInfoTile* tiles;
XP_U16 nTiles = moveInfo->nTiles;
XP_ASSERT( nTiles > 0 );
if ( moveInfo->isHorizontal ) {
row = moveInfo->commonCoord;
incr = &col;
} else {
col = moveInfo->commonCoord;
incr = &row;
}
for ( i = 0; i < nTiles; ++i ) {
*incr = moveInfo->tiles[i].varCoord;
moveMultiplier *= multipliers[i] = word_multiplier( model, col, row );
}
oneScore = scoreWord( model, moveInfo, (EngineCtxt*)NULL, stream,
notifyInfo, mainWord );
if ( !!stream ) {
formatWordScore( stream, oneScore, moveMultiplier );
}
oneScore *= moveMultiplier;
score += oneScore;
/* set up the invariant slots in tmpMI */
tmpMI.isHorizontal = !moveInfo->isHorizontal;
tmpMI.nTiles = 1;
tmpMI.tiles[0].varCoord = moveInfo->commonCoord;
for ( i = 0, tiles = moveInfo->tiles; i < nTiles; ++i, ++tiles ) {
/* Moves using only one tile will sometimes score only in the
crosscheck direction. Score may still be 0 after the call to
scoreWord above. Keep trying to get some text in mainWord until
something's been scored. */
if ( score > 0 ) {
mainWord = NULL;
}
tmpMI.commonCoord = tiles->varCoord;
tmpMI.tiles[0].tile = tiles->tile;
oneScore = scoreWord( model, &tmpMI, engine, stream,
notifyInfo, mainWord );
if ( !!stream ) {
formatWordScore( stream, oneScore, multipliers[i] );
}
oneScore *= multipliers[i];
score += oneScore;
}
/* did he use all 7 tiles? */
if ( nTiles == MAX_TRAY_TILES ) {
score += EMPTIED_TRAY_BONUS;
if ( !!stream ) {
const XP_UCHAR* bstr = util_getUserString( model->vol.util,
STR_BONUS_ALL );
stream_putString( stream, bstr );
}
}
if ( !!stream ) {
formatSummary( stream, model, score );
}
return score;
} /* figureMoveScore */
static XP_U16
word_multiplier( const ModelCtxt* model, XP_U16 col, XP_U16 row )
{
XWBonusType bonus = util_getSquareBonus( model->vol.util, model, col, row );
switch ( bonus ) {
case BONUS_DOUBLE_WORD:
return 2;
case BONUS_TRIPLE_WORD:
return 3;
default:
return 1;
}
} /* word_multiplier */
static XP_U16
tile_multiplier( const ModelCtxt* model, XP_U16 col, XP_U16 row )
{
XWBonusType bonus = util_getSquareBonus( model->vol.util, model,
col, row );
switch ( bonus ) {
case BONUS_DOUBLE_LETTER:
return 2;
case BONUS_TRIPLE_LETTER:
return 3;
default:
return 1;
}
} /* tile_multiplier */
static XP_U16
scoreWord( const ModelCtxt* model, MoveInfo* movei, /* new tiles */
EngineCtxt* engine,/* for crosswise caching */
XWStreamCtxt* stream,
WordNotifierInfo* notifyInfo,
XP_UCHAR* mainWord )
{
XP_U16 tileMultiplier;
XP_U16 restScore = 0;
XP_U16 scoreFromCache;
XP_U16 thisTileValue;
XP_U16 nTiles = movei->nTiles;
Tile tile;
XP_U16 start, end;
XP_U16* incr;
XP_U16 col, row;
MoveInfoTile* tiles = movei->tiles;
XP_U16 firstCoord = tiles->varCoord;
DictionaryCtxt* dict = model->vol.dict;
if ( movei->isHorizontal ) {
row = movei->commonCoord;
incr = &col;
} else {
col = movei->commonCoord;
incr = &row;
}
*incr = tiles[nTiles-1].varCoord;
end = find_end( model, col, row, movei->isHorizontal );
/* This is the value *incr needs to start with below */
*incr = tiles[0].varCoord;
start = find_start( model, col, row, movei->isHorizontal );
if ( (end - start) >= 1 ) { /* one-letter word: score 0 */
WordScoreFormatter fmtr;
if ( !!stream || !!mainWord ) {
wordScoreFormatterInit( &fmtr, dict );
}
if ( IS_BLANK(tiles->tile) ) {
tile = dict_getBlankTile( dict );
} else {
tile = tiles->tile & TILE_VALUE_MASK;
}
thisTileValue = dict_getTileValue( dict, tile );
XP_ASSERT( *incr == tiles[0].varCoord );
thisTileValue *= tile_multiplier( model, col, row );
XP_ASSERT( engine == NULL || nTiles == 1 );
if ( engine != NULL ) {
XP_ASSERT( nTiles==1 );
scoreFromCache = engine_getScoreCache( engine,
movei->commonCoord );
}
/* for a while, at least, calculate and use the cached crosscheck score
* each time through in the debug case */
if ( 0 ) { /* makes keeping parens balanced easier */
#ifdef DEBUG
} else if ( 1 ) {
#else
} else if ( engine == NULL ) {
#endif
Tile checkWordBuf[MAX_ROWS];
Tile* curTile = checkWordBuf;
for ( *incr = start; *incr <= end; ++*incr ) {
XP_U16 tileScore = 0;
XP_Bool isBlank;
/* a new move? */
if ( (nTiles > 0) && (*incr == tiles->varCoord) ) {
tile = tiles->tile & TILE_VALUE_MASK;
isBlank = IS_BLANK(tiles->tile);
/* don't call localGetBlankTile when in silent (robot called)
* mode, as the blank won't be known there. (Assert will
* fail.) */
tileMultiplier = tile_multiplier( model, col, row );
++tiles;
--nTiles;
} else { /* placed on the board before this move */
XP_Bool ignore;
tileMultiplier = 1;
(void)model_getTile( model, col, row, XP_FALSE, -1, &tile,
&isBlank, &ignore, (XP_Bool*)NULL );
XP_ASSERT( (tile & TILE_VALUE_MASK) == tile );
}
*curTile++ = tile; /* save in case we're checking phonies */
if ( !!stream || !!mainWord ) {
wordScoreFormatterAddTile( &fmtr, tile, tileMultiplier,
isBlank );
}
if ( isBlank ) {
tile = dict_getBlankTile( dict );
}
tileScore = dict_getTileValue( dict, tile );
/* The first tile in the move is already accounted for in
thisTileValue, so skip it here. */
if ( *incr != firstCoord ) {
restScore += tileScore * tileMultiplier;
}
} /* for each tile */
if ( !!notifyInfo ) {
XP_U16 len = curTile - checkWordBuf;
XP_Bool legal = engine_check( dict, checkWordBuf, len );
if ( !legal ) {
XP_UCHAR buf[(MAX_ROWS*2)+1];
dict_tilesToString( dict, checkWordBuf, len, buf,
sizeof(buf) );
(*notifyInfo->proc)( buf, notifyInfo->closure );
}
}
if ( !!stream || !!mainWord ) {
wordScoreFormatterFinish( &fmtr, checkWordBuf, stream,
mainWord );
}
#ifdef DEBUG
} else if ( engine != NULL ) {
#else
} else { /* non-debug case we know it's non-null */
#endif
XP_ASSERT( nTiles==1 );
XP_ASSERT( engine_getScoreCache( engine, movei->commonCoord )
== restScore );
restScore = engine_getScoreCache( engine, movei->commonCoord );
}
restScore += thisTileValue;
}
return restScore;
} /* scoreWord */
static XP_U16
find_start( const ModelCtxt* model, XP_U16 col, XP_U16 row,
XP_Bool isHorizontal )
{
XP_U16* incr = isHorizontal? &col: &row;
for ( ; ; ) {
if ( *incr == 0 ) {
return 0;
} else {
--*incr;
if ( modelIsEmptyAt( model, col, row ) ) {
return *incr + 1;
}
}
}
} /* find_start */
static XP_U16
find_end( const ModelCtxt* model, XP_U16 col, XP_U16 row,
XP_Bool isHorizontal )
{
XP_U16* incr = isHorizontal? &col: &row;
XP_U16 limit = isHorizontal? MAX_COLS-1:MAX_ROWS-1;
XP_U16 lastGood = *incr;
XP_ASSERT( col < MAX_COLS );
XP_ASSERT( row < MAX_ROWS );
for ( ; ; ) {
XP_ASSERT( *incr <= limit );
if ( *incr == limit ) {
return limit;
} else {
++*incr;
if ( modelIsEmptyAt( model, col, row ) ) {
return lastGood;
} else {
lastGood = *incr;
}
}
}
} /* find_end */
static void
wordScoreFormatterInit( WordScoreFormatter* fmtr, DictionaryCtxt* dict )
{
XP_MEMSET( fmtr, 0, sizeof(*fmtr) );
fmtr->dict = dict;
fmtr->firstPass = XP_TRUE;
} /* initWordScoreFormatter */
static void
wordScoreFormatterAddTile( WordScoreFormatter* fmtr, Tile tile,
XP_U16 tileMultiplier, XP_Bool isBlank )
{
XP_UCHAR buf[4];
XP_UCHAR* fullBufPtr;
XP_UCHAR* prefix;
XP_U16 tileScore;
++fmtr->nTiles;
dict_tilesToString( fmtr->dict, &tile, 1, buf, sizeof(buf) );
XP_ASSERT( XP_STRLEN(fmtr->wordBuf) + XP_STRLEN(buf) < sizeof(fmtr->wordBuf) );
XP_STRCAT( fmtr->wordBuf, buf );
if ( isBlank ) {
tile = dict_getBlankTile( fmtr->dict );
}
tileScore = dict_getTileValue( fmtr->dict, tile );
if ( fmtr->firstPass ) {
prefix = (XP_UCHAR*)" [";
fmtr->firstPass = XP_FALSE;
} else {
prefix = (XP_UCHAR*)"+";
}
fullBufPtr = fmtr->fullBuf + fmtr->bufLen;
fmtr->bufLen +=
XP_SNPRINTF( fullBufPtr,
(XP_U16)(sizeof(fmtr->fullBuf) - fmtr->bufLen),
(XP_UCHAR*)(tileMultiplier > 1?"%s(%dx%d)":"%s%d"),
prefix, tileScore, tileMultiplier );
XP_ASSERT( XP_STRLEN(fmtr->fullBuf) == fmtr->bufLen );
XP_ASSERT( fmtr->bufLen < sizeof(fmtr->fullBuf) );
} /* wordScoreFormatterAddTile */
static void
wordScoreFormatterFinish( WordScoreFormatter* fmtr, Tile* word, XWStreamCtxt* stream,
XP_UCHAR* mainWord )
{
XP_UCHAR buf[(MAX_ROWS*2)+1];
XP_U16 len = dict_tilesToString( fmtr->dict, word, fmtr->nTiles,
buf, sizeof(buf) );
if ( !!stream ) {
stream_putBytes( stream, buf, len );
stream_putBytes( stream, fmtr->fullBuf, fmtr->bufLen );
stream_putU8( stream, ']' );
}
if ( !!mainWord ) {
XP_MEMCPY( mainWord, fmtr->wordBuf, XP_STRLEN(fmtr->wordBuf) + 1 );
}
} /* wordScoreFormatterFinish */
static void
formatWordScore( XWStreamCtxt* stream, XP_U16 wordScore,
XP_U16 moveMultiplier )
{
if ( wordScore > 0 ) {
XP_U16 multipliedScore = wordScore * moveMultiplier;
XP_UCHAR tmpBuf[40];
if ( moveMultiplier > 1 ) {
XP_SNPRINTF( tmpBuf, sizeof(tmpBuf),
(XP_UCHAR*)" => %d x %d = %d" XP_CR,
wordScore, moveMultiplier, multipliedScore );
} else {
XP_SNPRINTF( tmpBuf, sizeof(tmpBuf), (XP_UCHAR*)" = %d" XP_CR,
multipliedScore );
}
XP_ASSERT( XP_STRLEN(tmpBuf) < sizeof(tmpBuf) );
stream_putString( stream, tmpBuf );
}
} /* formatWordScore */
static void
formatSummary( XWStreamCtxt* stream, const ModelCtxt* model, XP_U16 score )
{
XP_UCHAR buf[60];
XP_SNPRINTF(buf, sizeof(buf),
util_getUserString(model->vol.util, STRD_TURN_SCORE),
score);
XP_ASSERT( XP_STRLEN(buf) < sizeof(buf) );
stream_putString( stream, buf );
} /* formatSummary */
#ifdef CPLUS
}
#endif

581
xwords4/common/nwgamest.c Normal file
View file

@ -0,0 +1,581 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
/*
* Copyright 1997 - 2007 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.
*/
#include "nwgamest.h"
#include "strutils.h"
#include "LocalizedStrIncludes.h"
#ifdef CPLUS
extern "C" {
#endif
#define NG_NUM_COLS ((XP_U16)(NG_COL_PASSWD+1))
struct NewGameCtx {
NewGameEnableColProc enableColProc;
NewGameEnableAttrProc enableAttrProc;
NewGameSetColProc setColProc;
NewGameGetColProc getColProc;
NewGameSetAttrProc setAttrProc;
XW_UtilCtxt* util;
void* closure;
/* Palm needs to store cleartext passwords separately in order to
store '***' in the visible field */
XP_TriEnable enabled[NG_NUM_COLS][MAX_NUM_PLAYERS];
XP_U16 nPlayersShown; /* real nPlayers lives in gi */
XP_U16 nPlayersTotal; /* used only until changedNPlayers set */
XP_U16 nLocalPlayers; /* not changed except in newg_load */
DeviceRole role;
XP_Bool isNewGame;
XP_Bool changedNPlayers;
XP_TriEnable juggleEnabled;
MPSLOT
};
static void enableOne( NewGameCtx* ngc, XP_U16 player, NewGameColumn col,
XP_TriEnable enable, XP_Bool force );
static void adjustAllRows( NewGameCtx* ngc, XP_Bool force );
static void adjustOneRow( NewGameCtx* ngc, XP_U16 player, XP_Bool force );
static void setRoleStrings( NewGameCtx* ngc );
static void considerEnableJuggle( NewGameCtx* ngc );
static void storePlayer( NewGameCtx* ngc, XP_U16 player, LocalPlayer* lp );
static void loadPlayer( NewGameCtx* ngc, XP_U16 player,
const LocalPlayer* lp );
#ifndef XWFEATURE_STANDALONE_ONLY
static XP_Bool changeRole( NewGameCtx* ngc, DeviceRole role );
static XP_Bool checkConsistent( NewGameCtx* ngc, XP_Bool warnUser );
#else
# define checkConsistent( ngc, warnUser ) XP_TRUE
#endif
NewGameCtx*
newg_make( MPFORMAL XP_Bool isNewGame,
XW_UtilCtxt* util,
NewGameEnableColProc enableColProc,
NewGameEnableAttrProc enableAttrProc,
NewGameGetColProc getColProc, NewGameSetColProc setColProc,
NewGameSetAttrProc setAttrProc, void* closure )
{
NewGameCtx* result = XP_MALLOC( mpool, sizeof(*result) );
XP_MEMSET( result, 0, sizeof(*result) );
result->enableColProc = enableColProc;
result->enableAttrProc = enableAttrProc;
result->setColProc = setColProc;
result->getColProc = getColProc;
result->setAttrProc = setAttrProc;
result->closure = closure;
result->isNewGame = isNewGame;
result->util = util;
MPASSIGN(result->mpool, mpool);
return result;
} /* newg_make */
void
newg_destroy( NewGameCtx* ngc )
{
XP_FREE( ngc->mpool, ngc );
} /* newg_destroy */
void
newg_load( NewGameCtx* ngc, const CurGameInfo* gi )
{
void* closure = ngc->closure;
NGValue value;
XP_U16 nPlayers, nLoaded;
XP_S16 ii, jj;
DeviceRole role;
XP_Bool localOnly;
XP_Bool shown[MAX_NUM_PLAYERS] = { XP_FALSE, XP_FALSE, XP_FALSE, XP_FALSE};
ngc->juggleEnabled = TRI_ENAB_NONE;
for ( ii = 0; ii < NG_NUM_COLS; ++ii ) {
for ( jj = 0; jj < MAX_NUM_PLAYERS; ++jj ) {
ngc->enabled[ii][jj] = TRI_ENAB_NONE;
}
}
ngc->role = role = gi->serverRole;
localOnly = role == SERVER_ISCLIENT && ngc->isNewGame;
#ifndef XWFEATURE_STANDALONE_ONLY
value.ng_role = role;
(*ngc->setAttrProc)( closure, NG_ATTR_ROLE, value );
(*ngc->enableAttrProc)( closure, NG_ATTR_ROLE, ngc->isNewGame?
TRI_ENAB_ENABLED : TRI_ENAB_DISABLED );
#endif
nPlayers = gi->nPlayers;
ngc->nPlayersTotal = nPlayers;
#ifndef XWFEATURE_STANDALONE_ONLY
for ( ii = nPlayers - 1; ii >= 0; --ii ) {
if ( gi->players[ii].isLocal ) {
++ngc->nLocalPlayers;
}
}
#endif
if ( localOnly ) {
nPlayers = ngc->nLocalPlayers;
}
ngc->nPlayersShown = nPlayers;
value.ng_u16 = ngc->nPlayersShown;
(*ngc->setAttrProc)( closure, NG_ATTR_NPLAYERS, value );
(*ngc->enableAttrProc)( closure, NG_ATTR_NPLAYERS, ngc->isNewGame?
TRI_ENAB_ENABLED : TRI_ENAB_DISABLED );
setRoleStrings( ngc );
considerEnableJuggle( ngc );
/* Load local players first */
nLoaded = 0;
do {
for ( ii = 0; ii < MAX_NUM_PLAYERS; ++ii ) {
if ( !shown[ii] ) {
const LocalPlayer* lp = &gi->players[ii];
if ( !localOnly
|| (lp->isLocal && (nLoaded < ngc->nLocalPlayers)) ) {
shown[ii] = XP_TRUE;
loadPlayer( ngc, nLoaded++, lp );
}
}
}
XP_ASSERT( localOnly || nLoaded == MAX_NUM_PLAYERS );
localOnly = XP_FALSE; /* for second pass */
} while ( nLoaded < MAX_NUM_PLAYERS );
adjustAllRows( ngc, XP_TRUE );
} /* newg_load */
typedef struct NGCopyClosure {
XP_U16 player;
NewGameColumn col;
NewGameCtx* ngc;
LocalPlayer* lp;
} NGCopyClosure;
static void
cpToLP( NGValue value, const void* cbClosure )
{
NGCopyClosure* cpcl = (NGCopyClosure*)cbClosure;
LocalPlayer* lp = cpcl->lp;
XP_UCHAR** strAddr = NULL;
switch ( cpcl->col ) {
#ifndef XWFEATURE_STANDALONE_ONLY
case NG_COL_REMOTE:
lp->isLocal = !value.ng_bool;
break;
#endif
case NG_COL_NAME:
strAddr = &lp->name;
break;
case NG_COL_PASSWD:
strAddr = &lp->password;
break;
case NG_COL_ROBOT:
lp->isRobot = value.ng_bool;
break;
}
if ( !!strAddr ) {
/* This is leaking!!! But doesn't leak if am playing via IR, at least
in the simulator. */
replaceStringIfDifferent( cpcl->ngc->mpool, strAddr,
value.ng_cp );
}
} /* cpToLP */
XP_Bool
newg_store( NewGameCtx* ngc, CurGameInfo* gi,
XP_Bool XP_UNUSED_STANDALONE(warn) )
{
XP_U16 player;
XP_Bool consistent = checkConsistent( ngc, warn );
if ( consistent ) {
gi->nPlayers = ngc->nPlayersShown;
#ifndef XWFEATURE_STANDALONE_ONLY
gi->serverRole = ngc->role;
#endif
for ( player = 0; player < MAX_NUM_PLAYERS; ++player ) {
storePlayer( ngc, player, &gi->players[player] );
}
}
return consistent;
} /* newg_store */
void
newg_colChanged( NewGameCtx* ngc, XP_U16 player )
{
/* Sometimes we'll get this notification for inactive rows, e.g. when
setting default values. */
if ( player < ngc->nPlayersShown ) {
adjustOneRow( ngc, player, XP_FALSE );
}
}
void
newg_attrChanged( NewGameCtx* ngc, NewGameAttr attr, NGValue value )
{
XP_Bool changed = XP_FALSE;
if ( attr == NG_ATTR_NPLAYERS ) {
if ( ngc->nPlayersShown != value.ng_u16 ) {
ngc->nPlayersShown = value.ng_u16;
ngc->changedNPlayers = XP_TRUE;
changed = XP_TRUE;
}
#ifndef XWFEATURE_STANDALONE_ONLY
} else if ( NG_ATTR_ROLE == attr ) {
changed = changeRole( ngc, value.ng_role );
#endif
} else {
XP_ASSERT( 0 );
}
if ( changed ) {
considerEnableJuggle( ngc );
adjustAllRows( ngc, XP_FALSE );
}
}
typedef struct DeepValue {
NGValue value;
NewGameColumn col;
MPSLOT
} DeepValue;
static void
deepCopy( NGValue value, const void* closure )
{
DeepValue* dvp = (DeepValue*)closure;
switch ( dvp->col ) {
case NG_COL_ROBOT:
#ifndef XWFEATURE_STANDALONE_ONLY
case NG_COL_REMOTE:
#endif
dvp->value.ng_bool = value.ng_bool;
break;
case NG_COL_NAME:
case NG_COL_PASSWD:
dvp->value.ng_cp = copyString( dvp->mpool, value.ng_cp );
break;
}
}
XP_Bool
newg_juggle( NewGameCtx* ngc )
{
XP_Bool changed = XP_FALSE;
XP_U16 nPlayers = ngc->nPlayersShown;
XP_ASSERT( ngc->isNewGame );
if ( nPlayers > 1 ) {
LocalPlayer tmpPlayers[MAX_NUM_PLAYERS];
XP_U16 pos[MAX_NUM_PLAYERS];
XP_U16 player;
/* Get a randomly juggled array of numbers 0..nPlayers-1. Then the
number at pos[n] inicates where the entry currently at n should
be. */
changed = randIntArray( pos, nPlayers );
if ( changed ) {
/* Deep-copy off to tmp storage. But skip lines that won't be moved
in the juggle. */
XP_MEMSET( &tmpPlayers, 0, sizeof(tmpPlayers) );
for ( player = 0; player < nPlayers; ++player ) {
if ( player != pos[player] ) {
storePlayer( ngc, player, &tmpPlayers[player] );
}
}
for ( player = 0; player < nPlayers; ++player ) {
if ( player != pos[player] ) {
LocalPlayer* lp = &tmpPlayers[player];
XP_U16 dest = pos[player];
loadPlayer( ngc, dest, lp );
if ( !!lp->name ) {
XP_FREE( ngc->mpool, lp->name );
}
if ( !!lp->password ) {
XP_FREE( ngc->mpool, lp->password );
}
adjustOneRow( ngc, dest, XP_FALSE );
}
}
}
}
return changed;
} /* newg_juggle */
#ifndef XWFEATURE_STANDALONE_ONLY
static XP_Bool
checkConsistent( NewGameCtx* ngc, XP_Bool warnUser )
{
XP_Bool consistent;
XP_U16 i;
/* If ISSERVER, make sure there's at least one non-local player. */
consistent = ngc->role != SERVER_ISSERVER;
for ( i = 0; !consistent && i < ngc->nPlayersShown; ++i ) {
DeepValue dValue;
dValue.col = NG_COL_REMOTE;
(*ngc->getColProc)( ngc->closure, i, NG_COL_REMOTE,
deepCopy, &dValue );
if ( dValue.value.ng_bool ) {
consistent = XP_TRUE;
}
}
if ( !consistent && warnUser ) {
util_userError( ngc->util, ERR_REG_SERVER_SANS_REMOTE );
}
/* Add other consistency checks, and error messages, here. */
return consistent;
} /* checkConsistent */
#endif
static void
enableOne( NewGameCtx* ngc, XP_U16 player, NewGameColumn col,
XP_TriEnable enable, XP_Bool force )
{
XP_TriEnable* esp = &ngc->enabled[col][player];
if ( force || (*esp != enable) ) {
(*ngc->enableColProc)( ngc->closure, player, col, enable );
}
*esp = enable;
} /* enableOne */
static void
adjustAllRows( NewGameCtx* ngc, XP_Bool force )
{
XP_U16 player;
for ( player = 0; player < MAX_NUM_PLAYERS; ++player ) {
adjustOneRow( ngc, player, force );
}
} /* adjustAllRows */
static void
adjustOneRow( NewGameCtx* ngc, XP_U16 player, XP_Bool force )
{
XP_TriEnable enable[NG_NUM_COLS];
NewGameColumn col;
XP_Bool isLocal = XP_TRUE;
XP_Bool isNewGame = ngc->isNewGame;
DeviceRole role = ngc->role;
DeepValue dValue;
for ( col = 0; col < NG_NUM_COLS; ++col ) {
enable[col] = TRI_ENAB_HIDDEN;
}
/* If there aren't this many players, all are disabled */
if ( player >= ngc->nPlayersShown ) {
/* do nothing: all are hidden above */
} else {
#ifndef XWFEATURE_STANDALONE_ONLY
/* If standalone or client, remote is hidden. If server but not
new game, it's disabled */
if ( (role == SERVER_ISSERVER )
|| (role == SERVER_ISCLIENT && !isNewGame ) ) {
if ( isNewGame ) {
enable[NG_COL_REMOTE] = TRI_ENAB_ENABLED;
} else {
enable[NG_COL_REMOTE] = TRI_ENAB_DISABLED;
}
dValue.col = NG_COL_REMOTE;
(*ngc->getColProc)( ngc->closure, player, NG_COL_REMOTE,
deepCopy, &dValue );
isLocal = !dValue.value.ng_bool;
}
#endif
/* If remote is enabled and set, then if it's a new game all else is
hidden. But if it's not a new game, they're disabled. Password is
always hidden if robot is set. */
if ( isLocal ) {
XP_TriEnable tmp;
/* No changing name or robotness since they're sent to remote
host. */
tmp = (isNewGame || role == SERVER_STANDALONE)?
TRI_ENAB_ENABLED:TRI_ENAB_DISABLED;
enable[NG_COL_NAME] = tmp;
enable[NG_COL_ROBOT] = tmp;
/* Password and game info (the not isNewGame case): passwords are
not transmitted: they're local only. There's no harm in
allowing local players to change them. So passwords should be
enabled whenever it's not a robot regardless of both isNewGame
and role. */
dValue.col = NG_COL_ROBOT;
(*ngc->getColProc)( ngc->closure, player, NG_COL_ROBOT, deepCopy,
&dValue );
if ( !dValue.value.ng_bool ) {
/* If it's a robot, leave it hidden */
enable[NG_COL_PASSWD] = TRI_ENAB_ENABLED;
}
} else {
if ( isNewGame ) {
/* leave 'em hidden */
} else {
enable[NG_COL_NAME] = TRI_ENAB_DISABLED;
enable[NG_COL_ROBOT] = TRI_ENAB_DISABLED;
/* leave passwd hidden */
}
}
}
for ( col = 0; col < NG_NUM_COLS; ++col ) {
enableOne( ngc, player, col, enable[col], force );
}
} /* adjustOneRow */
/* changeRole. When role changes, number of players displayed, and which
* players, may change. Host shows all players (up to nPlayers). Guest shows
* only local players, but if role changes should show the rest. Change from
* Host or Standalone to guest should reduce the number shown.
*
* Here's the fun part: what happens when user changes nPlayers, then changes
* role? Say we're a guest with one player. User makes it two, than makes us
* host. Do we pull in a new player? No. Let's not change any of this stuff
* ONCE USER'S CHANGED NPLAYERS. Goal is to prevent his having to do that for
* the most common case, which is playing again with the same players. In
* that case changing role then back again should not lose/change data.
*/
#ifndef XWFEATURE_STANDALONE_ONLY
static XP_Bool
changeRole( NewGameCtx* ngc, DeviceRole newRole )
{
DeviceRole oldRole = ngc->role;
XP_Bool changing = oldRole != newRole;
if ( changing ) {
if ( !ngc->changedNPlayers ) {
NGValue value;
if ( newRole == SERVER_ISCLIENT ) {
value.ng_u16 = ngc->nLocalPlayers;
} else {
value.ng_u16 = ngc->nPlayersTotal;
}
if ( value.ng_u16 != ngc->nPlayersShown ) {
ngc->nPlayersShown = value.ng_u16;
(*ngc->setAttrProc)( ngc->closure, NG_ATTR_NPLAYERS, value );
}
}
ngc->role = newRole;
setRoleStrings( ngc );
}
return changing;
}
#endif
static void
setRoleStrings( NewGameCtx* ngc )
{
XP_U16 strID;
NGValue value;
void* closure = ngc->closure;
/* Tell client to set/change players label text, and also to add remote
checkbox column header if required. */
#ifndef XWFEATURE_STANDALONE_ONLY
(*ngc->enableAttrProc)( closure, NG_ATTR_REMHEADER,
( (ngc->role == SERVER_ISSERVER)
|| (!ngc->isNewGame
&& (ngc->role != SERVER_STANDALONE)) )?
TRI_ENAB_ENABLED : TRI_ENAB_HIDDEN );
#endif
if ( 0 ) {
#ifndef XWFEATURE_STANDALONE_ONLY
} else if ( ngc->role == SERVER_ISCLIENT && ngc->isNewGame ) {
strID = STR_LOCALPLAYERS;
#endif
} else {
strID = STR_TOTALPLAYERS;
}
value.ng_cp = util_getUserString( ngc->util, strID );
(*ngc->setAttrProc)( closure, NG_ATTR_NPLAYHEADER, value );
} /* setRoleStrings */
static void
considerEnableJuggle( NewGameCtx* ngc )
{
XP_TriEnable newEnable;
newEnable = (ngc->isNewGame && ngc->nPlayersShown > 1)?
TRI_ENAB_ENABLED : TRI_ENAB_HIDDEN;
if ( newEnable != ngc->juggleEnabled ) {
(*ngc->enableAttrProc)( ngc->closure, NG_ATTR_CANJUGGLE, newEnable );
ngc->juggleEnabled = newEnable;
}
} /* considerEnableJuggle */
static void
storePlayer( NewGameCtx* ngc, XP_U16 player, LocalPlayer* lp )
{
void* closure = ngc->closure;
NGCopyClosure cpcl;
cpcl.player = player;
cpcl.ngc = ngc;
cpcl.lp = lp;
for ( cpcl.col = 0; cpcl.col < NG_NUM_COLS; ++cpcl.col ) {
(*ngc->getColProc)( closure, cpcl.player, cpcl.col,
cpToLP, &cpcl );
}
}
static void
loadPlayer( NewGameCtx* ngc, XP_U16 player, const LocalPlayer* lp )
{
NGValue value;
void* closure = ngc->closure;
#ifndef XWFEATURE_STANDALONE_ONLY
value.ng_bool = !lp->isLocal;
(*ngc->setColProc)(closure, player, NG_COL_REMOTE, value );
#endif
value.ng_cp = lp->name;
(*ngc->setColProc)(closure, player, NG_COL_NAME, value );
value.ng_cp = lp->password;
(*ngc->setColProc)(closure, player, NG_COL_PASSWD, value );
value.ng_bool = lp->isRobot;
(*ngc->setColProc)(closure, player, NG_COL_ROBOT, value );
}
#ifdef CPLUS
}
#endif

115
xwords4/common/nwgamest.h Normal file
View file

@ -0,0 +1,115 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
/*
* 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
* 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 _NWGAMEST_H_
#define _NWGAMEST_H_
/* The new game/game info dialog is complicated, especially in non
* XWFEATURE_STANDALONE_ONLY case. The number of rows must be changed
* as the number of players changes, and whether the password field is
* enabled changes with the robot status etc. This file encapsulates
* all that logic, reducint the platform's role to reporting UI events
* and reflecting state changes, as reported by callbacks, in the
* platform's widgets.
*/
#include "comtypes.h"
EXTERN_C_START
#include "mempool.h"
#include "server.h"
#include "comms.h"
#include "util.h"
#include "game.h"
typedef struct NewGameCtx NewGameCtx;
typedef enum {
#ifndef XWFEATURE_STANDALONE_ONLY
NG_COL_REMOTE,
#endif
NG_COL_NAME
,NG_COL_ROBOT
,NG_COL_PASSWD
} NewGameColumn;
typedef enum {
#ifndef XWFEATURE_STANDALONE_ONLY
NG_ATTR_ROLE,
NG_ATTR_REMHEADER,
#endif
NG_ATTR_NPLAYERS
,NG_ATTR_NPLAYHEADER
,NG_ATTR_CANJUGGLE
} NewGameAttr;
typedef union NGValue {
const XP_UCHAR* ng_cp;
XP_U16 ng_u16;
XP_Bool ng_bool;
DeviceRole ng_role;
} NGValue;
/* Enable or disable (show or hide) controls */
typedef void (*NewGameEnableColProc)( void* closure, XP_U16 player,
NewGameColumn col, XP_TriEnable enable );
typedef void (*NewGameEnableAttrProc)( void* closure, NewGameAttr attr,
XP_TriEnable enable );
/* Get the contents of a control. Type of param "value" is either
boolean or char* */
typedef void (*NgCpCallbk)( NGValue value, const void* cpClosure );
typedef void (*NewGameGetColProc)( void* closure, XP_U16 player,
NewGameColumn col,
NgCpCallbk cpcb, const void* cbClosure );
/* Set the contents of a control. Type of param "value" is either
boolean or char* */
typedef void (*NewGameSetColProc)( void* closure, XP_U16 player,
NewGameColumn col, const NGValue value );
typedef void (*NewGameSetAttrProc)(void* closure, NewGameAttr attr,
const NGValue value );
NewGameCtx* newg_make( MPFORMAL XP_Bool isNewGame,
XW_UtilCtxt* util,
NewGameEnableColProc enableColProc,
NewGameEnableAttrProc enableAttrProc,
NewGameGetColProc getColProc,
NewGameSetColProc setColProc,
NewGameSetAttrProc setAttrProc,
void* closure );
void newg_destroy( NewGameCtx* ngc );
void newg_load( NewGameCtx* ngc, const CurGameInfo* gi );
XP_Bool newg_store( NewGameCtx* ngc, CurGameInfo* gi, XP_Bool warn );
void newg_colChanged( NewGameCtx* ngc, XP_U16 player );
void newg_attrChanged( NewGameCtx* ngc, NewGameAttr attr,
NGValue value );
/** newg_juggle: Return XP_TRUE if a juggle happened, XP_FALSE if randomness
* dictated that all players stay put. Platforms can call repeatedly until
* true if they want to force change.
*/
XP_Bool newg_juggle( NewGameCtx* ngc );
EXTERN_C_END
#endif /* _NWGAMEST_H_ */

240
xwords4/common/pool.c Normal file
View file

@ -0,0 +1,240 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
/*
* Copyright 2000 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.
*/
/* #include <assert.h> */
#include "pool.h"
#include "dictnry.h"
#include "xwstream.h"
#define pEND 0x70454e44
// #define BLANKS_FIRST 1
struct PoolContext {
XP_U8* lettersLeft;
XP_U16 numTilesLeft;
XP_U16 numFaces;
#ifdef BLANKS_FIRST
XP_S16 blankIndex;
#endif
MPSLOT
};
PoolContext*
pool_make( MPFORMAL_NOCOMMA )
{
PoolContext* result = (PoolContext*)XP_MALLOC(mpool, sizeof(*result) );
if ( result != NULL ) {
XP_MEMSET( result, 0, sizeof( *result ) );
MPASSIGN(result->mpool, mpool);
#ifdef BLANKS_FIRST
result->blankIndex = -1;
#endif
}
return result;
} /* pool_make */
void
pool_writeToStream( PoolContext* pool, XWStreamCtxt* stream )
{
stream_putU16( stream, pool->numTilesLeft );
stream_putU16( stream, pool->numFaces );
stream_putBytes( stream, pool->lettersLeft,
(XP_U16)(pool->numFaces * sizeof(pool->lettersLeft[0])) );
#ifdef DEBUG
stream_putU32( stream, pEND );
#endif
} /* pool_writeToStream */
PoolContext*
pool_makeFromStream( MPFORMAL XWStreamCtxt* stream )
{
PoolContext* pool = pool_make( MPPARM_NOCOMMA(mpool) );
pool->numTilesLeft = stream_getU16( stream );
pool->numFaces = stream_getU16( stream );
pool->lettersLeft = (XP_U8*)
XP_MALLOC( mpool, pool->numFaces * sizeof(pool->lettersLeft[0]) );
stream_getBytes( stream, pool->lettersLeft,
(XP_U16)(pool->numFaces * sizeof(pool->lettersLeft[0])) );
XP_ASSERT( stream_getU32( stream ) == pEND );
return pool;
} /* pool_makeFromStream */
void
pool_destroy( PoolContext* pool )
{
XP_ASSERT( pool != NULL );
XP_FREE( pool->mpool, pool->lettersLeft );
XP_FREE( pool->mpool, pool );
} /* pool_destroy */
static Tile
getNthPoolTile( PoolContext* pool, short index )
{
Tile result;
/* given an array of counts of remaining letters, subtract each in turn
from the total we seek until that total is at or below zero. The count
that put it (or would put it) under 0 is the one to pick. */
if ( 0 ) {
#ifdef BLANKS_FIRST
} else if ( pool->blankIndex >= 0 && pool->lettersLeft[pool->blankIndex] > 0 ) {
result = pool->blankIndex;
#endif
} else {
XP_S16 nextCount = index;
Tile curLetter = 0;
for ( ; ; ) {
nextCount -= pool->lettersLeft[(short)curLetter];
if ( nextCount < 0 ) {
XP_ASSERT( pool->lettersLeft[(short)curLetter] > 0 );
result = curLetter;
break;
} else {
++curLetter;
}
}
}
return result;
} /* getNthPoolTile */
static Tile
getRandomTile( PoolContext* pool )
{
/* There's a good little article on shuffling algorithms here:
* http://en.wikipedia.org/wiki/Shuffle#Shuffling_algorithms This puppy
* can definitely be improved. PENDING. But note that what's here still
* works when tiles are re-inserted in the pool. Will need to reshuffle
* in that case if move to shuffling once and just taking tiles off the
* top thereafter.
*/
XP_U16 r = (XP_U16)XP_RANDOM();
XP_U16 index = (XP_U16)(r % pool->numTilesLeft);
Tile result = getNthPoolTile( pool, index );
--pool->lettersLeft[result];
--pool->numTilesLeft;
return result;
} /* getRandomTile */
void
pool_requestTiles( PoolContext* pool, Tile* tiles, XP_U8* maxNum )
{
XP_S16 numWanted = *maxNum;
XP_U16 numWritten = 0;
XP_ASSERT( numWanted >= 0 );
while ( pool->numTilesLeft > 0 && numWanted-- ) {
Tile t = getRandomTile( pool );
*tiles++ = t;
++numWritten;
}
*maxNum = (XP_U8)numWritten;
} /* pool_requestTiles */
void
pool_replaceTiles( PoolContext* pool, TrayTileSet* tiles )
{
XP_U16 nTiles = tiles->nTiles;
Tile* tilesP = tiles->tiles;
while ( nTiles-- ) {
Tile tile = *tilesP++; /* do I need to filter off high bits? */
XP_ASSERT( nTiles < MAX_TRAY_TILES );
XP_ASSERT( tile < pool->numFaces );
++pool->lettersLeft[tile];
++pool->numTilesLeft;
}
} /* pool_replaceTiles */
void
pool_removeTiles( PoolContext* pool, TrayTileSet* tiles )
{
XP_U16 nTiles = tiles->nTiles;
Tile* tilesP = tiles->tiles;
XP_ASSERT( nTiles <= MAX_TRAY_TILES );
while ( nTiles-- ) {
Tile tile = *tilesP++; /* do I need to filter off high bits? */
XP_ASSERT( tile < pool->numFaces );
XP_ASSERT( pool->lettersLeft[tile] > 0 );
XP_ASSERT( pool->numTilesLeft > 0 );
--pool->lettersLeft[tile];
--pool->numTilesLeft;
}
} /* pool_removeTiles */
XP_U16
pool_getNTilesLeft( PoolContext* pool )
{
return pool->numTilesLeft;
} /* pool_remainingTileCount */
XP_U16
pool_getNTilesLeftFor( PoolContext* pool, Tile tile )
{
return pool->lettersLeft[tile];
} /* pool_remainingTileCount */
void
pool_initFromDict( PoolContext* pool, DictionaryCtxt* dict )
{
XP_U16 numFaces = dict_numTileFaces( dict );
Tile i;
if ( pool->lettersLeft != NULL ) {
XP_FREE( pool->mpool, pool->lettersLeft );
}
pool->lettersLeft
= (XP_U8*)XP_MALLOC( pool->mpool,
numFaces * sizeof(pool->lettersLeft[0]) );
pool->numTilesLeft = 0;
for ( i = 0; i < numFaces; ++i ) {
XP_U16 numTiles = dict_numTiles( dict, i );
pool->lettersLeft[i] = (XP_U8)numTiles;
pool->numTilesLeft += numTiles;
}
pool->numFaces = numFaces;
#ifdef BLANKS_FIRST
if ( dict_hasBlankTile( dict ) ) {
pool->blankIndex = dict_getBlankTile(dict);
} else {
pool->blankIndex = -1;
}
#endif
} /* pool_initFromDict */

43
xwords4/common/pool.h Normal file
View file

@ -0,0 +1,43 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
/*
* Copyright 2000-2001 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 _POOL_H_
#define _POOL_H_
#include "comtypes.h"
#include "mempool.h"
#include "model.h"
void pool_requestTiles( PoolContext* pool, Tile* tiles,
/*in out*/ XP_U8* maxNum );
void pool_replaceTiles( PoolContext* pool, TrayTileSet* tiles );
void pool_removeTiles( PoolContext* pool, TrayTileSet* tiles );
XP_U16 pool_getNTilesLeft( PoolContext* pool );
XP_U16 pool_getNTilesLeftFor( PoolContext* pool, Tile tile );
PoolContext* pool_make( MPFORMAL_NOCOMMA );
void pool_destroy( PoolContext* pool );
void pool_initFromDict( PoolContext* pool, DictionaryCtxt* dict );
void pool_writeToStream( PoolContext* pool, XWStreamCtxt* stream );
PoolContext* pool_makeFromStream( MPFORMAL XWStreamCtxt* stream );
#endif

31
xwords4/common/rules.mk Normal file
View file

@ -0,0 +1,31 @@
# -*- mode: makefile -*-
# Copyright 2002 by Eric House
#
# 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.
all: $(TARGET)
# Rule for (xplatform) objfiles in this directory
$(COMMONOBJDIR)/%.o: ../common/%.c
mkdir -p $(COMMONOBJDIR)
$(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) -DPLATFORM=$(PLATFORM) \
$< -o $@
# Rule for single-platform objfiles in directory of including Makefile
$(PLATFORM)/%.o: %.c
mkdir -p $(PLATFORM)
$(CC) -c -dD $(CFLAGS) $(INCLUDES) $(DEFINES) -DPLATFORM=$(PLATFORM) $< -o $@

369
xwords4/common/scorebdp.c Normal file
View file

@ -0,0 +1,369 @@
/* -*-mode: C; fill-column: 78; compile-command: "cd ../linux && make MEMDEBUG=TRUE"; -*- */
/*
* Copyright 1997 - 2007 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.
*/
#include "scorebdp.h"
#include "boardp.h"
#include "model.h"
#include "game.h"
#include "strutils.h"
#include "dbgutil.h"
#ifdef CPLUS
extern "C" {
#endif
static XP_Bool
board_ScoreCallback( void* closure, XP_S16 player, XP_UCHAR* expl,
XP_U16* explLen)
{
ModelCtxt* model = (ModelCtxt*)closure;
return model_getPlayersLastScore( model, player,
expl, explLen );
} /* board_ScoreCallback */
typedef struct DrawScoreData {
DrawScoreInfo dsi;
XP_U16 height;
XP_U16 width;
} DrawScoreData;
void
drawScoreBoard( BoardCtxt* board )
{
if ( board->scoreBoardInvalid ) {
short i;
XP_U16 nPlayers = board->gi->nPlayers;
if ( nPlayers > 0 ) {
ModelCtxt* model = board->model;
XP_S16 curTurn = server_getCurrentTurn( board->server );
XP_U16 selPlayer = board->selPlayer;
XP_S16 nTilesInPool = server_countTilesInPool( board->server );
XP_Rect scoreRect = board->scoreBdBounds;
XP_S16* adjustDim;
XP_S16* adjustPt;
XP_U16 totalDim, extra, nShares, remWidth, remHeight, remDim;
DrawScoreData* dp;
DrawScoreData datum[MAX_NUM_PLAYERS];
XP_S16 scores[MAX_NUM_PLAYERS];
XP_Bool isVertical = !board->scoreSplitHor;
#ifdef KEYBOARD_NAV
XP_Rect cursorRect;
XP_Rect* cursorRectP = NULL;
XP_Bool focusAll = XP_FALSE;
XP_Bool remFocussed = XP_FALSE;
XP_S16 cursorIndex = -1;
if ( (board->focussed == OBJ_SCORE) && !board->hideFocus ) {
focusAll = !board->focusHasDived;
if ( !focusAll ) {
cursorIndex = board->scoreCursorLoc;
remFocussed = CURSOR_LOC_REM == cursorIndex;
--cursorIndex;
}
}
#endif
draw_scoreBegin( board->draw, &board->scoreBdBounds, nPlayers,
dfsFor( board, OBJ_SCORE ) );
/* Let platform decide whether the rem: string should be given any
space once there are no tiles left. On Palm that space is
clickable to drop a menu, so will probably leave it. */
draw_measureRemText( board->draw, &board->scoreBdBounds,
nTilesInPool, &remWidth, &remHeight );
XP_ASSERT( remWidth <= board->scoreBdBounds.width );
XP_ASSERT( remHeight <= board->scoreBdBounds.height );
remDim = isVertical? remHeight : remWidth;
if ( isVertical ) {
adjustPt = &scoreRect.top;
adjustDim = &scoreRect.height;
} else {
adjustPt = &scoreRect.left;
adjustDim = &scoreRect.width;
}
/* Get the scores from the model or by calculating them based on
the end-of-game state. */
if ( board->gameOver ) {
model_figureFinalScores( model, scores, (XP_S16*)NULL );
} else {
for ( i = 0; i < nPlayers; ++i ) {
scores[i] = model_getPlayerScore( model, i );
}
}
totalDim = remDim;
/* figure spacing for each scoreboard entry */
XP_MEMSET( &datum, 0, sizeof(datum) );
for ( dp = datum, i = 0; i < nPlayers; ++i, ++dp ) {
LocalPlayer* lp = &board->gi->players[i];
/* This is a hack! */
dp->dsi.lsc = board_ScoreCallback;
dp->dsi.lscClosure = model;
#ifdef KEYBOARD_NAV
if ( (i == cursorIndex) || focusAll ) {
dp->dsi.flags |= CELL_ISCURSOR;
}
#endif
dp->dsi.playerNum = i;
dp->dsi.totalScore = scores[i];
dp->dsi.isTurn = (i == curTurn);
dp->dsi.name = emptyStringIfNull(lp->name);
dp->dsi.selected = board->trayVisState != TRAY_HIDDEN
&& i==selPlayer;
dp->dsi.isRobot = lp->isRobot;
dp->dsi.isRemote = !lp->isLocal;
dp->dsi.nTilesLeft = (nTilesInPool > 0)? -1:
model_getNumTilesTotal( model, i );
draw_measureScoreText( board->draw, &scoreRect,
&dp->dsi, &dp->width, &dp->height );
XP_ASSERT( dp->width <= scoreRect.width );
XP_ASSERT( dp->height <= scoreRect.height );
totalDim += isVertical ? dp->height : dp->width;
}
/* break extra space into chunks, one to follow REM and another to
preceed the timer, and then one for each player. Generally the
player's score will be centered in the rect it's given, so in
effect we're putting half the chunk on either side. The goal
here is for the scores to be closer to each other than they are
to the rem: string and timer on the ends. */
nShares = nPlayers;
XP_ASSERT( *adjustDim >= totalDim );
extra = (*adjustDim - totalDim) / nShares;
/* at this point, the scoreRect should be anchored at the
scoreboard rect's upper left. */
if ( remDim > 0 ) {
*adjustDim = remDim;
draw_drawRemText( board->draw, &scoreRect, &scoreRect,
nTilesInPool, focusAll || remFocussed );
board->remRect = scoreRect;
*adjustPt += remDim;
#ifdef KEYBOARD_NAV
/* Hack: don't let the cursor disappear if Rem: goes away */
} else if ( board->scoreCursorLoc == CURSOR_LOC_REM ) {
board->scoreCursorLoc = selPlayer + 1;
#endif
}
board->remDim = remDim;
for ( dp = datum, i = 0; i < nPlayers; ++dp, ++i ) {
XP_Rect innerRect;
XP_U16 dim = isVertical? dp->height:dp->width;
*adjustDim = board->pti[i].scoreDims = dim + extra;
innerRect.width = dp->width;
innerRect.height = dp->height;
innerRect.left = scoreRect.left +
((scoreRect.width - innerRect.width) / 2);
innerRect.top = scoreRect.top +
((scoreRect.height - innerRect.height) / 2);
draw_score_drawPlayer( board->draw, &innerRect, &scoreRect,
&dp->dsi );
#ifdef KEYBOARD_NAV
XP_MEMCPY( &board->pti[i].scoreRects, &scoreRect,
sizeof(scoreRect) );
if ( i == cursorIndex ) {
cursorRect = scoreRect;
cursorRectP = &cursorRect;
}
#endif
*adjustPt += *adjustDim;
}
draw_objFinished( board->draw, OBJ_SCORE, &board->scoreBdBounds,
dfsFor( board, OBJ_SCORE ) );
}
board->scoreBoardInvalid = XP_FALSE;
}
drawTimer( board );
} /* drawScoreBoard */
static XP_S16
figureSecondsLeft( BoardCtxt* board )
{
CurGameInfo* gi = board->gi;
XP_U16 secondsUsed = gi->players[board->selPlayer].secondsUsed;
XP_U16 secondsAvailable = gi->gameSeconds / gi->nPlayers;
XP_ASSERT( gi->timerEnabled );
return secondsAvailable - secondsUsed;
} /* figureSecondsLeft */
void
drawTimer( BoardCtxt* board )
{
if ( board->gi->timerEnabled ) {
XP_S16 secondsLeft = figureSecondsLeft( board );
draw_drawTimer( board->draw, &board->timerBounds, &board->timerBounds,
board->selPlayer, secondsLeft );
}
} /* drawTimer */
void
board_setScoreboardLoc( BoardCtxt* board, XP_U16 scoreLeft, XP_U16 scoreTop,
XP_U16 scoreWidth, XP_U16 scoreHeight,
XP_Bool divideHorizontally )
{
board->scoreBdBounds.left = scoreLeft;
board->scoreBdBounds.top = scoreTop;
board->scoreBdBounds.width = scoreWidth;
board->scoreBdBounds.height = scoreHeight;
board->scoreSplitHor = divideHorizontally;
} /* board_setScoreboardLoc */
XP_S16
figureScoreRectTapped( const BoardCtxt* board, XP_U16 xx, XP_U16 yy )
{
XP_S16 result = -1;
XP_S16 left;
XP_U16 nPlayers = board->gi->nPlayers;
if ( board->scoreSplitHor ) {
left = xx - board->scoreBdBounds.left;
} else {
left = yy - board->scoreBdBounds.top;
}
left -= board->remDim;
if ( left < 0 ) {
result = CURSOR_LOC_REM;
} else {
for ( result = 0; result < nPlayers; ) {
left -= board->pti[result].scoreDims;
++result; /* increment before test to skip REM */
if ( left < 0 ) {
break; /* found it! */
}
}
if ( result > nPlayers ) {
result = -1;
}
}
return result;
} /* figureScoreRectTapped */
/* If the pen also went down on the scoreboard, make the selected player the
* one closest to the mouse up loc.
*/
#if defined POINTER_SUPPORT || defined KEYBOARD_NAV
XP_Bool
handlePenUpScore( BoardCtxt* board, XP_U16 xx, XP_U16 yy )
{
XP_Bool result = XP_TRUE;
XP_S16 rectNum = figureScoreRectTapped( board, xx, yy );
if ( rectNum == CURSOR_LOC_REM ) {
util_remSelected( board->util );
} else if ( --rectNum >= 0 ) {
board_selectPlayer( board, rectNum );
} else {
result = XP_FALSE;
}
return result;
} /* handlePenUpScore */
#endif
#ifdef KEYBOARD_NAV
static XP_Key
flipKey( XP_Key key, XP_Bool flip )
{
XP_Key result = key;
if ( flip ) {
switch( key ) {
case XP_CURSOR_KEY_DOWN:
result = XP_CURSOR_KEY_RIGHT; break;
case XP_CURSOR_KEY_ALTDOWN:
result = XP_CURSOR_KEY_ALTRIGHT; break;
case XP_CURSOR_KEY_UP:
result = XP_CURSOR_KEY_LEFT; break;
case XP_CURSOR_KEY_ALTUP:
result = XP_CURSOR_KEY_ALTLEFT; break;
case XP_CURSOR_KEY_LEFT:
result = XP_CURSOR_KEY_UP; break;
case XP_CURSOR_KEY_ALTLEFT:
result = XP_CURSOR_KEY_ALTUP; break;
case XP_CURSOR_KEY_RIGHT:
result = XP_CURSOR_KEY_DOWN; break;
case XP_CURSOR_KEY_ALTRIGHT:
result = XP_CURSOR_KEY_ALTDOWN; break;
default:
/* not en error -- but we don't modify the key */
break;
}
}
return result;
} /* flipKey */
XP_Bool
moveScoreCursor( BoardCtxt* board, XP_Key key, XP_Bool preflightOnly,
XP_Bool* pUp )
{
XP_Bool result = XP_TRUE;
XP_S16 scoreCursorLoc = board->scoreCursorLoc;
XP_U16 top = board->gi->nPlayers;
/* Don't let cursor be 0 if rem square's not shown */
XP_U16 bottom = (board->remDim > 0) ? 0 : 1;
XP_Bool up = XP_FALSE;
/* Depending on scoreboard layout, keys move cursor or leave. */
key = flipKey( key, board->scoreSplitHor );
switch ( key ) {
case XP_CURSOR_KEY_RIGHT:
case XP_CURSOR_KEY_LEFT:
up = XP_TRUE;
break;
case XP_CURSOR_KEY_DOWN:
++scoreCursorLoc;
break;
case XP_CURSOR_KEY_UP:
--scoreCursorLoc;
break;
default:
result = XP_FALSE;
}
if ( !up && ((scoreCursorLoc < bottom) || (scoreCursorLoc > top)) ) {
up = XP_TRUE;
} else if ( !preflightOnly ) {
board->scoreCursorLoc = scoreCursorLoc;
board->scoreBoardInvalid = result;
}
*pUp = up;
return result;
} /* moveScoreCursor */
#endif /* KEYBOARD_NAV */
#ifdef CPLUS
}
#endif

38
xwords4/common/scorebdp.h Normal file
View file

@ -0,0 +1,38 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
/*
* Copyright 1997 - 2007 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 _SCOREBDP_H_
#define _SCOREBDP_H_
#include "boardp.h"
void drawScoreBoard( BoardCtxt* board );
XP_S16 figureScoreRectTapped( const BoardCtxt* board, XP_U16 x, XP_U16 y );
void drawTimer( BoardCtxt* board );
#if defined POINTER_SUPPORT || defined KEYBOARD_NAV
XP_Bool handlePenUpScore( BoardCtxt* board, XP_U16 x, XP_U16 y );
#endif
#ifdef KEYBOARD_NAV
XP_Bool moveScoreCursor( BoardCtxt* board, XP_Key key, XP_Bool preflightOnly,
XP_Bool* up );
#endif
#endif

2557
xwords4/common/server.c Normal file

File diff suppressed because it is too large Load diff

127
xwords4/common/server.h Normal file
View file

@ -0,0 +1,127 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
/*
* Copyright 1997 - 2000 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 _SERVER_H_
#define _SERVER_H_
#include "comtypes.h" /* that's *common* types */
#include "commmgr.h"
#include "model.h"
#ifdef CPLUS
extern "C" {
#endif
enum {
PHONIES_IGNORE,
PHONIES_WARN,
PHONIES_DISALLOW
};
typedef XP_U8 XWPhoniesChoice;
enum {
SERVER_STANDALONE,
SERVER_ISSERVER,
SERVER_ISCLIENT
};
typedef XP_U8 DeviceRole;
/* typedef struct ServerCtxt ServerCtxt; */
/* typedef struct ServerVtable { */
/* void (*m_registerPlayer)( ServerCtxt* server, XP_U16 playerNum, */
/* XP_PlayerSocket socket ); */
/* void (*m_getTileValueInfo)( ServerCtxt* server, void* valueBuf ); */
/* } ServerVtable; */
ServerCtxt* server_make( MPFORMAL ModelCtxt* model, CommsCtxt* comms,
XW_UtilCtxt* util );
ServerCtxt* server_makeFromStream( MPFORMAL XWStreamCtxt* stream,
ModelCtxt* model, CommsCtxt* comms,
XW_UtilCtxt* util, XP_U16 nPlayers );
void server_writeToStream( ServerCtxt* server, XWStreamCtxt* stream );
void server_reset( ServerCtxt* server, CommsCtxt* comms );
void server_destroy( ServerCtxt* server );
void server_prefsChanged( ServerCtxt* server, CommonPrefs* cp );
typedef void (*TurnChangeListener)( void* data );
void server_setTurnChangeListener( ServerCtxt* server, TurnChangeListener tl,
void* data );
typedef void (*GameOverListener)( void* data );
void server_setGameOverListener( ServerCtxt* server, GameOverListener gol,
void* data );
/* support random assignment by telling creator of new player what it's
* number will be */
/* XP_U16 server_assignNum( ServerCtxt* server ); */
EngineCtxt* server_getEngineFor( ServerCtxt* server, XP_U16 playerNum );
void server_resetEngine( ServerCtxt* server, XP_U16 playerNum );
XP_U16 server_secondsUsedBy( ServerCtxt* server, XP_U16 playerNum );
/* It might make more sense to have the board supply the undo method clients
call... */
XP_Bool server_handleUndo( ServerCtxt* server );
/* signed because negative number means nobody's turn yet */
XP_S16 server_getCurrentTurn( ServerCtxt* server );
XP_Bool server_getGameIsOver( ServerCtxt* server );
/* Signed in case no dictionary available */
XP_S16 server_countTilesInPool( ServerCtxt* server );
XP_Bool server_do( ServerCtxt* server );
XP_Bool server_commitMove( ServerCtxt* server );
XP_Bool server_commitTrade( ServerCtxt* server, TileBit bits );
/* call this when user wants to end the game */
void server_endGame( ServerCtxt* server );
/* called when running as either client or server */
XP_Bool server_receiveMessage( ServerCtxt* server, XWStreamCtxt* incomming );
/* client-side messages. Client (platform code)owns the stream used to talk
* to the server, and passes it in. */
#ifndef XWFEATURE_STANDALONE_ONLY
void server_initClientConnection( ServerCtxt* server, XWStreamCtxt* stream );
#endif
void server_formatDictCounts( ServerCtxt* server, XWStreamCtxt* stream,
XP_U16 nCols );
void server_formatRemainingTiles( ServerCtxt* server, XWStreamCtxt* stream,
XP_S16 player );
void server_writeFinalScores( ServerCtxt* server, XWStreamCtxt* stream );
#ifdef CPLUS
}
#endif
#endif

61
xwords4/common/states.h Normal file
View file

@ -0,0 +1,61 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
/*
* Copyright 2000 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 _STATES_H_
#define _STATES_H_
typedef enum {
XWSTATE_NONE,
XWSTATE_BEGIN,
__UNUSED1, /*XWSTATE_POOL_INITED,*/
XWSTATE_NEED_SHOWSCORE, /* client-only */
XWSTATE_WAITING_ALL_REG, /* includes waiting for dict from server */
XWSTATE_RECEIVED_ALL_REG, /* includes waiting for dict from server */
XWSTATE_NEEDSEND_BADWORD_INFO,
XWSTATE_MOVE_CONFIRM_WAIT, /* client's waiting to hear back */
XWSTATE_MOVE_CONFIRM_MUSTSEND, /* server should tell client asap */
XWSTATE_NEEDSEND_ENDGAME,
XWSTATE_INTURN,
XWSTATE_GAMEOVER
} XW_State;
/* Game starts out in BEGIN. If the server expects other players, it goes
* into XWSTATE_WAITING_ALL_REG. Likewise goes any client waiting to hear
* from the server after sending off its info. A stand-alone game (server)
* goes immediately from BEGIN to WAITING_INFO.
*
* When a device gets tiles for all players (which happens in a single
* message where there's communication involved) it moves to INTURN (either
* ONDEVICE or OFFDEVICE). ONDEVICE changes to WAITING_INFO when the device
* sends its move to the server; OFFDEVICE changes to ONDEVICE if a
* notification that a move's been made is received and it's now a local
* player's turn; otherwise that notification may arrive with no change in
* XW_State (but a change in whose turn it is.)
After a move is made (current player's device
* sends move
*/
#endif

283
xwords4/common/strutils.c Normal file
View file

@ -0,0 +1,283 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
/*
* Copyright 2001 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.
*/
#include "strutils.h"
#include "xwstream.h"
#include "mempool.h"
#include "xptypes.h"
#ifdef CPLUS
extern "C" {
#endif
XP_U16
bitsForMax( XP_U32 n )
{
XP_U16 result = 0;
XP_ASSERT( n > 0 );
while ( n != 0 ) {
n >>= 1;
++result;
}
return result;
} /* bitsForMax */
static void
tilesToStream( XWStreamCtxt* stream, const Tile* tiles, XP_U16 nTiles )
{
while ( nTiles-- ) {
stream_putBits( stream, TILE_NBITS, *tiles++ );
}
} /* tilesToStream */
void
traySetToStream( XWStreamCtxt* stream, const TrayTileSet* ts )
{
XP_U16 nTiles = ts->nTiles;
stream_putBits( stream, NTILES_NBITS, nTiles );
tilesToStream( stream, ts->tiles, nTiles );
} /* traySetFromStream */
static void
tilesFromStream( XWStreamCtxt* stream, Tile* tiles, XP_U16 nTiles )
{
while ( nTiles-- ) {
*tiles++ = (Tile)stream_getBits( stream, TILE_NBITS );
}
} /* tilesFromStream */
void
traySetFromStream( XWStreamCtxt* stream, TrayTileSet* ts )
{
XP_U16 nTiles = (XP_U16)stream_getBits( stream, NTILES_NBITS );
tilesFromStream( stream, ts->tiles, nTiles );
ts->nTiles = (XP_U8)nTiles;
} /* traySetFromStream */
#if 0
static void
signedToStream( XWStreamCtxt* stream, XP_U16 nBits, XP_S32 num )
{
XP_Bool negative = num < 0;
stream_putBits( stream, 1, negative );
if ( negative ) {
num *= -1;
}
stream_putBits( stream, nBits, num );
} /* signedToStream */
XP_S32
signedFromStream( XWStreamCtxt* stream, XP_U16 nBits )
{
XP_S32 result;
XP_Bool negative = stream_getBits( stream, 1 );
result = stream_getBits( stream, nBits );
if ( negative ) {
result *= -1;
}
return result;
} /* signedFromStream */
#endif
XP_UCHAR*
p_stringFromStream( MPFORMAL XWStreamCtxt* stream
#ifdef MEM_DEBUG
, const char* file, XP_U32 lineNo
#endif
)
{
XP_UCHAR buf[0xFF];
XP_UCHAR* str = (XP_UCHAR*)NULL;
XP_U16 len = stringFromStreamHere( stream, buf, sizeof(buf) );
if ( len > 0 ) {
#ifdef MEM_DEBUG
str = mpool_alloc( mpool, len + 1, file, lineNo );
#else
str = (XP_UCHAR*)XP_MALLOC( mpool, len + 1 ); /* leaked */
#endif
XP_MEMCPY( str, buf, len + 1 );
}
return str;
} /* makeStringFromStream */
XP_U16
stringFromStreamHere( XWStreamCtxt* stream, XP_UCHAR* buf, XP_U16 buflen )
{
XP_U16 len = stream_getU8( stream );
if ( len > 0 ) {
XP_ASSERT( len < buflen );
if ( len >= buflen ) {
/* better to leave stream in bad state than overwrite stack */
len = buflen - 1;
}
stream_getBytes( stream, buf, len );
}
buf[len] = '\0';
return len;
}
void
stringToStream( XWStreamCtxt* stream, const XP_UCHAR* str )
{
XP_U16 len = str==NULL? 0: XP_STRLEN( (const char*)str );
XP_ASSERT( len < 0xFF );
stream_putU8( stream, (XP_U8)len );
stream_putBytes( stream, str, len );
} /* putStringToStream */
/*****************************************************************************
*
****************************************************************************/
XP_UCHAR*
p_copyString( MPFORMAL const XP_UCHAR* instr
#ifdef MEM_DEBUG
, const char* file, XP_U32 lineNo
#endif
)
{
XP_UCHAR* result = (XP_UCHAR*)NULL;
if ( !!instr ) {
XP_U16 len = 1 + XP_STRLEN( (const char*)instr );
#ifdef MEM_DEBUG
result = mpool_alloc( mpool, len, file, lineNo );
#else
result = XP_MALLOC( ignore, len );
#endif
XP_ASSERT( !!result );
XP_MEMCPY( result, instr, len );
}
return result;
} /* copyString */
void
p_replaceStringIfDifferent( MPFORMAL XP_UCHAR** curLoc, const XP_UCHAR* newStr
#ifdef MEM_DEBUG
, const char* file, XP_U32 lineNo
#endif
)
{
XP_UCHAR* curStr = *curLoc;
if ( !!newStr && !!curStr &&
(0 == XP_STRCMP( (const char*)curStr, (const char*)newStr ) ) ) {
/* do nothing; we're golden */
} else {
if ( !!curStr ) {
XP_FREE( mpool, curStr );
}
#ifdef MEM_DEBUG
curStr = p_copyString( mpool, newStr, file, lineNo );
#else
curStr = p_copyString( newStr );
#endif
}
*curLoc = curStr;
} /* replaceStringIfDifferent */
/*
* A wrapper for printing etc. potentially null strings.
*/
XP_UCHAR*
emptyStringIfNull( XP_UCHAR* str )
{
return !!str? str : (XP_UCHAR*)"";
} /* emptyStringIfNull */
XP_Bool
randIntArray( XP_U16* rnums, XP_U16 count )
{
XP_Bool changed = XP_FALSE;
XP_U16 i;
for ( i = 0; i < count; ++i ) {
rnums[i] = i;
}
for ( i = count; i > 0 ; ) {
XP_U16 rIndex = ((XP_U16)XP_RANDOM()) % i;
if ( --i != rIndex ) {
XP_U16 tmp = rnums[rIndex];
rnums[rIndex] = rnums[i];
rnums[i] = tmp;
if ( !changed ) {
changed = XP_TRUE;
}
}
}
return changed;
} /* randIntArray */
#ifdef DEBUG
#define NUM_PER_LINE 8
void
log_hex( const XP_U8* memp, XP_U16 len, const char* tag )
{
const char* hex = "0123456789ABCDEF";
XP_U16 i, j;
XP_U16 offset = 0;
while ( offset < len ) {
XP_UCHAR buf[128];
XP_UCHAR vals[NUM_PER_LINE*3];
XP_UCHAR* valsp = vals;
XP_UCHAR chars[NUM_PER_LINE+1];
XP_UCHAR* charsp = chars;
XP_U16 oldOffset = offset;
for ( i = 0; i < NUM_PER_LINE && offset < len; ++i ) {
XP_U8 byte = memp[offset];
for ( j = 0; j < 2; ++j ) {
*valsp++ = hex[(byte & 0xF0) >> 4];
byte <<= 4;
}
*valsp++ = ':';
byte = memp[offset];
if ( (byte >= 'A' && byte <= 'Z')
|| (byte >= 'a' && byte <= 'z')
|| (byte >= '0' && byte <= '9') ) {
/* keep it */
} else {
byte = '.';
}
*charsp++ = byte;
++offset;
}
*(valsp-1) = '\0'; /* -1 to overwrite ':' */
*charsp = '\0';
if ( (NULL == tag) || (XP_STRLEN(tag) + sizeof(vals) >= sizeof(buf)) ) {
tag = "<tag>";
}
XP_SNPRINTF( buf, sizeof(buf), "%s[%d]: %s %s", tag, oldOffset,
vals, chars );
XP_LOGF( "%s", buf );
}
}
#endif
#ifdef CPLUS
}
#endif

97
xwords4/common/strutils.h Normal file
View file

@ -0,0 +1,97 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
/*
* Copyright 2001 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 _STRUTILS_H_
#define _STRUTILS_H_
#include "comtypes.h"
#include "model.h"
#ifdef CPLUS
extern "C" {
#endif
#define TILE_NBITS 6 /* 32 tiles plus the blank */
XP_U16 bitsForMax( XP_U32 n );
void traySetToStream( XWStreamCtxt* stream, const TrayTileSet* ts );
void traySetFromStream( XWStreamCtxt* stream, TrayTileSet* ts );
XP_S32 signedFromStream( XWStreamCtxt* stream, XP_U16 nBits );
void signedToStream( XWStreamCtxt* stream, XP_U16 nBits, XP_S32 num );
XP_UCHAR* p_stringFromStream( MPFORMAL XWStreamCtxt* stream
#ifdef MEM_DEBUG
, const char* file, XP_U32 lineNo
#endif
);
#ifdef MEM_DEBUG
# define stringFromStream( p, in ) p_stringFromStream( (p), (in), __FILE__, __LINE__ )
#else
# define stringFromStream( p, in ) p_stringFromStream( in )
#endif
XP_U16 stringFromStreamHere( XWStreamCtxt* stream, XP_UCHAR* buf, XP_U16 len );
void stringToStream( XWStreamCtxt* stream, const XP_UCHAR* str );
XP_UCHAR* p_copyString( MPFORMAL const XP_UCHAR* instr
#ifdef MEM_DEBUG
, const char* file, XP_U32 lineNo
#endif
);
#ifdef MEM_DEBUG
# define copyString( p, in ) p_copyString( (p), (in), __FILE__, __LINE__ )
#else
# define copyString( p, in ) p_copyString( in )
#endif
void p_replaceStringIfDifferent( MPFORMAL XP_UCHAR** curLoc,
const XP_UCHAR* newStr
#ifdef MEM_DEBUG
, const char* file, XP_U32 lineNo
#endif
);
#ifdef MEM_DEBUG
# define replaceStringIfDifferent(p, sp, n) \
p_replaceStringIfDifferent( (p), (sp), (n), __FILE__, __LINE__ )
#else
# define replaceStringIfDifferent(p, sp, n) p_replaceStringIfDifferent((sp),(n))
#endif
XP_UCHAR* emptyStringIfNull( XP_UCHAR* str );
/* Produce an array of ints 0..count-1, juggled */
XP_Bool randIntArray( XP_U16* rnums, XP_U16 count );
#ifdef DEBUG
void log_hex( const XP_U8*memp, XP_U16 len, const char* tag );
# define LOG_HEX(m,l,t) log_hex((const XP_U8*)(m),(l),(t))
#else
# define LOG_HEX(m,l,t)
#endif
#ifdef CPLUS
}
#endif
#endif /* _STRUTILS_H_ */

687
xwords4/common/tray.c Normal file
View file

@ -0,0 +1,687 @@
/* -*-mode: C; fill-column: 78; compile-command: "cd ../linux && make MEMDEBUG=TRUE"; -*- */
/*
* Copyright 1997 - 2008 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.
*/
#include "boardp.h"
#include "dragdrpp.h"
#include "engine.h"
#include "draw.h"
#include "strutils.h"
#ifdef CPLUS
extern "C" {
#endif
/****************************** prototypes ******************************/
static void drawPendingScore( BoardCtxt* board, XP_Bool hasCursor );
static XP_U16 countTilesToShow( BoardCtxt* board );
static void figureDividerRect( BoardCtxt* board, XP_Rect* rect );
static XP_S16
trayLocToIndex( BoardCtxt* board, XP_U16 loc )
{
if ( loc >= model_getNumTilesInTray( board->model,
board->selPlayer ) ) {
loc *= -1;
/* (0 * -1) is still 0, so reduce by 1. Will need to adjust
below. NOTE: this is something of a hack.*/
--loc;
}
return loc;
} /* trayLocToIndex */
XP_S16
pointToTileIndex( BoardCtxt* board, XP_U16 x, XP_U16 y, XP_Bool* onDividerP )
{
XP_S16 result = -1; /* not on a tile */
XP_Rect divider;
XP_Rect biggerRect;
XP_Bool onDivider;
figureDividerRect( board, &divider );
/* The divider rect is narrower and kinda hard to tap on. Let's expand
it just for this test */
biggerRect = divider;
if ( board->srcIsPen ) {
biggerRect.left -= 2; /* should be in proportion to tile dims */
biggerRect.width += 4;
}
onDivider = rectContainsPt( &biggerRect, x, y );
if ( !onDivider ) {
if ( x > divider.left ) {
XP_ASSERT( divider.width == board->dividerWidth );
x -= divider.width;
}
XP_ASSERT( x >= board->trayBounds.left );
x -= board->trayBounds.left;
result = x / board->trayScaleH;
result = trayLocToIndex( board, result );
}
if ( onDividerP != NULL ) {
*onDividerP = onDivider;
}
return result;
} /* pointToTileIndex */
void
figureTrayTileRect( BoardCtxt* board, XP_U16 index, XP_Rect* rect )
{
rect->left = board->trayBounds.left + (index * board->trayScaleH);
rect->top = board->trayBounds.top/* + 1 */;
rect->width = board->trayScaleH;
rect->height = board->trayScaleV;
if ( board->selInfo->dividerLoc <= index ) {
rect->left += board->dividerWidth;
}
} /* figureTileRect */
/* When drawing tray mid-drag:
*
* Rule is not to touch the model.
*
* Cases: Tile's been dragged into tray (but not yet dropped.); tile's been
* dragged out of tray (but not yet dropped); and tile's been dragged within
* tray. More's the point, there's an added tile and a removed one. We draw
* the added tile extra, and skip the removed one.
*
* We're walking two arrays at once, backwards. The first is the tile rects
* themselves. If the dirty bit is set, something must get drawn. The second
* is the model's view of tiles augmented by drag-and-drop. D-n-d may have
* removed a tile from the tray (for drawing purposes only), have added one,
* or both (drag-within-tray case). Since a drag lasts only until pen-up,
* there's never more than one tile involved. Adjustment is never by more
* than one.
*
* So while one counter (i) walks the array of rects, we can't use it
* unmodified to fetch from the model. Instead we increment or decrement it
* based on the drag state.
*/
void
drawTray( BoardCtxt* board )
{
XP_Rect tileRect;
if ( (board->trayInvalBits != 0) || board->dividerInvalid ) {
const XP_S16 turn = board->selPlayer;
PerTurnInfo* pti = board->selInfo;
if ( draw_trayBegin( board->draw, &board->trayBounds, turn,
dfsFor( board, OBJ_TRAY ) ) ) {
DictionaryCtxt* dictionary = model_getDictionary( board->model );
XP_S16 cursorBits = 0;
XP_Bool cursorOnDivider = XP_FALSE;
#ifdef KEYBOARD_NAV
XP_S16 cursorTile = pti->trayCursorLoc;
if ( (board->focussed == OBJ_TRAY) && !board->hideFocus ) {
cursorOnDivider = pti->dividerLoc == cursorTile;
if ( board->focusHasDived ) {
if ( !cursorOnDivider ) {
adjustForDivider( board, &cursorTile );
cursorBits = 1 << cursorTile;
}
} else {
cursorBits = ALLTILES;
cursorOnDivider = XP_TRUE;
}
}
#endif
if ( dictionary != NULL ) {
XP_Bool showFaces = board->trayVisState == TRAY_REVEALED;
Tile blank = dict_getBlankTile( dictionary );
if ( turn >= 0 ) {
XP_S16 ii; /* which tile slot are we drawing in */
XP_U16 ddAddedIndx, ddRmvdIndx;
XP_U16 numInTray = countTilesToShow( board );
XP_Bool isBlank;
XP_Bool isADrag = dragDropInProgress( board );
CellFlags baseFlags = board->hideValsInTray && !board->showCellValues
? CELL_VALHIDDEN : CELL_NONE;
dragDropGetTrayChanges( board, &ddRmvdIndx, &ddAddedIndx );
/* draw in reverse order so drawing happens after
erasing */
for ( ii = MAX_TRAY_TILES - 1; ii >= 0; --ii ) {
CellFlags flags = baseFlags;
XP_U16 mask = 1 << ii;
if ( (board->trayInvalBits & mask) == 0 ) {
continue;
}
#ifdef KEYBOARD_NAV
if ( (cursorBits & mask) != 0 ) {
flags |= CELL_ISCURSOR;
}
#endif
figureTrayTileRect( board, ii, &tileRect );
if ( ii >= numInTray ) {
draw_drawTile( board->draw, &tileRect, NULL,
NULL, -1, flags | CELL_ISEMPTY );
} else if ( showFaces ) {
XP_UCHAR buf[4];
XP_Bitmap bitmap = NULL;
XP_UCHAR* textP = (XP_UCHAR*)NULL;
XP_U8 traySelBits = pti->traySelBits;
XP_S16 value;
Tile tile;
if ( ddAddedIndx == ii ) {
dragDropTileInfo( board, &tile, &isBlank );
} else {
XP_U16 modIndex = ii;
if ( ddAddedIndx < ii ) {
--modIndex;
}
/* while we're right of the removal area,
draw the one from the right to cover. */
if ( ddRmvdIndx <= modIndex /*slotIndx*/ ) {
++modIndex;
}
tile = model_getPlayerTile( board->model,
turn, modIndex );
isBlank = tile == blank;
}
textP = getTileDrawInfo( board, tile, isBlank,
&bitmap, &value,
buf, sizeof(buf) );
if ( isADrag ) {
if ( ddAddedIndx == ii ) {
flags |= CELL_HIGHLIGHT;
}
} else if ( (traySelBits & (1<<ii)) != 0 ) {
flags |= CELL_HIGHLIGHT;
}
if ( isBlank ) {
flags |= CELL_ISBLANK;
}
draw_drawTile( board->draw, &tileRect, textP,
bitmap, value, flags );
} else {
draw_drawTileBack( board->draw, &tileRect, flags );
}
}
}
if ( (board->dividerWidth > 0) && board->dividerInvalid ) {
CellFlags flags = cursorOnDivider? CELL_ISCURSOR : CELL_NONE;
XP_Rect divider;
figureDividerRect( board, &divider );
if ( pti->dividerSelected
|| dragDropIsDividerDrag(board) ) {
flags |= CELL_HIGHLIGHT;
}
draw_drawTrayDivider( board->draw, &divider, flags );
board->dividerInvalid = XP_FALSE;
}
drawPendingScore( board,
(cursorBits & (1<<(MAX_TRAY_TILES-1))) != 0);
}
draw_objFinished( board->draw, OBJ_TRAY, &board->trayBounds,
dfsFor( board, OBJ_TRAY ) );
board->trayInvalBits = 0;
}
}
} /* drawTray */
XP_UCHAR*
getTileDrawInfo( const BoardCtxt* board, Tile tile, XP_Bool isBlank,
XP_Bitmap* bitmap, XP_S16* value, XP_UCHAR* buf, XP_U16 len )
{
XP_UCHAR* face = NULL;
DictionaryCtxt* dict = model_getDictionary( board->model );
if ( isBlank ) {
tile = dict_getBlankTile( dict );
} else {
dict_tilesToString( dict, &tile, 1, buf, len );
face = buf;
}
*value = dict_getTileValue( dict, tile );
if ( dict_faceIsBitmap( dict, tile ) ) {
*bitmap = dict_getFaceBitmap( dict, tile, XP_TRUE );
}
return face;
}
static XP_U16
countTilesToShow( BoardCtxt* board )
{
XP_U16 numToShow;
XP_S16 selPlayer = board->selPlayer;
XP_U16 ddAddedIndx, ddRemovedIndx;
XP_ASSERT( selPlayer >= 0 );
if ( board->trayVisState == TRAY_REVEALED ) {
numToShow = model_getNumTilesInTray( board->model, selPlayer );
} else {
numToShow = model_getNumTilesTotal( board->model, selPlayer );
}
dragDropGetTrayChanges( board, &ddRemovedIndx, &ddAddedIndx );
if ( ddAddedIndx < MAX_TRAY_TILES ) {
++numToShow;
}
if ( ddRemovedIndx < MAX_TRAY_TILES ) {
--numToShow;
}
XP_ASSERT( numToShow <= MAX_TRAY_TILES );
return numToShow;
} /* countTilesToShow */
static void
drawPendingScore( BoardCtxt* board, XP_Bool hasCursor )
{
/* Draw the pending score down in the last tray's rect */
if ( countTilesToShow( board ) < MAX_TRAY_TILES ) {
XP_U16 selPlayer = board->selPlayer;
XP_S16 turnScore = 0;
XP_Rect lastTileR;
(void)getCurrentMoveScoreIfLegal( board->model, selPlayer,
(XWStreamCtxt*)NULL, &turnScore );
figureTrayTileRect( board, MAX_TRAY_TILES-1, &lastTileR );
draw_score_pendingScore( board->draw, &lastTileR, turnScore,
selPlayer,
hasCursor?CELL_ISCURSOR:CELL_NONE );
}
} /* drawPendingScore */
static void
figureDividerRect( BoardCtxt* board, XP_Rect* rect )
{
figureTrayTileRect( board, board->selInfo->dividerLoc, rect );
rect->left -= board->dividerWidth;
rect->width = board->dividerWidth;
} /* figureDividerRect */
void
invalTilesUnderRect( BoardCtxt* board, const XP_Rect* rect )
{
/* This is an expensive way to do this -- calculating all the rects rather
than starting with the bounds of the rect passed in -- but this
function is called so infrequently and there are only 7 tiles, so leave
it for now. If it needs to be faster, invalCellsUnderRect is the model
to use. */
XP_U16 i;
XP_Rect locRect;
for ( i = 0; i < MAX_TRAY_TILES; ++i ) {
figureTrayTileRect( board, i, &locRect );
if ( rectsIntersect( rect, &locRect ) ) {
board_invalTrayTiles( board, (TileBit)(1 << i) );
}
}
figureDividerRect( board, &locRect );
if ( rectsIntersect( rect, &locRect ) ) {
board->dividerInvalid = XP_TRUE;
}
} /* invalTilesUnderRect */
XP_Bool
handleTrayDuringTrade( BoardCtxt* board, XP_S16 index )
{
TileBit bits;
XP_ASSERT( index >= 0 );
bits = 1 << index;
board->selInfo->traySelBits ^= bits;
board_invalTrayTiles( board, bits );
return XP_TRUE;
} /* handleTrayDuringTrade */
static XP_Bool
handleActionInTray( BoardCtxt* board, XP_S16 index, XP_Bool onDivider )
{
XP_Bool result = XP_FALSE;
const XP_U16 selPlayer = board->selPlayer;
PerTurnInfo* pti = board->selInfo;
if ( onDivider ) {
/* toggle divider sel state */
pti->dividerSelected = !pti->dividerSelected;
board->dividerInvalid = XP_TRUE;
pti->traySelBits = NO_TILES;
result = XP_TRUE;
} else if ( pti->tradeInProgress ) {
if ( index >= 0 ) {
result = handleTrayDuringTrade( board, index );
}
} else if ( index >= 0 ) {
result = moveTileToArrowLoc( board, (XP_U8)index );
if ( !result ) {
TileBit newBits = 1 << index;
XP_U8 selBits = pti->traySelBits;
/* Tap on selected tile unselects. If we don't do this,
then there's no way to unselect and so no way to turn
off the placement arrow */
if ( newBits == selBits ) {
board_invalTrayTiles( board, selBits );
pti->traySelBits = NO_TILES;
} else if ( selBits != 0 ) {
XP_U16 selIndex = indexForBits( selBits );
model_moveTileOnTray( board->model, selPlayer,
selIndex, index );
pti->traySelBits = NO_TILES;
} else {
board_invalTrayTiles( board, newBits );
pti->traySelBits = newBits;
}
board->dividerInvalid =
board->dividerInvalid || pti->dividerSelected;
pti->dividerSelected = XP_FALSE;
result = XP_TRUE;
}
} else if ( index == -(MAX_TRAY_TILES) ) { /* pending score tile */
result = board_commitTurn( board );
} else if ( index < 0 ) { /* other empty area */
/* it better be true */
(void)board_replaceTiles( board );
result = XP_TRUE;
}
return result;
} /* handleActionInTray */
XP_Bool
handlePenUpTray( BoardCtxt* board, XP_U16 x, XP_U16 y )
{
XP_Bool onDivider;
XP_S16 index = pointToTileIndex( board, x, y, &onDivider );
return handleActionInTray( board, index, onDivider );
} /* handlePenUpTray */
XP_U16
indexForBits( XP_U8 bits )
{
XP_U16 result = 0;
XP_U16 mask = 1;
XP_ASSERT( bits != 0 ); /* otherwise loops forever */
while ( (mask & bits) == 0 ) {
++result;
mask <<= 1;
}
return result;
} /* indexForBits */
XP_Bool
dividerMoved( BoardCtxt* board, XP_U8 newLoc )
{
XP_U8 oldLoc = board->selInfo->dividerLoc;
XP_Bool moved = oldLoc != newLoc;
if ( moved ) {
board->selInfo->dividerLoc = newLoc;
/* This divider's index corresponds to the tile it's to the left of, and
there's no need to invalidate any tiles to the left of the uppermore
divider position. */
if ( oldLoc > newLoc ) {
--oldLoc;
} else {
--newLoc;
}
invalTrayTilesBetween( board, newLoc, oldLoc );
board->dividerInvalid = XP_TRUE;
/* changed number of available tiles */
board_resetEngine( board );
}
return moved;
} /* dividerMoved */
void
board_invalTrayTiles( BoardCtxt* board, TileBit what )
{
board->trayInvalBits |= what;
} /* invalTrayTiles */
void
invalTrayTilesAbove( BoardCtxt* board, XP_U16 tileIndex )
{
TileBit bits = 0;
while ( tileIndex < MAX_TRAY_TILES ) {
bits |= 1 << tileIndex++;
}
board_invalTrayTiles( board, bits );
}
void
invalTrayTilesBetween( BoardCtxt* board, XP_U16 tileIndex1,
XP_U16 tileIndex2 )
{
TileBit bits = 0;
if ( tileIndex1 > tileIndex2 ) {
XP_U16 tmp = tileIndex1;
tileIndex1 = tileIndex2;
tileIndex2 = tmp;
}
while ( tileIndex1 <= tileIndex2 ) {
bits |= (1 << tileIndex1);
++tileIndex1;
}
board_invalTrayTiles( board, bits );
} /* invalTrayTilesBetween */
XP_Bool
board_juggleTray( BoardCtxt* board )
{
XP_Bool result = XP_FALSE;
const XP_S16 turn = board->selPlayer;
if ( checkRevealTray( board ) ) {
XP_S16 nTiles;
XP_U16 dividerLoc = board->selInfo->dividerLoc;
ModelCtxt* model = board->model;
nTiles = model_getNumTilesInTray( model, turn ) - dividerLoc;
if ( nTiles > 1 ) {
XP_S16 i;
Tile tmpT[MAX_TRAY_TILES];
XP_U16 newT[MAX_TRAY_TILES];
/* loop until there'll be change */
while ( !randIntArray( newT, nTiles ) ) {
}
/* save copies of the tiles in juggled order */
for ( i = 0; i < nTiles; ++i ) {
tmpT[i] = model_getPlayerTile( model, turn,
(Tile)(dividerLoc + newT[i]) );
}
/* delete tiles off right end; put juggled ones back on the other */
for ( i = nTiles - 1; i >= 0; --i ) {
(void)model_removePlayerTile( model, turn, -1 );
model_addPlayerTile( model, turn, dividerLoc, tmpT[i] );
}
board->selInfo->traySelBits = 0;
result = XP_TRUE;
}
}
return result;
} /* board_juggleTray */
#ifdef KEYBOARD_NAV
void
adjustForDivider( const BoardCtxt* board, XP_S16* index )
{
XP_U16 dividerLoc = board->selInfo->dividerLoc;
if ( dividerLoc <= *index ) {
--*index;
}
}
XP_Bool
tray_moveCursor( BoardCtxt* board, XP_Key cursorKey, XP_Bool preflightOnly,
XP_Bool* pUp )
{
XP_Bool draw = XP_FALSE;
XP_Bool up = XP_FALSE;
if ( cursorKey == XP_CURSOR_KEY_UP || cursorKey == XP_CURSOR_KEY_DOWN ) {
up = XP_TRUE;
} else if ( (cursorKey == XP_CURSOR_KEY_RIGHT)
|| (cursorKey == XP_CURSOR_KEY_LEFT) ) {
XP_Bool resetEngine = XP_FALSE;
XP_S16 delta = cursorKey == XP_CURSOR_KEY_RIGHT ? 1 : -1;
const XP_U16 selPlayer = board->selPlayer;
PerTurnInfo* pti = board->selInfo;
XP_S16 trayCursorLoc;
XP_S16 newLoc;
for ( ; ; ) {
trayCursorLoc = pti->trayCursorLoc;
newLoc = trayCursorLoc + delta;
if ( newLoc < 0 || newLoc > MAX_TRAY_TILES ) {
up = XP_TRUE;
} else if ( !preflightOnly ) {
XP_S16 tileLoc = trayCursorLoc;
XP_U16 nTiles = board->trayVisState == TRAY_REVEALED
? model_getNumTilesInTray( board->model, selPlayer )
: MAX_TRAY_TILES;
XP_Bool cursorOnDivider = trayCursorLoc == pti->dividerLoc;
XP_Bool cursorObjSelected;
XP_S16 newTileLoc;
adjustForDivider( board, &tileLoc );
cursorObjSelected = cursorOnDivider?
pti->dividerSelected : pti->traySelBits == (1 << tileLoc);
if ( !cursorObjSelected ) {
/* nothing to do */
} else if ( cursorOnDivider ) {
/* just drag the divider */
pti->dividerLoc = newLoc;
resetEngine = XP_TRUE;
} else if ( pti->tradeInProgress ) {
/* nothing to do */
} else {
/* drag the tile, skipping over the divider if needed */
if ( (newLoc == pti->dividerLoc) && (newLoc > 0) ) {
newLoc += delta;
resetEngine = XP_TRUE;
}
newTileLoc = newLoc;
adjustForDivider( board, &newTileLoc );
if ( newTileLoc >= 0 ) {
XP_ASSERT( tileLoc < nTiles );
if ( newTileLoc < nTiles ) {
model_moveTileOnTray( board->model, selPlayer,
tileLoc, newTileLoc );
pti->traySelBits = (1 << newTileLoc);
} else {
pti->traySelBits = 0; /* clear selection */
}
}
}
pti->trayCursorLoc = newLoc;
/* Check if we're settling on an empty tile location other
than the rightmost one. If so, loop back and move
further. */
newTileLoc = newLoc;
adjustForDivider( board, &newTileLoc );
if ( (newTileLoc > nTiles)
&& (newLoc != pti->dividerLoc)
&& (newTileLoc < MAX_TRAY_TILES-1) ) {
continue;
}
}
break; /* always exit loop if we get here */
}
/* PENDING: don't just inval everything */
board->dividerInvalid = XP_TRUE;
board_invalTrayTiles( board, ALLTILES );
if ( resetEngine ) {
board_resetEngine( board );
}
}
draw = XP_TRUE;
*pUp = up;
return draw;
} /* tray_moveCursor */
void
getFocussedTileCenter( BoardCtxt* board, XP_U16* xp, XP_U16* yp )
{
XP_Rect rect;
PerTurnInfo* pti = board->selInfo;
XP_S16 cursorTile = pti->trayCursorLoc;
XP_Bool cursorOnDivider = pti->dividerLoc == cursorTile;
if ( cursorOnDivider ) {
figureDividerRect( board, &rect );
} else {
XP_S16 indx = pti->trayCursorLoc;
adjustForDivider( board, &indx );
XP_ASSERT( indx >= 0 );
figureTrayTileRect( board, indx, &rect );
}
getRectCenter( &rect, xp, yp );
}
#endif /* KEYBOARD_NAV */
#if defined FOR_GREMLINS
XP_Bool
board_moveDivider( BoardCtxt* board, XP_Bool right )
{
XP_Bool result = board->trayVisState == TRAY_REVEALED;
if ( result ) {
XP_U8 loc = board->selInfo->dividerLoc;
loc += MAX_TRAY_TILES + 1;
loc += right? 1:-1;
loc %= MAX_TRAY_TILES + 1;
(void)dividerMoved( board, loc );
}
return result;
} /* board_moveDivider */
#endif
#ifdef CPLUS
}
#endif

272
xwords4/common/util.h Normal file
View file

@ -0,0 +1,272 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
/*
* Copyright 1997 - 2007 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 _UTIL_H_
#define _UTIL_H_
#include "comtypes.h"
#include "dawg.h"
#include "model.h"
#include "board.h"
#include "mempool.h"
#include "vtabmgr.h"
#include "comms.h"
#include "xwrelay.h"
#define LETTER_NONE '\0'
typedef enum {
ERR_NONE, /* 0 is special case */
ERR_TILES_NOT_IN_LINE, /* scoring a move where tiles aren't in line */
ERR_NO_EMPTIES_IN_TURN,
ERR_TWO_TILES_FIRST_MOVE,
ERR_TILES_MUST_CONTACT,
/* ERR_NO_HINT_MID_TURN, */
ERR_TOO_FEW_TILES_LEFT_TO_TRADE,
ERR_NOT_YOUR_TURN,
ERR_NO_PEEK_ROBOT_TILES,
#ifndef XWFEATURE_STANDALONE_ONLY
ERR_SERVER_DICT_WINS,
ERR_NO_PEEK_REMOTE_TILES,
ERR_REG_UNEXPECTED_USER, /* server asked to register too many remote
users */
ERR_REG_SERVER_SANS_REMOTE,
STR_NEED_BT_HOST_ADDR,
#endif
ERR_CANT_TRADE_MID_MOVE,
/* ERR_CANT_ENGINE_MID_MOVE, */
/* ERR_NOT_YOUR_TURN_TO_TRADE, */
/* ERR_NOT_YOUR_TURN_TO_MOVE, */
ERR_CANT_UNDO_TILEASSIGN,
ERR_CANT_HINT_WHILE_DISABLED,
ERR_RELAY_BASE,
ERR_RELAY_END = ERR_RELAY_BASE + XWRELAY_ERROR_LASTERR
} UtilErrID;
typedef enum {
QUERY_COMMIT_TURN, /* 0 means cancel; 1 means commit */
QUERY_COMMIT_TRADE,
QUERY_ROBOT_MOVE,
QUERY_ROBOT_TRADE,
QUERY_LAST_COMMON
} UtilQueryID;
typedef enum {
PICK_FOR_BLANK
, PICK_FOR_CHEAT
} PICK_WHY;
#define PICKER_PICKALL -1
#define PICKER_BACKUP -2
typedef struct PickInfo {
XP_UCHAR4* curTiles;
XP_U16 nCurTiles;
XP_U16 nTotal; /* count to fetch for turn, <= MAX_TRAY_TILES */
XP_U16 thisPick; /* <= nTotal */
PICK_WHY why;
} PickInfo;
typedef struct BadWordInfo {
XP_U16 nWords;
XP_UCHAR* words[MAX_TRAY_TILES+1]; /* can form in both directions */
} BadWordInfo;
/* XWTimerProc returns true if redraw was necessitated by what the proc did */
typedef XP_Bool (*XWTimerProc)( void* closure, XWTimerReason why );
/* Platform-specific utility functions that need to be
*/
typedef struct UtilVtable {
VTableMgr* (*m_util_getVTManager)(XW_UtilCtxt* uc);
#ifndef XWFEATURE_STANDALONE_ONLY
XWStreamCtxt* (*m_util_makeStreamFromAddr )(XW_UtilCtxt* uc,
XP_PlayerAddr channelNo );
#endif
XWBonusType (*m_util_getSquareBonus)( XW_UtilCtxt* uc,
const ModelCtxt* model,
XP_U16 col, XP_U16 row );
void (*m_util_userError)( XW_UtilCtxt* uc, UtilErrID id );
XP_Bool (*m_util_userQuery)( XW_UtilCtxt* uc, UtilQueryID id,
XWStreamCtxt* stream );
/* return of < 0 means computer should pick */
XP_S16 (*m_util_userPickTile)( XW_UtilCtxt* uc, const PickInfo* pi,
XP_U16 playerNum,
const XP_UCHAR4* texts, XP_U16 nTiles );
XP_Bool (*m_util_askPassword)( XW_UtilCtxt* uc, const XP_UCHAR* name,
XP_UCHAR* buf, XP_U16* len );
void (*m_util_trayHiddenChange)(XW_UtilCtxt* uc,
XW_TrayVisState newState,
XP_U16 nVisibleRows );
void (*m_util_yOffsetChange)(XW_UtilCtxt* uc, XP_U16 oldOffset,
XP_U16 newOffset );
#ifdef XWFEATURE_TURNCHANGENOTIFY
void (*m_util_turnChanged)(XW_UtilCtxt* uc);
#endif
void (*m_util_notifyGameOver)( XW_UtilCtxt* uc );
XP_Bool (*m_util_hiliteCell)( XW_UtilCtxt* uc, XP_U16 col, XP_U16 row );
XP_Bool (*m_util_engineProgressCallback)( XW_UtilCtxt* uc );
void (*m_util_setTimer)( XW_UtilCtxt* uc, XWTimerReason why, XP_U16 when,
XWTimerProc proc, void* closure );
void (*m_util_requestTime)( XW_UtilCtxt* uc );
XP_Bool (*m_util_altKeyDown)( XW_UtilCtxt* uc );
XP_U32 (*m_util_getCurSeconds)( XW_UtilCtxt* uc );
DictionaryCtxt* (*m_util_makeEmptyDict)( XW_UtilCtxt* uc );
const XP_UCHAR* (*m_util_getUserString)( XW_UtilCtxt* uc,
XP_U16 stringCode );
XP_Bool (*m_util_warnIllegalWord)( XW_UtilCtxt* uc, BadWordInfo* bwi,
XP_U16 turn, XP_Bool turnLost );
void (*m_util_remSelected)(XW_UtilCtxt* uc);
#if defined XWFEATURE_RELAY || defined XWFEATURE_BLUETOOTH
void (*m_util_addrChange)( XW_UtilCtxt* uc, const CommsAddrRec* oldAddr,
const CommsAddrRec* newAddr );
#endif
#ifdef XWFEATURE_SEARCHLIMIT
XP_Bool (*m_util_getTraySearchLimits)(XW_UtilCtxt* uc,
XP_U16* min, XP_U16* max );
#endif
#ifdef SHOW_PROGRESS
void (*m_util_engineStarting)( XW_UtilCtxt* uc, XP_U16 nBlanks );
void (*m_util_engineStopping)( XW_UtilCtxt* uc );
#endif
} UtilVtable;
struct XW_UtilCtxt {
UtilVtable* vtable;
struct CurGameInfo* gameInfo;
void* closure;
MPSLOT
};
#define util_getVTManager(uc) \
(uc)->vtable->m_util_getVTManager((uc))
#define util_makeStreamFromAddr(uc,a) \
(uc)->vtable->m_util_makeStreamFromAddr((uc),(a))
#define util_getSquareBonus(uc,m,c,r) \
(uc)->vtable->m_util_getSquareBonus((uc),(m),(c),(r))
#define util_userError(uc,err) \
(uc)->vtable->m_util_userError((uc),(err))
#define util_userQuery(uc,qcode,str) \
(uc)->vtable->m_util_userQuery((uc),(qcode),(str))
#define util_userPickTile( uc, w, n, tx, nt ) \
(uc)->vtable->m_util_userPickTile( (uc), (w), (n), (tx), (nt) )
#define util_askPassword( uc, n, b, lp ) \
(uc)->vtable->m_util_askPassword( (uc), (n), (b), (lp) )
#define util_trayHiddenChange( uc, b, n ) \
(uc)->vtable->m_util_trayHiddenChange((uc), (b), (n))
#define util_yOffsetChange( uc, o, n ) \
(uc)->vtable->m_util_yOffsetChange((uc), (o), (n) )
#ifdef XWFEATURE_TURNCHANGENOTIFY
# define util_turnChanged( uc ) \
(uc)->vtable->m_util_turnChanged((uc) )
#else
# define util_turnChanged( uc )
#endif
#define util_notifyGameOver( uc ) \
(uc)->vtable->m_util_notifyGameOver((uc))
#define util_hiliteCell( uc, c, r ) \
(uc)->vtable->m_util_hiliteCell((uc), (c), (r))
#define util_engineProgressCallback( uc ) \
(uc)->vtable->m_util_engineProgressCallback((uc))
#define util_setTimer( uc, why, when, proc, clos ) \
(uc)->vtable->m_util_setTimer((uc),(why),(when),(proc),(clos))
#define util_requestTime( uc ) \
(uc)->vtable->m_util_requestTime((uc))
#define util_altKeyDown( uc ) \
(uc)->vtable->m_util_altKeyDown((uc))
#define util_getCurSeconds(uc) \
(uc)->vtable->m_util_getCurSeconds((uc))
#define util_makeEmptyDict( uc ) \
(uc)->vtable->m_util_makeEmptyDict((uc))
#define util_getUserString( uc, c ) \
(uc)->vtable->m_util_getUserString((uc),(c))
#define util_warnIllegalWord( uc, w, p, b ) \
(uc)->vtable->m_util_warnIllegalWord((uc),(w),(p),(b))
#define util_remSelected( uc ) \
(uc)->vtable->m_util_remSelected((uc))
#if defined XWFEATURE_RELAY || defined XWFEATURE_BLUETOOTH
#define util_addrChange( uc, addro, addrn ) \
(uc)->vtable->m_util_addrChange((uc), (addro), (addrn))
#endif
#ifdef XWFEATURE_SEARCHLIMIT
#define util_getTraySearchLimits(uc,min,max) \
(uc)->vtable->m_util_getTraySearchLimits((uc), (min), (max))
#endif
# ifdef SHOW_PROGRESS
# define util_engineStarting( uc, nb ) \
(uc)->vtable->m_util_engineStarting((uc),(nb))
# define util_engineStopping( uc ) \
(uc)->vtable->m_util_engineStopping((uc))
# else
# define util_engineStarting( uc, nb )
# define util_engineStopping( uc )
# endif
#endif

33
xwords4/common/virtuals.h Normal file
View file

@ -0,0 +1,33 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
/*
* Copyright 1997 - 2000 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 _VIRTUALS_H_
#define _VIRTUALS_H_
/* List of classes requiring vtables -- for allocating and keeping track of
vtables in some central location. */
enum {
VIRTUAL_UTIL,
VIRTUAL_DRAW,
VIRTUAL_STREAM,
VIRTUAL_NUM_VIRTUALS /* must be last */
} XW_VIRTUALS;
#endif

75
xwords4/common/vtabmgr.c Normal file
View file

@ -0,0 +1,75 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
/*
* Copyright 2001 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.
*/
#include "vtabmgr.h"
#define VTABLE_NUM_SLOTS VTABLE_LAST_ENTRY
#ifdef CPLUS
extern "C" {
#endif
struct VTableMgr {
void* slots[VTABLE_NUM_SLOTS];
};
VTableMgr*
make_vtablemgr( MPFORMAL_NOCOMMA )
{
VTableMgr* result = (VTableMgr*)XP_MALLOC( mpool, sizeof(*result) );
XP_MEMSET( result, 0, sizeof(*result) );
return result;
} /* make_vtablemgr */
void
vtmgr_destroy( MPFORMAL VTableMgr* vtmgr )
{
XP_U16 i;
XP_ASSERT( !!vtmgr );
for ( i = 0; i < VTABLE_NUM_SLOTS; ++i ) {
void* vtable = vtmgr->slots[i];
if ( !!vtable ) {
XP_FREE( mpool, vtable );
}
}
XP_FREE( mpool, vtmgr );
} /* vtmgr_destroy */
void
vtmgr_setVTable( VTableMgr* vtmgr, VtableType typ, void* vtable )
{
XP_ASSERT( typ < VTABLE_NUM_SLOTS );
XP_ASSERT( !vtmgr->slots[typ] );
vtmgr->slots[typ] = vtable;
} /* VTMSetVtable */
void*
vtmgr_getVTable( VTableMgr* vtmgr, VtableType typ )
{
XP_ASSERT( typ < VTABLE_NUM_SLOTS );
return vtmgr->slots[typ];
} /* VTMGetVtable */
#ifdef CPLUS
}
#endif

50
xwords4/common/vtabmgr.h Normal file
View file

@ -0,0 +1,50 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
/*
* Copyright 2001 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 _VTABMGR_H_
#define _VTABMGR_H_
#include "comtypes.h"
#include "mempool.h"
#ifdef CPLUS
extern "C" {
#endif
typedef enum {
VTABLE_MEM_STREAM = 0,
VTABLE_LAST_ENTRY
} VtableType;
typedef struct VTableMgr VTableMgr;
VTableMgr* make_vtablemgr( MPFORMAL_NOCOMMA );
void vtmgr_destroy( MPFORMAL VTableMgr* vtmgr );
void vtmgr_setVTable( VTableMgr* vtmgr, VtableType typ, void* vtable );
void* vtmgr_getVTable( VTableMgr* vtmgr, VtableType typ );
#ifdef CPLUS
}
#endif
#endif

53
xwords4/common/xwproto.h Normal file
View file

@ -0,0 +1,53 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
/*
* Copyright 2000 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 _XWPROTO_H_
#define _XWPROTO_H_
typedef enum {
XWPROTO_ERROR = 0, /* illegal value */
XWPROTO_CHAT, /* reserved... */
XWPROTO_DEVICE_REGISTRATION, /* client's first message to server */
XWPROTO_CLIENT_SETUP, /* server's first message to client */
XWPROTO_MOVEMADE_INFO_CLIENT, /* client reports a move it made */
XWPROTO_MOVEMADE_INFO_SERVER, /* server tells all clients about a move
made by it or another client */
XWPROTO_UNDO_INFO_CLIENT, /* client reports undo[s] on the device */
XWPROTO_UNDO_INFO_SERVER, /* server reports undos[s] happening
elsewhere*/
//XWPROTO_CLIENT_MOVE_INFO, /* client says "I made this move" */
//XWPROTO_SERVER_MOVE_INFO, /* server says "Player X made this move" */
/* XWPROTO_CLIENT_TRADE_INFO, */
/* XWPROTO_TRADEMADE_INFO, */
XWPROTO_BADWORD_INFO,
XWPROTO_MOVE_CONFIRM, /* server tells move sender that move was
legal */
//XWPROTO_MOVEMADE_INFO, /* info about tiles placed and received */
XWPROTO_CLIENT_REQ_END_GAME, /* non-server wants to end the game */
XWPROTO_END_GAME /* server says to end game */
} XW_Proto;
#define XWPROTO_NBITS 4
#endif

29
xwords4/common/xwstate.h Normal file
View file

@ -0,0 +1,29 @@
/*
* Copyright 2000 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 XWSTATE_H_
#define XWSTATE_H_
typedef enum {
XW_UNDEFINED,
XW_SERVER_WAITING_CLIENT_SIGNON,
XW_SERVER_READY_TO_PLAY,
} XWGameState;
#endif

164
xwords4/common/xwstream.h Normal file
View file

@ -0,0 +1,164 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
/*
* Copyright 1997 - 2000 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 _XWSTREAM_H_
#define _XWSTREAM_H_
#include "comtypes.h"
#include "memstream.h"
/* #include "xptypes.h" */
#define START_OF_STREAM 0
#define END_OF_STREAM -1
typedef XP_U32 XWStreamPos; /* low 3 bits are bit offset; rest byte offset */
enum { POS_READ, POS_WRITE };
typedef XP_U8 PosWhich;
#ifdef DEBUG
# define DBG_LINE_FILE_FORMAL , XP_U16 lin, const char* fil
# define DBG_LINE_FILE_PARM , __LINE__, __FILE__
#else
# define DBG_LINE_FILE_FORMAL
# define DBG_LINE_FILE_PARM
#endif
typedef struct StreamCtxVTable {
void (*m_stream_destroy)( XWStreamCtxt* dctx );
XP_U8 (*m_stream_getU8)( XWStreamCtxt* dctx );
void (*m_stream_getBytes)( XWStreamCtxt* dctx, void* where,
XP_U16 count );
XP_U16 (*m_stream_getU16)( XWStreamCtxt* dctx );
XP_U32 (*m_stream_getU32)( XWStreamCtxt* dctx );
XP_U32 (*m_stream_getBits)( XWStreamCtxt* dctx, XP_U16 nBits );
void (*m_stream_putU8)( XWStreamCtxt* dctx, XP_U8 byt );
void (*m_stream_putBytes)( XWStreamCtxt* dctx, const void* whence,
XP_U16 count );
void (*m_stream_putString)( XWStreamCtxt* dctx, const char* whence );
void (*m_stream_putU16)( XWStreamCtxt* dctx, XP_U16 data );
void (*m_stream_putU32)( XWStreamCtxt* dctx, XP_U32 data );
void (*m_stream_putBits)( XWStreamCtxt* dctx, XP_U16 nBits, XP_U32 bits
DBG_LINE_FILE_FORMAL );
void (*m_stream_copyFromStream)( XWStreamCtxt* dctx, XWStreamCtxt* src,
XP_U16 nBytes );
XWStreamPos (*m_stream_getPos)( XWStreamCtxt* dctx, PosWhich which );
XWStreamPos (*m_stream_setPos)( XWStreamCtxt* dctx, XWStreamPos newpos,
PosWhich which );
void (*m_stream_open)( XWStreamCtxt* dctx );
void (*m_stream_close)( XWStreamCtxt* dctx );
XP_U16 (*m_stream_getSize)( XWStreamCtxt* dctx );
/* void (*m_stream_makeReturnAddr)( XWStreamCtxt* dctx, XP_PlayerAddr* addr, */
/* XP_U16* addrLen ); */
XP_PlayerAddr (*m_stream_getAddress)( XWStreamCtxt* dctx );
void (*m_stream_setAddress)( XWStreamCtxt* dctx, XP_PlayerAddr channelNo );
void (*m_stream_setVersion)( XWStreamCtxt* dctx, XP_U16 vers );
XP_U16 (*m_stream_getVersion)( XWStreamCtxt* dctx );
void (*m_stream_setOnCloseProc)( XWStreamCtxt* dctx,
MemStreamCloseCallback proc );
} StreamCtxVTable;
struct XWStreamCtxt {
StreamCtxVTable* vtable;
};
#define stream_destroy(sc) \
(sc)->vtable->m_stream_destroy(sc)
#define stream_getU8(sc) \
(sc)->vtable->m_stream_getU8(sc)
#define stream_getBytes(sc, wh, c ) \
(sc)->vtable->m_stream_getBytes((sc), (wh), (c))
#define stream_getU16(sc) \
(sc)->vtable->m_stream_getU16(sc)
#define stream_getU32(sc) \
(sc)->vtable->m_stream_getU32(sc)
#define stream_getBits(sc, n) \
(sc)->vtable->m_stream_getBits((sc), (n))
#define stream_putU8(sc, b) \
(sc)->vtable->m_stream_putU8((sc), (b))
#define stream_putBytes( sc, w, c ) \
(sc)->vtable->m_stream_putBytes((sc), (w), (c))
#define stream_putString( sc, w ) \
(sc)->vtable->m_stream_putString((sc), (w))
#define stream_putU16(sc, d) \
(sc)->vtable->m_stream_putU16((sc), (d))
#define stream_putU32(sc, d) \
(sc)->vtable->m_stream_putU32((sc), (d))
#define stream_putBits(sc, n, b) \
(sc)->vtable->m_stream_putBits((sc), (n), (b) DBG_LINE_FILE_PARM )
#define stream_copyFromStream( sc, src, nb ) \
(sc)->vtable->m_stream_copyFromStream((sc), (src), (nb))
#define stream_getPos(sc, w) \
(sc)->vtable->m_stream_getPos((sc), (w))
#define stream_setPos(sc, p, w) \
(sc)->vtable->m_stream_setPos((sc), (p), (w))
#define stream_open(sc) \
(sc)->vtable->m_stream_open((sc))
#define stream_close(sc) \
(sc)->vtable->m_stream_close((sc))
#define stream_getSize(sc) \
(sc)->vtable->m_stream_getSize((sc))
#define stream_makeReturnAddr(sc,addr,len) \
(sc)->vtable->m_stream_makeReturnAddr((sc),(addr),(len))
#define stream_getAddress(sc) \
(sc)->vtable->m_stream_getAddress((sc))
#define stream_setAddress(sc,ch) \
(sc)->vtable->m_stream_setAddress((sc),(ch))
#define stream_setVersion(sc,ch) \
(sc)->vtable->m_stream_setVersion((sc),(ch))
#define stream_getVersion(sc) \
(sc)->vtable->m_stream_getVersion((sc))
#define stream_setOnCloseProc(sc, p) \
(sc)->vtable->m_stream_setOnCloseProc((sc), (p))
#endif /* _XWSTREAM_H_ */

View file

@ -0,0 +1,96 @@
# Copyright 2002,2006 by Eric House (fixin@peak.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.
LANGCODE:ca_ES
NEEDSSORT:true
LANGINFO: <p>Catalan includes several special tiles, "L.L", "NY" and
LANGINFO: "QU" in addition to Ç. There are no "Y" or "Q" tiles,
LANGINFO: and all words containing either of these letters not in
LANGINFO: combination with a "N" or "U" will be excluded from the
LANGINFO: dictionary. </p>
LANGINFO: <p>"L" is legal by itself, as are words in which two "L"s
LANGINFO: appear side-by-side. If you want your dictionary to include
LANGINFO: the "L.L" tile you'll need to make sure that the exact
LANGINFO: string "L.L" (or "l.l") appears in the wordlist you
LANGINFO: upload.</p>
LANGFILTER_PRECLIP: tr 'ça-z' 'ÇA-Z' |
LANGFILTER_PRECLIP: grep -v 'Q[^U]' |
LANGFILTER_PRECLIP: grep -v '[^N]Y' |
LANGFILTER_PRECLIP: grep -v '^Y' |
LANGFILTER_PRECLIP: grep '^[ÇA-JL-VXYZ\.]*$' |
LANGFILTER_PRECLIP: sed -e 's/L\.L/1/g' -e 's/NY/2/g' -e 's/QU/3/g' |
LANGFILTER_POSTCLIP: | tr -d '\r'
LANGFILTER_POSTCLIP: | sort -u
LANGFILTER_POSTCLIP: | tr -s '\n' '\000'
#LANGFILTER_PRECLIP: sed 's/NY/2/g' |
#LANGFILTER_PRECLIP: sed 's/QU/3/g' |
LANGFILTER_POSTCLIP: | tr '123' '\001\002\003'
# High bit means "official". Next 7 bits are an enum where
# Catalan==c. Low byte is padding
XLOC_HEADER:0x8C00
<BEGIN_TILES>
2 0 {"_"}
12 1 'A'
2 3 'B'
3 2 'C'
1 10 'Ç'
3 2 'D'
13 1 'E'
1 4 'F'
2 3 'G'
1 8 'H'
8 1 'I'
1 8 'J'
4 1 'L'
1 10 {"L.L"}
3 2 'M'
6 1 'N'
1 10 {"NY"}
5 1 'O'
2 3 'P'
1 8 {"QU"}
8 1 'R'
8 1 'S'
5 1 'T'
4 1 'U'
1 4 'V'
1 10 'X'
1 8 'Z'
<END_TILES>
#
# NOTES:
#------
# (1) - Just for avoiding character set mistakes: in the "INT." section of the Palm
# screen keyboard, this letter is on the first line, at the very right of "ae".
# (2) - This is another curious catalan double-letter: two "L" separated by a dot.
# (3) - In catalan, the "Y" is only used for the double-letter "NY".
# (4) - In catalan, the tile is not [Q], i [QU]; because it is not possible to
# use a "Q" alone.
# (5) - Blank tile.

View file

@ -0,0 +1,43 @@
# -*-mode: Makefile; coding: windows-1250; -*-
# Copyright 2002-2008 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.
XWLANG=Czech-CP1250
LANGCODE=cs_CS
TARGET_TYPE ?= PALM
include ../Makefile.2to8
include ../Makefile.langcommon
SOURCEDICT ?= $(XWDICTPATH)/$(XWLANG)/czech2_5.dict.gz
$(XWLANG)Main.dict.gz: $(SOURCEDICT) Makefile
export LC_ALL=$(LANGCODE); \
zcat $< | \
tr [aábcèdïeéìfghiíjklmnòoóprøsšt<EFBFBD>uúùvxyýzž] [AÁBCÈDÏEÉÌFGHIÍJKLMNÒOÓPRØSŠT<EFBFBD>UÚÙVXYÝZŽ] | \
grep '^[AÁBCÈDÏEÉÌFGHIÍJKLMNÒOÓPRØSŠT<C5A0>UÚÙVXYÝZŽ]\+$$' | \
gzip -c > $@
# Everything but creating of the Main.dict file is inherited from the
# "parent" Makefile.langcommon in the parent directory.
clean: clean_common
rm -f $(XWLANG)Main.dict.gz *.bin $(XWLANG)*.pdb $(XWLANG)*.seb
help:
@echo 'make [SOURCEDICT=$(XWDICTPATH)/$(XWLANG)/czech2_5.dict.gz]'

View file

@ -0,0 +1,84 @@
# -*- coding: windows-1250; mode: conf; -*-
# Copyright 2002-2008 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.
LANGCODE:cs_CZ
CHARSET:windows-1250
# deal with DOS files
LANGFILTER: tr -d '\r'
# tr seems to work on systems that don't know the Czech locale, but
# grep does not. So don't use grep, e.g. to eliminate words
# containing letters not in our alphabet. Instead, pass the -r flag
# via D2DARGS so they're dropped.
LANGFILTER: | tr [aábcèdïeéìfghiíjklmnòoóprøsšt<C5A1>uúùvxyýzž] [AÁBCÈDÏEÉÌFGHIÍJKLMNÒOÓPRØSŠT<C5A0>UÚÙVXYÝZŽ]
LANGFILTER: | sort -u
# presence of high-ascii means we must not pass -nosort
D2DARGS: -term 10 -r
LANGINFO: <p>This BYOD language works on Czech wordlists encoded in
LANGINFO: windows-1250 and produces dictionaries that should work on
LANGINFO: windows-1250-localized systems. If your Czech wordlist is
LANGINFO: iso-8859-2-encoded, go back and choose Czech-ISO8859-2. </p>
# High bit means "official". Next 7 bits are an enum where
# Czech-CP1250==0x10. Low byte is padding.
XLOC_HEADER:0x9000
#COUNT VAL FACE
<BEGIN_TILES>
2 0 {"_"}
5 1 'A'
2 2 'Á'
2 3 'B'
3 2 'C'
1 4 'È'
3 1 'D'
1 8 'Ï'
5 1 'E'
2 3 'É'
2 3 'Ì'
1 5 'F'
1 5 'G'
3 2 'H'
4 1 'I'
3 2 'Í'
2 2 'J'
3 1 'K'
3 1 'L'
3 2 'M'
5 1 'N'
1 6 'Ò'
6 1 'O'
1 7 'Ó'
3 1 'P'
3 1 'R'
2 4 'Ø'
4 1 'S'
2 4 'Š'
4 1 'T'
1 7 '<27>'
3 2 'U'
1 5 'Ú'
1 4 'Ù'
4 1 'V'
1 10 'X'
2 2 'Y'
2 4 'Ý'
2 2 'Z'
1 4 'Ž'
<END_TILES>

View file

@ -0,0 +1,43 @@
# -*-mode: Makefile; coding: iso-8859-2; -*-
# Copyright 2002-2008 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.
XWLANG=Czech-ISO8859-2
LANGCODE=cs_CS
TARGET_TYPE ?= PALM
include ../Makefile.2to8
include ../Makefile.langcommon
SOURCEDICT ?= $(XWDICTPATH)/$(XWLANG)/czech2_10_iso.dict.gz
$(XWLANG)Main.dict.gz: $(SOURCEDICT) Makefile
export LC_ALL=$(LANGCODE); \
zcat $< | \
tr [aábcèdïeéìfghiíjklmnòoóprøs¹t»uúùvxyýz¾] [AÁBCÈDÏEÉÌFGHIÍJKLMNÒOÓPRØS©T«UÚÙVXYÝZ®] | \
grep '^[AÁBCÈDÏEÉÌFGHIÍJKLMNÒOÓPRØS©T«UÚÙVXYÝZ®]\+$$' | \
gzip -c > $@
# Everything but creating of the Main.dict file is inherited from the
# "parent" Makefile.langcommon in the parent directory.
clean: clean_common
rm -f $(XWLANG)Main.dict.gz *.bin $(XWLANG)*.pdb $(XWLANG)*.seb
help:
@echo 'make [SOURCEDICT=$(XWDICTPATH)/$(XWLANG)/czech2_5.dict.gz]'

View file

@ -0,0 +1,84 @@
# -*- coding: iso-8859-2; mode: conf; -*-
# Copyright 2002-2008 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.
LANGCODE:cs_CZ
CHARSET:iso-8859-2
# deal with DOS files
LANGFILTER: tr -d '\r'
# tr seems to work on systems that don't know the Czech locale, but
# grep does not. So don't use grep, e.g. to eliminate words
# containing letters not in our alphabet. Instead, pass the -r flag
# via D2DARGS so they're dropped.
LANGFILTER: | tr [aábcèdïeéìfghiíjklmnòoóprøs¹t»uúùvxyýz¾] [AÁBCÈDÏEÉÌFGHIÍJKLMNÒOÓPRØS©T«UÚÙVXYÝZ®]
LANGFILTER: | sort -u
# presence of high-ascii means we must not pass -nosort
D2DARGS: -term 10 -r
LANGINFO: <p>This BYOD language works on Czech wordlists encoded in
LANGINFO: iso-8859-2 and produces dictionaries that should work on
LANGINFO: iso-8859-2-localized systems. If your Czech wordlist is
LANGINFO: windows-1250-encoded, go back and choose Czech-CP1250. </p>
# High bit means "official". Next 7 bits are an enum where
# Czech-ISO8859-2==0x11. Low byte is padding.
XLOC_HEADER:0x9100
#COUNT VAL FACE
<BEGIN_TILES>
2 0 {"_"}
5 1 'A'
2 2 'Á'
2 3 'B'
3 2 'C'
1 4 'È'
3 1 'D'
1 8 'Ï'
5 1 'E'
2 3 'É'
2 3 'Ì'
1 5 'F'
1 5 'G'
3 2 'H'
4 1 'I'
3 2 'Í'
2 2 'J'
3 1 'K'
3 1 'L'
3 2 'M'
5 1 'N'
1 6 'Ò'
6 1 'O'
1 7 'Ó'
3 1 'P'
3 1 'R'
2 4 'Ø'
4 1 'S'
2 4 '©'
4 1 'T'
1 7 '«'
3 2 'U'
1 5 'Ú'
1 4 'Ù'
4 1 'V'
1 10 'X'
2 2 'Y'
2 4 'Ý'
2 2 'Z'
1 4 '®'
<END_TILES>

View file

@ -0,0 +1,5 @@
*.bin
*.xwd
*.pdb
*.inf
*.dict.gz

View file

@ -0,0 +1,42 @@
# -*- mode: makefile -*-
# Copyright 2002-2005 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.
XWLANG=Danish
LANGCODE=da_DK
TARGET_TYPE ?= PALM
include ../Makefile.2to8
include ../Makefile.langcommon
SOURCEDICT ?= $(XWDICTPATH)/$(XWLANG)/LarsDanish.dict.gz
$(XWLANG)Main.dict.gz: $(SOURCEDICT) Makefile
zcat $< | tr -d '\r' | tr [a-zåæø] [A-ZÅÆØ] | \
grep '[AEIOUÅÆØ]' | \
grep '^[A-PR-VX-ZÅÆØ]\+$$' | sort -u | \
gzip -c > $@
# Everything but creating of the Main.dict file is inherited from the
# "parent" Makefile.langcommon in the parent directory.
clean: clean_common
rm -f $(XWLANG)Main.dict.gz *.bin $(XWLANG)*.pdb $(XWLANG)*.seb
help:
@echo 'make [SOURCEDICT=LarsDanish.dict.gz] [TARGET_TYPE=WINCE|PALM]'

View file

@ -0,0 +1,79 @@
# Copyright 2005 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.
LANGCODE:da_DK
# deal with DOS files
LANGFILTER: tr -d '\r'
# uppercase all
LANGFILTER: | tr [a-zåæø] [A-ZÅÆØ]
# no words not containing a vowel
LANGFILTER: | grep '[AEIOUYÅÆØ]'
# none with illegal chars
LANGFILTER: | grep '^[A-PR-VX-ZÅÆØ]\+$'
# remove duplicates
LANGFILTER: | sort -u
# Until I can figure out how to force sort to use a locale's collation
# rules we can't trust sort in the filtering rules above and so must
# leave the sorting work to dict2dawg.pl.
D2DARGS: -r -term 10
LANGINFO: <p>Danish uses all English letters except Q and W. There
LANGINFO: are three non-English letters: 'Å', 'Æ' and 'Ø'. </p>
# High bit means "official". Next 7 bits are an enum where
# Danish==9. Low byte is padding
XLOC_HEADER:0x8900
<BEGIN_TILES>
2 0 {"_"}
7 1 'A'
4 3 'B'
2 8 'C'
5 2 'D'
9 1 'E'
3 3 'F'
3 3 'G'
2 4 'H'
4 3 'I'
2 4 'J'
4 3 'K'
5 2 'L'
3 3 'M'
6 1 'N'
5 2 'O'
2 4 'P'
6 1 'R'
5 2 'S'
5 2 'T'
3 3 'U'
3 3 'V'
1 8 'X'
2 4 'Y'
1 8 'Z'
# These are the hard ones. O-with-slaththru, A-with-circle-over, and
# AE ASCII for AE is 198, for O-with-slaththru is 216, and for
# A-WITH-CIRCLE-OVER is 197.
2 4 'Å'
2 4 'Æ'
2 4 'Ø'
<END_TILES>
# should ignore all after the <END_TILES> above

View file

@ -0,0 +1,3 @@
*.bin
*.xwd
*.pdb

View file

@ -0,0 +1,41 @@
# -*- mode: makefile -*-
# Copyright 2002 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.
XWLANG=Dutch
LANGCODE=nl_NL
TARGET_TYPE ?= PALM
include ../Makefile.2to8
include ../Makefile.langcommon
SOURCEDICT ?= $(XWDICTPATH)/$(XWLANG)/Dutch__unofficial_alphabetical.dict.gz
$(XWLANG)Main.dict.gz: $(SOURCEDICT) Makefile
zcat $< | tr -d '\r' | tr [a-zäöü] [A-ZÄÖÜ] | \
grep '^[A-Z]\+$$' | sort -u | \
gzip -c > $@
# Everything but creating of the Main.dict file is inherited from the
# "parent" Makefile.langcommon in the parent directory.
clean: clean_common
rm -f $(XWLANG)Main.dict.gz *.bin $(XWLANG)*.pdb $(XWLANG)*.seb
help:
@echo 'make [SOURCEDICT=Dutch__unofficial_alphabetical.dict.gz]'

View file

@ -0,0 +1,72 @@
# -*- mode:conf; -*-
# Copyright 2002 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.
LANGCODE:nl_NL
# deal with DOS files
LANGFILTER: tr -d '\r'
# uppercase all
LANGFILTER: | tr [a-z] [A-Z]
# none with illegal chars
LANGFILTER: | grep '^[A-Z]\+$'
LANGFILTER: | sort -u
# Until I can figure out how to force sort to use a locale's collation
# rules we can't trust sort in the filtering rules above and so must
# leave the sorting work to dict2dawg.pl.
D2DARGS: -r -term 10
LANGINFO: <p>Dutch has the same 26 letters as English, though of
LANGINFO: course the counts and values are different. Filtering rules
LANGINFO: eliminate all words that contain letters not found on tiles.</p>
# High bit means "official". Next 7 bits are an enum where
# Dutch==B. Low byte is padding
XLOC_HEADER:0x8B00
<BEGIN_TILES>
2 0 {"_"}
6 1 'A'
2 3 'B'
2 5 'C'
5 2 'D'
18 1 'E'
2 4 'F'
3 3 'G'
2 4 'H'
4 1 'I'
2 4 'J'
3 3 'K'
3 3 'L'
3 3 'M'
10 1 'N'
6 1 'O'
2 3 'P'
1 10 'Q'
5 2 'R'
5 2 'S'
5 2 'T'
3 4 'U'
2 4 'V'
2 5 'W'
1 8 'X'
1 8 'Y'
2 4 'Z'
<END_TILES>
# should ignore all after the <END_TILES> above

View file

@ -0,0 +1,10 @@
*.bin
*.pdb
*.xwd
*.saved
*.pdr
*.ehouse
*.seb
decompose
temp
*.stamp

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,42 @@
# -*-mode: Makefile -*-
# Copyright 2002 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.
TARGET_TYPE ?= FRANK
include ../Makefile.langcommon
# This represents the default -- for now
COMMAND = -f Makefile.BasEnglish TARGET_TYPE=FRANK
alleng:
for mfile in Makefile.BasEnglish Makefile.OSW Makefile.TWL98 Makefile.CollegeEng; do \
$(MAKE) -f $$mfile TARGET_TYPE=$(TARGET_TYPE); \
done
%:
$(MAKE) $(COMMAND) $@
all:
$(MAKE) $(COMMAND)
clean:
$(MAKE) $(COMMAND) clean
help:
@echo "try make -f Makefile.[BasEnglish|CollegeEng] \\"
@echo " TARGET_TYPE=[PALM|FRANK]"

View file

@ -0,0 +1,35 @@
# -*-mode: Makefile; compile-command: "make -f Makefile.BasEnglish"; -*-
# Copyright 2002 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.
XWLANG=BasEnglish
LANGCODE=en_US
DICT2DAWGARGS = -r -nosort
TARGET_TYPE ?= PALM
include ../Makefile.2to8
include ../Makefile.langcommon
$(XWLANG)Main.dict.gz: BasEnglish.dict.gz
ln -s $< $@
# Everything but creating of the Main.dict file is inherited from the
# "parent" Makefile.langcommon in the parent directory.
clean: clean_common
rm -f $(XWLANG)Main.dict.gz *.bin $(XWLANG)*.pdb $(XWLANG)*.seb

View file

@ -0,0 +1,36 @@
# -*- mode: makefile; compile-command: "make -f Makefile.COSD"; -*-
# Copyright 2002 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.
XWLANG=CO
LANGCODE=en_US
TARGET_TYPE=WINCE
include ../Makefile.2to8
include ../Makefile.langcommon
SOURCEDICT ?= $(XWDICTPATH)/English/COSD.dict.gz
$(XWLANG)Main.dict.gz: $(SOURCEDICT) Makefile
zcat $< | tr -d '\r' | tr [a-z] [A-Z] | grep -e "^[A-Z]\{2,15\}$$" | \
gzip -c > $@
# Everything but creating of the Main.dict file is inherited from the
# "parent" Makefile.langcommon in the parent directory.
clean: clean_common
rm -f $(XWLANG)Main.dict.gz *.bin $(XWLANG)*.pdb $(XWLANG)*.seb

View file

@ -0,0 +1,39 @@
# -*- mode: makefile; -*-
# Copyright 2002-2004 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.
#
# I got enable1.txt from ftp://puzzlers.org/pub/wordlists/enable1.txt,
# then gzippped it.
#
XWLANG=Enable
LANGCODE=en_US
TARGET_TYPE=FRANK
include ../Makefile.2to8
include ../Makefile.langcommon
$(XWLANG)Main.dict.gz: Enable1.txt.gz
zcat $< | tr -d '\r' | tr [a-z] [A-Z] | grep -e "^[A-Z]\{2,15\}$$" | \
gzip -c > $@
# Everything but creating of the Main.dict file is inherited from the
# "parent" Makefile.langcommon in the parent directory.
clean: clean_common
rm -f $(XWLANG)Main.dict.gz *.bin $(XWLANG)*.pdb $(XWLANG)*.seb

View file

@ -0,0 +1,36 @@
# -*- mode: makefile; compile-command: "make -f Makefile.OWL2"; -*-
# Copyright 2002 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.
XWLANG=OWL2_
LANGCODE=en_US
TARGET_TYPE=PALM
include ../Makefile.2to8
include ../Makefile.langcommon
SOURCEDICT ?= $(XWDICTPATH)/English/OWL2.dict.gz
$(XWLANG)Main.dict.gz: $(SOURCEDICT) Makefile
zcat $< | tr -d '\r' | tr [a-z] [A-Z] | grep -e "^[A-Z]\{2,15\}$$" | \
gzip -c > $@
# Everything but creating of the Main.dict file is inherited from the
# "parent" Makefile.langcommon in the parent directory.
clean: clean_common
rm -f $(XWLANG)Main.dict.gz *.bin $(XWLANG)*.pdb $(XWLANG)*.seb

View file

@ -0,0 +1,36 @@
# -*- mode: makefile; -*-
# Copyright 2002 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.
XWLANG=SOWPODS
LANGCODE=en_US
TARGET_TYPE=FRANK
include ../Makefile.2to8
include ../Makefile.langcommon
SOURCEDICT ?= $(XWDICTPATH)/English/sow-twl.txt.gz
$(XWLANG)Main.dict.gz: $(SOURCEDICT) Makefile
zcat $< | tr -d '\r' | tr [a-z] [A-Z] | grep -e "^[A-Z]\{2,15\}$$" | \
gzip -c > $@
# Everything but creating of the Main.dict file is inherited from the
# "parent" Makefile.langcommon in the parent directory.
clean: clean_common
rm -f $(XWLANG)Main.dict.gz *.bin $(XWLANG)*.pdb $(XWLANG)*.seb

View file

@ -0,0 +1,38 @@
This file describes how to build dictionaries for the various versions
of Crosswords.
Short version:
For a Palm dictionary, type:
# make -f Makefile.BasEnglish TARGET_TYPE=PALM
which will create BasEnglish2to8.pdb.
For a Franklin or Wince or Linux dictionary, type
# make -f Makefile.BasEnglish TARGET_TYPE=FRANK
which will create BasEnglish2to8.seb and BasEnglish2to8.xwd.saved.
The .seb file is for the eBookman, and is just a wrapper around an
.xwd file. Unwrapped .xwd files are for Wince and Linux versions of
Crosswords. Remove the .saved from the end of the filename. It's
only there because I haven't figure out how to stop the build system
from deleting .xwd files after making .seb files out of them.
English is unusual in having multiple dictionaries. In most language
directories there's only one, and so only one Makefile. So you skip
the -f option to make.
The 2to8 part of the name is a convention meaning that only words from
2 to 8 letters long are included. 2to8 is the default, but you can
explicitly use a different target and the build system will adjust what
words are included. For example
# make -f Makefile.BasEnglish TARGET_TYPE=FRANK BasEnglish2to5.xwd
will produce an even smaller dictionary for Wince and Linux.

View file

@ -0,0 +1,70 @@
# Copyright 2002 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.
LANGCODE:en_US
# deal with DOS files
LANGFILTER: tr -d '\r'
LANGFILTER: | tr [a-z] [A-Z]
LANGFILTER: | grep '^[A-Z]*$'
LANGFILTER: | sort -u
# We can trust sort (above) to do the right thing since there's no
# high ascii. dict2dawg.pl is much faster if I can trust that its
# input is in sorted order.
D2DARGS: -nosort -term 10
LANGINFO: <p>English dictionaries can contain words with any of the 26
LANGINFO: letters you think of as making up the alphabet: A-Z. At
LANGINFO: this point any word in your list containing anything else
LANGINFO: will simply be excluded from the dictionary.</p>
# High bit means "official". Next 7 bits are an enum where
# English==1. Low byte is padding
XLOC_HEADER:0x8100
<BEGIN_TILES>
2 0 {"_"}
9 1 'A'
2 3 'B'
2 3 'C'
4 2 'D'
12 1 'E'
2 4 'F'
3 2 'G'
2 4 'H'
9 1 'I'
1 8 'J'
1 5 'K'
4 1 'L'
2 3 'M'
6 1 'N'
8 1 'O'
2 3 'P'
1 10 'Q'
6 1 'R'
4 1 'S'
6 1 'T'
4 1 'U'
2 4 'V'
2 4 'W'
1 8 'X'
2 4 'Y'
1 10 'Z'
<END_TILES>
# should ignore all after the <END> above

View file

@ -0,0 +1,3 @@
*.bin
*.pdb
*.xwd

View file

@ -0,0 +1,34 @@
# -*-mode: Makefile -*-
# Copyright 2002 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.
XWLANG=French
LANGCODE=fr_FR
TARGET_TYPE ?= FRANK
include ../Makefile.2to8
include ../Makefile.langcommon
$(XWLANG)Main.dict.gz: ods3.txt.gz
zcat $< | tr a-z A-Z | gzip >$@
# Everything but creating of the Main.dict file is inherited from the
# "parent" Makefile.langcommon in the parent directory.
clean: clean_common
rm -f $(XWLANG)Main.dict.gz *.bin $(XWLANG)*.pdb $(XWLANG)*.seb

View file

@ -0,0 +1,34 @@
# -*-mode: Makefile -*-
# Copyright 2002 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.
XWLANG=ODS4_
LANGCODE=fr_FR
TARGET_TYPE ?= PALM
include ../Makefile.2to8
include ../Makefile.langcommon
$(XWLANG)Main.dict.gz: $(XWDICTPATH)/$(XWLANG)/ods4c.txt.gz
zcat $< | tr a-z A-Z | tr -d '\r' | gzip >$@
# Everything but creating of the Main.dict file is inherited from the
# "parent" Makefile.langcommon in the parent directory.
clean: clean_common
rm -f $(XWLANG)Main.dict.gz *.bin $(XWLANG)*.pdb $(XWLANG)*.seb

67
xwords4/dawg/French/info.txt Executable file
View file

@ -0,0 +1,67 @@
# Copyright 2002 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.
LANGCODE:fr_FR
# deal with DOS files
LANGFILTER: tr -d '\r'
LANGFILTER: | tr [a-z] [A-Z]
LANGFILTER: | grep '^[A-Z]*$'
LANGFILTER: | tr '\n' '\000'
LANGFILTER: | sort -u -z
D2DARGS: -r -nosort -term 0
LANGINFO: <p>At this point French is getting treated the same as
LANGINFO: English. But I think I should be transforming accented
LANGINFO: vowels into their unaccented equivalents rather than
LANGINFO: dropping those words from the list prior to compression.</p>
# High bit means "official". Next 7 bits are an enum where
# French==2. Low byte is padding
XLOC_HEADER:0x8200
<BEGIN_TILES>
2 0 {"_"}
9 1 'A'
2 3 'B'
2 3 'C'
3 2 'D'
15 1 'E'
2 4 'F'
2 2 'G'
2 4 'H'
8 1 'I'
1 8 'J'
1 10 'K'
5 1 'L'
3 2 'M'
6 1 'N'
6 1 'O'
2 3 'P'
1 8 'Q'
6 1 'R'
6 1 'S'
6 1 'T'
6 1 'U'
2 4 'V'
1 10 'W'
1 10 'X'
1 10 'Y'
1 10 'Z'
<END_TILES>

View file

@ -0,0 +1,3 @@
*.bin
*.xwd
*.pdb

View file

@ -0,0 +1,42 @@
# -*- mode: makefile -*-
# Copyright 2002 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.
XWLANG=German
LANGCODE=de_DE
TARGET_TYPE ?= PALM
include ../Makefile.2to8
include ../Makefile.langcommon
SOURCEDICT ?= $(XWDICTPATH)/$(XWLANG)/HansGerman.dict.gz
$(XWLANG)Main.dict.gz: $(SOURCEDICT) Makefile
zcat $< | tr [a-zäöü] [A-ZÄÖÜ] | \
sed -e 's/ß/SS/g' | \
grep '[AEIOUÄÖÜ]' | grep '^[A-ZÄÖÜ]\+$$' | \
gzip -c > $@
# Everything but creating of the Main.dict file is inherited from the
# "parent" Makefile.langcommon in the parent directory.
clean: clean_common
rm -f $(XWLANG)Main.dict.gz *.bin $(XWLANG)*.pdb $(XWLANG)*.seb
help:
@echo 'make [SOURCEDICT=HansGerman.dict.gz|deutsch.dict.gz]'

View file

@ -0,0 +1,82 @@
# Copyright 2002 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.
LANGCODE:de_DE
# deal with DOS files
LANGFILTER: tr -d '\r'
# substitute for sharfes-s
LANGFILTER: | sed -e 's/ß/SS/g'
# uppercase all
LANGFILTER: | tr [a-zäöü] [A-ZÄÖÜ]
# no words not containing a vowel
LANGFILTER: | grep '[AEIOUÄÖÜ]'
# none with illegal chars
LANGFILTER: | grep '^[A-ZÄÖÜ]\+$'
# Until I can figure out how to force sort to use a locale's collation
# rules we can't trust sort in the filtering rules above and so must
# leave the sorting work to dict2dawg.pl.
D2DARGS: -r -term 10
LANGINFO: <p>German has the 26 English letters plus the three umlaut
LANGINFO: vowels. Scharfes-s is not a legal tile, but if present in
LANGINFO: the wordlist submitted it'll be converted to "SS" by our
LANGINFO: filtering rules. Additional filtering rules eliminate all
LANGINFO: words that don't contain at least one vowel and any that
LANGINFO: contain letters not found on tiles.</p>
# High bit means "official". Next 7 bits are an enum where
# German==3. Low byte is padding
XLOC_HEADER:0x8300
<BEGIN_TILES>
2 0 {"_"}
5 1 'A'
# A mit umlaut
1 6 196
2 3 'B'
2 4 'C'
4 1 'D'
15 1 'E'
2 4 'F'
3 2 'G'
4 2 'H'
6 1 'I'
1 6 'J'
2 4 'K'
3 2 'L'
4 3 'M'
9 1 'N'
3 2 'O'
# O mit umlaut
1 8 214
1 4 'P'
1 10 'Q'
6 1 'R'
7 1 'S'
6 1 'T'
6 1 'U'
# U mit umlaut
1 6 220
1 6 'V'
1 3 'W'
1 8 'X'
1 10 'Y'
1 3 'Z'
<END_TILES>
# should ignore all after the <END_TILES> above

View file

@ -0,0 +1,4 @@
*.bin
*.pdb
*.xwd
*.seb

41
xwords4/dawg/Hex/Makefile Normal file
View file

@ -0,0 +1,41 @@
# Copyright 2002 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.
XWLANG = Hex
LANGCODE = hex
TARGET_TYPE = WINCE
include ../Makefile.2to8
include ../Makefile.langcommon
# Pass in your own dict here by setting DICT
DICT ?= $(XWDICTPATH)/English/SOWPODS_official.txt.gz
# Feel free to base this on whatever dictionary you have at hand. I'm
# using CollegeEng for no particular reason.
$(XWLANG)Main.dict.gz: $(DICT)
@echo "building $@ from $<"
zcat $< | tr [a-f] [A-F] | grep -e '^[A-F]\{2,8\}$$' | \
echo CAFEBABE DEADBEEF $$(cat -) | \
tr ' ' '\n' | sort | gzip > $@
# Everything but creating of the Main.dict file is inherited from the
# "parent" Makefile.langcommon in the parent directory.
clean: clean_common
rm -f $(XWLANG)Main.dict.gz *.bin $(XWLANG)*.pdb $(XWLANG)*.seb

61
xwords4/dawg/Hex/info.txt Executable file
View file

@ -0,0 +1,61 @@
# Copyright 2002 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.
LANGCODE:HEX
# uppercase all
LANGFILTER: tr [a-f] [A-F]
LANGFILTER: | grep '^[A-F]*$'
LANGFILTER: | sort -u
D2DARGS: -nosort -term 10
LANGINFO: <p>The hex "language" is something of a programmers' joke.
LANGINFO: Hex is short for hexadecimal, a 16-base number system whose
LANGINFO: "digits" are the numerals 0-9 plus the letters A-F. Hex
LANGINFO: letters are often used to represent computer data, and
LANGINFO: certain sequences are sometimes used as markers because
LANGINFO: they're easy to pick out in large dumps of otherwise
LANGINFO: meaningless (to humans) garbage. In staring at Mac memory
LANGINFO: dumps, for example, you'd occasionally see the letters
LANGINFO: DEADBEEF and know that memory in that area was probably
LANGINFO: undamaged.</p>
LANGINFO: <p>I use Hex dictionaries for testing since they have few
LANGINFO: tiles and games play quickly. That's also why the Hex
LANGINFO: tile set has four blanks; that's the largest number
LANGINFO: Crosswords supports and I needed to test at the limit.</p>
# High bit means "official". Next 7 bits are an enum where Hex==127
# (I just made that up; not sure what it was originally.) Low byte is
# padding
XLOC_HEADER:0xFF00
<BEGIN_TILES>
4 0 {"_"}
9 1 'A'
2 3 'B'
2 3 'C'
4 2 'D'
12 1 'E'
2 4 'F'
<END_TILES>
# should ignore all after the <END_TILES> above

View file

@ -0,0 +1,3 @@
*.bin
*.xwd
*.pdb

View file

@ -0,0 +1,34 @@
# -*-mode: Makefile -*-
# Copyright 2002-2004 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.
XWLANG=Italian
LANGCODE=it_IT
TARGET_TYPE ?= PALM
include ../Makefile.2to8
include ../Makefile.langcommon
$(XWLANG)Main.dict.gz: $(XWDICTPATH)/$(XWLANG)/ITALIANO.txt.gz
zcat $< | tr a-z A-Z | grep '^[A-IL-VZ]*$$' | gzip >$@
# Everything but creating of the Main.dict file is inherited from the
# "parent" Makefile.langcommon in the parent directory.
clean: clean_common
rm -f $(XWLANG)Main.dict.gz *.bin $(XWLANG)*.pdb $(XWLANG)*.seb

60
xwords4/dawg/Italian/info.txt Executable file
View file

@ -0,0 +1,60 @@
# Copyright 2002-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
# 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.
LANGCODE:it_IT
# deal with DOS files
LANGFILTER: tr -d '\r'
LANGFILTER: | tr [a-z] [A-Z]
LANGFILTER: | grep '^[A-IL-VZ]*$'
LANGFILTER: | sort -u
D2DARGS: -r -term 10 -nosort
LANGINFO: <p>Italian is treated the same as English but for
LANGINFO: missing letters J, K, W, X and Y.</p>
# High bit means "official". Next 7 bits are an enum where
# Italian==0xA. Low byte is padding
XLOC_HEADER:0x8A00
# tile values taken from http://www.gtoal.com/wordgames/details/italian/
<BEGIN_TILES>
2 0 {"_"}
13 1 'A'
3 5 'B'
4 4 'C'
3 5 'D'
13 1 'E'
2 8 'F'
3 5 'G'
2 8 'H'
13 1 'I'
5 3 'L'
5 3 'M'
6 2 'N'
13 1 'O'
3 5 'P'
1 10 'Q'
6 2 'R'
6 2 'S'
6 2 'T'
5 3 'U'
4 4 'V'
2 8 'Z'
<END_TILES>

39
xwords4/dawg/Makefile Normal file
View file

@ -0,0 +1,39 @@
# -*-mode: Makefile -*-
#
# Copyright 2007 by Eric House (xwords@eehouse.org)
#
# 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.
all: byodfiles.tgz
byodfiles.tgz: byodfiles.tar
gzip -c $< > $@
byodfiles.tar:
rm -f $@
tar cvf $@ ./dict2dawg.cpp ./par.pl ./xloc.pl ./xloc.pm
for dir in $$(ls .); do \
if [ -f $$dir/info.txt ] && [ -f $$dir/Makefile ]; then \
(cd $$dir; make TARGET_TYPE=PALM table.bin values.bin palmvalues.bin); \
(cd $$dir; make TARGET_TYPE=FRANK frankspecials.bin); \
tar rvf $@ $$dir/table.bin $$dir/values.bin $$dir/palmvalues.bin $$dir/frankspecials.bin $$dir/info.txt; \
fi \
done
clean:
rm -f byodfiles.tgz byodfiles.tar dict2dawg
dict2dawg: dict2dawg.cpp
$(CXX) $< -o $@

View file

@ -0,0 +1,7 @@
# -*-mode: Makefile -*-
# These are the targets that almost all language makefiles will want.
SHORT_WORD = 2
LONG_WORD = 8

View file

@ -0,0 +1,285 @@
# -*-mode: Makefile -*-
# Copyright 2000-2002 by Eric House (xwords@eehouse.org)
#
# 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.
XWLANG := $(XWLANG)_
FRANK_EXT = xwd
# This is now on for all dicts and languages. dict2dawg.pl can't
# produce the old form any longer.
NEWDAWG=foo
# this will make all dicts the new, larger type
#FORCE_4 = -force4
PALM_DICT_TYPE = DAWG
PAR = ../par.pl
LANGUAGE = $(shell basename $$(pwd))
# prefer the compiled version if available. But don't compile it
# automatically until it's a bit better tested.
# DICT2DAWG = $(if $(shell test -x ../dict2dawg && echo foo),\
# ../dict2dawg,../dict2dawg.pl)
DICT2DAWG = ../dict2dawg
#all: target_all
# let languages set this first, but we always add blank to it.
BLANK_INFO = "_" /dev/null /dev/null
# Supply a default so don't have to type so much; feel free to change
TARGET_TYPE ?= FRANK
ifdef NEWDAWG
TABLE_ARG = -mn
else
TABLE_ARG = -m
endif
ifeq ($(TARGET_TYPE),WINCE)
WINCE_ONLY = true
endif
.PHONY: clean_common help allbins checkARCH
##############################################################################
# PalmOS rules
##############################################################################
ifeq ($(TARGET_TYPE),PALM)
ifdef NEWDAWG
PDBTYPE = XwrD
else
PDBTYPE = Xwr3
endif
all: $(XWLANG)2to8.pdb $(XWLANG)2to9.pdb $(XWLANG)2to15.pdb
empty: $(XWLANG)0to0.pdb
# Those languages that have bitmap files for custom glyphs will need to
# define BMPBINFILES and perhaps provide a rule for building the files
binfiles.stamp: $(BMPBINFILES)
touch binfiles.stamp
palmspecials.bin: ../palm_mkspecials.pl $(BMPFILES)
$< $(BLANK_INFO) $(LANG_SPECIAL_INFO) > $@
# can't just use values.bin because the specials bitmap info is
# platform-specific
palmvalues.bin: values.bin palmspecials.bin
cat $^ > $@
# values.bin: palmspecials.bin ../xloc binfiles.stamp
# cd ../ && $(MAKE) xloc
# binfileparms=""; \
# if [ "$(BMPBINFILES)" != "" ]; then \
# for f in $(BMPBINFILES)""; \
# do binfileparms="$$binfileparms -i $$f"; \
# done; \
# fi; \
# ../xloc -l $(LANGCODE) $$binfileparms -T $@
# cat palmspecials.bin >> $@
# header (first record) is node count (long) and 4 chars:
# unsigned char firstEdgeRecNum;
# unsigned char charTableRecNum;
# unsigned char valTableRecNum;
# unsigned char reserved[3]; // worst case this points to a new resource
# include "flags" as used on the other platforms
palmheader%.bin: $(XWLANG)%_wordcount.bin $(XWLANG)%_flags.bin
rm -f $@
touch $@
cat $< >> $@
perl -e "print pack(\"C\",3)" >> $@ # first edge
perl -e "print pack(\"C\",1)" >> $@ # char table rec number
perl -e "print pack(\"C\",2)" >> $@ # valTable rec number
perl -e "print pack(\"CCC\",0)" >> $@ # reserved 3 bytes
ifdef NEWDAWG
cat $(XWLANG)$*_flags.bin >> $@
else
perl -e "print pack(\"CC\",0)" >> $@ # c code added two more...
endif
# This works, but leaves out the header info that the current version
# has. I'm not sure anybody cares, though...
$(XWLANG)%.pdb: dawg$(XWLANG)%.stamp table.bin palmvalues.bin palmheader%.bin
$(PAR) c -a backup $@ \
$(basename $(@F)) $(PALM_DICT_TYPE) $(PDBTYPE) \
palmheader$*.bin table.bin palmvalues.bin dawg$(XWLANG)$*_*.bin
# the files to export for byod
byodbins: table.bin values.bin palmvalues.bin info.txt
#endif # TARGET_TYPE==PALM
##############################################################################
# Franklin ebook rules
##############################################################################
else
ifeq ($(TARGET_TYPE),FRANK)
# If we're on a system that can build for Franklin, assume that's what
# we want to build (and the .xwd.saved [<-bug] file for other non-palm
# platforms is a by-product). But if the EBM tools aren't there, just
# build the .xwd file.
ifeq (x$(shell echo -n $$EBOOKMAN_SDK)x,xx)
all: $(XWLANG)2to8.xwd $(XWLANG)2to9.xwd $(XWLANG)2to15.xwd
empty: $(XWLANG)0to0.xwd
else
all: checkARCH $(XWLANG)2to8.seb
empty: $(XWLANG)0to0.seb
include ${EBOOKMAN_SDK}/ebsdk.uses
endif
checkARCH:
if [[ $$ARCH == "" ]]; then \
$(error "ARCH must be defined in ENV if TARGET_TYPE==FRANK"); \
fi
$(XWLANG)%.seb: $(XWLANG)%.$(FRANK_EXT) $(XWLANG)%.atts
${ESDK_CREATESEB_EXE} $<
cp $< $<.saved
$(XWLANG)%.atts: #recreate it each time based on params
echo '_PUB|global+read-only|"Eric_House"' >> $@
echo "_NAME|global+read-only|\"$(XWLANG)2to8\"" >> $@
echo "_EXT|global+read-only|\"$(FRANK_EXT)\"" >> $@
echo '_LCAT|nosign+global|"CONTENT"' >> $@
echo '_PERM|global+read-only|"r"' >> $@
# the files to export for byod
byodbins: table.bin values.bin frankspecials.bin info.txt
else
ifeq ($(TARGET_TYPE),WINCE)
### WINCE section here ###
all: $(XWLANG)2to8.xwd $(XWLANG)2to9.xwd $(XWLANG)2to15.xwd
../mkxwdcab.pl -f $<
else
(Need to define TARGET_TYPE if get error pointing to this line)
endif #ifeq ($(TARGET_TYPE),FRANK)
endif
endif
ifeq (s$(TARGET_TYPE),s)
echo "It\'s an error not to specify a TARGET_TYPE"
endif
##############################################################################
# shared rules
##############################################################################
# For each entry in the table whose face < 32, there needs to be a pair of
# pbitm files and a string giving the printing form
frankspecials.bin: ../frank_mkspecials.pl $(BMPFILES)
$< $(BLANK_INFO) $(LANG_SPECIAL_INFO) > $@
# a binary file (one byte) giving the number of tiles in the dict
charcount.bin: table.bin
ifdef NEWDAWG
siz=$$(ls -l $< | awk '{print $$5}'); \
perl -e "print pack(\"c\",$$siz/2)" > $@
else
siz=$$(wc -c $< | sed -e 's/$<//'); \
perl -e "print pack(\"c\",$$siz)" > $@
endif
$(XWLANG)%.$(FRANK_EXT): dawg$(XWLANG)%.stamp $(XWLANG)%_flags.bin charcount.bin table.bin values.bin frankspecials.bin
cat $(XWLANG)$*_flags.bin charcount.bin table.bin values.bin \
frankspecials.bin $(XWLANG)StartLoc.bin \
$$(ls dawg$(XWLANG)$*_*.bin) > $@
cp $@ saveme.bin
# For some reason I can't fathom dawg$(XWLANG)% gets nuked every time
# the top-level rule fires (all: for whatever TARGET_TYPE.) It
# happens after the rule finishes....
# 16 bits worth of flags for the start of the eventual file. At this
# point, the flags mean this:
# 1: old-style DAWG.
# 2: new-style DAWG, three bytes per node.
# 3: new-style DAWG, four bytes per node
$(XWLANG)%_flags.bin: dawg$(XWLANG)%.stamp
ifdef NEWDAWG
if [ 3 = $$(cat $(XWLANG)$*_nodesize.bin) ] ; \
then perl -e "print pack(\"n\",0x0002)" > $@; echo "flags=2"; \
elif [ 4 = $$(cat $(XWLANG)$*_nodesize.bin) ] ; \
then perl -e "print pack(\"n\",0x0003)" > $@; echo "flags=3"; \
elif true; \
then echo "Unexpected node size"; exit 1; \
fi
else
if [ 3 == $$(cat $(XWLANG)$*_nodesize.bin) ] ; \
then perl -e "print pack(\"n\",0x0001)" > $@; echo "flags=1"; \
else echo "ERROR: old format can't handle 4-byte"; exit 1; \
fi
endif
dawg$(XWLANG)%.stamp: $(XWLANG)Main.dict.gz $(DICT2DAWG) table.bin ../Makefile.langcommon
start=$$(echo $@ | sed -e 's/dawg$(XWLANG)\([0-9]*\)to[0-9]*.stamp/\1/'); \
end=$$(echo $@ | sed -e 's/dawg$(XWLANG)[0-9]*to\([0-9]*\).stamp/\1/'); \
echo $${start} and $${end}; \
zcat $< | $(DICT2DAWG) $(DICT2DAWGARGS) $(TABLE_ARG) table.bin -b 28000 \
-ob dawg$(XWLANG)$* \
-sn $(XWLANG)StartLoc.bin -min $${start} -max $${end} \
-wc $(XWLANG)$*_wordcount.bin $(FORCE_4) -ns $(XWLANG)$*_nodesize.bin
touch $@
$(XWLANG)%_wordcount.bin: dawg$(XWLANG)%.stamp
@echo
# the files to export for byod
allbins:
$(MAKE) TARGET_TYPE=PALM byodbins
$(MAKE) TARGET_TYPE=FRANK byodbins
rm palmspecials.bin
table.bin: ../xloc.pl
ifdef NEWDAWG
perl -I../ ../xloc.pl -tn $@
else
perl -I../ ../xloc.pl -t $@
endif
values.bin: ../xloc.pl
perl -I../ ../xloc.pl -v $@
%.dict: %.dict.gz
zcat $< > $@
# clean this up....
../dict2dawg: ../dict2dawg.cpp
cd ../ && g++ -DDEBUG -O -o dict2dawg dict2dawg.cpp
clean_common:
rm -f $(XWLANG)Main.dict *.bin *.pdb *.seb dawg*.stamp *.$(FRANK_EXT) \
$(XWLANG)*.pdb $(XWLANG)*.seb
help:
@echo "make TARGET_TYPE=[FRANK|PALM]"

View file

@ -0,0 +1,8 @@
*.bin
*.pdb
*.saved
*.pdr
*.ehouse
*.seb
decompose
temp

View file

@ -0,0 +1,35 @@
# -*-mode: Makefile -*-
# Copyright 2002 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.
XWLANG=Polish
LANGCODE=pl_PL
TARGET_TYPE ?= FRANK
include ../Makefile.2to8
include ../Makefile.langcommon
$(XWLANG)Main.dict.gz: slowa.txt.gz
zcat $< | tr -d '\r' | tr [a-z±æê³ñ󶼿] [A-Z¡ÆÊ£ÑÓ¦¬¯] | \
grep '^[A-PR-UWYZ¡ÆÊ£ÑÓ¦¬¯]*$$' | gzip >$@
# Everything but creating of the Main.dict file is inherited from the
# "parent" Makefile.langcommon in the parent directory.
clean: clean_common
rm -f $(XWLANG)Main.dict.gz *.bin $(XWLANG)*.pdb $(XWLANG)*.seb

View file

@ -0,0 +1,86 @@
# Copyright 2002 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.
LANGCODE:pl_PL
CHARSET:iso-8859-2
# deal with DOS files
LANGFILTER_PRECLIP: tr -d '\r' |
LANGFILTER_POSTCLIP: | tr [a-z±æê³ñ󶼿] [A-Z¡ÆÊ£ÑÓ¦¬¯]
LANGFILTER_POSTCLIP: | grep '^[A-PR-UWYZ¡ÆÊ£ÑÓ¦¬¯]*$'
LANGFILTER_POSTCLIP: | tr '\n' '\000'
NEEDSSORT:true
LANGINFO: <p>Polish is interesting because it has 32 letters plus a
LANGINFO: blank, a larger number than any other supported language.
LANGINFO: Yet while I call it "supported", in fact this combination
LANGINFO: has never been tested because I don't have a Polish
LANGINFO: wordlist. So if you are the first and have problems you've
LANGINFO: probably found a bug. Please let <a
LANGINFO: href="mailto:xwords@eehouse.org">me</a> know so that I can get
LANGINFO: this working.</p>
LANGINFO: <p>Note that the blank is the last tile here, while with all
LANGINFO: other languages it's the first.</p>
LANGINFO: <p>Also, please note that we currently require the files you
LANGINFO: upload to use the iso-8859-2 character encoding.</p>
# High bit means "official". Next 7 bits are an enum where
# Polish==8. Low byte is padding
XLOC_HEADER:0x8800
<BEGIN_TILES>
9 1 'A'
1 5 '¡'
2 3 'B'
3 2 'C'
1 6 'Æ'
3 2 'D'
7 1 'E'
1 5 'Ê'
1 5 'F'
2 3 'G'
2 3 'H'
8 1 'I'
2 3 'J'
3 2 'K'
3 2 'L'
2 3 '£'
3 2 'M'
5 1 'N'
1 7 'Ñ'
6 1 'O'
1 5 'Ó'
3 2 'P'
4 1 'R'
4 1 'S'
1 5 '¦'
3 2 'T'
2 3 'U'
4 1 'W'
4 2 'Y'
5 1 'Z'
1 9 '¬'
1 5 '¯'
# the blank *must* be last here!!!
2 0 {"_"}
<END_TILES>

View file

@ -0,0 +1,42 @@
# -*- mode: makefile -*-
# Copyright 2002, 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
# 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.
LANG=PortugueseBR
LANGCODE=pt_PT
TARGET_TYPE ?= PALM
include ../Makefile.2to8
include ../Makefile.langcommon
SOURCEDICT ?= $(XWDICTPATH)/Portuguese/portugueseBR.txt.gz
$(LANG)Main.dict.gz: $(SOURCEDICT) Makefile.BrOffice
zcat $< | tr [a-zç] [A-ZÇ] | \
grep '^[A-JL-VXZÇ]\+$$' | \
gzip -c > $@
# Everything but creating of the Main.dict file is inherited from the
# "parent" Makefile.langcommon in the parent directory.
clean: clean_common
rm -f $(LANG)Main.dict.gz *.bin $(LANG)*.pdb $(LANG)*.seb
help:
@echo "make [SOURCEDICT=$(XWDICTPATH)/Portuguese/portugueseBR.txt]"

View file

@ -0,0 +1,42 @@
# -*- mode: makefile -*-
# Copyright 2002, 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
# 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.
XWLANG=PortuguesePT
LANGCODE=pt_PT
TARGET_TYPE ?= PALM
include ../Makefile.2to8
include ../Makefile.langcommon
SOURCEDICT ?= $(XWDICTPATH)/Portuguese/portuguese_pt.bz2
$(XWLANG)Main.dict.gz: $(SOURCEDICT) Makefile.Minho
bzcat $< | tr [a-zç] [A-ZÇ] | \
grep '^[A-JL-VXZÇ]\+$$' | \
gzip -c > $@
# Everything but creating of the Main.dict file is inherited from the
# "parent" Makefile.langcommon in the parent directory.
clean: clean_common
rm -f $(XWLANG)Main.dict.gz *.bin $(XWLANG)*.pdb $(XWLANG)*.seb
help:
@echo "make [SOURCEDICT=$(XWDICTPATH)/Portuguese/portuguese_pt.bz2]"

View file

@ -0,0 +1,70 @@
# Copyright 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
# 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.
LANGCODE:pt_PT
# deal with DOS files
LANGFILTER: tr -d '\r'
# uppercase all
LANGFILTER: | tr [a-zç] [A-ZÇ]
# no words not containing a vowel
LANGFILTER: | grep '[AEIOU]'
# none with illegal chars
LANGFILTER: | grep '^[A-JL-VXZÇ]\+$'
# Until I can figure out how to force sort to use a locale's collation
# rules we can't trust sort in the filtering rules above and so must
# leave the sorting work to dict2dawg.pl.
D2DARGS: -r -term 10
LANGINFO: <p>Portugese uses the letter A-Z, excluding K, W and Y, and adds
LANGINFO: Ç. Words containing any other letters are dropped. </p>
# High bit means "official". Next 7 bits are an enum where
# Portuguese==D. Low byte is padding
XLOC_HEADER:0x8D00
<BEGIN_TILES>
3 0 {"_"}
14 1 'A'
3 3 'B'
4 2 'C'
2 3 'Ç'
5 2 'D'
11 1 'E'
2 4 'F'
2 4 'G'
2 4 'H'
10 1 'I'
2 5 'J'
5 2 'L'
6 1 'M'
4 3 'N'
10 1 'O'
4 2 'P'
1 6 'Q'
6 1 'R'
8 1 'S'
5 1 'T'
7 1 'U'
2 4 'V'
1 8 'X'
1 8 'Z'
<END_TILES>
# should ignore all after the <END_TILES> above

Some files were not shown because too many files have changed in this diff Show more