mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2025-01-15 15:41:24 +01:00
support new phony to block words not in dict
Currently detects the same as tiles not in a line and calls out to a new util method that's currently parameter-less. On Android the option only appears in d variants.
This commit is contained in:
parent
988facccd1
commit
c0f074c1bf
19 changed files with 138 additions and 29 deletions
|
@ -1861,6 +1861,18 @@ public class BoardDelegate extends DelegateBase
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void informWordBlocked()
|
||||
{
|
||||
runOnUiThread( new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
makeOkOnlyBuilder( "Word blocked" )
|
||||
.show();
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playerScoreHeld( int player )
|
||||
{
|
||||
|
|
|
@ -51,7 +51,7 @@ public class CurGameInfo implements Serializable {
|
|||
private static final String PHONIES = "PHONIES";
|
||||
private static final String DUP = "DUP";
|
||||
|
||||
public enum XWPhoniesChoice { PHONIES_IGNORE, PHONIES_WARN, PHONIES_DISALLOW };
|
||||
public enum XWPhoniesChoice { PHONIES_IGNORE, PHONIES_WARN, PHONIES_DISALLOW, PHONIES_BLOCK, };
|
||||
public enum DeviceRole { SERVER_STANDALONE, SERVER_ISSERVER, SERVER_ISCLIENT };
|
||||
|
||||
public String dictName;
|
||||
|
|
|
@ -62,6 +62,7 @@ public interface UtilCtxt {
|
|||
void remSelected();
|
||||
void timerSelected( boolean inDuplicateMode, boolean canPause );
|
||||
void setIsServer( boolean isServer );
|
||||
void informWordBlocked();
|
||||
|
||||
void bonusSquareHeld( int bonus );
|
||||
void playerScoreHeld( int player );
|
||||
|
|
|
@ -106,6 +106,12 @@ public class UtilCtxtImpl implements UtilCtxt {
|
|||
subclassOverride( "setIsServer" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void informWordBlocked()
|
||||
{
|
||||
subclassOverride( "informWordBlocked" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bonusSquareHeld( int bonus )
|
||||
{
|
||||
|
|
17
xwords4/android/app/src/xw4d/res/values/tmp_for_phony.xml
Normal file
17
xwords4/android/app/src/xw4d/res/values/tmp_for_phony.xml
Normal file
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<resources xmlns:tools="http://schemas.android.com/tools"
|
||||
tools:ignore="MissingTranslation"
|
||||
>
|
||||
|
||||
<!-- These are temporary, until the new feature's released -->
|
||||
<string name="phonies_block">Block phonies</string>
|
||||
|
||||
<string-array name="phony_names">
|
||||
<item>@string/phonies_ignore</item>
|
||||
<item>@string/phonies_warn</item>
|
||||
<item>@string/phonies_disallow</item>
|
||||
<item>@string/phonies_block</item>
|
||||
</string-array>
|
||||
|
||||
</resources>
|
1
xwords4/android/app/src/xw4dNoSMS/res/values/tmp_for_phony.xml
Symbolic link
1
xwords4/android/app/src/xw4dNoSMS/res/values/tmp_for_phony.xml
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../../xw4d/res/values/tmp_for_phony.xml
|
|
@ -706,6 +706,14 @@ and_util_setIsServer( XW_UtilCtxt* uc, XP_Bool isServer )
|
|||
UTIL_CBK_TAIL();
|
||||
}
|
||||
|
||||
static void
|
||||
and_util_informWordBlocked( XW_UtilCtxt* uc )
|
||||
{
|
||||
UTIL_CBK_HEADER( "informWordBlocked", "()V" );
|
||||
(*env)->CallVoidMethod( env, util->jutil, mid );
|
||||
UTIL_CBK_TAIL();
|
||||
}
|
||||
|
||||
#ifdef XWFEATURE_DEVID
|
||||
static const XP_UCHAR*
|
||||
and_dutil_getDevID( XW_DUtilCtxt* duc, DevIDType* typ )
|
||||
|
@ -908,6 +916,7 @@ makeUtil( MPFORMAL EnvThreadInfo* ti, jobject jutil, CurGameInfo* gi,
|
|||
#endif
|
||||
|
||||
SET_PROC(getDevUtilCtxt);
|
||||
SET_PROC(informWordBlocked);
|
||||
|
||||
#undef SET_PROC
|
||||
assertTableFull( vtable, sizeof(*vtable), "util" );
|
||||
|
|
|
@ -1040,10 +1040,10 @@ typedef struct _BadWordList {
|
|||
} BadWordList;
|
||||
|
||||
static void
|
||||
saveBadWords( const WNParams* wnp )
|
||||
saveBadWords( const WNParams* wnp, void* closure )
|
||||
{
|
||||
if ( !wnp->isLegal ) {
|
||||
BadWordList* bwlp = (BadWordList*)wnp->closure;
|
||||
BadWordList* bwlp = (BadWordList*)closure;
|
||||
bwlp->bwi.words[bwlp->bwi.nWords] = &bwlp->buf[bwlp->index];
|
||||
XP_STRCAT( &bwlp->buf[bwlp->index], wnp->word );
|
||||
bwlp->index += XP_STRLEN(wnp->word) + 1;
|
||||
|
|
|
@ -140,8 +140,12 @@ typedef XP_U8 DeviceRole;
|
|||
|
||||
enum {
|
||||
PHONIES_IGNORE,
|
||||
/* You can commit a phony after viewing a warning */
|
||||
PHONIES_WARN,
|
||||
PHONIES_DISALLOW
|
||||
/* You can commit a phony, but you'll lose your turn */
|
||||
PHONIES_DISALLOW,
|
||||
/* a phony is an illegal move, like tiles out-of-line */
|
||||
PHONIES_BLOCK,
|
||||
};
|
||||
typedef XP_U8 XWPhoniesChoice;
|
||||
|
||||
|
|
|
@ -1104,9 +1104,9 @@ considerMove( EngineCtxt* engine, Tile* tiles, XP_S16 tileLength,
|
|||
} /* considerMove */
|
||||
|
||||
static void
|
||||
countWords( const WNParams* wnp )
|
||||
countWords( const WNParams* wnp, void* closure )
|
||||
{
|
||||
XP_U16* wcp = (XP_U16*)wnp->closure;
|
||||
XP_U16* wcp = (XP_U16*)closure;
|
||||
if ( wnp->isLegal ) {
|
||||
++*wcp;
|
||||
}
|
||||
|
|
|
@ -77,7 +77,7 @@ static void loadPlayerCtxt( const ModelCtxt* model, XWStreamCtxt* stream,
|
|||
static void writePlayerCtxt( const ModelCtxt* model, XWStreamCtxt* stream,
|
||||
const PlayerCtxt* pc );
|
||||
static XP_U16 model_getRecentPassCount( ModelCtxt* model );
|
||||
static void recordWord( const WNParams* wnp );
|
||||
static void recordWord( const WNParams* wnp, void *closure );
|
||||
#ifdef DEBUG
|
||||
typedef struct _DiffTurnState {
|
||||
XP_S16 lastPlayerNum;
|
||||
|
@ -2459,9 +2459,9 @@ typedef struct _FirstWordData {
|
|||
} FirstWordData;
|
||||
|
||||
static void
|
||||
getFirstWord( const WNParams* wnp )
|
||||
getFirstWord( const WNParams* wnp, void* closure )
|
||||
{
|
||||
FirstWordData* data = (FirstWordData*)wnp->closure;
|
||||
FirstWordData* data = (FirstWordData*)closure;
|
||||
if ( '\0' == data->word[0] && '\0' != wnp->word[0] ) {
|
||||
XP_STRCAT( data->word, wnp->word );
|
||||
}
|
||||
|
@ -2548,9 +2548,9 @@ appendWithCR( XWStreamCtxt* stream, const XP_UCHAR* word, XP_U16* counter )
|
|||
}
|
||||
|
||||
static void
|
||||
recordWord( const WNParams* wnp )
|
||||
recordWord( const WNParams* wnp, void* closure )
|
||||
{
|
||||
RecordWordsInfo* info = (RecordWordsInfo*)wnp->closure;
|
||||
RecordWordsInfo* info = (RecordWordsInfo*)closure;
|
||||
appendWithCR( info->stream, wnp->word, &info->nWords );
|
||||
}
|
||||
|
||||
|
@ -2572,9 +2572,9 @@ typedef struct _ListWordsThroughInfo {
|
|||
} ListWordsThroughInfo;
|
||||
|
||||
static void
|
||||
listWordsThrough( const WNParams* wnp )
|
||||
listWordsThrough( const WNParams* wnp, void* closure )
|
||||
{
|
||||
ListWordsThroughInfo* info = (ListWordsThroughInfo*)wnp->closure;
|
||||
ListWordsThroughInfo* info = (ListWordsThroughInfo*)closure;
|
||||
const MoveInfo* movei = wnp->movei;
|
||||
|
||||
XP_Bool contained = XP_FALSE;
|
||||
|
|
|
@ -291,10 +291,9 @@ typedef struct _WNParams {
|
|||
XP_U16 start;
|
||||
XP_U16 end;
|
||||
#endif
|
||||
void* closure;
|
||||
} WNParams;
|
||||
|
||||
typedef void (*WordNotifierProc)( const WNParams* wnp );
|
||||
typedef void (*WordNotifierProc)( const WNParams* wnp, void* closure );
|
||||
typedef struct WordNotifierInfo {
|
||||
WordNotifierProc proc;
|
||||
void* closure;
|
||||
|
|
|
@ -217,6 +217,24 @@ model_figureFinalScores( ModelCtxt* model, ScoresArray* finalScoresP,
|
|||
}
|
||||
} /* model_figureFinalScores */
|
||||
|
||||
typedef struct _BlockCheckState {
|
||||
WordNotifierInfo* chainNI;
|
||||
XP_Bool allLegal;
|
||||
} BlockCheckState;
|
||||
|
||||
static void
|
||||
blockCheck( const WNParams* wnp, void* closure )
|
||||
{
|
||||
BlockCheckState* bcs = (BlockCheckState*)closure;
|
||||
|
||||
if ( !!bcs->chainNI ) {
|
||||
(bcs->chainNI->proc)( wnp, bcs->chainNI->closure );
|
||||
}
|
||||
if ( !wnp->isLegal ) {
|
||||
bcs->allLegal = XP_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* checkScoreMove.
|
||||
* Negative score means illegal.
|
||||
*/
|
||||
|
@ -238,17 +256,38 @@ checkScoreMove( ModelCtxt* model, XP_S16 turn, EngineCtxt* engine,
|
|||
formatSummary( stream, model, 0 );
|
||||
}
|
||||
|
||||
} else if ( tilesInLine( model, turn, &isHorizontal ) ) {
|
||||
} else if ( !tilesInLine( model, turn, &isHorizontal ) ) {
|
||||
if ( !silent ) { /* tiles out of line */
|
||||
util_userError( model->vol.util, ERR_TILES_NOT_IN_LINE );
|
||||
}
|
||||
} else {
|
||||
MoveInfo moveInfo;
|
||||
|
||||
normalizeMoves( model, turn, isHorizontal, &moveInfo );
|
||||
|
||||
if ( isLegalMove( model, &moveInfo, silent ) ) {
|
||||
score = figureMoveScore( model, turn, &moveInfo, engine, stream,
|
||||
notifyInfo );
|
||||
/* If I'm testing for blocking, I need to chain my test onto any
|
||||
existing WordNotifierInfo. blockCheck() does that. */
|
||||
XP_Bool checkDict = PHONIES_BLOCK == model->vol.gi->phoniesAction;
|
||||
WordNotifierInfo blockWNI;
|
||||
BlockCheckState bcs;
|
||||
if ( checkDict ) {
|
||||
bcs.allLegal = XP_TRUE;
|
||||
bcs.chainNI = notifyInfo;
|
||||
blockWNI.proc = blockCheck;
|
||||
blockWNI.closure = &bcs;
|
||||
notifyInfo = &blockWNI;
|
||||
}
|
||||
|
||||
XP_S16 tmpScore = figureMoveScore( model, turn, &moveInfo,
|
||||
engine, stream, notifyInfo );
|
||||
if ( checkDict && !bcs.allLegal ) {
|
||||
if ( !silent ) {
|
||||
util_informWordBlocked( model->vol.util );
|
||||
}
|
||||
} else {
|
||||
score = tmpScore;
|
||||
}
|
||||
}
|
||||
} else if ( !silent ) { /* tiles out of line */
|
||||
util_userError( model->vol.util, ERR_TILES_NOT_IN_LINE );
|
||||
}
|
||||
return score;
|
||||
} /* checkScoreMove */
|
||||
|
@ -700,9 +739,8 @@ scoreWord( const ModelCtxt* model, XP_U16 turn,
|
|||
#ifdef XWFEATURE_BOARDWORDS
|
||||
.movei = movei, .start = start, .end = end,
|
||||
#endif
|
||||
.closure = notifyInfo->closure,
|
||||
};
|
||||
(void)(*notifyInfo->proc)( &wnp );
|
||||
(void)(*notifyInfo->proc)( &wnp, notifyInfo->closure );
|
||||
}
|
||||
|
||||
if ( !!stream ) {
|
||||
|
|
|
@ -2613,10 +2613,10 @@ server_setGameOverListener( ServerCtxt* server, GameOverListener gol,
|
|||
} /* server_setGameOverListener */
|
||||
|
||||
static void
|
||||
storeBadWords( const WNParams* wnp )
|
||||
storeBadWords( const WNParams* wnp, void* closure )
|
||||
{
|
||||
if ( !wnp->isLegal ) {
|
||||
ServerCtxt* server = (ServerCtxt*)wnp->closure;
|
||||
ServerCtxt* server = (ServerCtxt*)closure;
|
||||
const XP_UCHAR* name = dict_getShortName( wnp->dict );
|
||||
|
||||
XP_LOGF( "storeBadWords called with \"%s\" (name=%s)", wnp->word, name );
|
||||
|
|
|
@ -173,6 +173,8 @@ typedef struct UtilVtable {
|
|||
void (*m_util_setIsServer)(XW_UtilCtxt* uc, XP_Bool isServer );
|
||||
#endif
|
||||
|
||||
void (*m_util_informWordBlocked)( XW_UtilCtxt* uc );
|
||||
|
||||
#ifdef XWFEATURE_SEARCHLIMIT
|
||||
XP_Bool (*m_util_getTraySearchLimits)(XW_UtilCtxt* uc,
|
||||
XP_U16* min, XP_U16* max );
|
||||
|
@ -308,6 +310,8 @@ struct XW_UtilCtxt {
|
|||
# define util_addrChange( uc, addro, addrn )
|
||||
#endif
|
||||
|
||||
#define util_informWordBlocked(uc) (uc)->vtable->m_util_informWordBlocked( uc )
|
||||
|
||||
#ifdef XWFEATURE_SEARCHLIMIT
|
||||
#define util_getTraySearchLimits(uc,min,max) \
|
||||
(uc)->vtable->m_util_getTraySearchLimits((uc), (min), (max))
|
||||
|
|
|
@ -1049,6 +1049,11 @@ curses_util_cellSquareHeld( XW_UtilCtxt* uc, XWStreamCtxt* words )
|
|||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
curses_util_informWordBlocked( XW_UtilCtxt* XP_UNUSED(uc) )
|
||||
{
|
||||
LOG_FUNC();
|
||||
}
|
||||
|
||||
#ifndef XWFEATURE_STANDALONE_ONLY
|
||||
static XWStreamCtxt*
|
||||
|
@ -1120,6 +1125,7 @@ setupCursesUtilCallbacks( CursesBoardGlobals* bGlobals, XW_UtilCtxt* util )
|
|||
#ifdef XWFEATURE_BOARDWORDS
|
||||
SET_PROC(cellSquareHeld);
|
||||
#endif
|
||||
SET_PROC(informWordBlocked);
|
||||
|
||||
#ifdef XWFEATURE_SEARCHLIMIT
|
||||
SET_PROC(getTraySearchLimits);
|
||||
|
|
|
@ -1997,6 +1997,13 @@ gtk_util_cellSquareHeld( XW_UtilCtxt* uc, XWStreamCtxt* words )
|
|||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
gtk_util_informWordBlocked( XW_UtilCtxt* uc )
|
||||
{
|
||||
GtkGameGlobals* globals = (GtkGameGlobals*)uc->closure;
|
||||
gtkUserError( globals, "Word blocked by phonies setting" );
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_util_userError( XW_UtilCtxt* uc, UtilErrID id )
|
||||
{
|
||||
|
@ -2229,7 +2236,7 @@ setupGtkUtilCallbacks( GtkGameGlobals* globals, XW_UtilCtxt* util )
|
|||
#ifdef XWFEATURE_BOARDWORDS
|
||||
SET_PROC(cellSquareHeld);
|
||||
#endif
|
||||
|
||||
SET_PROC(informWordBlocked);
|
||||
#undef SET_PROC
|
||||
|
||||
assertTableFull( util->vtable, sizeof(*util->vtable), "gtk util" );
|
||||
|
|
|
@ -218,7 +218,7 @@ addPhoniesCombo( GtkNewGameState* state, GtkWidget* parent )
|
|||
FALSE, TRUE, 0 );
|
||||
GtkWidget* phoniesCombo = gtk_combo_box_text_new();
|
||||
|
||||
const char* ptxts[] = { "IGNORE", "WARN", "DISALLOW" };
|
||||
const char* ptxts[] = { "IGNORE", "WARN", "LOSE TURN", "BLOCK" };
|
||||
|
||||
for ( int ii = 0; ii < VSIZE(ptxts); ++ii ) {
|
||||
gtk_combo_box_text_append_text( GTK_COMBO_BOX_TEXT(phoniesCombo),
|
||||
|
@ -227,6 +227,8 @@ addPhoniesCombo( GtkNewGameState* state, GtkWidget* parent )
|
|||
|
||||
g_signal_connect( phoniesCombo, "changed",
|
||||
G_CALLBACK(phonies_combo_changed), state );
|
||||
XWPhoniesChoice startChoice = state->globals->cGlobals.params->pgi.phoniesAction;
|
||||
gtk_combo_box_set_active( GTK_COMBO_BOX(phoniesCombo), startChoice );
|
||||
gtk_widget_show( phoniesCombo );
|
||||
gtk_box_pack_start( GTK_BOX(hbox), phoniesCombo, FALSE, TRUE, 0 );
|
||||
gtk_widget_show( hbox );
|
||||
|
|
|
@ -1018,7 +1018,7 @@ static CmdInfoRec CmdInfoRecs[] = {
|
|||
,{ CMD_ADVERTISEROOM, false, "make-public", "make room public on relay" }
|
||||
,{ CMD_JOINADVERTISED, false, "join-public", "look for a public room" }
|
||||
,{ CMD_PHONIES, true, "phonies",
|
||||
"ignore (0, default), warn (1) or lose turn (2)" }
|
||||
"ignore (0, default), warn (1), lose turn (2), or refuse to commit (3)" }
|
||||
,{ CMD_BONUSFILE, true, "bonus-file",
|
||||
"provides bonus info: . + * ^ and ! are legal" }
|
||||
,{ CMD_INVITEE_RELAYID, true, "invitee-relayid", "relayID to send any invitation to" }
|
||||
|
@ -2823,8 +2823,11 @@ main( int argc, char** argv )
|
|||
case 2:
|
||||
mainParams.pgi.phoniesAction = PHONIES_DISALLOW;
|
||||
break;
|
||||
case 3:
|
||||
mainParams.pgi.phoniesAction = PHONIES_BLOCK;
|
||||
break;
|
||||
default:
|
||||
usage( argv[0], "phonies takes 0 or 1 or 2" );
|
||||
usage( argv[0], "phonies takes 0 or 1 or 2 or 3" );
|
||||
}
|
||||
break;
|
||||
case CMD_BONUSFILE:
|
||||
|
|
Loading…
Reference in a new issue