mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2025-02-04 20:46:28 +01:00
branch for smartphone release
This commit is contained in:
parent
4d0122816b
commit
144ecb3934
450 changed files with 95959 additions and 0 deletions
5
xwords4/Makefile
Normal file
5
xwords4/Makefile
Normal 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
11
xwords4/common/.cvsignore
Normal 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
5
xwords4/common/Makefile
Normal file
|
@ -0,0 +1,5 @@
|
|||
# -*- mode: Makefile; -*-
|
||||
|
||||
clean:
|
||||
rm -rf $(PLATFORM)
|
||||
|
3051
xwords4/common/board.c
Normal file
3051
xwords4/common/board.c
Normal file
File diff suppressed because it is too large
Load diff
167
xwords4/common/board.h
Normal file
167
xwords4/common/board.h
Normal 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
568
xwords4/common/boarddrw.c
Normal 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
300
xwords4/common/boardp.h
Normal 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
54
xwords4/common/commmgr.h
Normal 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
1643
xwords4/common/comms.c
Normal file
File diff suppressed because it is too large
Load diff
138
xwords4/common/comms.h
Normal file
138
xwords4/common/comms.h
Normal 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
241
xwords4/common/comtypes.h
Normal 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
81
xwords4/common/config.mk
Normal 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
88
xwords4/common/dawg.h
Normal 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
75
xwords4/common/dbgutil.c
Normal 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
29
xwords4/common/dbgutil.h
Normal 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
531
xwords4/common/dictnry.c
Normal 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
168
xwords4/common/dictnry.h
Normal 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
36
xwords4/common/dictnryp.h
Normal 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
573
xwords4/common/dragdrpp.c
Normal 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
61
xwords4/common/dragdrpp.h
Normal 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
366
xwords4/common/draw.c
Normal 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
309
xwords4/common/draw.h
Normal 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
1245
xwords4/common/engine.c
Normal file
File diff suppressed because it is too large
Load diff
67
xwords4/common/engine.h
Normal file
67
xwords4/common/engine.h
Normal 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
511
xwords4/common/game.c
Normal 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
114
xwords4/common/game.h
Normal 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
276
xwords4/common/mempool.c
Normal 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
53
xwords4/common/mempool.h
Normal 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
469
xwords4/common/memstream.c
Normal 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
|
46
xwords4/common/memstream.h
Normal file
46
xwords4/common/memstream.h
Normal 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
1837
xwords4/common/model.c
Normal file
File diff suppressed because it is too large
Load diff
261
xwords4/common/model.h
Normal file
261
xwords4/common/model.h
Normal 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
80
xwords4/common/modelp.h
Normal 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
386
xwords4/common/movestak.c
Normal 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
95
xwords4/common/movestak.h
Normal 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
850
xwords4/common/mscore.c
Normal 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
581
xwords4/common/nwgamest.c
Normal 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
115
xwords4/common/nwgamest.h
Normal 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
240
xwords4/common/pool.c
Normal 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
43
xwords4/common/pool.h
Normal 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
31
xwords4/common/rules.mk
Normal 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
369
xwords4/common/scorebdp.c
Normal 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
38
xwords4/common/scorebdp.h
Normal 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
2557
xwords4/common/server.c
Normal file
File diff suppressed because it is too large
Load diff
127
xwords4/common/server.h
Normal file
127
xwords4/common/server.h
Normal 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
61
xwords4/common/states.h
Normal 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
283
xwords4/common/strutils.c
Normal 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
97
xwords4/common/strutils.h
Normal 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
687
xwords4/common/tray.c
Normal 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, ÷r );
|
||||
|
||||
/* 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, ÷r );
|
||||
if ( pti->dividerSelected
|
||||
|| dragDropIsDividerDrag(board) ) {
|
||||
flags |= CELL_HIGHLIGHT;
|
||||
}
|
||||
draw_drawTrayDivider( board->draw, ÷r, 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
272
xwords4/common/util.h
Normal 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
33
xwords4/common/virtuals.h
Normal 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
75
xwords4/common/vtabmgr.c
Normal 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
50
xwords4/common/vtabmgr.h
Normal 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
53
xwords4/common/xwproto.h
Normal 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
29
xwords4/common/xwstate.h
Normal 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
164
xwords4/common/xwstream.h
Normal 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_ */
|
96
xwords4/dawg/Catalan/info.txt
Normal file
96
xwords4/dawg/Catalan/info.txt
Normal 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.
|
||||
|
43
xwords4/dawg/Czech-CP1250/Makefile
Normal file
43
xwords4/dawg/Czech-CP1250/Makefile
Normal 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]'
|
84
xwords4/dawg/Czech-CP1250/info.txt
Normal file
84
xwords4/dawg/Czech-CP1250/info.txt
Normal 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>
|
43
xwords4/dawg/Czech-ISO8859-2/Makefile
Normal file
43
xwords4/dawg/Czech-ISO8859-2/Makefile
Normal 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]'
|
84
xwords4/dawg/Czech-ISO8859-2/info.txt
Normal file
84
xwords4/dawg/Czech-ISO8859-2/info.txt
Normal 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>
|
5
xwords4/dawg/Danish/.cvsignore
Normal file
5
xwords4/dawg/Danish/.cvsignore
Normal file
|
@ -0,0 +1,5 @@
|
|||
*.bin
|
||||
*.xwd
|
||||
*.pdb
|
||||
*.inf
|
||||
*.dict.gz
|
42
xwords4/dawg/Danish/Makefile
Normal file
42
xwords4/dawg/Danish/Makefile
Normal 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]'
|
79
xwords4/dawg/Danish/info.txt
Normal file
79
xwords4/dawg/Danish/info.txt
Normal 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
|
3
xwords4/dawg/Dutch/.cvsignore
Normal file
3
xwords4/dawg/Dutch/.cvsignore
Normal file
|
@ -0,0 +1,3 @@
|
|||
*.bin
|
||||
*.xwd
|
||||
*.pdb
|
41
xwords4/dawg/Dutch/Makefile
Normal file
41
xwords4/dawg/Dutch/Makefile
Normal 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]'
|
72
xwords4/dawg/Dutch/info.txt
Normal file
72
xwords4/dawg/Dutch/info.txt
Normal 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
|
10
xwords4/dawg/English/.cvsignore
Normal file
10
xwords4/dawg/English/.cvsignore
Normal file
|
@ -0,0 +1,10 @@
|
|||
*.bin
|
||||
*.pdb
|
||||
*.xwd
|
||||
*.saved
|
||||
*.pdr
|
||||
*.ehouse
|
||||
*.seb
|
||||
decompose
|
||||
temp
|
||||
*.stamp
|
BIN
xwords4/dawg/English/BasEnglish.dict.gz
Normal file
BIN
xwords4/dawg/English/BasEnglish.dict.gz
Normal file
Binary file not shown.
BIN
xwords4/dawg/English/BasEnglish2to8.xwd
Normal file
BIN
xwords4/dawg/English/BasEnglish2to8.xwd
Normal file
Binary file not shown.
42
xwords4/dawg/English/Makefile
Normal file
42
xwords4/dawg/English/Makefile
Normal 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]"
|
||||
|
35
xwords4/dawg/English/Makefile.BasEnglish
Normal file
35
xwords4/dawg/English/Makefile.BasEnglish
Normal 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
|
36
xwords4/dawg/English/Makefile.CSW
Normal file
36
xwords4/dawg/English/Makefile.CSW
Normal 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
|
39
xwords4/dawg/English/Makefile.Enable
Normal file
39
xwords4/dawg/English/Makefile.Enable
Normal 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
|
36
xwords4/dawg/English/Makefile.OWL2
Normal file
36
xwords4/dawg/English/Makefile.OWL2
Normal 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
|
36
xwords4/dawg/English/Makefile.SOWPODS
Normal file
36
xwords4/dawg/English/Makefile.SOWPODS
Normal 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
|
38
xwords4/dawg/English/README.txt
Normal file
38
xwords4/dawg/English/README.txt
Normal 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.
|
||||
|
70
xwords4/dawg/English/info.txt
Normal file
70
xwords4/dawg/English/info.txt
Normal 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
|
3
xwords4/dawg/French/.cvsignore
Normal file
3
xwords4/dawg/French/.cvsignore
Normal file
|
@ -0,0 +1,3 @@
|
|||
*.bin
|
||||
*.pdb
|
||||
*.xwd
|
34
xwords4/dawg/French/Makefile
Normal file
34
xwords4/dawg/French/Makefile
Normal 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
|
34
xwords4/dawg/French/Makefile.ODS4
Normal file
34
xwords4/dawg/French/Makefile.ODS4
Normal 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
67
xwords4/dawg/French/info.txt
Executable 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>
|
3
xwords4/dawg/German/.cvsignore
Normal file
3
xwords4/dawg/German/.cvsignore
Normal file
|
@ -0,0 +1,3 @@
|
|||
*.bin
|
||||
*.xwd
|
||||
*.pdb
|
42
xwords4/dawg/German/Makefile
Normal file
42
xwords4/dawg/German/Makefile
Normal 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]'
|
82
xwords4/dawg/German/info.txt
Normal file
82
xwords4/dawg/German/info.txt
Normal 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
|
4
xwords4/dawg/Hex/.cvsignore
Normal file
4
xwords4/dawg/Hex/.cvsignore
Normal file
|
@ -0,0 +1,4 @@
|
|||
*.bin
|
||||
*.pdb
|
||||
*.xwd
|
||||
*.seb
|
41
xwords4/dawg/Hex/Makefile
Normal file
41
xwords4/dawg/Hex/Makefile
Normal 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
61
xwords4/dawg/Hex/info.txt
Executable 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
|
3
xwords4/dawg/Italian/.cvsignore
Normal file
3
xwords4/dawg/Italian/.cvsignore
Normal file
|
@ -0,0 +1,3 @@
|
|||
*.bin
|
||||
*.xwd
|
||||
*.pdb
|
34
xwords4/dawg/Italian/Makefile
Normal file
34
xwords4/dawg/Italian/Makefile
Normal 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
60
xwords4/dawg/Italian/info.txt
Executable 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
39
xwords4/dawg/Makefile
Normal 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 $@
|
7
xwords4/dawg/Makefile.2to8
Normal file
7
xwords4/dawg/Makefile.2to8
Normal file
|
@ -0,0 +1,7 @@
|
|||
# -*-mode: Makefile -*-
|
||||
|
||||
# These are the targets that almost all language makefiles will want.
|
||||
|
||||
SHORT_WORD = 2
|
||||
LONG_WORD = 8
|
||||
|
285
xwords4/dawg/Makefile.langcommon
Normal file
285
xwords4/dawg/Makefile.langcommon
Normal 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]"
|
||||
|
8
xwords4/dawg/Polish/.cvsignore
Normal file
8
xwords4/dawg/Polish/.cvsignore
Normal file
|
@ -0,0 +1,8 @@
|
|||
*.bin
|
||||
*.pdb
|
||||
*.saved
|
||||
*.pdr
|
||||
*.ehouse
|
||||
*.seb
|
||||
decompose
|
||||
temp
|
35
xwords4/dawg/Polish/Makefile
Normal file
35
xwords4/dawg/Polish/Makefile
Normal 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
|
86
xwords4/dawg/Polish/info.txt
Normal file
86
xwords4/dawg/Polish/info.txt
Normal 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>
|
42
xwords4/dawg/Portuguese/Makefile.BrOffice
Normal file
42
xwords4/dawg/Portuguese/Makefile.BrOffice
Normal 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]"
|
42
xwords4/dawg/Portuguese/Makefile.Minho
Normal file
42
xwords4/dawg/Portuguese/Makefile.Minho
Normal 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]"
|
70
xwords4/dawg/Portuguese/info.txt
Normal file
70
xwords4/dawg/Portuguese/info.txt
Normal 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
Loading…
Add table
Reference in a new issue