diff --git a/xwords4/android/INSTALL.txt b/xwords4/android/INSTALL.txt index b154ce8fc..b70187669 100644 --- a/xwords4/android/INSTALL.txt +++ b/xwords4/android/INSTALL.txt @@ -1,15 +1,19 @@ Here's how I'm building crosswords for Android. -First, my working directory is XWords within this (android/) -directory. And note that local.properties, also there, needs to be -edited so that sdk.dir points to where your sdk is installed. +First, the build process requires a file called local.properties that +must be generated locally. Generate it before your first build by +running ./scripts/setup_local_props.sh. + +The working directory is XWords4 within this (android/) directory. +Run the following commands from there. Build the jni library (the cross-platform code): # ../scripts/ndkbuild.sh -Then build the app for the emulator -# ant install +Then build the app for the emulator (assuming it's running) +# ant debug install Build for a device (requires you've set up your keys. I did this too long ago to remember how but the info's easy to find): # ant release +(The above command not yet verified for new SDK I installed on 11/19/11) diff --git a/xwords4/android/XWords4/build.xml b/xwords4/android/XWords4/build.xml index 5d64dabe8..e6818db59 100644 --- a/xwords4/android/XWords4/build.xml +++ b/xwords4/android/XWords4/build.xml @@ -2,69 +2,86 @@ - - + It contains the path to the SDK. It should *NOT* be checked into + Version Control Systems. --> + - - + - - + - - - - - - - + This contains project specific properties such as project target, and library + dependencies. Lower level build properties are stored in ant.properties + (or in .classpath for Eclipse projects). - + This file is an integral part of the build system for your + application and should be checked into Version Control Systems. --> + - + + - - To customize some build steps for your project: - - copy the content of the main node from android_rules.xml - - paste it in this build.xml below the task. - - disable the import by changing the setup task below to + + + + + + - + + diff --git a/xwords4/android/XWords4/default.properties b/xwords4/android/XWords4/default.properties deleted file mode 100644 index 08f98cd25..000000000 --- a/xwords4/android/XWords4/default.properties +++ /dev/null @@ -1,14 +0,0 @@ -# This file is automatically generated by Android Tools. -# Do not modify this file -- YOUR CHANGES WILL BE ERASED! -# -# This file must be checked in Version Control Systems. -# -# To customize properties used by the Ant build system use, -# "build.properties", and override values to adapt the script to your -# project structure. - -# Indicates whether an apk should be generated for each density. -split.density=false -# Project target. 4 == 1.6, but I need that for the SMS APIs. Later -# set it back to android-3 and figure out how to gracefully degrade. -target=android-4 diff --git a/xwords4/android/XWords4/jni/Android.mk b/xwords4/android/XWords4/jni/Android.mk index d9e3c4dbf..37d25f3f0 100644 --- a/xwords4/android/XWords4/jni/Android.mk +++ b/xwords4/android/XWords4/jni/Android.mk @@ -26,12 +26,14 @@ local_DEFINES += \ -DDISABLE_TILE_SEL \ -DXWFEATURE_BOARDWORDS \ -DXWFEATURE_WALKDICT \ + -DXWFEATURE_WALKDICT_FILTER \ -DXWFEATURE_DICTSANITY \ -DFEATURE_TRAY_EDIT \ -DNODE_CAN_4 \ -DRELAY_ROOM_DEFAULT=\"\"\ -D__LITTLE_ENDIAN \ + local_SRC_FILES += \ xwjni.c \ utilwrapper.c \ diff --git a/xwords4/android/XWords4/jni/anddict.c b/xwords4/android/XWords4/jni/anddict.c index 8cd53e6a3..2f986efd2 100644 --- a/xwords4/android/XWords4/jni/anddict.c +++ b/xwords4/android/XWords4/jni/anddict.c @@ -1,7 +1,7 @@ -/* -*-mode: C; compile-command: "../../scripts/ndkbuild.sh"; -*- */ +/* -*- compile-command: "../../scripts/ndkbuild.sh"; -*- */ /* - * Copyright © 2009-2010 by Eric House (xwords@eehouse.org). All - * rights reserved. + * Copyright © 2009 - 2011 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 @@ -45,7 +45,7 @@ typedef struct _AndDictionaryCtxt { } AndDictionaryCtxt; #define CHECK_PTR(p,c,e) \ - if ( ((p)+(c)) >= (e) ) { \ + if ( ((p)+(c)) > (e) ) { \ XP_LOGF( "%s (line %d); out of bytes", __func__, __LINE__ ); \ goto error; \ } @@ -568,14 +568,15 @@ makeDict( MPFORMAL JNIEnv *env, JNIUtilCtxt* jniutil, jstring jname, XP_U32 numEdges; XP_Bool parses = parseDict( anddict, (XP_U8*)anddict->bytes, bytesSize, &numEdges ); - if ( !parses || (check && !checkSanity( &anddict->super, numEdges ) ) ) { + if ( !parses || (check && !checkSanity( &anddict->super, + numEdges ) ) ) { and_dictionary_destroy( (DictionaryCtxt*)anddict ); anddict = NULL; } } return (DictionaryCtxt*)anddict; -} +} /* makeDict */ void destroyDicts( PlayerDicts* dicts ) diff --git a/xwords4/android/XWords4/jni/utilwrapper.c b/xwords4/android/XWords4/jni/utilwrapper.c index 8e065e038..6a2d6b82e 100644 --- a/xwords4/android/XWords4/jni/utilwrapper.c +++ b/xwords4/android/XWords4/jni/utilwrapper.c @@ -77,10 +77,11 @@ and_util_makeStreamFromAddr( XW_UtilCtxt* uc, XP_PlayerAddr channelNo ) } static XWBonusType and_util_getSquareBonus( XW_UtilCtxt* XP_UNUSED(uc), - const ModelCtxt* XP_UNUSED(model), + XP_U16 boardSize, XP_U16 col, XP_U16 row ) { - static const int s_buttsBoard[8][8] = { +#define BONUS_DIM 8 + static const int s_buttsBoard[BONUS_DIM][BONUS_DIM] = { { BONUS_TRIPLE_WORD, BONUS_NONE, BONUS_NONE,BONUS_DOUBLE_LETTER,BONUS_NONE,BONUS_NONE,BONUS_NONE,BONUS_TRIPLE_WORD }, { BONUS_NONE, BONUS_DOUBLE_WORD, BONUS_NONE,BONUS_NONE,BONUS_NONE,BONUS_TRIPLE_LETTER,BONUS_NONE,BONUS_NONE }, @@ -94,10 +95,12 @@ static XWBonusType and_util_getSquareBonus( XW_UtilCtxt* XP_UNUSED(uc), { BONUS_TRIPLE_WORD, BONUS_NONE, BONUS_NONE,BONUS_DOUBLE_LETTER,BONUS_NONE,BONUS_NONE,BONUS_NONE,BONUS_DOUBLE_WORD }, }; /* buttsBoard */ - int half = 15 / 2; /* remove 15!!!! PENDING */ + int half = boardSize / 2; if ( col > half ) { col = (half*2) - col; } if ( row > half ) { row = (half*2) - row; } + XP_ASSERT( col < BONUS_DIM && row < BONUS_DIM ); return s_buttsBoard[row][col]; +#undef BONUS_DIM } static void diff --git a/xwords4/android/XWords4/jni/xwjni.c b/xwords4/android/XWords4/jni/xwjni.c index 587e79ad6..d053916b1 100644 --- a/xwords4/android/XWords4/jni/xwjni.c +++ b/xwords4/android/XWords4/jni/xwjni.c @@ -1310,13 +1310,11 @@ Java_org_eehouse_android_xw4_jni_XwJNI_dict_1iter_1init data->vtMgr = make_vtablemgr( MPPARM_NOCOMMA(mpool) ); data->jniutil = jniutil; data->dict = dict; + data->depth = 2; #ifdef MEM_DEBUG data->mpool = mpool; #endif closure = (int)data; - - dict_initIter( data->dict, &data->iter ); - (void)dict_firstWord( &data->iter ); } else { destroyJNIUtil( &jniutil ); XP_FREE( mpool, data ); @@ -1327,6 +1325,63 @@ Java_org_eehouse_android_xw4_jni_XwJNI_dict_1iter_1init return closure; } +static void +freeIndices( DictIterData* data ) +{ + IndexData* idata = &data->idata; + if ( !!idata->prefixes ) { + XP_FREE( data->mpool, idata->prefixes ); + idata->prefixes = NULL; + } + if( !!idata->indices ) { + XP_FREE( data->mpool, idata->indices ); + idata->indices = NULL; + } +} + +static void +makeIndex( DictIterData* data ) +{ + XP_U16 nFaces = dict_numTileFaces( data->dict ); + XP_U16 ii; + XP_U16 count; + for ( count = 1, ii = 0; ii < data->depth; ++ii ) { + count *= nFaces; + } + + freeIndices( data ); + + IndexData* idata = &data->idata; + idata->prefixes = XP_MALLOC( data->mpool, count * data->depth + * sizeof(*idata->prefixes) ); + idata->indices = XP_MALLOC( data->mpool, + count * sizeof(*idata->indices) ); + idata->count = count; + + dict_makeIndex( &data->iter, data->depth, idata ); + if ( 0 < idata->count ) { + idata->prefixes = XP_REALLOC( data->mpool, idata->prefixes, + idata->count * data->depth * + sizeof(*idata->prefixes) ); + idata->indices = XP_REALLOC( data->mpool, idata->indices, + idata->count * sizeof(*idata->indices) ); + } else { + freeIndices( data ); + } +} /* makeIndex */ + +JNIEXPORT void JNICALL +Java_org_eehouse_android_xw4_jni_XwJNI_dict_1iter_1setMinMax +( JNIEnv* env, jclass C, jint closure, jint min, jint max ) +{ + DictIterData* data = (DictIterData*)closure; + if ( NULL != data ) { + dict_initIter( &data->iter, data->dict, min, max ); + makeIndex( data ); + (void)dict_firstWord( &data->iter ); + } +} + JNIEXPORT void JNICALL Java_org_eehouse_android_xw4_jni_XwJNI_dict_1iter_1destroy ( JNIEnv* env, jclass C, jint closure ) @@ -1338,12 +1393,7 @@ Java_org_eehouse_android_xw4_jni_XwJNI_dict_1iter_1destroy #endif dict_destroy( data->dict ); destroyJNIUtil( &data->jniutil ); - if ( !!data->idata.indices ) { - XP_FREE( mpool, data->idata.indices ); - } - if ( !!data->idata.prefixes ) { - XP_FREE( mpool, data->idata.prefixes ); - } + freeIndices( data ); vtmgr_destroy( MPPARM(mpool) data->vtMgr ); XP_FREE( mpool, data ); #ifdef MEM_DEBUG @@ -1364,37 +1414,24 @@ Java_org_eehouse_android_xw4_jni_XwJNI_dict_1iter_1wordCount return result; } -JNIEXPORT void JNICALL -Java_org_eehouse_android_xw4_jni_XwJNI_dict_1iter_1makeIndex -( JNIEnv* env, jclass C, jint closure ) +JNIEXPORT jintArray JNICALL +Java_org_eehouse_android_xw4_jni_XwJNI_dict_1iter_1getCounts +(JNIEnv* env, jclass C, jint closure ) { + jintArray result = NULL; DictIterData* data = (DictIterData*)closure; if ( NULL != data ) { - data->depth = 2; /* for now */ - XP_U16 nFaces = dict_numTileFaces( data->dict ); - XP_U16 ii; - XP_U16 count; - for ( count = 1, ii = 0; ii < data->depth; ++ii ) { - count *= nFaces; + DictIter iter; + dict_initIter( &iter, data->dict, 0, MAX_COLS_DICT ); + + LengthsArray lens; + if ( 0 < dict_countWords( &iter, &lens ) ) { + XP_ASSERT( sizeof(jint) == sizeof(lens.lens[0]) ); + result = makeIntArray( env, VSIZE(lens.lens), (jint*)&lens.lens ); + (*env)->DeleteLocalRef( env, result ); } - - IndexData* idata = &data->idata; - XP_ASSERT( !idata->prefixes ); - idata->prefixes = XP_MALLOC( data->mpool, count * data->depth - * sizeof(*idata->prefixes) ); - XP_ASSERT( !idata->indices ); - idata->indices = XP_MALLOC( data->mpool, - count * sizeof(*idata->indices) ); - idata->count = count; - - dict_makeIndex( &data->iter, data->depth, idata ); - - idata->prefixes = XP_REALLOC( data->mpool, idata->prefixes, - idata->count * data->depth * - sizeof(*idata->prefixes) ); - idata->indices = XP_REALLOC( data->mpool, idata->indices, - idata->count * sizeof(*idata->indices) ); } + return result; } JNIEXPORT jobjectArray JNICALL diff --git a/xwords4/android/XWords4/res/layout/dict_browser.xml b/xwords4/android/XWords4/res/layout/dict_browser.xml index 41b27633b..98f02ed64 100644 --- a/xwords4/android/XWords4/res/layout/dict_browser.xml +++ b/xwords4/android/XWords4/res/layout/dict_browser.xml @@ -35,4 +35,30 @@ android:drawSelectorOnTop="false" /> + + + + + + + diff --git a/xwords4/android/XWords4/res/values/strings.xml b/xwords4/android/XWords4/res/values/strings.xml index d282ed05a..5bd5f32a3 100644 --- a/xwords4/android/XWords4/res/values/strings.xml +++ b/xwords4/android/XWords4/res/values/strings.xml @@ -1784,10 +1784,20 @@ Tile picker\n(so far: %s) Pick tiles face-up - %1$s (%2$d words) + %1$s (%2$d words using %3$d-%4$d + tiles) + %1$s (%2$d words using %3$d + tiles) No word in %1$s starts with %2$s. This button opens the wordlist browser on the current player\'s wordlist. + The wordlist %s contains only + tile information. There are no words to browse. + + Min len + Max len + Words no shorter than + Words no longer than diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java index 5521a720b..cb2ca06ac 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* * Copyright 2009-2011 by Eric House (xwords@eehouse.org). All * rights reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardDims.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardDims.java index b8f81474b..f04c1fe58 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardDims.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardDims.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* * Copyright 2009-2010 by Eric House (xwords@eehouse.org). All * rights reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardView.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardView.java index 12e936dcc..866715509 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardView.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardView.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* * Copyright 2009-2010 by Eric House (xwords@eehouse.org). All * rights reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/ChatActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/ChatActivity.java index 3f5c8163d..7b7e8c6cf 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/ChatActivity.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/ChatActivity.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* * Copyright 2011 by Eric House (xwords@eehouse.org). All rights * reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/CommsTransport.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/CommsTransport.java index 336773f6f..f3120e1c6 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/CommsTransport.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/CommsTransport.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* * Copyright 2009-2010 by Eric House (xwords@eehouse.org). All * rights reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBHelper.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBHelper.java index 7e835f829..1239b8a52 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBHelper.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBHelper.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* * Copyright 2009-2010 by Eric House (xwords@eehouse.org). All * rights reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java index 9bed7ef77..02f4ebbf4 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* * Copyright 2009-2010 by Eric House (xwords@eehouse.org). All * rights reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictBrowseActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictBrowseActivity.java index c0418fe38..7983982a8 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictBrowseActivity.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictBrowseActivity.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* * Copyright 2009 - 2011 by Eric House (xwords@eehouse.org). All * rights reserved. @@ -27,12 +27,16 @@ import android.os.Bundle; import android.text.TextUtils; import android.view.View; import android.view.ViewGroup; +import android.widget.ArrayAdapter; import android.widget.BaseAdapter; import android.widget.Button; import android.widget.EditText; import android.widget.ListAdapter; import android.widget.SectionIndexer; +import android.widget.Spinner; import android.widget.TextView; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemSelectedListener; import java.util.Arrays; import junit.framework.Assert; @@ -41,15 +45,27 @@ import org.eehouse.android.xw4.jni.JNIUtilsImpl; import org.eehouse.android.xw4.jni.XwJNI; public class DictBrowseActivity extends XWListActivity - implements View.OnClickListener { + implements View.OnClickListener, OnItemSelectedListener { public static final String DICT_NAME = "DICT_NAME"; + public static final String DICT_MIN = "DICT_MIN"; + public static final String DICT_MAX = "DICT_MAX"; + public static final String DICT_COUNTS = "DICT_COUNTS"; + + private static final int MIN_LEN = 2; + private static final int FINISH_ACTION = 1; private int m_dictClosure = 0; private int m_lang; private String m_name; - private int m_nWords; - private float m_textSize; + private Spinner m_minSpinner; + private Spinner m_maxSpinner; + private int m_minShown; + private int m_maxShown; + private int m_minAvail; + private int m_maxAvail; + private int[] m_counts; + // - Steps to reproduce the problem: // Create ListView, set custom adapter which implements ListAdapter and @@ -62,15 +78,30 @@ public class DictBrowseActivity extends XWListActivity private String[] m_prefixes; private int[] m_indices; + private int m_nWords; + + public DictListAdapter() + { + super(); + + XwJNI.dict_iter_setMinMax( m_dictClosure, m_minShown, m_maxShown ); + m_nWords = XwJNI.dict_iter_wordCount( m_dictClosure ); + + int format = m_minShown == m_maxShown ? + R.string.dict_browse_title1f : R.string.dict_browse_titlef; + setTitle( Utils.format( DictBrowseActivity.this, format, + m_name, m_nWords, m_minShown, m_maxShown )); + } public Object getItem( int position ) { - TextView text = new TextView( DictBrowseActivity.this ); + TextView text = + (TextView)Utils.inflate( DictBrowseActivity.this, + android.R.layout.simple_list_item_1 ); String str = XwJNI.dict_iter_nthWord( m_dictClosure, position ); if ( null != str ) { text.setText( str ); text.setOnClickListener( DictBrowseActivity.this ); - text.setTextSize( m_textSize ); } return text; } @@ -125,33 +156,44 @@ public class DictBrowseActivity extends XWListActivity m_name = name; m_lang = DictLangCache.getDictLangCode( this, name ); - m_textSize = 2.0f + new TextView( this ).getTextSize(); - String[] names = { name }; DictUtils.DictPairs pairs = DictUtils.openDicts( this, names ); m_dictClosure = XwJNI.dict_iter_init( pairs.m_bytes[0], pairs.m_paths[0], JNIUtilsImpl.get() ); - m_nWords = XwJNI.dict_iter_wordCount( m_dictClosure ); - setTitle( Utils.format( this, R.string.dict_browse_titlef, - name, m_nWords ) ); + m_counts = intent.getIntArrayExtra( DICT_COUNTS ); + if ( null == m_counts ) { + m_counts = XwJNI.dict_iter_getCounts( m_dictClosure ); + } + if ( null == m_counts ) { + // empty dict? Just close down for now. Later if + // this is extended to include tile info -- it should + // be -- then use an empty list elem and disable + // search/minmax stuff. + String msg = Utils.format( this, R.string.alert_empty_dictf, + name ); + showOKOnlyDialogThen( msg, FINISH_ACTION ); + } else { + figureMinMax(); - Utils.logf( "calling makeIndex" ); - XwJNI.dict_iter_makeIndex( m_dictClosure ); - Utils.logf( "makeIndex done" ); + setContentView( R.layout.dict_browser ); - setContentView( R.layout.dict_browser ); - setListAdapter( new DictListAdapter() ); - getListView().setFastScrollEnabled( true ); + Button button = (Button)findViewById( R.id.search_button ); + button.setOnClickListener( new View.OnClickListener() { + public void onClick( View view ) + { + findButtonClicked(); + } + } ); - Button button = (Button)findViewById( R.id.search_button ); - button.setOnClickListener( new View.OnClickListener() { - public void onClick( View view ) - { - findButtonClicked(); - } - } ); + m_minShown = intent.getIntExtra( DICT_MIN, m_minAvail ); + m_maxShown = intent.getIntExtra( DICT_MAX, m_maxAvail ); + setUpSpinners(); + + setListAdapter( new DictListAdapter() ); + getListView().setFastScrollEnabled( true ); + } } } @@ -187,6 +229,36 @@ public class DictBrowseActivity extends XWListActivity launchLookup( words, m_lang, true ); } + + ////////////////////////////////////////////////// + // AdapterView.OnItemSelectedListener interface + ////////////////////////////////////////////////// + public void onItemSelected( AdapterView parent, View view, + int position, long id ) + { + TextView text = (TextView)view; + int newval = Integer.parseInt( text.getText().toString() ); + if ( parent == m_minSpinner ) { + setMinMax( newval, m_maxShown ); + } else if ( parent == m_maxSpinner ) { + setMinMax( m_minShown, newval ); + } + } + + public void onNothingSelected( AdapterView parent ) + { + } + + ////////////////////////////////////////////////// + // DlgDelegate.DlgClickNotify interface + ////////////////////////////////////////////////// + @Override + public void dlgButtonClicked( int id, int which ) + { + Assert.assertTrue( FINISH_ACTION == id ); + finish(); + } + private void findButtonClicked() { EditText edit = (EditText)findViewById( R.id.word_edit ); @@ -202,6 +274,75 @@ public class DictBrowseActivity extends XWListActivity } } + private void setMinMax( int min, int max ) + { + // I can't make a second call to setListAdapter() work, nor + // does notifyDataSetChanged do anything toward refreshing the + // adapter/making it recognized a changed dataset. So, as a + // workaround, relaunch the activity with different + // parameters. + if ( m_minShown != min || m_maxShown != max ) { + Intent intent = getIntent(); + intent.putExtra( DICT_MIN, min ); + intent.putExtra( DICT_MAX, max ); + intent.putExtra( DICT_COUNTS, m_counts ); + startActivity( intent ); + + finish(); + } + } + + private void figureMinMax() + { + Assert.assertTrue( m_counts.length == XwJNI.MAX_COLS_DICT + 1 ); + m_minAvail = 0; + while ( 0 == m_counts[m_minAvail] ) { + ++m_minAvail; + } + m_maxAvail = XwJNI.MAX_COLS_DICT; + while ( 0 == m_counts[m_maxAvail] ) { // + --m_maxAvail; + } + } + + private void makeAdapter( Spinner spinner, int min, int max, int cur ) + { + int sel = -1; + String[] nums = new String[max - min + 1]; + for ( int ii = 0; ii < nums.length; ++ii ) { + int val = min + ii; + if ( val == cur ) { + sel = ii; + } + nums[ii] = String.format( "%d", min + ii ); + } + ArrayAdapter adapter = new + ArrayAdapter( this, + //android.R.layout.simple_spinner_dropdown_item, + android.R.layout.simple_spinner_item, + nums ); + adapter.setDropDownViewResource( android.R.layout. + simple_spinner_dropdown_item ); + spinner.setAdapter( adapter ); + spinner.setSelection( sel ); + } + + private void setUpSpinners() + { + // Min and max-length spinners. To avoid empty lists, + // don't allow min to exceed max. Do that by making the + // current max the largest min allowed, and the current + // min the smallest max allowed. + m_minSpinner = (Spinner)findViewById( R.id.wordlen_min ); + makeAdapter( m_minSpinner, m_minAvail, m_maxShown, m_minShown ); + m_minSpinner.setOnItemSelectedListener( this ); + + m_maxSpinner = (Spinner)findViewById( R.id.wordlen_max ); + makeAdapter( m_maxSpinner, m_minShown, m_maxAvail, m_maxShown ); + m_maxSpinner.setOnItemSelectedListener( this ); + } + + public static void launch( Context caller, String name ) { Intent intent = new Intent( caller, DictBrowseActivity.class ); diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictImportActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictImportActivity.java index a11ff4090..ea4f6f9fa 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictImportActivity.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictImportActivity.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* * Copyright 2009-2010 by Eric House (xwords@eehouse.org). All * rights reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictLangCache.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictLangCache.java index 3589e1b7b..2226df485 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictLangCache.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictLangCache.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* * Copyright 2010 by Eric House (xwords@eehouse.org). All rights * reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictListPreference.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictListPreference.java index 572bb1962..c4dd54542 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictListPreference.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictListPreference.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* * Copyright 2010 by Eric House (xwords@eehouse.org). All * rights reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictUtils.java index 556aa4379..b2ea774cf 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictUtils.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictUtils.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* * Copyright 2009-2011 by Eric House (xwords@eehouse.org). All rights * reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictsActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictsActivity.java index cd955715e..d1c4d4fd2 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictsActivity.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictsActivity.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* * Copyright 2009 - 2011 by Eric House (xwords@eehouse.org). All * rights reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DispatchNotify.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DispatchNotify.java index b4e69587f..fee6956dd 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DispatchNotify.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DispatchNotify.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* * Copyright 2010 by Eric House (xwords@eehouse.org). All rights * reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DlgDelegate.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DlgDelegate.java index 16ee34442..307e9b4a2 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DlgDelegate.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DlgDelegate.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* * Copyright 2009-2010 by Eric House (xwords@eehouse.org). All * rights reserved. @@ -160,7 +160,7 @@ public class DlgDelegate { // showNotAgainDlgThen() is called // FALLTHRU case DIALOG_OKONLY: - ad.setMessage( m_activity.getString(m_msgID) ); + ad.setMessage( m_msg ); break; case CONFIRM_THEN: ad.getButton(AlertDialog.BUTTON_POSITIVE). @@ -170,10 +170,19 @@ public class DlgDelegate { } } + public void showOKOnlyDialog( String msg, int callbackID ) + { + m_msg = msg; + if ( 0 != callbackID ) { + Assert.assertTrue( 0 == m_cbckID ); + m_cbckID = callbackID; + } + m_activity.showDialog( DIALOG_OKONLY ); + } + public void showOKOnlyDialog( int msgID ) { - m_msgID = msgID; - m_activity.showDialog( DIALOG_OKONLY ); + showOKOnlyDialog( m_activity.getString( msgID ), 0 ); } public void showDictGoneFinish() @@ -289,11 +298,15 @@ public class DlgDelegate { private Dialog createOKDialog() { - return new AlertDialog.Builder( m_activity ) + Dialog dialog = new AlertDialog.Builder( m_activity ) .setTitle( R.string.info_title ) - .setMessage( m_msgID ) + .setMessage( m_msg ) .setPositiveButton( R.string.button_ok, null ) .create(); + if ( 0 != m_cbckID ) { + dialog = setCallbackDismissListener( dialog ); + } + return dialog; } private Dialog createNotAgainDialog() diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/EditColorPreference.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/EditColorPreference.java index e33eaf313..b0bb65747 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/EditColorPreference.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/EditColorPreference.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* * Copyright 2009-2010 by Eric House (xwords@eehouse.org). All * rights reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/FirstRunDialog.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/FirstRunDialog.java index 01efffaf5..46539ca39 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/FirstRunDialog.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/FirstRunDialog.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* * Copyright 2010 by Eric House (xwords@eehouse.org). All rights * reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameConfig.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameConfig.java index 51b80d9b6..cbe7e8844 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameConfig.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameConfig.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* * Copyright 2009-2010 by Eric House (xwords@eehouse.org). All * rights reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListAdapter.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListAdapter.java index f1237bc5e..9e861ff1d 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListAdapter.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameListAdapter.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* * Copyright 2009-2010 by Eric House (xwords@eehouse.org). All * rights reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java index 38a7ae85e..e5c34b1bb 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* * Copyright 2009-2010 by Eric House (xwords@eehouse.org). All * rights reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java index bb8788075..354d6f6d2 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* * Copyright 2009-2010 by Eric House (xwords@eehouse.org). All * rights reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/LookupView.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/LookupView.java index 9803d707a..25bbfa994 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/LookupView.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/LookupView.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* * Copyright 2009-2011 by Eric House (xwords@eehouse.org). All * rights reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/MountEventReceiver.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/MountEventReceiver.java index fb49a8487..f3c9652f0 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/MountEventReceiver.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/MountEventReceiver.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* * Copyright 2009-2010 by Eric House (xwords@eehouse.org). All * rights reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/NBSReceiver.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/NBSReceiver.java index 51d2a5a5d..471200df5 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/NBSReceiver.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/NBSReceiver.java @@ -1,4 +1,4 @@ -// /* -*- compile-command: "cd ../../../../../; ant install"; -*- */ +// /* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ // /* // * Copyright 2010 by Eric House (xwords@eehouse.org). All rights // * reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/NetLaunchInfo.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/NetLaunchInfo.java index 1893bb0a3..79f56e489 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/NetLaunchInfo.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/NetLaunchInfo.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* * Copyright 2009-2011 by Eric House (xwords@eehouse.org). All * rights reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/NetStateCache.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/NetStateCache.java index 81c7df04b..84beb91a5 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/NetStateCache.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/NetStateCache.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* * Copyright 2010 by Eric House (xwords@eehouse.org). All rights * reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/NetUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/NetUtils.java index 7513dbc94..082984f2d 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/NetUtils.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/NetUtils.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* * Copyright 2009-2010 by Eric House (xwords@eehouse.org). All * rights reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/NewGameActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/NewGameActivity.java index af638595f..86783fc87 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/NewGameActivity.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/NewGameActivity.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* * Copyright 2009-2010 by Eric House (xwords@eehouse.org). All * rights reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/PollListPreference.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/PollListPreference.java index a54da4336..48b516070 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/PollListPreference.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/PollListPreference.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* * Copyright 2009-2010 by Eric House (xwords@eehouse.org). All * rights reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/PrefsActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/PrefsActivity.java index ba45c5052..a9a65aad7 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/PrefsActivity.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/PrefsActivity.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* * Copyright 2009-2010 by Eric House (xwords@eehouse.org). All * rights reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/RefreshNamesTask.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/RefreshNamesTask.java index e4f456a26..64c75c427 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/RefreshNamesTask.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/RefreshNamesTask.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* * Copyright 2009-2010 by Eric House (xwords@eehouse.org). All * rights reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/RelayGameActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/RelayGameActivity.java index 4f23b8ede..7363acc59 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/RelayGameActivity.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/RelayGameActivity.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* * Copyright 2009-2010 by Eric House (xwords@eehouse.org). All * rights reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/RelayReceiver.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/RelayReceiver.java index aca23d33c..04429a758 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/RelayReceiver.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/RelayReceiver.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* * Copyright 2010 by Eric House (xwords@eehouse.org). All rights * reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/RelayService.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/RelayService.java index c8f597dd4..1b5096ce9 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/RelayService.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/RelayService.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* * Copyright 2010 - 2011 by Eric House (xwords@eehouse.org). All * rights reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/StatusReceiver.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/StatusReceiver.java index 1c6b1de85..f4495e9ab 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/StatusReceiver.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/StatusReceiver.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* * Copyright 2009-2010 by Eric House (xwords@eehouse.org). All * rights reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/Toolbar.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/Toolbar.java index 5d9f15097..a2d3dc763 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/Toolbar.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/Toolbar.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* * Copyright 2009-2010 by Eric House (xwords@eehouse.org). All * rights reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/Utils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/Utils.java index 0a46f90bf..3923d283e 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/Utils.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/Utils.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* * Copyright 2009-2010 by Eric House (xwords@eehouse.org). All * rights reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWActivity.java index 3ecebe44e..eb5167c70 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWActivity.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWActivity.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* * Copyright 2010 by Eric House (xwords@eehouse.org). All rights * reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWApp.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWApp.java index 5605981d4..8bc856c86 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWApp.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWApp.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* * Copyright 2010 - 2011 by Eric House (xwords@eehouse.org). All * rights reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWConstants.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWConstants.java index 2c8e84c90..9dee0732b 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWConstants.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWConstants.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* * Copyright 2009-2010 by Eric House (xwords@eehouse.org). All * rights reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWEditTextPreference.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWEditTextPreference.java index 26639a685..12daebf3c 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWEditTextPreference.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWEditTextPreference.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* * Copyright 2010 by Eric House (xwords@eehouse.org). All * rights reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWListActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWListActivity.java index 1dc105f12..7ae6f6d12 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWListActivity.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWListActivity.java @@ -1,7 +1,7 @@ -/* -*- compile-command: "cd ../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* - * Copyright 2010 by Eric House (xwords@eehouse.org). All rights - * reserved. + * Copyright 2010 - 2011 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 @@ -122,6 +122,16 @@ public class XWListActivity extends ListActivity m_delegate.showNotAgainDlgThen( msgID, prefsKey ); } + protected void showOKOnlyDialogThen( String msg, int action ) + { + m_delegate.showOKOnlyDialog( msg, action ); + } + + protected void showOKOnlyDialog( String msg ) + { + m_delegate.showOKOnlyDialog( msg, 0 ); + } + protected void showOKOnlyDialog( int msgID ) { m_delegate.showOKOnlyDialog( msgID ); diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWListAdapter.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWListAdapter.java index 5a3f557fc..069191e81 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWListAdapter.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWListAdapter.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* * Copyright 2009-2010 by Eric House (xwords@eehouse.org). All * rights reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWListItem.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWListItem.java index ec4e3a8ce..6c17298f6 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWListItem.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWListItem.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* * Copyright 2009-2010 by Eric House (xwords@eehouse.org). All * rights reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWListPreference.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWListPreference.java index e608ba1d1..9a3754e87 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWListPreference.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWListPreference.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */ /* * Copyright 2010 - 2011 by Eric House (xwords@eehouse.org). All * rights reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/BoardHandler.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/BoardHandler.java index bdadcdecd..bd50db042 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/BoardHandler.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/BoardHandler.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../../; ant debug install"; -*- */ /* * Copyright 2009-2010 by Eric House (xwords@eehouse.org). All * rights reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/CommonPrefs.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/CommonPrefs.java index db5b0cdda..22081769b 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/CommonPrefs.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/CommonPrefs.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../../; ant debug install"; -*- */ /* * Copyright 2009-2010 by Eric House (xwords@eehouse.org). All * rights reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/CommsAddrRec.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/CommsAddrRec.java index 995783e9b..a6dddf6dc 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/CommsAddrRec.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/CommsAddrRec.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../../; ant debug install"; -*- */ /* * Copyright 2009-2010 by Eric House (xwords@eehouse.org). All * rights reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/CurGameInfo.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/CurGameInfo.java index 18e930bdc..9eec87d35 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/CurGameInfo.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/CurGameInfo.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../../; ant debug install"; -*- */ /* * Copyright 2009-2010 by Eric House (xwords@eehouse.org). All * rights reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/DictInfo.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/DictInfo.java index bdd366df4..26aa1f7bb 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/DictInfo.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/DictInfo.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../../; ant debug install"; -*- */ /* * Copyright 2009-2010 by Eric House (xwords@eehouse.org). All * rights reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/DrawCtx.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/DrawCtx.java index b1767e1ef..41740544f 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/DrawCtx.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/DrawCtx.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../../; ant debug install"; -*- */ /* * Copyright 2009-2010 by Eric House (xwords@eehouse.org). All * rights reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/GameSummary.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/GameSummary.java index e1abd23c6..7ce28e681 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/GameSummary.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/GameSummary.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../../; ant debug install"; -*- */ /* * Copyright 2009-2010 by Eric House (xwords@eehouse.org). All * rights reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIThread.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIThread.java index f272e64a3..06b5021e5 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIThread.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIThread.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../../; ant debug install"; -*- */ /* * Copyright 2009-2010 by Eric House (xwords@eehouse.org). All * rights reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIUtils.java index 42fef3cb2..03bbe39cb 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIUtils.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIUtils.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../../; ant debug install"; -*- */ /* * Copyright 2009-2010 by Eric House (xwords@eehouse.org). All * rights reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIUtilsImpl.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIUtilsImpl.java index 349fbb8fe..1e9deb4f6 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIUtilsImpl.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIUtilsImpl.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../../; ant debug install"; -*- */ /* * Copyright 2009-2010 by Eric House (xwords@eehouse.org). All * rights reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/LocalPlayer.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/LocalPlayer.java index a2b8cdd11..09854bc48 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/LocalPlayer.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/LocalPlayer.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../../; ant debug install"; -*- */ /* * Copyright 2009-2010 by Eric House (xwords@eehouse.org). All * rights reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/SyncedDraw.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/SyncedDraw.java index 856a423b9..08673e84c 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/SyncedDraw.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/SyncedDraw.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../../; ant debug install"; -*- */ /* * Copyright 2009-2010 by Eric House (xwords@eehouse.org). All * rights reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/TransportProcs.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/TransportProcs.java index 53f7603b5..879cc170c 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/TransportProcs.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/TransportProcs.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../../; ant debug install"; -*- */ /* * Copyright 2009-2010 by Eric House (xwords@eehouse.org). All * rights reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/UtilCtxt.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/UtilCtxt.java index ecccfa073..f2d95790b 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/UtilCtxt.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/UtilCtxt.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../../; ant debug install"; -*- */ /* * Copyright 2009-2010 by Eric House (xwords@eehouse.org). All * rights reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/UtilCtxtImpl.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/UtilCtxtImpl.java index 2b5d2c1bb..bb335d2a3 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/UtilCtxtImpl.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/UtilCtxtImpl.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../../; ant debug install"; -*- */ /* * Copyright 2009-2010 by Eric House (xwords@eehouse.org). All * rights reserved. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/XwJNI.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/XwJNI.java index 9b71bec9b..1cca98edb 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/XwJNI.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/XwJNI.java @@ -1,4 +1,4 @@ -/* -*- compile-command: "cd ../../../../../../; ant install"; -*- */ +/* -*- compile-command: "cd ../../../../../../; ant debug install"; -*- */ /* * Copyright 2009-2010 by Eric House (xwords@eehouse.org). All * rights reserved. @@ -244,12 +244,15 @@ public class XwJNI { public static native int dict_getTileValue( int dictPtr, int tile ); // Dict iterator + public final static int MAX_COLS_DICT = 15; // from dictiter.h public static native int dict_iter_init( byte[] dict, String path, JNIUtils jniu ); + public static native void dict_iter_setMinMax( int closure, + int min, int max ); public static native void dict_iter_destroy( int closure ); public static native int dict_iter_wordCount( int closure ); + public static native int[] dict_iter_getCounts( int closure ); public static native String dict_iter_nthWord( int closure, int nn ); - public static native void dict_iter_makeIndex( int closure ); public static native String[] dict_iter_getPrefixes( int closure ); public static native int[] dict_iter_getIndices( int closure ); public static native int dict_iter_getStartsWith( int closure, diff --git a/xwords4/android/scripts/setup_local_props.sh b/xwords4/android/scripts/setup_local_props.sh index 3016c9319..032deb1d6 100755 --- a/xwords4/android/scripts/setup_local_props.sh +++ b/xwords4/android/scripts/setup_local_props.sh @@ -1,14 +1,16 @@ #!/bin/sh +echo $0 + cd $(dirname $0) cd ../XWords4 -if [ ! -e local.properties ]; then - ANDROID="$(which android)" - SDK_DIR=$(dirname $ANDROID) - SDK_DIR=$(dirname $SDK_DIR) - echo "# generated by $0" > local.properties - echo "sdk.dir=$SDK_DIR" >> local.properties -fi +# create local.properties for 1.6 sdk (target id 4). Use 'android +# list targets' to get the full set. +android update project --path . --target 4 +echo "local.properties looks like this:" +echo "" +cat local.properties +echo "" exit 0 diff --git a/xwords4/common/board.c b/xwords4/common/board.c index f877b0a03..0d381cab6 100644 --- a/xwords4/common/board.c +++ b/xwords4/common/board.c @@ -1002,8 +1002,7 @@ timerFiredForPen( BoardCtxt* board ) #endif if ( !listWords ) { XWBonusType bonus; - bonus = util_getSquareBonus( board->util, board->model, - col, row ); + bonus = model_getSquareBonus( board->model, col, row ); if ( bonus != BONUS_NONE ) { #ifdef XWFEATURE_MINIWIN text = draw_getMiniWText( board->draw, @@ -1198,7 +1197,7 @@ invalPerimeter( BoardCtxt* board ) ScrollData* hsd = &board->sd[SCROLL_H]; XP_U16 firstCol = hsd->offset; XP_U16 lastCol = hsd->lastVisible; - XP_U16 firstAndLast = (1 << lastCol) | (1 << firstCol); + RowFlags firstAndLast = (1 << lastCol) | (1 << firstCol); ScrollData* vsd = &board->sd[SCROLL_V]; XP_U16 firstRow = vsd->offset; XP_U16 lastRow = vsd->lastVisible; @@ -1588,7 +1587,7 @@ invalReflection( BoardCtxt* board ) while ( nRows-- ) { XP_U16 nCols; - XP_U16 redrawFlag = board->redrawFlags[nRows]; + RowFlags redrawFlag = board->redrawFlags[nRows]; if ( !redrawFlag ) { continue; /* nothing set this row */ } diff --git a/xwords4/common/boarddrw.c b/xwords4/common/boarddrw.c index 8b29038fe..88570fa13 100644 --- a/xwords4/common/boarddrw.c +++ b/xwords4/common/boarddrw.c @@ -1,6 +1,6 @@ -/* -*-mode: C; fill-column: 78; compile-command: "cd ../linux && make MEMDEBUG=TRUE"; -*- */ +/* -*- compile-command: "cd ../linux && make MEMDEBUG=TRUE -j3"; -*- */ /* - * Copyright 1997 - 2010 by Eric House (xwords@eehouse.org). All rights + * Copyright 1997 - 2011 by Eric House (xwords@eehouse.org). All rights * reserved. * * This program is free software; you can redistribute it and/or @@ -299,11 +299,11 @@ drawBoard( BoardCtxt* board ) nVisCols = model_numCols( model ) - board->zoomCount; for ( row = vsd->offset; row <= vsd->lastVisible; ++row ) { - XP_U16 rowFlags = board->redrawFlags[row]; + RowFlags rowFlags = board->redrawFlags[row]; if ( rowFlags != 0 ) { - XP_U16 failedBits = 0; + RowFlags failedBits = 0; for ( col = 0; col < nVisCols; ++col ) { - XP_U16 colMask = 1 << (col + hsd->offset); + RowFlags colMask = 1 << (col + hsd->offset); if ( 0 != (rowFlags & colMask) ) { if ( !drawCell( board, col + hsd->offset, row, XP_TRUE )) { @@ -331,7 +331,7 @@ drawBoard( BoardCtxt* board ) XWBonusType bonus; HintAtts hintAtts; CellFlags flags = CELL_NONE; - bonus = util_getSquareBonus( board->util, model, col, row ); + bonus = model_getSquareBonus( model, col, row ); hintAtts = figureHintAtts( board, col, row ); #ifdef KEYBOARD_NAV if ( cellFocused( board, col, row ) ) { @@ -436,7 +436,7 @@ drawCell( BoardCtxt* board, XP_U16 col, XP_U16 row, XP_Bool skipBlanks ) textP = dict_getTileString( dict, tile ); } } - bonus = util_getSquareBonus( board->util, model, col, row ); + bonus = model_getSquareBonus( model, col, row ); hintAtts = figureHintAtts( board, col, row ); if ( (col==board->star_row) && (row==board->star_row) ) { diff --git a/xwords4/common/boardp.h b/xwords4/common/boardp.h index d9a50015b..10b4a9f0f 100644 --- a/xwords4/common/boardp.h +++ b/xwords4/common/boardp.h @@ -157,7 +157,7 @@ struct BoardCtxt { XP_S16 timerStoppedTurn; #endif - XP_U16 redrawFlags[MAX_ROWS]; + RowFlags redrawFlags[MAX_ROWS]; XP_Rect boardBounds; XP_U16 heightAsSet; diff --git a/xwords4/common/comtypes.h b/xwords4/common/comtypes.h index 10e38a518..0aafedf94 100644 --- a/xwords4/common/comtypes.h +++ b/xwords4/common/comtypes.h @@ -42,6 +42,37 @@ #define VSIZE(arr) (sizeof(arr)/sizeof(arr[0])) +#if MAX_COLS > 16 +# define STREAM_VERS_BIGBOARD 0x12 +#endif +#define STREAM_SAVE_PREVWORDS 0x11 +#define STREAM_VERS_SERVER_SAVES_TOSHOW 0x10 +#define STREAM_VERS_PLAYERDICTS 0x0F +#define STREAM_SAVE_PREVMOVE 0x0E /* server saves prev move explanation */ +#define STREAM_VERS_ROBOTIQ STREAM_SAVE_PREVMOVE /* robots have different smarts */ +#define STREAM_VERS_DICTLANG 0x0D /* save dict lang code in CurGameInfo */ +#define STREAM_VERS_NUNDONE 0x0C /* save undone tile in model */ +#define STREAM_VERS_GAMESECONDS 0x0B /* save gameSeconds whether or not + timer's enabled */ +#define STREAM_VERS_4YOFFSET 0x0A /* 4 bits for yOffset on board */ +#define STREAM_VERS_CHANNELSEED 0x09 /* new short in relay connect must be + saved in comms */ +#define STREAM_VERS_UTF8 0x08 +#define STREAM_VERS_ALWAYS_MULTI 0x07 /* stream format same for multi and + one-device game builds */ +#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 + +#if MAX_COLS > 16 +# define CUR_STREAM_VERS STREAM_VERS_BIGBOARD +#else +# define CUR_STREAM_VERS STREAM_SAVE_PREVWORDS +#endif + typedef struct XP_Rect { XP_S16 left; XP_S16 top; @@ -115,7 +146,9 @@ typedef enum { } XWTimerReason; #define MAX_NUM_PLAYERS 4 -#define MAX_ROWS 16 +#ifndef MAX_ROWS +# define MAX_ROWS 16 +#endif #define MAX_COLS MAX_ROWS #ifdef EIGHT_TILES # define MAX_TRAY_TILES 8 @@ -127,6 +160,24 @@ typedef enum { #define NPLAYERS_NBITS 3 #define EMPTIED_TRAY_BONUS 50 +#if MAX_ROWS <= 16 +typedef XP_U16 RowFlags; +#elif MAX_ROWS <= 32 +typedef XP_U32 RowFlags; +#else + error +#endif + +typedef enum { + BONUS_NONE, + BONUS_DOUBLE_LETTER, + BONUS_DOUBLE_WORD, + BONUS_TRIPLE_LETTER, + BONUS_TRIPLE_WORD, + + BONUS_LAST +} XWBonusType; + /* 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 diff --git a/xwords4/common/dictiter.c b/xwords4/common/dictiter.c index a360bc767..9f51fc92b 100644 --- a/xwords4/common/dictiter.c +++ b/xwords4/common/dictiter.c @@ -38,10 +38,33 @@ extern "C" { #endif typedef struct _EdgeArray { - array_edge* edges[MAX_COLS]; + array_edge* edges[MAX_COLS_DICT]; XP_U16 nEdges; } EdgeArray; +static XP_Bool prevWord( DictIter* iter ); + +#ifdef XWFEATURE_WALKDICT_FILTER +#define LENOK( iter, nEdges ) \ + (iter)->min <= (nEdges) && (nEdges) <= (iter)->max + +static XP_Bool +_isAccepting( DictIter* iter, XP_U16 nEdges ) +{ + return ISACCEPTING( iter->dict, iter->edges[nEdges-1] ) + && LENOK( iter, nEdges ); +} +# define ACCEPT_ITER( iter, nEdges) _isAccepting( iter, nEdges ) +# define ACCEPT_NODE( iter, node, nEdges ) \ + ISACCEPTING( iter->dict, node ) && LENOK(iter,nEdges) +# define FILTER_TEST(iter,nEdges) ((nEdges) <= (iter)->max) +#else +# define ACCEPT_ITER(iter, nEdges) \ + ISACCEPTING( (iter)->dict, (iter)->edges[(nEdges)-1] ) +# define ACCEPT_NODE( iter, node, nEdges ) ISACCEPTING( iter->dict, node ) +# define FILTER_TEST(iter, nEdges) XP_TRUE +#endif + /* On entry and exit, edge at end of array should be ACCEPTING. The job of * this function is to iterate from one such edge to the next. Steps are: 1) * try to follow the edge, to expand to a longer word with the last one as a @@ -53,15 +76,17 @@ static XP_Bool nextWord( DictIter* iter ) { const DictionaryCtxt* dict = iter->dict; - XP_U16 nEdges = iter->nEdges; XP_Bool success = XP_FALSE; + XP_U16 nEdges = iter->nEdges; while ( 0 < nEdges && ! success ) { - array_edge* next = dict_follow( dict, iter->edges[nEdges-1] ); - if ( !!next ) { - iter->edges[nEdges++] = next; - success = ISACCEPTING( dict, next ); - continue; /* try with longer word */ - } + if ( FILTER_TEST( iter, nEdges ) ) { + array_edge* next = dict_follow( dict, iter->edges[nEdges-1] ); + if ( !!next ) { + iter->edges[nEdges++] = next; + success = ACCEPT_NODE( iter, next, nEdges ); + continue; /* try with longer word */ + } + } while ( IS_LAST_EDGE( dict, iter->edges[nEdges-1] ) && 0 < --nEdges ) { @@ -69,10 +94,9 @@ nextWord( DictIter* iter ) if ( 0 < nEdges ) { iter->edges[nEdges-1] += dict->nodeSize; - success = ISACCEPTING( dict, iter->edges[nEdges-1] ); + success = ACCEPT_NODE( iter, iter->edges[nEdges-1], nEdges ); } } - iter->nEdges = nEdges; return success; } @@ -88,48 +112,60 @@ isFirstEdge( const DictionaryCtxt* dict, array_edge* edge ) } static XP_Bool -lastEdges( DictIter* iter ) +lastEdges( DictIter* iter, XP_U16* nEdgesP ) { const DictionaryCtxt* dict = iter->dict; - array_edge* edge = iter->edges[iter->nEdges-1]; + XP_U16 nEdges = *nEdgesP; + array_edge* edge = iter->edges[nEdges-1]; for ( ; ; ) { while ( !IS_LAST_EDGE( dict, edge ) ) { edge += dict->nodeSize; } - iter->edges[iter->nEdges-1] = edge; + iter->edges[nEdges-1] = edge; edge = dict_follow( dict, edge ); if ( NULL == edge ) { break; } - ++iter->nEdges; + if ( !FILTER_TEST( iter, nEdges + 1 ) ) { + break; + } + ++nEdges; } - return ISACCEPTING( dict, iter->edges[iter->nEdges-1] ); + *nEdgesP = nEdges; + return ACCEPT_ITER( iter, nEdges ); } static XP_Bool prevWord( DictIter* iter ) { const DictionaryCtxt* dict = iter->dict; + XP_U16 nEdges = iter->nEdges; XP_Bool success = XP_FALSE; - while ( 0 < iter->nEdges && ! success ) { - if ( isFirstEdge( dict, iter->edges[iter->nEdges-1] ) ) { - --iter->nEdges; - success = 0 < iter->nEdges - && ISACCEPTING( dict, iter->edges[iter->nEdges-1] ); + while ( 0 < nEdges && ! success ) { + if ( isFirstEdge( dict, iter->edges[nEdges-1] ) ) { + --nEdges; + success = 0 < nEdges + && ACCEPT_NODE( iter, iter->edges[nEdges-1], nEdges ); continue; } - iter->edges[iter->nEdges-1] -= dict->nodeSize; - array_edge* next = dict_follow( dict, iter->edges[iter->nEdges-1] ); - if ( NULL != next ) { - iter->edges[iter->nEdges++] = next; - success = lastEdges( iter ); - if ( success ) { - continue; + + iter->edges[nEdges-1] -= dict->nodeSize; + + if ( FILTER_TEST( iter, nEdges ) ) { + array_edge* next = dict_follow( dict, iter->edges[nEdges-1] ); + if ( NULL != next ) { + iter->edges[nEdges++] = next; + success = lastEdges( iter, &nEdges ); + if ( success ) { + continue; + } } } - success = ISACCEPTING( dict, iter->edges[iter->nEdges-1] ); + + success = ACCEPT_NODE( iter, iter->edges[nEdges-1], nEdges ); } + iter->nEdges = nEdges; return success; } @@ -137,19 +173,28 @@ static XP_Bool findStartsWith( DictIter* iter, const Tile* tiles, XP_U16 nTiles ) { const DictionaryCtxt* dict = iter->dict; - XP_Bool success = XP_TRUE; array_edge* edge = dict_getTopEdge( dict ); iter->nEdges = 0; - while ( nTiles-- > 0 ) { + while ( FILTER_TEST( iter, iter->nEdges ) && nTiles > 0 ) { Tile tile = *tiles++; edge = dict_edge_with_tile( dict, edge, tile ); if ( NULL == edge ) { - success = XP_FALSE; break; } iter->edges[iter->nEdges++] = edge; edge = dict_follow( dict, edge ); + --nTiles; + } + return 0 == nTiles; +} + +static XP_Bool +startsWith( const DictIter* iter, const Tile* tiles, XP_U16 nTiles ) +{ + XP_Bool success = nTiles <= iter->nEdges; + while ( success && nTiles-- ) { + success = tiles[nTiles] == EDGETILE( iter->dict, iter->edges[nTiles] ); } return success; } @@ -159,9 +204,9 @@ findWordStartsWith( DictIter* iter, const Tile* tiles, XP_U16 nTiles ) { XP_Bool found = XP_FALSE; if ( findStartsWith( iter, tiles, nTiles ) ) { - found = ISACCEPTING( iter->dict, iter->edges[iter->nEdges-1] ); + found = ACCEPT_ITER( iter, iter->nEdges ); if ( !found ) { - found = nextWord( iter ); + found = nextWord( iter ) && startsWith( iter, tiles, nTiles ); } } return found; @@ -178,38 +223,73 @@ wordsEqual( const DictIter* word1, const DictIter* word2 ) return success; } +static void +dict_initIterFrom( DictIter* dest, const DictIter* src ) +{ + dict_initIter( dest, src->dict, +#ifdef XWFEATURE_WALKDICT_FILTER + src->min, src->max +#else + 0, 0 +#endif + ); +} + static XP_Bool firstWord( DictIter* iter ) { - iter->nEdges = 1; - iter->edges[0] = dict_getTopEdge( iter->dict ); - return ISACCEPTING( iter->dict, iter->edges[0] ) || nextWord( iter ); + array_edge* top = dict_getTopEdge( iter->dict ); + XP_Bool success = !!top; + if ( success ) { + iter->nEdges = 1; + iter->edges[0] = top; + success = ACCEPT_ITER( iter, 1 ) || nextWord( iter ); + } + return success; } XP_U32 -dict_countWords( const DictionaryCtxt* dict ) +dict_countWords( const DictIter* iter, LengthsArray* lens ) { - XP_U32 count = 0; - DictIter iter; - dict_initIter( dict, &iter ); + DictIter counter; + dict_initIterFrom( &counter, iter ); + if ( NULL != lens ) { + XP_MEMSET( lens, 0, sizeof(*lens) ); + } + + XP_U32 count; XP_Bool ok; - for ( ok = firstWord( &iter ); ok; ok = nextWord( &iter ) ) { + for ( count = 0, ok = firstWord( &counter ); + ok; ok = nextWord( &counter) ) { ++count; + + if ( NULL != lens ) { + ++lens->lens[counter.nEdges]; + } } return count; } #define GUARD_VALUE 0x12345678 #define ASSERT_INITED( iter ) XP_ASSERT( (iter)->guard == GUARD_VALUE ) + void -dict_initIter( const DictionaryCtxt* dict, DictIter* iter ) +dict_initIter( DictIter* iter, const DictionaryCtxt* dict, + XP_U16 min, XP_U16 max ) { XP_MEMSET( iter, 0, sizeof(*iter) ); iter->dict = dict; #ifdef DEBUG iter->guard = GUARD_VALUE; #endif +#ifdef XWFEATURE_WALKDICT_FILTER + iter->min = min; + iter->max = max; +#else + XP_USE( min ); + XP_USE( max ); +#endif } static void @@ -221,7 +301,7 @@ copyIter( DictIter* dest, const DictIter* src ) } static DictPosition -placeWordClose( DictIter* iter, DictPosition position, XP_U16 depth, +placeWordClose( DictIter* iter, const DictPosition position, XP_U16 depth, const IndexData* data ) { XP_S16 low = 0; @@ -283,7 +363,7 @@ indexOne( XP_U16 depth, Tile* tiles, IndexData* data, DictIter* prevIter, DictPosition* prevIndex ) { DictIter curIter; - dict_initIter( prevIter->dict, &curIter ); + dict_initIterFrom( &curIter, prevIter ); if ( findWordStartsWith( &curIter, tiles, depth ) ) { while ( !wordsEqual( &curIter, prevIter ) ) { ++*prevIndex; @@ -324,7 +404,7 @@ dict_makeIndex( const DictIter* iter, XP_U16 depth, IndexData* data ) { ASSERT_INITED( iter ); const DictionaryCtxt* dict = iter->dict; - XP_ASSERT( depth < MAX_COLS ); + XP_ASSERT( depth < MAX_COLS_DICT ); XP_U16 ii, needCount; const XP_U16 nFaces = dict_numTileFaces( dict ); XP_U16 nNonBlankFaces = nFaces; @@ -352,7 +432,7 @@ dict_makeIndex( const DictIter* iter, XP_U16 depth, IndexData* data ) */ data->count = 0; DictIter prevIter; - dict_initIter( dict, &prevIter ); + dict_initIterFrom( &prevIter, iter ); if ( firstWord( &prevIter ) ) { DictPosition prevIndex = 0; Tile prefix[depth]; @@ -371,7 +451,7 @@ dict_makeIndex( const DictIter* iter, XP_U16 depth, IndexData* data ) static void initWord( DictIter* iter ) { - iter->nWords = dict_getWordCount( iter->dict ); + iter->nWords = dict_countWords( iter, NULL ); } XP_Bool @@ -405,7 +485,7 @@ dict_lastWord( DictIter* iter ) iter->nEdges = 1; iter->edges[0] = dict_getTopEdge( iter->dict ); - XP_Bool success = lastEdges( iter ); + XP_Bool success = lastEdges( iter, &iter->nEdges ) || prevWord( iter ); if ( success ) { initWord( iter ); iter->position = iter->nWords - 1; @@ -438,7 +518,7 @@ dict_getNthWord( DictIter* iter, DictPosition position, XP_U16 depth, XP_Bool validWord = 0 < iter->nEdges; if ( validWord ) { /* uninitialized */ wordCount = iter->nWords; - XP_ASSERT( wordCount == dict_getWordCount( dict ) ); + XP_ASSERT( wordCount == dict_countWords( iter, NULL ) ); } else { wordCount = dict_getWordCount( dict ); } @@ -516,12 +596,12 @@ dict_findStartsWith( DictIter* iter, const IndexData* data, XP_LOGF( "%s: not using data", __func__ ); DictIter targetIter; - dict_initIter( iter->dict, &targetIter ); + dict_initIterFrom( &targetIter, iter ); if ( findWordStartsWith( &targetIter, prefix, len ) ) { DictPosition result = 0; DictIter iterZero; - dict_initIter( iter->dict, &iterZero ); + dict_initIterFrom( &iterZero, iter ); if ( !firstWord( &iterZero ) ) { XP_ASSERT( 0 ); } diff --git a/xwords4/common/dictiter.h b/xwords4/common/dictiter.h index ee88b4292..61969dd97 100644 --- a/xwords4/common/dictiter.h +++ b/xwords4/common/dictiter.h @@ -33,10 +33,17 @@ extern "C" { #endif +#define MAX_COLS_DICT 15 /* API for iterating over a dict */ typedef XP_S32 DictPosition; typedef struct _DictIter { + XP_U16 nEdges; + array_edge* edges[MAX_COLS_DICT]; +#ifdef XWFEATURE_WALKDICT_FILTER + XP_U16 min; + XP_U16 max; +#endif #ifdef DEBUG XP_U32 guard; #endif @@ -44,8 +51,6 @@ typedef struct _DictIter { XP_U32 nWords; DictPosition position; - XP_U16 nEdges; - array_edge* edges[MAX_COLS]; } DictIter; typedef struct _IndexData { @@ -54,8 +59,13 @@ typedef struct _IndexData { XP_U16 count; /* in-out: must indicate others are large enough */ } IndexData; -XP_U32 dict_countWords( const DictionaryCtxt* dict ); -void dict_initIter( const DictionaryCtxt* dict, DictIter* iter ); +typedef struct _LengthsArray { + XP_U32 lens[MAX_COLS_DICT+1]; +} LengthsArray; + +void dict_initIter( DictIter* iter, const DictionaryCtxt* dict, + XP_U16 min, XP_U16 max ); +XP_U32 dict_countWords( const DictIter* iter, LengthsArray* lens ); void dict_makeIndex( const DictIter* iter, XP_U16 depth, IndexData* data ); XP_Bool dict_firstWord( DictIter* iter ); XP_Bool dict_lastWord( DictIter* iter ); diff --git a/xwords4/common/dictnry.c b/xwords4/common/dictnry.c index af2bf67a7..bd30d8a13 100644 --- a/xwords4/common/dictnry.c +++ b/xwords4/common/dictnry.c @@ -481,7 +481,9 @@ dict_getWordCount( const DictionaryCtxt* dict ) XP_U32 nWords = dict->nWords; #ifdef XWFEATURE_WALKDICT if ( 0 == nWords ) { - nWords = dict_countWords( dict ); + DictIter iter; + dict_initIter( &iter, dict, 0, MAX_COLS_DICT ); + nWords = dict_countWords( &iter, NULL ); } #endif return nWords; @@ -705,36 +707,38 @@ checkSanity( DictionaryCtxt* dict, const XP_U32 numEdges ) { XP_U32 ii; XP_Bool passed = XP_TRUE; - XP_U16 nFaces = dict_numTileFaces( dict ); array_edge* edge = dict->base; - Tile prevTile = 0; - for ( ii = 0; ii < numEdges && passed; ++ii ) { - Tile tile = EDGETILE( dict, edge ); - if ( tile < prevTile || tile >= nFaces ) { - XP_LOGF( "%s: node %ld (out of %ld) has too-large or " - "out-of-order tile", __func__, ii, numEdges ); - passed = XP_FALSE; - break; - } - prevTile = tile; + if ( NULL != edge ) { /* not empty dict */ + XP_U16 nFaces = dict_numTileFaces( dict ); + Tile prevTile = 0; + for ( ii = 0; ii < numEdges && passed; ++ii ) { + Tile tile = EDGETILE( dict, edge ); + if ( tile < prevTile || tile >= nFaces ) { + XP_LOGF( "%s: node %ld (out of %ld) has too-large or " + "out-of-order tile", __func__, ii, numEdges ); + passed = XP_FALSE; + break; + } + prevTile = tile; - unsigned long index = dict_index_from( dict, edge ); - if ( index >= numEdges ) { - XP_LOGF( "%s: node %ld (out of %ld) has too-high index %ld", __func__, - ii, numEdges, index ); - passed = XP_FALSE; - break; + unsigned long index = dict_index_from( dict, edge ); + if ( index >= numEdges ) { + XP_LOGF( "%s: node %ld (out of %ld) has too-high index %ld", + __func__, ii, numEdges, index ); + passed = XP_FALSE; + break; + } + + if ( IS_LAST_EDGE( dict, edge ) ) { + prevTile = 0; + } + edge += dict->nodeSize; } - if ( IS_LAST_EDGE( dict, edge ) ) { - prevTile = 0; + if ( passed ) { + passed = 0 == prevTile; /* last edge seen was a LAST_EDGE */ } - edge += dict->nodeSize; - } - - if ( passed ) { - passed = 0 == prevTile; /* last edge seen was a LAST_EDGE */ } XP_LOGF( "%s(numEdges=%ld)=>%d", __func__, numEdges, passed ); diff --git a/xwords4/common/dictnry.h b/xwords4/common/dictnry.h index 16efe36e6..53788e77a 100644 --- a/xwords4/common/dictnry.h +++ b/xwords4/common/dictnry.h @@ -39,16 +39,6 @@ extern "C" { typedef XP_U8 XP_LangCode; -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; diff --git a/xwords4/common/game.c b/xwords4/common/game.c index b02d58ee0..61de69f4e 100644 --- a/xwords4/common/game.c +++ b/xwords4/common/game.c @@ -426,13 +426,18 @@ gi_readFromStream( MPFORMAL XWStreamCtxt* stream, CurGameInfo* gi ) XP_U16 ii; XP_UCHAR* str; XP_U16 strVersion = stream_getVersion( stream ); +#ifdef STREAM_VERS_BIGBOARD + XP_U16 nColsNBits = STREAM_VERS_BIGBOARD > strVersion ? 4 : NUMCOLS_NBITS; +#else + XP_U16 nColsNBits = NUMCOLS_NBITS; +#endif str = stringFromStream( mpool, stream ); replaceStringIfDifferent( mpool, &gi->dictName, str ); XP_FREEP( mpool, &str ); gi->nPlayers = (XP_U8)stream_getBits( stream, NPLAYERS_NBITS ); - gi->boardSize = (XP_U8)stream_getBits( stream, 4 ); + gi->boardSize = (XP_U8)stream_getBits( stream, nColsNBits ); gi->serverRole = (DeviceRole)stream_getBits( stream, 2 ); gi->hintsNotAllowed = stream_getBits( stream, 1 ); if ( strVersion < STREAM_VERS_ROBOTIQ ) { @@ -491,10 +496,19 @@ gi_writeToStream( XWStreamCtxt* stream, const CurGameInfo* gi ) const LocalPlayer* pl; XP_U16 ii; +#ifdef STREAM_VERS_BIGBOARD + XP_U16 strVersion = stream_getVersion( stream ); + XP_ASSERT( STREAM_SAVE_PREVWORDS <= strVersion ); + XP_U16 nColsNBits = STREAM_VERS_BIGBOARD > strVersion ? 4 : NUMCOLS_NBITS; +#else + XP_U16 nColsNBits = NUMCOLS_NBITS; +#endif + + stringToStream( stream, gi->dictName ); stream_putBits( stream, NPLAYERS_NBITS, gi->nPlayers ); - stream_putBits( stream, 4, gi->boardSize ); + stream_putBits( stream, nColsNBits, gi->boardSize ); stream_putBits( stream, 2, gi->serverRole ); stream_putBits( stream, 1, gi->hintsNotAllowed ); stream_putBits( stream, 2, gi->phoniesAction ); diff --git a/xwords4/common/game.h b/xwords4/common/game.h index 139ac8878..62064decd 100644 --- a/xwords4/common/game.h +++ b/xwords4/common/game.h @@ -31,30 +31,6 @@ extern "C" { #endif -#define STREAM_SAVE_PREVWORDS 0x11 -#define STREAM_VERS_SERVER_SAVES_TOSHOW 0x10 -#define STREAM_VERS_PLAYERDICTS 0x0F -#define STREAM_SAVE_PREVMOVE 0x0E /* server saves prev move explanation */ -#define STREAM_VERS_ROBOTIQ STREAM_SAVE_PREVMOVE /* robots have different smarts */ -#define STREAM_VERS_DICTLANG 0x0D /* save dict lang code in CurGameInfo */ -#define STREAM_VERS_NUNDONE 0x0C /* save undone tile in model */ -#define STREAM_VERS_GAMESECONDS 0x0B /* save gameSeconds whether or not - timer's enabled */ -#define STREAM_VERS_4YOFFSET 0x0A /* 4 bits for yOffset on board */ -#define STREAM_VERS_CHANNELSEED 0x09 /* new short in relay connect must be - saved in comms */ -#define STREAM_VERS_UTF8 0x08 -#define STREAM_VERS_ALWAYS_MULTI 0x07 /* stream format same for multi and - one-device game builds */ -#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_SAVE_PREVWORDS - typedef struct LocalPlayer { XP_UCHAR* name; XP_UCHAR* password; diff --git a/xwords4/common/model.c b/xwords4/common/model.c index c40976c8c..f6fc9fb49 100644 --- a/xwords4/common/model.c +++ b/xwords4/common/model.c @@ -1,6 +1,7 @@ /* -*- compile-command: "cd ../linux && make -j3 MEMDEBUG=TRUE"; -*- */ /* - * Copyright 2000-2009 by Eric House (xwords@eehouse.org). All rights reserved. + * Copyright 2000-2011 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 @@ -88,7 +89,9 @@ model_make( MPFORMAL DictionaryCtxt* dict, const PlayerDicts* dicts, XW_UtilCtxt* util, XP_U16 nCols, XP_U16 nRows ) { - ModelCtxt* result = (ModelCtxt*)XP_MALLOC( mpool, sizeof( *result ) ); + ModelCtxt* result; + XP_U16 size = sizeof(*result) + TILES_SIZE(result, nCols); + result = (ModelCtxt*)XP_MALLOC( mpool, size ); if ( result != NULL ) { XP_MEMSET( result, 0, sizeof(*result) ); MPASSIGN(result->vol.mpool, mpool); @@ -115,15 +118,21 @@ model_makeFromStream( MPFORMAL XWStreamCtxt* stream, DictionaryCtxt* dict, { ModelCtxt* model; XP_U16 nCols, nRows; - short i; + XP_U16 ii; XP_Bool hasDict; XP_U16 nPlayers; + XP_U16 nColsNBits; XP_U16 version = stream_getVersion( stream ); +#ifdef STREAM_VERS_BIGBOARD + nColsNBits = STREAM_VERS_BIGBOARD > version ? 4 : NUMCOLS_NBITS; +#else + nColsNBits = NUMCOLS_NBITS; +#endif XP_ASSERT( !!dict || !!dicts ); - nCols = (XP_U16)stream_getBits( stream, NUMCOLS_NBITS ); - nRows = (XP_U16)stream_getBits( stream, NUMCOLS_NBITS ); + nCols = (XP_U16)stream_getBits( stream, nColsNBits ); + nRows = (XP_U16)stream_getBits( stream, nColsNBits ); hasDict = (version >= STREAM_VERS_MODEL_NO_DICT) ? XP_FALSE : stream_getBits( stream, 1 ); @@ -138,6 +147,20 @@ model_makeFromStream( MPFORMAL XWStreamCtxt* stream, DictionaryCtxt* dict, model = model_make( MPPARM(mpool) dict, dicts, util, nCols, nRows ); model->nPlayers = nPlayers; +#ifdef STREAM_VERS_BIGBOARD + if ( STREAM_VERS_BIGBOARD <= version ) { + model->nBonuses = stream_getBits( stream, 7 ); + if ( 0 < model->nBonuses ) { + model->bonuses = + XP_MALLOC( model->vol.mpool, + model->nBonuses * sizeof( model->bonuses[0] ) ); + for ( ii = 0; ii < model->nBonuses; ++ii ) { + model->bonuses[ii] = stream_getBits( stream, 4 ); + } + } + } +#endif + stack_loadFromStream( model->vol.stack, stream ); buildModelFromStack( model, model->vol.stack, XP_FALSE, 0, @@ -145,10 +168,10 @@ model_makeFromStream( MPFORMAL XWStreamCtxt* stream, DictionaryCtxt* dict, (MovePrintFuncPre)NULL, (MovePrintFuncPost)NULL, NULL ); - for ( i = 0; i < model->nPlayers; ++i ) { - loadPlayerCtxt( stream, version, &model->players[i] ); - setPendingCounts( model, i ); - invalidateScore( model, i ); + for ( ii = 0; ii < model->nPlayers; ++ii ) { + loadPlayerCtxt( stream, version, &model->players[ii] ); + setPendingCounts( model, ii ); + invalidateScore( model, ii ); } return model; @@ -157,7 +180,7 @@ model_makeFromStream( MPFORMAL XWStreamCtxt* stream, DictionaryCtxt* dict, void model_writeToStream( ModelCtxt* model, XWStreamCtxt* stream ) { - short i; + XP_U16 ii; stream_putBits( stream, NUMCOLS_NBITS, model->nCols ); stream_putBits( stream, NUMCOLS_NBITS, model->nRows ); @@ -165,10 +188,17 @@ model_writeToStream( ModelCtxt* model, XWStreamCtxt* stream ) /* we have two bits for nPlayers, so range must be 0..3, not 1..4 */ stream_putBits( stream, NPLAYERS_NBITS, model->nPlayers ); +#ifdef STREAM_VERS_BIGBOARD + stream_putBits( stream, 7, model->nBonuses ); + for ( ii = 0; ii < model->nBonuses; ++ii ) { + stream_putBits( stream, 4, model->bonuses[ii] ); + } +#endif + stack_writeToStream( model->vol.stack, stream ); - for ( i = 0; i < model->nPlayers; ++i ) { - writePlayerCtxt( stream, &model->players[i] ); + for ( ii = 0; ii < model->nPlayers; ++ii ) { + writePlayerCtxt( stream, &model->players[ii] ); } } /* model_writeToStream */ @@ -220,7 +250,7 @@ model_init( ModelCtxt* model, XP_U16 nCols, XP_U16 nRows ) XP_ASSERT( model != NULL ); XP_MEMSET( model, 0, sizeof( *model ) ); - XP_MEMSET( &model->tiles, TILE_EMPTY_BIT, sizeof(model->tiles) ); + XP_MEMSET( &model->tiles, TILE_EMPTY_BIT, TILES_SIZE(model, nCols) ); model->nCols = nCols; model->nRows = nRows; @@ -240,9 +270,90 @@ model_destroy( ModelCtxt* model ) { stack_destroy( model->vol.stack ); /* is this it!? */ + if ( !!model->bonuses ) { + XP_FREE( model->vol.mpool, model->bonuses ); + } XP_FREE( model->vol.mpool, model ); } /* model_destroy */ +#ifdef STREAM_VERS_BIGBOARD +void +model_setSquareBonuses( ModelCtxt* model, XWBonusType* bonuses, XP_U16 nBonuses ) +{ +#ifdef DEBUG + XP_U16 nCols = (1 + model_numCols( model )) / 2; + XP_ASSERT( 0 < nCols ); + XP_U16 wantLen = 0; + while ( nCols > 0 ) { + wantLen += nCols--; + } + XP_ASSERT( wantLen == nBonuses ); +#endif + + if ( !!model->bonuses ) { + XP_FREE( model->vol.mpool, model->bonuses ); + } + model->bonuses = XP_MALLOC( model->vol.mpool, + nBonuses * sizeof(model->bonuses[0]) ); + XP_MEMCPY( model->bonuses, bonuses, nBonuses * sizeof(model->bonuses[0]) ); + model->nBonuses = nBonuses; +} + +static void +borrowSquareBonuses( ModelCtxt* dest, const ModelCtxt* src ) +{ + XP_ASSERT( !dest->bonuses ); + dest->bonuses = src->bonuses; + dest->nBonuses = src->nBonuses; +} + +static void +returnSquareBonuses( ModelCtxt* dest ) +{ + dest->bonuses = NULL; + dest->nBonuses = 0; +} +#else +# define borrowSquareBonuses(d,s) +# define returnSquareBonuses(d) +#endif + +XWBonusType +model_getSquareBonus( const ModelCtxt* model, XP_U16 col, XP_U16 row ) +{ + XWBonusType result = BONUS_NONE; + + if ( 0 ) { +#ifdef STREAM_VERS_BIGBOARD + } else if ( !!model->bonuses ) { + XP_U16 nCols = model_numCols( model ); + XP_U16 ii; + if ( col > (nCols/2) ) { + col = nCols - 1 - col; + } + if ( row > (nCols/2) ) { + row = nCols - 1 - row; + } + if ( col > row ) { + XP_U16 tmp = col; + col = row; + row = tmp; + } + for ( ii = 1; ii <= row; ++ii ) { + col += ii; + } + + if ( col < model->nBonuses ) { + result = model->bonuses[col]; + } +#endif + } else { + result = util_getSquareBonus( model->vol.util, model_numRows(model), + col, row ); + } + return result; +} + static void modelAddEntry( ModelCtxt* model, XP_U16 indx, const StackEntry* entry, XP_Bool useStack, XWStreamCtxt* stream, @@ -581,17 +692,23 @@ model_getCellOwner( ModelCtxt* model, XP_U16 col, XP_U16 row ) static void setModelTileRaw( ModelCtxt* model, XP_U16 col, XP_U16 row, CellTile tile ) { - XP_ASSERT( col < MAX_COLS ); - XP_ASSERT( row < MAX_ROWS ); - model->tiles[col][row] = tile; + XP_ASSERT( col < model->nCols ); + XP_ASSERT( row < model->nRows ); + model->tiles[(row*model->nCols) + col] = tile; } /* model_setTile */ static CellTile getModelTileRaw( const ModelCtxt* model, XP_U16 col, XP_U16 row ) { - XP_ASSERT( col < MAX_COLS ); - XP_ASSERT( row < MAX_ROWS ); - return model->tiles[col][row]; + CellTile tile; + XP_U16 nCols = model->nCols; + XP_ASSERT( model->nRows == nCols ); + if ( col < nCols && row < nCols ) { + tile = model->tiles[(row*nCols) + col]; + } else { + tile = TILE_EMPTY_BIT; + } + return tile; } /* getModelTileRaw */ static void @@ -815,6 +932,12 @@ model_currentMoveToStream( ModelCtxt* model, XP_S16 turn, { PlayerCtxt* player; XP_S16 numTiles; +#ifdef STREAM_VERS_BIGBOARD + XP_U16 version = stream_getVersion( stream ); + XP_U16 nColsNBits = STREAM_VERS_BIGBOARD > version ? 4 : NUMCOLS_NBITS; +#else + XP_U16 nColsNBits = NUMCOLS_NBITS; +#endif XP_ASSERT( turn >= 0 ); player = &model->players[turn]; @@ -831,8 +954,8 @@ model_currentMoveToStream( ModelCtxt* model, XP_S16 turn, &col, &row, &isBlank ); XP_ASSERT( numTiles >= 0 ); stream_putBits( stream, TILE_NBITS, tile ); - stream_putBits( stream, NUMCOLS_NBITS, col ); - stream_putBits( stream, NUMCOLS_NBITS, row ); + stream_putBits( stream, nColsNBits, col ); + stream_putBits( stream, nColsNBits, row ); stream_putBits( stream, 1, isBlank ); } } /* model_currentMoveToStream */ @@ -847,8 +970,15 @@ void model_makeTurnFromStream( ModelCtxt* model, XP_U16 playerNum, XWStreamCtxt* stream ) { - XP_U16 numTiles; + XP_U16 numTiles, ii; Tile blank = dict_getBlankTile( model_getDictionary(model) ); +#ifdef STREAM_VERS_BIGBOARD + XP_U16 version = stream_getVersion( stream ); + XP_U16 nColsNBits = STREAM_VERS_BIGBOARD > version ? 4 : NUMCOLS_NBITS; +#else + XP_U16 nColsNBits = NUMCOLS_NBITS; +#endif + model_resetCurrentTurn( model, playerNum ); @@ -856,12 +986,12 @@ model_makeTurnFromStream( ModelCtxt* model, XP_U16 playerNum, XP_LOGF( "%s: numTiles=%d", __func__, numTiles ); - while ( numTiles-- ) { + for ( ii = 0; ii < numTiles; ++ii ) { XP_S16 foundAt; Tile moveTile; Tile tileFace = (Tile)stream_getBits( stream, TILE_NBITS ); - XP_U16 col = (XP_U16)stream_getBits( stream, NUMCOLS_NBITS ); - XP_U16 row = (XP_U16)stream_getBits( stream, NUMCOLS_NBITS ); + XP_U16 col = (XP_U16)stream_getBits( stream, nColsNBits ); + XP_U16 row = (XP_U16)stream_getBits( stream, nColsNBits ); XP_Bool isBlank = stream_getBits( stream, 1 ); /* This code gets called both for the server, which has all the @@ -1931,6 +2061,7 @@ makeTmpModel( ModelCtxt* model, XWStreamCtxt* stream, model->vol.util, model_numCols(model), model_numRows(model)); model_setNPlayers( tmpModel, model->nPlayers ); + borrowSquareBonuses( tmpModel, model ); buildModelFromStack( tmpModel, model->vol.stack, XP_FALSE, 0, stream, (WordNotifierInfo*)NULL, mpf_pre, mpf_post, closure ); @@ -1952,6 +2083,7 @@ model_writeGameHistory( ModelCtxt* model, XWStreamCtxt* stream, tmpModel = makeTmpModel( model, stream, printMovePre, printMovePost, &closure ); + returnSquareBonuses( tmpModel ); model_destroy( tmpModel ); if ( gameOver ) { @@ -2215,6 +2347,11 @@ loadPlayerCtxt( XWStreamCtxt* stream, XP_U16 version, PlayerCtxt* pc ) { PendingTile* pt; XP_U16 nTiles; +#ifdef STREAM_VERS_BIGBOARD + XP_U16 nColsNBits = STREAM_VERS_BIGBOARD > version ? 4 : NUMCOLS_NBITS; +#else + XP_U16 nColsNBits = NUMCOLS_NBITS; +#endif pc->curMoveValid = stream_getBits( stream, 1 ); @@ -2230,8 +2367,8 @@ loadPlayerCtxt( XWStreamCtxt* stream, XP_U16 version, PlayerCtxt* pc ) nTiles = pc->nPending + pc->nUndone; for ( pt = pc->pendingTiles; nTiles-- > 0; ++pt ) { XP_U16 nBits; - pt->col = (XP_U8)stream_getBits( stream, NUMCOLS_NBITS ); - pt->row = (XP_U8)stream_getBits( stream, NUMCOLS_NBITS ); + pt->col = (XP_U8)stream_getBits( stream, nColsNBits ); + pt->row = (XP_U8)stream_getBits( stream, nColsNBits ); nBits = (version <= STREAM_VERS_RELAY) ? 6 : 7; pt->tile = (Tile)stream_getBits( stream, nBits ); diff --git a/xwords4/common/model.h b/xwords4/common/model.h index 614829a0a..dbdf0e986 100644 --- a/xwords4/common/model.h +++ b/xwords4/common/model.h @@ -29,7 +29,11 @@ extern "C" { #endif -#define NUMCOLS_NBITS 4 +#if MAX_COLS <= 16 +# define NUMCOLS_NBITS 4 +#elif MAX_COLS <= 32 +# define NUMCOLS_NBITS 5 +#endif #ifdef EIGHT_TILES # define NTILES_NBITS 4 @@ -265,6 +269,13 @@ void model_listWordsThrough( ModelCtxt* model, XP_U16 col, XP_U16 row, /* Have there been too many passes (so game should end)? */ XP_Bool model_recentPassCountOk( ModelCtxt* model ); +XWBonusType model_getSquareBonus( const ModelCtxt* model, + XP_U16 col, XP_U16 row ); +#ifdef STREAM_VERS_BIGBOARD +void model_setSquareBonuses( ModelCtxt* model, XWBonusType* bonuses, + XP_U16 nBonuses ); +#endif + XP_Bool model_checkMoveLegal( ModelCtxt* model, XP_S16 player, XWStreamCtxt* stream, WordNotifierInfo* notifyInfo ); diff --git a/xwords4/common/modelp.h b/xwords4/common/modelp.h index f9b15db7d..dfcc5afe8 100644 --- a/xwords4/common/modelp.h +++ b/xwords4/common/modelp.h @@ -1,6 +1,7 @@ -/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */ +/* -*- compile-command: "cd ../linux && make -j3 MEMDEBUG=TRUE"; -*- */ /* - * Copyright 2000 by Eric House (xwords@eehouse.org). All rights reserved. + * Copyright 2000 - 2011 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 @@ -70,14 +71,18 @@ struct ModelCtxt { ModelVolatiles vol; - CellTile tiles[MAX_COLS][MAX_ROWS]; - PlayerCtxt players[MAX_NUM_PLAYERS]; XP_U16 nPlayers; XP_U16 nCols; XP_U16 nRows; + XP_U16 nBonuses; + XWBonusType* bonuses; + + CellTile tiles[]; }; +#define TILES_SIZE(m,nc) ((nc) * (nc) * sizeof((m)->tiles[0])) + 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, diff --git a/xwords4/common/mscore.c b/xwords4/common/mscore.c index 80426c21d..4077f613c 100644 --- a/xwords4/common/mscore.c +++ b/xwords4/common/mscore.c @@ -526,7 +526,7 @@ figureMoveScore( const ModelCtxt* model, XP_U16 turn, MoveInfo* moveInfo, static XP_U16 word_multiplier( const ModelCtxt* model, XP_U16 col, XP_U16 row ) { - XWBonusType bonus = util_getSquareBonus( model->vol.util, model, col, row ); + XWBonusType bonus = model_getSquareBonus( model, col, row ); switch ( bonus ) { case BONUS_DOUBLE_WORD: return 2; @@ -540,8 +540,7 @@ word_multiplier( const ModelCtxt* model, XP_U16 col, XP_U16 row ) static XP_U16 tile_multiplier( const ModelCtxt* model, XP_U16 col, XP_U16 row ) { - XWBonusType bonus = util_getSquareBonus( model->vol.util, model, - col, row ); + XWBonusType bonus = model_getSquareBonus( model, col, row ); switch ( bonus ) { case BONUS_DOUBLE_LETTER: return 2; diff --git a/xwords4/common/server.c b/xwords4/common/server.c index b48732bfe..56947b9a6 100644 --- a/xwords4/common/server.c +++ b/xwords4/common/server.c @@ -60,6 +60,9 @@ typedef struct ServerPlayer { typedef struct RemoteAddress { XP_PlayerAddr channelNo; +#ifdef STREAM_VERS_BIGBOARD + XP_U8 streamVersion; +#endif } RemoteAddress; /* These are the parts of the server's state that needs to be preserved @@ -84,6 +87,9 @@ typedef struct ServerNonvolatiles { XP_U8 pendingRegistrations; XP_Bool showRobotScores; XP_Bool sortNewTiles; +#ifdef STREAM_VERS_BIGBOARD + XP_U8 streamVersion; +#endif #ifdef XWFEATURE_SLOW_ROBOT XP_U16 robotThinkMin, robotThinkMax; /* not saved (yet) */ #endif @@ -139,12 +145,14 @@ static XWStreamCtxt* messageStreamWithHeader( ServerCtxt* server, XP_U16 devIndex, XW_Proto code ); static XP_Bool handleRegistrationMsg( ServerCtxt* server, XWStreamCtxt* stream ); -static void registerRemotePlayer( ServerCtxt* server, XWStreamCtxt* stream ); +static XP_S8 registerRemotePlayer( ServerCtxt* server, XWStreamCtxt* stream ); static void server_sendInitialMessage( ServerCtxt* server ); static void sendBadWordMsgs( ServerCtxt* server ); static XP_Bool handleIllegalWord( ServerCtxt* server, XWStreamCtxt* incoming ); static void tellMoveWasLegal( ServerCtxt* server ); +static void writeProto( const ServerCtxt* server, XWStreamCtxt* stream, + XW_Proto proto ); #endif #define PICK_NEXT -1 @@ -230,6 +238,9 @@ initServer( ServerCtxt* server ) syncPlayers( server ); server->nv.nDevices = 1; /* local device (0) is always there */ +#ifdef STREAM_VERS_BIGBOARD + server->nv.streamVersion = STREAM_SAVE_PREVWORDS; /* default to old */ +#endif } /* initServer */ ServerCtxt* @@ -280,7 +291,18 @@ getNV( XWStreamCtxt* stream, ServerNonvolatiles* nv, XP_U16 nPlayers ) for ( ii = 0; ii < nPlayers; ++ii ) { nv->addresses[ii].channelNo = (XP_PlayerAddr)stream_getBits( stream, 16 ); +#ifdef STREAM_VERS_BIGBOARD + if ( STREAM_VERS_BIGBOARD <= version ) { + nv->addresses[ii].streamVersion = stream_getBits( stream, 8 ); + } +#endif } +#ifdef STREAM_VERS_BIGBOARD + if ( STREAM_SAVE_PREVWORDS < version ) { + nv->streamVersion = stream_getU8 ( stream ); + } + XP_LOGF( "%s: read streamVersion: 0x%x", __func__, nv->streamVersion ); +#endif } /* getNV */ static void @@ -301,7 +323,14 @@ putNV( XWStreamCtxt* stream, ServerNonvolatiles* nv, XP_U16 nPlayers ) for ( ii = 0; ii < nPlayers; ++ii ) { stream_putBits( stream, 16, nv->addresses[ii].channelNo ); +#ifdef STREAM_VERS_BIGBOARD + stream_putBits( stream, 8, nv->addresses[ii].streamVersion ); +#endif } +#ifdef STREAM_VERS_BIGBOARD + stream_putU8( stream, nv->streamVersion ); + XP_LOGF( "%s: wrote streamVersion: 0x%x", __func__, nv->streamVersion ); +#endif } /* putNV */ static XWStreamCtxt* @@ -515,7 +544,7 @@ server_initClientConnection( ServerCtxt* server, XWStreamCtxt* stream ) if ( server->nv.gameState == XWSTATE_NONE ) { stream_open( stream ); - stream_putBits( stream, XWPROTO_NBITS, XWPROTO_DEVICE_REGISTRATION ); + writeProto( server, stream, XWPROTO_DEVICE_REGISTRATION ); nPlayers = gi->nPlayers; XP_ASSERT( nPlayers > 0 ); @@ -531,8 +560,8 @@ server_initClientConnection( ServerCtxt* server, XWStreamCtxt* stream ) continue; } - stream_putBits( stream, 1, LP_IS_ROBOT(lp) ); /* better not to send this */ - + stream_putBits( stream, 1, LP_IS_ROBOT(lp) ); /* better not to + send this */ /* The first nPlayers players are the ones we'll use. The local flag doesn't matter when for SERVER_ISCLIENT. */ name = emptyStringIfNull(lp->name); @@ -543,6 +572,10 @@ server_initClientConnection( ServerCtxt* server, XWStreamCtxt* stream ) stream_putBits( stream, NAME_LEN_NBITS, len ); stream_putBytes( stream, name, len ); } +#ifdef STREAM_VERS_BIGBOARD + stream_putU8( stream, CUR_STREAM_VERS ); +#endif + } else { XP_LOGF( "%s: wierd state %s; dropping message", __func__, getStateStr(server->nv.gameState) ); @@ -593,11 +626,32 @@ callTurnChangeListener( ServerCtxt* server ) } /* callTurnChangeListener */ #ifndef XWFEATURE_STANDALONE_ONLY +# ifdef STREAM_VERS_BIGBOARD +static void +setStreamVersion( ServerCtxt* server ) +{ + XP_U16 devIndex; + XP_U8 streamVersion = CUR_STREAM_VERS; + for ( devIndex = 1; devIndex < server->nv.nDevices; ++devIndex ) { + XP_U8 devVersion = server->nv.addresses[devIndex].streamVersion; + if ( devVersion < streamVersion ) { + streamVersion = devVersion; + } + } + XP_LOGF( "%s: setting streamVersion: %d", __func__, streamVersion ); + server->nv.streamVersion = streamVersion; +} +# else +# define setStreamVersion(s) +# endif + static XP_Bool handleRegistrationMsg( ServerCtxt* server, XWStreamCtxt* stream ) { XP_Bool success = XP_TRUE; - XP_U16 playersInMsg, i; + XP_U16 playersInMsg; + XP_S8 clientIndex; + XP_U16 ii = 0; LOG_FUNC(); /* code will have already been consumed */ @@ -608,21 +662,41 @@ handleRegistrationMsg( ServerCtxt* server, XWStreamCtxt* stream ) util_userError( server->vol.util, ERR_REG_UNEXPECTED_USER ); success = XP_FALSE; } else { - for ( i = 0; i < playersInMsg; ++i ) { - registerRemotePlayer( server, stream ); + XP_S8 prevIndex = -1; + for ( ; ii < playersInMsg; ++ii ) { + clientIndex = registerRemotePlayer( server, stream ); /* This is abusing the semantics of turn change -- at least in the case where there is another device yet to register -- but we need to let the board know to redraw the scoreboard with more players there. */ callTurnChangeListener( server ); + XP_ASSERT( ii == 0 || prevIndex == clientIndex ); + prevIndex = clientIndex; } - if ( server->nv.pendingRegistrations == 0 ) { - assignTilesToAll( server ); - SETSTATE( server, XWSTATE_RECEIVED_ALL_REG ); + } + +#ifdef STREAM_VERS_BIGBOARD + if ( 0 < stream_getSize(stream) ) { + XP_U8 streamVersion = stream_getU8( stream ); + if ( streamVersion >= STREAM_VERS_BIGBOARD ) { + XP_LOGF( "%s: upping device %d streamVersion to %d", + __func__, clientIndex, streamVersion ); + server->nv.addresses[clientIndex].streamVersion = streamVersion; } } +#endif + + if ( server->nv.pendingRegistrations == 0 ) { + XP_ASSERT( ii == playersInMsg ); /* otherwise malformed */ + setStreamVersion( server ); + assignTilesToAll( server ); + SETSTATE( server, XWSTATE_RECEIVED_ALL_REG ); + } +/* now set server's streamVersion if all remote players have the higher one. */ +/* But first need to pass it in the strramx */ + return success; } /* handleRegistrationMsg */ #endif @@ -1005,7 +1079,7 @@ findFirstPending( ServerCtxt* server, ServerPlayer** playerP ) return lp; } /* findFirstPending */ -static void +static XP_S8 registerRemotePlayer( ServerCtxt* server, XWStreamCtxt* stream ) { XP_S8 deviceIndex; @@ -1045,10 +1119,13 @@ registerRemotePlayer( ServerCtxt* server, XWStreamCtxt* stream ) XP_ASSERT( channelNo != 0 ); addr->channelNo = channelNo; +#ifdef STREAM_VERS_BIGBOARD + addr->streamVersion = STREAM_SAVE_PREVWORDS; +#endif } player->deviceIndex = deviceIndex; - + return deviceIndex; } /* registerRemotePlayer */ static void @@ -1102,6 +1179,7 @@ client_readInitialMessage( ServerCtxt* server, XWStreamCtxt* stream ) /* version; any dependencies here? */ XP_U8 streamVersion = stream_getU8( stream ); + XP_LOGF( "%s: set streamVersion to %d", __func__, streamVersion ); stream_setVersion( stream, streamVersion ); gameID = stream_getU32( stream ); @@ -1240,10 +1318,8 @@ server_sendInitialMessage( ServerCtxt* server ) DictionaryCtxt* dict = model_getDictionary(model); XP_ASSERT( !!stream ); stream_open( stream ); - stream_putBits( stream, XWPROTO_NBITS, XWPROTO_CLIENT_SETUP ); + writeProto( server, stream, XWPROTO_CLIENT_SETUP ); - /* write version for server's benefit; use old version until format - changes */ stream_putU8( stream, CUR_STREAM_VERS ); XP_LOGF( "putting gameID %lx into msg", gameID ); @@ -1329,6 +1405,7 @@ printCode(char* intro, XW_Proto code) caseStr( str, XWPROTO_MOVE_CONFIRM ); caseStr( str, XWPROTO_CLIENT_REQ_END_GAME ); caseStr( str, XWPROTO_END_GAME ); + caseStr( str, XWPROTO_NEW_PROTO ); } XP_STATUSF( "\t%s for %s", intro, str ); @@ -1347,9 +1424,11 @@ messageStreamWithHeader( ServerCtxt* server, XP_U16 devIndex, XW_Proto code ) printCode("making", code); stream = util_makeStreamFromAddr( server->vol.util, channelNo ); - +#ifdef STREAM_VERS_BIGBOARD + stream_setVersion( stream, server->nv.streamVersion ); +#endif stream_open( stream ); - stream_putBits( stream, XWPROTO_NBITS, code ); + writeProto( server, stream, code ); return stream; } /* messageStreamWithHeader */ @@ -2446,15 +2525,46 @@ server_handleUndo( ServerCtxt* server ) } /* server_handleUndo */ #ifndef XWFEATURE_STANDALONE_ONLY +static void +writeProto( const ServerCtxt* server, XWStreamCtxt* stream, XW_Proto proto ) +{ +#ifdef STREAM_VERS_BIGBOARD + XP_ASSERT( server->nv.streamVersion > 0 ); + if ( STREAM_SAVE_PREVWORDS < server->nv.streamVersion ) { + stream_putBits( stream, XWPROTO_NBITS, XWPROTO_NEW_PROTO ); + stream_putBits( stream, 8, CUR_STREAM_VERS ); + } +#else + XP_USE(server); +#endif + stream_putBits( stream, XWPROTO_NBITS, proto ); +} + +static XW_Proto +readProto( ServerCtxt* server, XWStreamCtxt* stream ) +{ + XW_Proto proto = (XW_Proto)stream_getBits( stream, XWPROTO_NBITS ); + XP_U8 version = STREAM_SAVE_PREVWORDS; /* version prior to fmt change */ +#ifdef STREAM_VERS_BIGBOARD + if ( XWPROTO_NEW_PROTO == proto ) { + version = stream_getBits( stream, 8 ); + proto = (XW_Proto)stream_getBits( stream, XWPROTO_NBITS ); + } + server->nv.streamVersion = version; +#else + XP_USE(server); +#endif + stream_setVersion( stream, version ); + return proto; +} + XP_Bool server_receiveMessage( ServerCtxt* server, XWStreamCtxt* incoming ) { - XW_Proto code; XP_Bool accepted = XP_FALSE; + XW_Proto code = readProto( server, incoming ); - code = (XW_Proto)stream_getBits( incoming, XWPROTO_NBITS ); - - printCode("Receiving", code); + printCode( "Receiving", code ); if ( code == XWPROTO_DEVICE_REGISTRATION ) { /* This message is special: doesn't have the header that's possible @@ -2541,7 +2651,8 @@ server_receiveMessage( ServerCtxt* server, XWStreamCtxt* incoming ) accepted = XP_TRUE; break; default: - XP_WARNF( "Unknown code on incoming message: %d\n", code ); + XP_WARNF( "%s: Unknown code on incoming message: %d\n", + __func__, code ); break; } /* switch */ } diff --git a/xwords4/common/util.h b/xwords4/common/util.h index dc25d28da..6815ebb46 100644 --- a/xwords4/common/util.h +++ b/xwords4/common/util.h @@ -99,8 +99,7 @@ typedef struct UtilVtable { XP_PlayerAddr channelNo ); #endif - XWBonusType (*m_util_getSquareBonus)( XW_UtilCtxt* uc, - const ModelCtxt* model, + XWBonusType (*m_util_getSquareBonus)( XW_UtilCtxt* uc, XP_U16 boardSize, XP_U16 col, XP_U16 row ); void (*m_util_userError)( XW_UtilCtxt* uc, UtilErrID id ); @@ -201,8 +200,8 @@ struct XW_UtilCtxt { #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_getSquareBonus(uc,b,c,r) \ + (uc)->vtable->m_util_getSquareBonus((uc),(b),(c),(r)) #define util_userError(uc,err) \ (uc)->vtable->m_util_userError((uc),(err)) diff --git a/xwords4/common/xwproto.h b/xwords4/common/xwproto.h index 011fe7f73..6361cd157 100644 --- a/xwords4/common/xwproto.h +++ b/xwords4/common/xwproto.h @@ -44,6 +44,8 @@ typedef enum { //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 */ + + ,XWPROTO_NEW_PROTO } XW_Proto; #define XWPROTO_NBITS 4 diff --git a/xwords4/linux/Makefile b/xwords4/linux/Makefile index f7e34d4d1..2f90dc32e 100644 --- a/xwords4/linux/Makefile +++ b/xwords4/linux/Makefile @@ -92,7 +92,9 @@ DEFINES += -DDISABLE_TILE_SEL DEFINES += -DSET_GAMESEED DEFINES += -DTEXT_MODEL DEFINES += -DXWFEATURE_WALKDICT +DEFINES += -DXWFEATURE_WALKDICT_FILTER DEFINES += -DXWFEATURE_DICTSANITY +#DEFINES += -DMAX_ROWS=32 ifdef CURSES_CELL_HT DEFINES += -DCURSES_CELL_HT=$(CURSES_CELL_HT) diff --git a/xwords4/linux/cursesmain.c b/xwords4/linux/cursesmain.c index 0f3578cf6..5bb0ab7fd 100644 --- a/xwords4/linux/cursesmain.c +++ b/xwords4/linux/cursesmain.c @@ -1570,15 +1570,16 @@ positionSizeStuff( CursesAppGlobals* globals, int width, int height ) XP_U16 cellWidth, cellHt, scoreLeft, scoreWidth; BoardCtxt* board = globals->cGlobals.game.board; int remWidth = width; + int nRows = globals->cGlobals.params->gi.boardSize; cellWidth = CURSES_CELL_WIDTH; cellHt = CURSES_CELL_HT; board_setPos( board, BOARD_OFFSET, BOARD_OFFSET, - cellWidth * MAX_COLS, cellHt * MAX_ROWS, + cellWidth * nRows, cellHt * nRows, cellWidth, XP_FALSE ); /* board_setScale( board, cellWidth, cellHt ); */ - scoreLeft = (cellWidth * MAX_COLS);// + BOARD_SCORE_PADDING; - remWidth -= cellWidth * MAX_COLS; + scoreLeft = (cellWidth * nRows);// + BOARD_SCORE_PADDING; + remWidth -= cellWidth * nRows; /* If the scoreboard will right of the board, put it there. Otherwise try to fit it below the boards. */ @@ -1592,8 +1593,9 @@ positionSizeStuff( CursesAppGlobals* globals, int width, int height ) trayTop = 8; } else { trayLeft = BOARD_OFFSET; - trayTop = BOARD_OFFSET + (cellHt * MAX_ROWS); + trayTop = BOARD_OFFSET + (cellHt * nRows); if ( trayTop + trayHt > height ) { + XP_ASSERT( height > trayTop ); trayHt = height - trayTop; } } @@ -1819,7 +1821,7 @@ cursesmain( XP_Bool isServer, LaunchParams* params ) #endif model_setDictionary( g_globals.cGlobals.game.model, params->dict ); - + setSquareBonuses( &g_globals.cGlobals ); positionSizeStuff( &g_globals, width, height ); #ifndef XWFEATURE_STANDALONE_ONLY diff --git a/xwords4/linux/gtkmain.c b/xwords4/linux/gtkmain.c index f0b66b4a3..18578b9db 100644 --- a/xwords4/linux/gtkmain.c +++ b/xwords4/linux/gtkmain.c @@ -486,6 +486,7 @@ createOrLoadObjects( GtkAppGlobals* globals ) } #endif model_setDictionary( globals->cGlobals.game.model, params->dict ); + setSquareBonuses( &globals->cGlobals ); model_setPlayerDicts( globals->cGlobals.game.model, ¶ms->dicts ); #ifdef XWFEATURE_SEARCHLIMIT @@ -528,6 +529,8 @@ configure_event( GtkWidget* widget, GdkEventConfigure* XP_UNUSED(event), gint trayTop; gint boardTop = 0; XP_U16 netStatWidth = 0; + gint nCols = globals->cGlobals.params->gi.boardSize; + gint nRows = nCols; if ( globals->draw == NULL ) { createOrLoadObjects( globals ); @@ -541,25 +544,23 @@ configure_event( GtkWidget* widget, GdkEventConfigure* XP_UNUSED(event), bdHeight = widget->allocation.height - (GTK_TOP_MARGIN + GTK_BOTTOM_MARGIN) - GTK_MIN_TRAY_SCALEV - GTK_BOTTOM_MARGIN; - hscale = bdWidth / GTK_NUM_COLS; + hscale = bdWidth / nCols; if ( 0 != globals->cGlobals.params->nHidden ) { vscale = hscale; } else { - vscale = (bdHeight / (GTK_NUM_ROWS + GTK_TRAY_HT_ROWS)); /* makd tray - height 3x cell - height */ + vscale = (bdHeight / (nCols + GTK_TRAY_HT_ROWS)); /* makd tray height + 3x cell height */ } if ( !globals->cGlobals.params->verticalScore ) { boardTop += GTK_HOR_SCORE_HEIGHT; } - trayTop = boardTop + (vscale * GTK_NUM_ROWS); + trayTop = boardTop + (vscale * nRows); /* move tray up if part of board's meant to be hidden */ trayTop -= vscale * globals->cGlobals.params->nHidden; board_setPos( globals->cGlobals.game.board, GTK_BOARD_LEFT, boardTop, - hscale*GTK_NUM_COLS, vscale * GTK_NUM_ROWS, - hscale * 2, XP_FALSE ); + hscale * nCols, vscale * nRows, hscale * 2, XP_FALSE ); /* board_setScale( globals->cGlobals.game.board, hscale, vscale ); */ globals->gridOn = XP_TRUE; @@ -569,16 +570,16 @@ configure_event( GtkWidget* widget, GdkEventConfigure* XP_UNUSED(event), timerTop = GTK_TIMER_TOP; if ( globals->cGlobals.params->verticalScore ) { - timerLeft = GTK_BOARD_LEFT + (hscale*GTK_NUM_COLS) + 1; + timerLeft = GTK_BOARD_LEFT + (hscale*nCols) + 1; board_setScoreboardLoc( globals->cGlobals.game.board, timerLeft, GTK_VERT_SCORE_TOP, GTK_VERT_SCORE_WIDTH, - vscale*GTK_NUM_COLS, + vscale*nCols, XP_FALSE ); } else { - timerLeft = GTK_BOARD_LEFT + (hscale*GTK_NUM_COLS) + timerLeft = GTK_BOARD_LEFT + (hscale*nCols) - GTK_TIMER_WIDTH - netStatWidth; board_setScoreboardLoc( globals->cGlobals.game.board, GTK_BOARD_LEFT, GTK_HOR_SCORE_TOP, @@ -598,7 +599,7 @@ configure_event( GtkWidget* widget, GdkEventConfigure* XP_UNUSED(event), GTK_TIMER_WIDTH, GTK_HOR_SCORE_HEIGHT ); board_setTrayLoc( globals->cGlobals.game.board, GTK_TRAY_LEFT, trayTop, - hscale * GTK_NUM_COLS, vscale * GTK_TRAY_HT_ROWS + 10, + hscale * nCols, vscale * GTK_TRAY_HT_ROWS + 10, GTK_DIVIDER_WIDTH ); setCtrlsForTray( globals ); @@ -1251,7 +1252,8 @@ handle_hide_button( GtkWidget* XP_UNUSED(widget), GtkAppGlobals* globals ) XP_Bool draw = XP_FALSE; if ( globals->cGlobals.params->nHidden > 0 ) { - globals->adjustment->page_size = GTK_NUM_ROWS; + gint nRows = globals->cGlobals.params->gi.boardSize; + globals->adjustment->page_size = nRows; globals->adjustment->value = 0.0; gtk_signal_emit_by_name( GTK_OBJECT(globals->adjustment), "changed" ); @@ -1341,7 +1343,7 @@ setCtrlsForTray( GtkAppGlobals* XP_UNUSED(globals) ) XP_S16 nHidden = globals->cGlobals.params->nHidden; if ( nHidden != 0 ) { - XP_U16 pageSize = GTK_NUM_ROWS; + XP_U16 pageSize = nRows; if ( state == TRAY_HIDDEN ) { /* we recover what tray covers */ nHidden -= GTK_TRAY_HT_ROWS; @@ -1373,7 +1375,8 @@ gtk_util_yOffsetChange( XW_UtilCtxt* uc, XP_U16 maxOffset, { GtkAppGlobals* globals = (GtkAppGlobals*)uc->closure; if ( !!globals->adjustment ) { - globals->adjustment->page_size = GTK_NUM_ROWS - maxOffset; + gint nRows = globals->cGlobals.params->gi.boardSize; + globals->adjustment->page_size = nRows - maxOffset; globals->adjustment->value = newOffset; gtk_adjustment_value_changed( GTK_ADJUSTMENT(globals->adjustment) ); } @@ -2317,9 +2320,10 @@ gtkmain( LaunchParams* params, int argc, char *argv[] ) /* install scrollbar even if not needed -- since zooming can make it needed later */ GtkWidget* vscrollbar; + gint nRows = globals.cGlobals.params->gi.boardSize; globals.adjustment = (GtkAdjustment*) - gtk_adjustment_new( 0, 0, GTK_NUM_ROWS, 1, 2, - GTK_NUM_ROWS-globals.cGlobals.params->nHidden ); + gtk_adjustment_new( 0, 0, nRows, 1, 2, + nRows - globals.cGlobals.params->nHidden ); vscrollbar = gtk_vscrollbar_new( globals.adjustment ); g_signal_connect( GTK_OBJECT(globals.adjustment), "value_changed", G_CALLBACK(scroll_value_changed), &globals ); diff --git a/xwords4/linux/gtkmain.h b/xwords4/linux/gtkmain.h index f99713213..ca06ea8b3 100644 --- a/xwords4/linux/gtkmain.h +++ b/xwords4/linux/gtkmain.h @@ -132,8 +132,6 @@ typedef struct GtkAppGlobals { /* DictionaryCtxt* gtk_dictionary_make(); */ int gtkmain( LaunchParams* params, int argc, char *argv[] ); -#define GTK_NUM_COLS 15 -#define GTK_NUM_ROWS 15 #define GTK_MIN_SCALE 12 /* was 14 */ #define GTK_MIN_TRAY_SCALEH 24 @@ -156,7 +154,7 @@ int gtkmain( LaunchParams* params, int argc, char *argv[] ); #define GTK_TIMER_WIDTH 40 #define GTK_NETSTAT_WIDTH 20 #define GTK_TIMER_TOP GTK_HOR_SCORE_TOP -#define GTK_HOR_SCORE_WIDTH ((GTK_MIN_SCALE*MAX_COLS)-GTK_TIMER_PAD) +#define GTK_HOR_SCORE_WIDTH ((GTK_MIN_SCALE*20)-GTK_TIMER_PAD) #define GTK_VERT_SCORE_WIDTH 40 #define GTK_BOARD_TOP (GTK_SCORE_TOP + GTK_SCORE_HEIGHT \ diff --git a/xwords4/linux/linuxdict.c b/xwords4/linux/linuxdict.c index 4d065b4a6..76eace460 100644 --- a/xwords4/linux/linuxdict.c +++ b/xwords4/linux/linuxdict.c @@ -370,6 +370,7 @@ initFromDictFile( LinuxDictionaryCtxt* dctx, const char* fileName ) } else { dctx->super.base = NULL; dctx->super.topEdge = NULL; + numEdges = 0; } dctx->super.name = copyString( dctx->super.mpool, fileName ); diff --git a/xwords4/linux/linuxmain.c b/xwords4/linux/linuxmain.c index 4764f988c..aaa8c4d40 100644 --- a/xwords4/linux/linuxmain.c +++ b/xwords4/linux/linuxmain.c @@ -379,6 +379,7 @@ typedef enum { #ifdef XWFEATURE_WALKDICT ,CMD_TESTDICT ,CMD_TESTPRFX + ,CMD_TESTMINMAX #endif ,CMD_PLAYERDICT ,CMD_SEED @@ -458,6 +459,7 @@ static CmdInfoRec CmdInfoRecs[] = { #ifdef XWFEATURE_WALKDICT ,{ CMD_TESTDICT, true, "test-dict", "dictionary to be used for iterator test" } ,{ CMD_TESTPRFX, true, "test-prefix", "list first word starting with this" } + ,{ CMD_TESTMINMAX, true, "test-minmax", "M:M -- include only words whose len in range" } #endif ,{ CMD_PLAYERDICT, true, "player-dict", "dictionary name for player (in sequence)" } ,{ CMD_SEED, true, "seed", "random seed" } @@ -1036,28 +1038,35 @@ tmp_noop_sigintterm( int XP_UNUSED(sig) ) //# define PRINT_ALL static void testGetNthWord( const DictionaryCtxt* dict, char** words, - XP_U16 depth, IndexData* data ) + XP_U16 depth, IndexData* data, XP_U16 min, XP_U16 max ) { - XP_U32 half = dict_getWordCount( dict ) / 2; XP_UCHAR buf[64]; XP_U32 ii, jj; DictIter iter; - XP_U32 interval = 1000; - dict_initIter( dict, &iter ); + dict_initIter( &iter, dict, min, max ); + XP_U32 half = dict_countWords( &iter, NULL ) / 2; + XP_U32 interval = half / 100; + if ( interval == 0 ) { + ++interval; + } for ( ii = 0, jj = half; ii < half; ii += interval, jj += interval ) { if ( dict_getNthWord( &iter, ii, depth, data ) ) { dict_wordToString( &iter, buf, VSIZE(buf) ); XP_ASSERT( 0 == strcmp( buf, words[ii] ) ); - // XP_LOGF( "%s: word[%ld]: %s", __func__, ii, buf ); +# ifdef PRINT_ALL + XP_LOGF( "%s: word[%ld]: %s", __func__, ii, buf ); +# endif } else { XP_ASSERT( 0 ); } if ( dict_getNthWord( &iter, jj, depth, data ) ) { dict_wordToString( &iter, buf, VSIZE(buf) ); XP_ASSERT( 0 == strcmp( buf, words[jj] ) ); - // XP_LOGF( "%s: word[%ld]: %s", __func__, jj, buf ); +# ifdef PRINT_ALL + XP_LOGF( "%s: word[%ld]: %s", __func__, jj, buf ); +# endif } else { XP_ASSERT( 0 ); } @@ -1066,7 +1075,7 @@ testGetNthWord( const DictionaryCtxt* dict, char** words, static void walk_dict_test( const LaunchParams* params, const DictionaryCtxt* dict, - GSList* testPrefixes ) + GSList* testPrefixes, const char* testMinMax ) { /* This is just to test that the dict-iterating code works. The words are meant to be printed e.g. in a scrolling dialog on Android. */ @@ -1074,139 +1083,147 @@ walk_dict_test( const LaunchParams* params, const DictionaryCtxt* dict, long jj; XP_Bool gotOne; - XP_U32 count = dict_getWordCount( dict ); - XP_ASSERT( count > 0 ); - XP_ASSERT( count == dict_countWords( dict ) ); - char** words = g_malloc( count * sizeof(char*) ); - XP_ASSERT( !!words ); - - /* if ( dict_firstWord( dict, &word ) */ - /* && dict_getNextWord( dict, &word ) */ - /* && dict_getPrevWord( dict, &word ) ) { */ - /* fprintf( stderr, "yay!: dict_getPrevWord returned\n" ); */ - /* } */ - /* exit( 0 ); */ - - dict_initIter( dict, &iter ); - for ( jj = 0, gotOne = dict_firstWord( &iter ); - gotOne; - ++jj, gotOne = dict_getNextWord( &iter ) ) { - XP_ASSERT( dict_getPosition( &iter ) == jj ); - XP_UCHAR buf[64]; - dict_wordToString( &iter, buf, VSIZE(buf) ); -# ifdef PRINT_ALL - fprintf( stderr, "%.6ld: %s\n", jj, buf ); -# endif - if ( !!words ) { - words[jj] = g_strdup( buf ); - } + XP_U16 min, max; + if ( !testMinMax || !parsePair( testMinMax, &min, &max ) ) { + min = 0; + max = MAX_COLS_DICT; } - XP_ASSERT( count == jj ); - for ( jj = 0, gotOne = dict_lastWord( &iter ); - gotOne; - ++jj, gotOne = dict_getPrevWord( &iter ) ) { - XP_ASSERT( dict_getPosition(&iter) == count-jj-1 ); - XP_UCHAR buf[64]; - dict_wordToString( &iter, buf, VSIZE(buf) ); + dict_initIter( &iter, dict, min, max ); + LengthsArray lens; + XP_U32 count = dict_countWords( &iter, &lens ); + + XP_U32 sum = 0; + for ( jj = 0; jj < VSIZE(lens.lens); ++jj ) { + sum += lens.lens[jj]; + XP_LOGF( "%ld words of length %ld", lens.lens[jj], jj ); + } + XP_ASSERT( sum == count ); + + if ( count > 0 ) { + char** words = g_malloc( count * sizeof(char*) ); + XP_ASSERT( !!words ); + + for ( jj = 0, gotOne = dict_firstWord( &iter ); + gotOne; + gotOne = dict_getNextWord( &iter ) ) { + XP_ASSERT( dict_getPosition( &iter ) == jj ); + XP_UCHAR buf[64]; + dict_wordToString( &iter, buf, VSIZE(buf) ); # ifdef PRINT_ALL - fprintf( stderr, "%.6ld: %s\n", jj, buf ); + fprintf( stderr, "%.6ld: %s\n", jj, buf ); # endif - if ( !!words ) { - if ( strcmp( buf, words[count-jj-1] ) ) { - fprintf( stderr, "failure at %ld: %s going forward; %s " - "going backward\n", jj, words[count-jj-1], buf ); - break; + if ( !!words ) { + words[jj] = g_strdup( buf ); } + ++jj; } - } - XP_ASSERT( count == jj ); - XP_LOGF( "finished comparing runs in both directions" ); + XP_ASSERT( count == jj ); - XP_LOGF( "testing getNth" ); - testGetNthWord( dict, words, 0, NULL ); - - XP_U16 depth = 2; - XP_U16 maxCount = dict_numTileFaces( dict ); - IndexData data; - data.count = maxCount * maxCount; - data.indices = XP_MALLOC( params->util->mpool, - data.count * depth * sizeof(data.indices[0]) ); - data.prefixes = XP_MALLOC( params->util->mpool, - depth * data.count * sizeof(data.prefixes[0]) ); - - XP_LOGF( "making index..." ); - dict_makeIndex( &iter, depth, &data ); - XP_LOGF( "DONE making index" ); - - data.indices = XP_REALLOC( params->util->mpool, data.indices, - data.count * depth * sizeof(*data.indices) ); - data.prefixes = XP_REALLOC( params->util->mpool, data.prefixes, - depth * data.count * sizeof(*data.prefixes) ); -#if 0 - for ( ii = 0; ii < nIndices; ++ii ) { - if ( !dict_getNthWord( dict, &word, indices[ii] ) ) { - XP_ASSERT( 0 ); - } - XP_ASSERT( word.index == indices[ii] ); - XP_UCHAR buf1[64]; - dict_wordToString( dict, &word, buf1, VSIZE(buf1) ); - XP_UCHAR buf2[64] = {0}; - if ( ii > 0 && dict_getNthWord( dict, &word, indices[ii]-1 ) ) { - dict_wordToString( dict, &word, buf2, VSIZE(buf2) ); - } - char prfx[8]; - dict_tilesToString( dict, &prefixes[depth*ii], depth, prfx, VSIZE(prfx) ); - fprintf( stderr, "%d: index: %ld; prefix: %s; word: %s (prev: %s)\n", - ii, indices[ii], prfx, buf1, buf2 ); - } -#endif - - XP_LOGF( "testing getNth WITH INDEXING" ); - testGetNthWord( dict, words, depth, &data ); - - if ( !!testPrefixes ) { - int ii; - guint count = g_slist_length( testPrefixes ); - for ( ii = 0; ii < count; ++ii ) { - gchar* prefix = (gchar*)g_slist_nth_data( testPrefixes, ii ); - Tile tiles[MAX_COLS]; - XP_U16 nTiles = VSIZE(tiles); - if ( dict_tilesForString( dict, prefix, tiles, &nTiles ) ) { - if ( dict_findStartsWith( &iter, NULL, tiles, nTiles ) ) { - XP_UCHAR buf[32]; - XP_UCHAR bufPrev[32] = {0}; - dict_wordToString( &iter, buf, VSIZE(buf) ); - - XP_ASSERT( 0 == strncmp( buf, prefix, strlen(prefix) ) ); - - DictPosition pos = dict_getPosition( &iter ); - XP_ASSERT( 0 == strcmp( buf, words[pos] ) ); - if ( pos > 0 ) { - if ( !dict_getNthWord( &iter, pos-1, depth, &data ) ) { - XP_ASSERT( 0 ); - } - dict_wordToString( &iter, bufPrev, VSIZE(bufPrev) ); - XP_ASSERT( 0 == strcmp( bufPrev, words[pos-1] ) ); - } - XP_LOGF( "dict_getStartsWith(%s) => %s (prev=%s)", - prefix, buf, bufPrev ); - } else { - XP_LOGF( "nothing starts with %s", prefix ); + for ( jj = 0, gotOne = dict_lastWord( &iter ); + gotOne; + ++jj, gotOne = dict_getPrevWord( &iter ) ) { + XP_ASSERT( dict_getPosition(&iter) == count-jj-1 ); + XP_UCHAR buf[64]; + dict_wordToString( &iter, buf, VSIZE(buf) ); +# ifdef PRINT_ALL + fprintf( stderr, "%.6ld: %s\n", jj, buf ); +# endif + if ( !!words ) { + if ( strcmp( buf, words[count-jj-1] ) ) { + fprintf( stderr, "failure at %ld: %s going forward; %s " + "going backward\n", jj, words[count-jj-1], buf ); + break; } } } + XP_ASSERT( count == jj ); + XP_LOGF( "finished comparing runs in both directions" ); + XP_LOGF( "testing getNth" ); + testGetNthWord( dict, words, 0, NULL, min, max ); + + XP_U16 depth = 2; + XP_U16 maxCount = dict_numTileFaces( dict ); + IndexData data; + data.count = maxCount * maxCount; + data.indices = XP_MALLOC( params->util->mpool, + data.count * depth * sizeof(data.indices[0]) ); + data.prefixes = XP_MALLOC( params->util->mpool, + depth * data.count * sizeof(data.prefixes[0]) ); + + XP_LOGF( "making index..." ); + dict_makeIndex( &iter, depth, &data ); + XP_LOGF( "DONE making index" ); + + data.indices = XP_REALLOC( params->util->mpool, data.indices, + data.count * depth * sizeof(*data.indices) ); + data.prefixes = XP_REALLOC( params->util->mpool, data.prefixes, + depth * data.count * sizeof(*data.prefixes) ); +#if 0 + for ( ii = 0; ii < nIndices; ++ii ) { + if ( !dict_getNthWord( dict, &word, indices[ii] ) ) { + XP_ASSERT( 0 ); + } + XP_ASSERT( word.index == indices[ii] ); + XP_UCHAR buf1[64]; + dict_wordToString( dict, &word, buf1, VSIZE(buf1) ); + XP_UCHAR buf2[64] = {0}; + if ( ii > 0 && dict_getNthWord( dict, &word, indices[ii]-1 ) ) { + dict_wordToString( dict, &word, buf2, VSIZE(buf2) ); + } + char prfx[8]; + dict_tilesToString( dict, &prefixes[depth*ii], depth, prfx, VSIZE(prfx) ); + fprintf( stderr, "%d: index: %ld; prefix: %s; word: %s (prev: %s)\n", + ii, indices[ii], prfx, buf1, buf2 ); + } +#endif + + XP_LOGF( "testing getNth WITH INDEXING" ); + testGetNthWord( dict, words, depth, &data, min, max ); + + if ( !!testPrefixes ) { + int ii; + guint count = g_slist_length( testPrefixes ); + for ( ii = 0; ii < count; ++ii ) { + gchar* prefix = (gchar*)g_slist_nth_data( testPrefixes, ii ); + Tile tiles[MAX_COLS_DICT]; + XP_U16 nTiles = VSIZE(tiles); + if ( dict_tilesForString( dict, prefix, tiles, &nTiles ) ) { + if ( dict_findStartsWith( &iter, NULL, tiles, nTiles ) ) { + XP_UCHAR buf[32]; + XP_UCHAR bufPrev[32] = {0}; + dict_wordToString( &iter, buf, VSIZE(buf) ); + + XP_ASSERT( 0 == strncmp( buf, prefix, strlen(prefix) ) ); + + DictPosition pos = dict_getPosition( &iter ); + XP_ASSERT( 0 == strcmp( buf, words[pos] ) ); + if ( pos > 0 ) { + if ( !dict_getNthWord( &iter, pos-1, depth, &data ) ) { + XP_ASSERT( 0 ); + } + dict_wordToString( &iter, bufPrev, VSIZE(bufPrev) ); + XP_ASSERT( 0 == strcmp( bufPrev, words[pos-1] ) ); + } + XP_LOGF( "dict_getStartsWith(%s) => %s (prev=%s)", + prefix, buf, bufPrev ); + } else { + XP_LOGF( "nothing starts with %s", prefix ); + } + } + } + + } + XP_FREE( params->util->mpool, data.indices ); + XP_FREE( params->util->mpool, data.prefixes ); } XP_LOGF( "done" ); - - XP_FREE( params->util->mpool, data.indices ); - XP_FREE( params->util->mpool, data.prefixes ); -} /* walk_dict_test */ +} static void walk_dict_test_all( const LaunchParams* params, GSList* testDicts, - GSList* testPrefixes ) + GSList* testPrefixes, const char* testMinMax ) { int ii; guint count = g_slist_length( testDicts ); @@ -1217,7 +1234,7 @@ walk_dict_test_all( const LaunchParams* params, GSList* testDicts, params->useMmap ); if ( NULL != dict ) { XP_LOGF( "walk_dict_test(%s)", name ); - walk_dict_test( params, dict, testPrefixes ); + walk_dict_test( params, dict, testPrefixes, testMinMax ); dict_destroy( dict ); } } @@ -1242,6 +1259,7 @@ main( int argc, char** argv ) #ifdef XWFEATURE_WALKDICT GSList* testDicts = NULL; GSList* testPrefixes = NULL; + char* testMinMax = NULL; #endif /* install a no-op signal handler. Later curses- or gtk-specific code @@ -1366,6 +1384,9 @@ main( int argc, char** argv ) case CMD_TESTPRFX: testPrefixes = g_slist_prepend( testPrefixes, g_strdup(optarg) ); break; + case CMD_TESTMINMAX: + testMinMax = optarg; + break; #endif case CMD_PLAYERDICT: mainParams.gi.players[nPlayerDicts++].dictName = optarg; @@ -1631,7 +1652,7 @@ main( int argc, char** argv ) /* } */ #ifdef XWFEATURE_WALKDICT if ( !!testDicts ) { - walk_dict_test_all( &mainParams, testDicts, testPrefixes ); + walk_dict_test_all( &mainParams, testDicts, testPrefixes, testMinMax ); exit( 0 ); } #endif diff --git a/xwords4/linux/linuxutl.c b/xwords4/linux/linuxutl.c index c8cc8db0a..7a21e9af0 100644 --- a/xwords4/linux/linuxutl.c +++ b/xwords4/linux/linuxutl.c @@ -80,6 +80,63 @@ linux_util_makeEmptyDict( XW_UtilCtxt* XP_UNUSED_DBG(uctx) ) #define TL BONUS_TRIPLE_LETTER #define TW BONUS_TRIPLE_WORD +static XWBonusType* +bonusesFor( XP_U16 boardSize, XP_U16* len ) +{ + static XWBonusType scrabbleBoard[] = { + TW,//EM,EM,DL,EM,EM,EM,TW, + EM,DW,//EM,EM,EM,TL,EM,EM, + + EM,EM,DW,//EM,EM,EM,DL,EM, + DL,EM,EM,DW,//EM,EM,EM,DL, + + EM,EM,EM,EM,DW,//EM,EM,EM, + EM,TL,EM,EM,EM,TL,//EM,EM, + + EM,EM,DL,EM,EM,EM,DL,//EM, + TW,EM,EM,DL,EM,EM,EM,DW, + }; /* scrabbleBoard */ + + static XWBonusType seventeen[] = { + TW,//EM,EM,DL,EM,EM,EM,TW, + EM,DW,//EM,EM,EM,TL,EM,EM, + + EM,EM,DW,//EM,EM,EM,DL,EM, + DL,EM,EM,DW,//EM,EM,EM,DL, + + EM,EM,EM,EM,DW,//EM,EM,EM, + EM,TL,EM,EM,EM,TL,//EM,EM, + + EM,EM,DL,EM,EM,EM,DL,//EM, + TW,EM,EM,DL,EM,EM,EM,DW, + TW,EM,EM,DL,EM,EM,EM,DW,DW, + }; /* scrabbleBoard */ + + XWBonusType* result = NULL; + if ( boardSize == 15 ) { + result = scrabbleBoard; + *len = VSIZE(scrabbleBoard); + } else if ( boardSize == 17 ) { + result = seventeen; + *len = VSIZE(seventeen); + } + + return result; +} + +#ifdef STREAM_VERS_BIGBOARD +void +setSquareBonuses( const CommonGlobals* cGlobals ) +{ + XP_U16 nBonuses; + XWBonusType* bonuses = + bonusesFor( cGlobals->params->gi.boardSize, &nBonuses ); + if ( !!bonuses ) { + model_setSquareBonuses( cGlobals->game.model, bonuses, nBonuses ); + } +} +#endif + static XWBonusType* parseBonusFile( XP_U16 nCols, const char* bonusFile ) { @@ -146,14 +203,13 @@ parseBonusFile( XP_U16 nCols, const char* bonusFile ) } static XWBonusType -linux_util_getSquareBonus( XW_UtilCtxt* uc, const ModelCtxt* model, +linux_util_getSquareBonus( XW_UtilCtxt* uc, XP_U16 nCols, XP_U16 col, XP_U16 row ) { static XWBonusType* parsedFile = NULL; XWBonusType result = EM; CommonGlobals* cGlobals = (CommonGlobals*)uc->closure; - XP_U16 nCols = model_numCols( model ); if ( NULL == parsedFile && NULL != cGlobals->params->bonusFile ) { if ( !parsedFile ) { parsedFile = parseBonusFile( nCols, cGlobals->params->bonusFile ); @@ -162,25 +218,12 @@ linux_util_getSquareBonus( XW_UtilCtxt* uc, const ModelCtxt* model, if ( NULL != parsedFile ) { result = parsedFile[(row*nCols) + col]; } else { + XP_U16 nEntries; + XWBonusType* scrabbleBoard = bonusesFor( 15, &nEntries ); + XP_U16 index, ii; - /* This must be static or won't compile under multilink (for Palm). - Fix! */ - static char scrabbleBoard[8*8] = { - TW,//EM,EM,DL,EM,EM,EM,TW, - EM,DW,//EM,EM,EM,TL,EM,EM, - - EM,EM,DW,//EM,EM,EM,DL,EM, - DL,EM,EM,DW,//EM,EM,EM,DL, - - EM,EM,EM,EM,DW,//EM,EM,EM, - EM,TL,EM,EM,EM,TL,//EM,EM, - - EM,EM,DL,EM,EM,EM,DL,//EM, - TW,EM,EM,DL,EM,EM,EM,DW, - }; /* scrabbleBoard */ - - if ( col > 7 ) col = 14 - col; - if ( row > 7 ) row = 14 - row; + if ( col > (nCols/2) ) col = nCols - 1 - col; + if ( row > (nCols/2) ) row = nCols - 1 - row; if ( col > row ) { XP_U16 tmp = col; col = row; @@ -191,8 +234,8 @@ linux_util_getSquareBonus( XW_UtilCtxt* uc, const ModelCtxt* model, index += ii; } - if ( index < VSIZE(scrabbleBoard) ) { - result = (XWBonusType)scrabbleBoard[index]; + if ( index < nEntries) { + result = scrabbleBoard[index]; } } return result; diff --git a/xwords4/linux/linuxutl.h b/xwords4/linux/linuxutl.h index 03881b3a6..8685d33ea 100644 --- a/xwords4/linux/linuxutl.h +++ b/xwords4/linux/linuxutl.h @@ -1,6 +1,6 @@ -/* -*-mode: C; fill-column: 78; c-basic-offset: 4; compile-command: "make MEMDEBUG=TRUE"; -*- */ +/* -*- compile-command: "make MEMDEBUG=TRUE -j3"; -*- */ /* - * Copyright 2000-2008 by Eric House (xwords@eehouse.org). All rights + * Copyright 2000 - 2011 by Eric House (xwords@eehouse.org). All rights * reserved. * * This program is free software; you can redistribute it and/or @@ -47,4 +47,10 @@ XP_Bool storeNoConnMsg( CommonGlobals* cGlobals, const XP_U8* msg, XP_U16 len, const XP_UCHAR* relayID ); void writeNoConnMsgs( CommonGlobals* cGlobals, int fd ); +#ifdef STREAM_VERS_BIGBOARD +void setSquareBonuses( const CommonGlobals* cGlobals ); +#else +# define setSquareBonuses( cg ) +#endif + #endif