When pen held on committed tile on board, cons up list of all words

played that include that tile and pass to new util_cellSquareHeld()
method.  In java implementation of that method, use existing lookup
activity code to display list of words.  Enabled on the C side by a
compile-time flag in case it has problems.  Right now the time spent
saving a game before launching the lookup activity, and reloading it
after, is pretty apparent, but that's in emulator which is slow.
This commit is contained in:
Andy2 2011-10-13 19:14:08 -07:00
parent 7449923328
commit 0e6b4d749f
13 changed files with 201 additions and 26 deletions

View file

@ -23,6 +23,7 @@ local_DEFINES += \
-DDROP_BITMAPS \
-DDISABLE_EMPTYTRAY_UNDO \
-DDISABLE_TILE_SEL \
-DXWFEATURE_BOARDWORDS \
-DNODE_CAN_4 \
-DRELAY_ROOM_DEFAULT=\"\"\
-D__LITTLE_ENDIAN \

View file

@ -422,6 +422,21 @@ and_util_playerScoreHeld( XW_UtilCtxt* uc, XP_U16 player )
}
#endif
#ifdef XWFEATURE_BOARDWORDS
static void
and_util_cellSquareHeld( XW_UtilCtxt* uc, XWStreamCtxt* words )
{
if ( NULL != words ) {
UTIL_CBK_HEADER( "cellSquareHeld", "(Ljava/lang/String;)V" );
jstring jwords =
streamToJString( MPPARM(util->util.mpool) env, words );
(*env)->CallVoidMethod( env, util->jutil, mid, jwords );
(*env)->DeleteLocalRef( env, jwords );
UTIL_CBK_TAIL();
}
}
#endif
#ifndef XWFEATURE_STANDALONE_ONLY
static void
and_util_addrChange( XW_UtilCtxt* uc, const CommsAddrRec* oldAddr,
@ -512,6 +527,10 @@ makeUtil( MPFORMAL JNIEnv** envp, jobject jutil, CurGameInfo* gi,
SET_PROC(playerScoreHeld);
#endif
#ifdef XWFEATURE_BOARDWORDS
SET_PROC(cellSquareHeld);
#endif
#ifndef XWFEATURE_STANDALONE_ONLY
SET_PROC(addrChange);
#endif

View file

@ -1,6 +1,6 @@
/* -*- compile-command: "cd ../../../../../; ant install"; -*- */
/*
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
* Copyright 2009-2011 by Eric House (xwords@eehouse.org). All
* rights reserved.
*
* This program is free software; you can redistribute it and/or
@ -993,6 +993,16 @@ public class BoardActivity extends XWActivity
} );
}
@Override
public void cellSquareHeld( final String words )
{
post( new Runnable() {
public void run() {
launchLookup( wordsToArray( words ) );
}
} );
}
public void setTimer( int why, int when, int handle )
{
if ( null != m_timers[why] ) {

View file

@ -49,6 +49,7 @@ public interface UtilCtxt {
void bonusSquareHeld( int bonus );
void playerScoreHeld( int player );
void cellSquareHeld( String words );
static final int STRD_ROBOT_TRADED = 1;
static final int STR_ROBOT_MOVED = 2;

View file

@ -91,6 +91,10 @@ public class UtilCtxtImpl implements UtilCtxt {
{
}
public void cellSquareHeld( String words )
{
}
public String getUserString( int stringCode )
{
int id = 0;

View file

@ -726,7 +726,12 @@ hideMiniWindow( BoardCtxt* board, XP_Bool destroy, MiniWindowType winType )
#endif
static XP_Bool
warnBadWords( const XP_UCHAR* word, XP_Bool isLegal, void* closure )
warnBadWords( const XP_UCHAR* word, XP_Bool isLegal,
#ifdef XWFEATURE_BOARDWORDS
const MoveInfo* XP_UNUSED(movei),
XP_U16 XP_UNUSED(start), XP_U16 XP_UNUSED(end),
#endif
void* closure )
{
XP_Bool ok = XP_TRUE;
if ( !isLegal ) {
@ -965,15 +970,37 @@ timerFiredForPen( BoardCtxt* board )
draw = dragDropSetAdd( board );
#endif
} else {
XWBonusType bonus;
bonus = util_getSquareBonus( board->util, board->model,
col, row );
if ( bonus != BONUS_NONE ) {
#ifdef XWFEATURE_MINIWIN
text = draw_getMiniWText( board->draw, (XWMiniTextType)bonus );
#else
util_bonusSquareHeld( board->util, bonus );
XP_Bool listWords = XP_FALSE;
#ifdef XWFEATURE_BOARDWORDS
XP_U16 modelCol, modelRow;
flipIf( board, col, row, &modelCol, &modelRow );
listWords = model_getTile( board->model, modelCol, modelRow,
XP_TRUE, board->selPlayer, NULL,
NULL, NULL, NULL );
if ( listWords ) {
XWStreamCtxt* stream =
mem_stream_make( MPPARM(board->mpool)
util_getVTManager(board->util), NULL,
CHANNEL_NONE,
(MemStreamCloseCallback)NULL );
model_listWordsThrough( board->model, modelCol, modelRow,
stream );
util_cellSquareHeld( board->util, stream );
stream_destroy( stream );
}
#endif
if ( !listWords ) {
XWBonusType bonus;
bonus = util_getSquareBonus( board->util, board->model,
col, row );
if ( bonus != BONUS_NONE ) {
#ifdef XWFEATURE_MINIWIN
text = draw_getMiniWText( board->draw,
(XWMiniTextType)bonus );
#else
util_bonusSquareHeld( board->util, bonus );
#endif
}
}
}
board->penTimerFired = XP_TRUE;

View file

@ -75,7 +75,11 @@ static void loadPlayerCtxt( XWStreamCtxt* stream, XP_U16 version,
PlayerCtxt* pc );
static void writePlayerCtxt( XWStreamCtxt* stream, PlayerCtxt* pc );
static XP_U16 model_getRecentPassCount( ModelCtxt* model );
static XP_Bool recordWord( const XP_UCHAR* word, XP_Bool isLegal, void* clsur );
static XP_Bool recordWord( const XP_UCHAR* word, XP_Bool isLegal,
#ifdef XWFEATURE_BOARDWORDS
const MoveInfo* movei, XP_U16 start, XP_U16 end,
#endif
void* clsur );
/*****************************************************************************
*
@ -1948,7 +1952,11 @@ typedef struct _FirstWordData {
} FirstWordData;
static XP_Bool
getFirstWord( const XP_UCHAR* word, XP_Bool isLegal, void* closure )
getFirstWord( const XP_UCHAR* word, XP_Bool isLegal,
#ifdef XWFEATURE_BOARDWORDS
const MoveInfo* XP_UNUSED(movei), XP_U16 XP_UNUSED(start), XP_U16 XP_UNUSED(end),
#endif
void* closure )
{
LOG_FUNC();
if ( isLegal ) {
@ -2035,16 +2043,26 @@ model_recentPassCountOk( ModelCtxt* model )
return count < okCount;
}
static XP_Bool
recordWord( const XP_UCHAR* word, XP_Bool XP_UNUSED(isLegal), void* closure )
static void
appendWithCR( XWStreamCtxt* stream, const XP_UCHAR* word, XP_U16* counter )
{
RecordWordsInfo* info = (RecordWordsInfo*)closure;
XWStreamCtxt* stream = info->stream;
XP_LOGF( "%s(%s)", __func__, word );
if ( 0 < info->nWords++ ) {
if ( 0 < (*counter)++ ) {
stream_putU8( stream, '\n' );
}
stream_catString( stream, word );
}
static XP_Bool
recordWord( const XP_UCHAR* word, XP_Bool XP_UNUSED(isLegal),
#ifdef XWFEATURE_BOARDWORDS
const MoveInfo* XP_UNUSED(movei), XP_U16 XP_UNUSED(start),
XP_U16 XP_UNUSED(end),
#endif
void* closure )
{
RecordWordsInfo* info = (RecordWordsInfo*)closure;
appendWithCR( info->stream, word, &info->nWords );
return XP_TRUE;
}
@ -2085,6 +2103,65 @@ model_getWordsPlayed( ModelCtxt* model, XP_U16 nTurns, XWStreamCtxt* stream )
stack_destroy( tmpStack );
}
#ifdef XWFEATURE_BOARDWORDS
typedef struct _ListWordsThroughInfo {
XWStreamCtxt* stream;
XP_U16 col, row;
XP_U16 nWords;
} ListWordsThroughInfo;
static XP_Bool
listWordsThrough( const XP_UCHAR* word, XP_Bool XP_UNUSED(isLegal),
const MoveInfo* movei, XP_U16 start, XP_U16 end,
void* closure )
{
ListWordsThroughInfo* info = (ListWordsThroughInfo*)closure;
XP_Bool contained = XP_FALSE;
if ( movei->isHorizontal && movei->commonCoord == info->row ) {
contained = start <= info->col && end >= info->col;
} else if ( !movei->isHorizontal && movei->commonCoord == info->col ) {
contained = start <= info->row && end >= info->row;
}
if ( contained ) {
appendWithCR( info->stream, word, &info->nWords );
}
return XP_TRUE;
}
/* List every word played that includes the tile on {col,row}.
*
* How? Undo backwards until we find the move that placed that tile.*/
void
model_listWordsThrough( ModelCtxt* model, XP_U16 col, XP_U16 row,
XWStreamCtxt* stream )
{
XP_ASSERT( !!stream );
StackCtxt* stack = model->vol.stack;
StackCtxt* tmpStack = stack_copy( stack );
XP_U16 nPlayers = model->nPlayers;
XP_U16 nEntries = stack_getNEntries( stack ) - nPlayers; /* skip assignments */
if ( model_undoLatestMoves( model, NULL, nEntries, NULL, NULL ) ) {
ListWordsThroughInfo lwtInfo = { .stream = stream, .col = col,
.row = row, .nWords = 0,
};
WordNotifierInfo ni = { .proc = listWordsThrough, .closure = &lwtInfo };
/* Now push the undone moves back into the model one at a time.
recordWord() will add each played word to the stream as it's
scored */
buildModelFromStack( model, tmpStack, XP_TRUE, nPlayers,
(XWStreamCtxt*)NULL, &ni, (MovePrintFuncPre)NULL,
(MovePrintFuncPost)NULL, NULL );
}
stack_destroy( tmpStack );
}
#endif
XP_Bool
model_getPlayersLastScore( ModelCtxt* model, XP_S16 player,
XP_UCHAR* expl, XP_U16* explLen )

View file

@ -239,6 +239,10 @@ void model_countAllTrayTiles( ModelCtxt* model, XP_U16* counts,
/********************* scoring ********************/
typedef XP_Bool (*WordNotifierProc)( const XP_UCHAR* word, XP_Bool isLegal,
#ifdef XWFEATURE_BOARDWORDS
const MoveInfo* movei, XP_U16 start,
XP_U16 end,
#endif
void* closure );
typedef struct WordNotifierInfo {
WordNotifierProc proc;
@ -254,6 +258,10 @@ XP_Bool model_getPlayersLastScore( ModelCtxt* model, XP_S16 player,
XP_UCHAR* expl, XP_U16* explLen );
void model_getWordsPlayed( ModelCtxt* model, XP_U16 nTurns,
XWStreamCtxt* stream );
#ifdef XWFEATURE_BOARDWORDS
void model_listWordsThrough( ModelCtxt* model, XP_U16 col, XP_U16 row,
XWStreamCtxt* stream );
#endif
/* Have there been too many passes (so game should end)? */
XP_Bool model_recentPassCountOk( ModelCtxt* model );

View file

@ -40,9 +40,9 @@ static XP_U16 find_start( const ModelCtxt* model, XP_U16 col, XP_U16 row,
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, XP_U16 turn, MoveInfo* movei,
EngineCtxt* engine, XWStreamCtxt* stream,
WordNotifierInfo* notifyInfo );
static XP_U16 scoreWord( const ModelCtxt* model, XP_U16 turn,
const MoveInfo* movei, EngineCtxt* engine,
XWStreamCtxt* stream, WordNotifierInfo* notifyInfo );
/* 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
@ -553,7 +553,7 @@ tile_multiplier( const ModelCtxt* model, XP_U16 col, XP_U16 row )
static XP_U16
scoreWord( const ModelCtxt* model, XP_U16 turn,
MoveInfo* movei, /* new tiles */
const MoveInfo* movei, /* new tiles */
EngineCtxt* engine,/* for crosswise caching */
XWStreamCtxt* stream,
WordNotifierInfo* notifyInfo )
@ -567,7 +567,7 @@ scoreWord( const ModelCtxt* model, XP_U16 turn,
XP_U16 start, end;
XP_U16* incr;
XP_U16 col, row;
MoveInfoTile* tiles = movei->tiles;
const MoveInfoTile* tiles = movei->tiles;
XP_U16 firstCoord = tiles->varCoord;
DictionaryCtxt* dict = model_getPlayerDict( model, turn );
@ -671,7 +671,11 @@ scoreWord( const ModelCtxt* model, XP_U16 turn,
XP_UCHAR buf[(MAX_ROWS*2)+1];
dict_tilesToString( dict, checkWordBuf, len, buf,
sizeof(buf) );
(void)(*notifyInfo->proc)( buf, legal, notifyInfo->closure );
(void)(*notifyInfo->proc)( buf, legal,
#ifdef XWFEATURE_BOARDWORDS
movei, start, end,
#endif
notifyInfo->closure );
}
if ( !!stream ) {

View file

@ -1734,7 +1734,12 @@ server_setGameOverListener( ServerCtxt* server, GameOverListener gol,
} /* server_setGameOverListener */
static XP_Bool
storeBadWords( const XP_UCHAR* word, XP_Bool isLegal, void* closure )
storeBadWords( const XP_UCHAR* word, XP_Bool isLegal,
#ifdef XWFEATURE_BOARDWORDS
const MoveInfo* XP_UNUSED(movei), XP_U16 XP_UNUSED(start),
XP_U16 XP_UNUSED(end),
#endif
void* closure )
{
if ( !isLegal ) {
ServerCtxt* server = (ServerCtxt*)closure;

View file

@ -162,6 +162,9 @@ typedef struct UtilVtable {
void (*m_util_bonusSquareHeld)( XW_UtilCtxt* uc, XWBonusType bonus );
void (*m_util_playerScoreHeld)( XW_UtilCtxt* uc, XP_U16 player );
#endif
#ifdef XWFEATURE_BOARDWORDS
void (*m_util_cellSquareHeld)( XW_UtilCtxt* uc, XWStreamCtxt* words );
#endif
#ifndef XWFEATURE_STANDALONE_ONLY
void (*m_util_addrChange)( XW_UtilCtxt* uc, const CommsAddrRec* oldAddr,
@ -271,7 +274,10 @@ struct XW_UtilCtxt {
# define util_playerScoreHeld( uc, player ) \
(uc)->vtable->m_util_playerScoreHeld( (uc), (player) )
#endif
#ifdef XWFEATURE_BOARDWORDS
#define util_cellSquareHeld(uc, s) \
(uc)->vtable->m_util_cellSquareHeld( (uc), (s) )
#endif
#ifndef XWFEATURE_STANDALONE_ONLY
# define util_addrChange( uc, addro, addrn ) \
(uc)->vtable->m_util_addrChange((uc), (addro), (addrn))

View file

@ -38,6 +38,7 @@ ifdef CURSES_SMALL_SCREEN
DO_CURSES += -DCURSES_SMALL_SCREEN
endif
DO_GTK = -DPLATFORM_GTK
DO_GTK += -DXWFEATURE_BOARDWORDS
# DO_GTK += -DUSE_CAIRO
# uncomment for standalone build

View file

@ -1730,6 +1730,15 @@ gtk_util_playerScoreHeld( XW_UtilCtxt* uc, XP_U16 player )
}
#endif
#ifdef XWFEATURE_BOARDWORDS
static void
gtk_util_cellSquareHeld( XW_UtilCtxt* uc, XWStreamCtxt* words )
{
XP_USE( uc );
XP_USE( words );
}
#endif
static void
gtk_util_userError( XW_UtilCtxt* uc, UtilErrID id )
{
@ -1952,6 +1961,9 @@ setupGtkUtilCallbacks( GtkAppGlobals* globals, XW_UtilCtxt* util )
util->vtable->m_util_bonusSquareHeld = gtk_util_bonusSquareHeld;
util->vtable->m_util_playerScoreHeld = gtk_util_playerScoreHeld;
#endif
#ifdef XWFEATURE_BOARDWORDS
util->vtable->m_util_cellSquareHeld = gtk_util_cellSquareHeld;
#endif
util->closure = globals;
} /* setupGtkUtilCallbacks */