mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2024-12-27 09:58:45 +01:00
add filtering to wordlist browser
Add a basic regular expression engine to the dictiter, and to the UI add the ability to filter for "starts with", "contains" and "ends with", which translate into ANDed RE_*, _*RE_* and _*RE, respectively (with _ standing for blank/wildcard). The engine's tightly integrated with the next/prevWord() functions for greatest possible speed, but unless there's no pattern does slow things down a bit (especially when "ENDS WITH" is used.) The full engine is not exposed (users can't provide raw REs), and while the parser will accept nesting (e.g. ([AB]_*[CD]){2,5} to mean words from 2-5 tiles long starting with A or B and ending with C or D) the engine can't handle it. Which is why filtering for word length is handled separately from REs (but also tightly integrated.) Users can enter strings that don't map to tiles. They now get an error. It made sense for the error alert to have a "Show tiles" button, so there's now a dialog listing all the tiles in a wordlist, something the browser has needed all along.
This commit is contained in:
parent
d71cf6cac6
commit
b8f359c3e5
66 changed files with 3446 additions and 1167 deletions
|
@ -146,7 +146,6 @@ public class BoardCanvas extends Canvas implements DrawCtx {
|
|||
m_context = context;
|
||||
m_activity = activity;
|
||||
m_jniThread = jniThread;
|
||||
m_dict = new DictWrapper();
|
||||
|
||||
m_hasSmallScreen = Utils.hasSmallScreen( m_context );
|
||||
|
||||
|
@ -583,7 +582,7 @@ public class BoardCanvas extends Canvas implements DrawCtx {
|
|||
@Override
|
||||
public void dictChanged( final long newPtr )
|
||||
{
|
||||
long curPtr = m_dict.getDictPtr();
|
||||
long curPtr = null == m_dict ? 0 : m_dict.getDictPtr();
|
||||
boolean doPost = false;
|
||||
if ( curPtr != newPtr ) {
|
||||
if ( 0 == newPtr ) {
|
||||
|
@ -595,7 +594,9 @@ public class BoardCanvas extends Canvas implements DrawCtx {
|
|||
m_dictChars = null;
|
||||
doPost = true;
|
||||
}
|
||||
m_dict.release();
|
||||
if ( null != m_dict ) {
|
||||
m_dict.release();
|
||||
}
|
||||
m_dict = new DictWrapper( newPtr );
|
||||
}
|
||||
|
||||
|
|
|
@ -122,15 +122,6 @@ public class DBUtils {
|
|||
int ts;
|
||||
}
|
||||
|
||||
public static class DictBrowseState {
|
||||
public int m_minShown;
|
||||
public int m_maxShown;
|
||||
public int m_pos;
|
||||
public int m_top;
|
||||
public String m_prefix;
|
||||
public int[] m_counts;
|
||||
}
|
||||
|
||||
public static GameSummary getSummary( Context context,
|
||||
GameLock lock )
|
||||
{
|
||||
|
@ -1951,86 +1942,6 @@ public class DBUtils {
|
|||
return success;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// DictsDB stuff
|
||||
/////////////////////////////////////////////////////////////////
|
||||
public static DictBrowseState dictsGetOffset( Context context, String name,
|
||||
DictLoc loc )
|
||||
{
|
||||
Assert.assertTrue( DictLoc.UNKNOWN != loc );
|
||||
DictBrowseState result = null;
|
||||
String[] columns = { DBHelper.ITERPOS, DBHelper.ITERTOP,
|
||||
DBHelper.ITERMIN, DBHelper.ITERMAX,
|
||||
DBHelper.WORDCOUNTS, DBHelper.ITERPREFIX };
|
||||
String selection =
|
||||
String.format( NAMELOC_FMT, DBHelper.DICTNAME,
|
||||
name, DBHelper.LOC, loc.ordinal() );
|
||||
initDB( context );
|
||||
synchronized( s_dbHelper ) {
|
||||
Cursor cursor = query( TABLE_NAMES.DICTBROWSE, columns, selection );
|
||||
if ( 1 >= cursor.getCount() && cursor.moveToFirst() ) {
|
||||
result = new DictBrowseState();
|
||||
result.m_pos = cursor.getInt( cursor
|
||||
.getColumnIndex(DBHelper.ITERPOS));
|
||||
result.m_top = cursor.getInt( cursor
|
||||
.getColumnIndex(DBHelper.ITERTOP));
|
||||
result.m_minShown =
|
||||
cursor.getInt( cursor
|
||||
.getColumnIndex(DBHelper.ITERMIN));
|
||||
result.m_maxShown =
|
||||
cursor.getInt( cursor
|
||||
.getColumnIndex(DBHelper.ITERMAX));
|
||||
result.m_prefix =
|
||||
cursor.getString( cursor
|
||||
.getColumnIndex(DBHelper.ITERPREFIX));
|
||||
String counts =
|
||||
cursor.getString( cursor.getColumnIndex(DBHelper.WORDCOUNTS));
|
||||
if ( null != counts ) {
|
||||
String[] nums = TextUtils.split( counts, ":" );
|
||||
int[] ints = new int[nums.length];
|
||||
for ( int ii = 0; ii < nums.length; ++ii ) {
|
||||
ints[ii] = Integer.parseInt( nums[ii] );
|
||||
}
|
||||
result.m_counts = ints;
|
||||
}
|
||||
}
|
||||
cursor.close();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void dictsSetOffset( Context context, String name,
|
||||
DictLoc loc, DictBrowseState state )
|
||||
{
|
||||
Assert.assertTrue( DictLoc.UNKNOWN != loc );
|
||||
String selection =
|
||||
String.format( NAMELOC_FMT, DBHelper.DICTNAME,
|
||||
name, DBHelper.LOC, loc.ordinal() );
|
||||
ContentValues values = new ContentValues();
|
||||
values.put( DBHelper.ITERPOS, state.m_pos );
|
||||
values.put( DBHelper.ITERTOP, state.m_top );
|
||||
values.put( DBHelper.ITERMIN, state.m_minShown );
|
||||
values.put( DBHelper.ITERMAX, state.m_maxShown );
|
||||
values.put( DBHelper.ITERPREFIX, state.m_prefix );
|
||||
if ( null != state.m_counts ) {
|
||||
String[] nums = new String[state.m_counts.length];
|
||||
for ( int ii = 0; ii < nums.length; ++ii ) {
|
||||
nums[ii] = String.format( "%d", state.m_counts[ii] );
|
||||
}
|
||||
values.put( DBHelper.WORDCOUNTS, TextUtils.join( ":", nums ) );
|
||||
}
|
||||
|
||||
initDB( context );
|
||||
synchronized( s_dbHelper ) {
|
||||
int result = update( TABLE_NAMES.DICTBROWSE, values, selection );
|
||||
if ( 0 == result ) {
|
||||
values.put( DBHelper.DICTNAME, name );
|
||||
values.put( DBHelper.LOC, loc.ordinal() );
|
||||
insert( TABLE_NAMES.DICTBROWSE, values );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Called from jni
|
||||
public static String dictsGetMD5Sum( Context context, String name )
|
||||
{
|
||||
|
|
|
@ -592,6 +592,11 @@ public class DelegateBase implements DlgClickNotify,
|
|||
m_dlgDelegate.startProgress( titleID, msg, null );
|
||||
}
|
||||
|
||||
protected void startProgress( String title, String msg )
|
||||
{
|
||||
m_dlgDelegate.startProgress( title, msg, null );
|
||||
}
|
||||
|
||||
protected void startProgress( int titleID, int msgID,
|
||||
OnCancelListener lstnr )
|
||||
{
|
||||
|
|
|
@ -25,9 +25,10 @@ import android.app.Dialog;
|
|||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView.OnItemSelectedListener;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.BaseAdapter;
|
||||
|
@ -39,39 +40,99 @@ import android.widget.SectionIndexer;
|
|||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eehouse.android.xw4.DlgDelegate.Action;
|
||||
import org.eehouse.android.xw4.ExpandImageButton.ExpandChangeListener;
|
||||
import org.eehouse.android.xw4.jni.DictInfo;
|
||||
import org.eehouse.android.xw4.jni.JNIUtilsImpl;
|
||||
import org.eehouse.android.xw4.jni.XwJNI.DictWrapper;
|
||||
import org.eehouse.android.xw4.jni.XwJNI.IterWrapper;
|
||||
import org.eehouse.android.xw4.jni.XwJNI.PatDesc;
|
||||
import org.eehouse.android.xw4.jni.XwJNI;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.io.Serializable;
|
||||
|
||||
public class DictBrowseDelegate extends DelegateBase
|
||||
implements View.OnClickListener, OnItemSelectedListener {
|
||||
implements View.OnClickListener {
|
||||
private static final String TAG = DictBrowseDelegate.class.getSimpleName();
|
||||
private static final String DELIM = ".";
|
||||
private static final boolean SHOW_NUM = false;
|
||||
|
||||
private static final String DICT_NAME = "DICT_NAME";
|
||||
private static final String DICT_LOC = "DICT_LOC";
|
||||
|
||||
private static final int MIN_LEN = 2;
|
||||
private static final int MAX_LEN = 15;
|
||||
|
||||
// Struct to show both what user's configuring AND what's been
|
||||
// successfully fed to create the current iterator. The config setting
|
||||
// become the filter params when the user presses the Apply Filter button
|
||||
// and corrects any tile problems.
|
||||
private static class DictBrowseState implements Serializable {
|
||||
public int m_chosenMin, m_chosenMax;
|
||||
public int m_passedMin, m_passedMax;
|
||||
public int m_pos;
|
||||
public int m_top;
|
||||
public PatDesc[] m_pats;
|
||||
public int[] m_counts;
|
||||
public boolean m_expanded;
|
||||
|
||||
public DictBrowseState()
|
||||
{
|
||||
m_chosenMin = MIN_LEN;
|
||||
m_chosenMax = MAX_LEN;
|
||||
m_pats = new PatDesc[3];
|
||||
for ( int ii = 0; ii < m_pats.length; ++ii ) {
|
||||
m_pats[ii] = new PatDesc();
|
||||
}
|
||||
}
|
||||
|
||||
private void onFilterAccepted( DictWrapper dict, String delim )
|
||||
{
|
||||
m_passedMin = m_chosenMin;
|
||||
m_passedMax = m_chosenMax;
|
||||
|
||||
for ( PatDesc desc : m_pats ) {
|
||||
String str = XwJNI.dict_tilesToStr( dict, desc.tilePat, delim );
|
||||
desc.strPat = str;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder("{pats:[");
|
||||
for ( PatDesc pd : m_pats ) {
|
||||
sb.append(pd).append(",");
|
||||
}
|
||||
sb.append("],");
|
||||
sb.append( "passedMin:").append(m_passedMin).append(",")
|
||||
.append( "passedMax:").append(m_passedMax).append(",")
|
||||
.append( "chosenMin:").append(m_chosenMin).append(",")
|
||||
.append( "chosenMax:").append(m_chosenMax).append(",")
|
||||
;
|
||||
sb.append("}");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
private Activity m_activity;
|
||||
private long m_dictClosure = 0L;
|
||||
private int m_lang;
|
||||
private String m_name;
|
||||
private DictUtils.DictLoc m_loc;
|
||||
private DBUtils.DictBrowseState m_browseState;
|
||||
private DictBrowseState m_browseState;
|
||||
private int m_minAvail;
|
||||
private int m_maxAvail;
|
||||
private ListView m_list;
|
||||
|
||||
|
||||
// - Steps to reproduce the problem:
|
||||
// Create ListView, set custom adapter which implements ListAdapter and
|
||||
// SectionIndexer but do not extends BaseAdapter. Enable fast scroll in
|
||||
// layout. This will effect in ClassCastException.
|
||||
|
||||
private IterWrapper m_diClosure;
|
||||
private DictWrapper m_dict;
|
||||
private DictInfo mDictInfo;
|
||||
private PatTableRow m_rows[] = { null, null, null };
|
||||
private Spinner m_spinnerMin;
|
||||
private Spinner m_spinnerMax;
|
||||
|
||||
private class DictListAdapter extends BaseAdapter
|
||||
implements SectionIndexer {
|
||||
|
@ -84,23 +145,19 @@ public class DictBrowseDelegate extends DelegateBase
|
|||
{
|
||||
super();
|
||||
|
||||
XwJNI.di_setMinMax( m_dictClosure, m_browseState.m_minShown,
|
||||
m_browseState.m_maxShown );
|
||||
m_nWords = XwJNI.di_wordCount( m_dictClosure );
|
||||
|
||||
int format = m_browseState.m_minShown == m_browseState.m_maxShown ?
|
||||
R.string.dict_browse_title1_fmt : R.string.dict_browse_title_fmt;
|
||||
setTitle( getString( format, m_name, m_nWords,
|
||||
m_browseState.m_minShown,
|
||||
m_browseState.m_maxShown ));
|
||||
m_nWords = XwJNI.di_wordCount( m_diClosure );
|
||||
Log.d( TAG, "making DictListAdapter; have %d words", m_nWords );
|
||||
}
|
||||
|
||||
public Object getItem( int position )
|
||||
{
|
||||
TextView text = (TextView)
|
||||
inflate( android.R.layout.simple_list_item_1 );
|
||||
String str = XwJNI.di_nthWord( m_dictClosure, position, null );
|
||||
String str = XwJNI.di_nthWord( m_diClosure, position, null );
|
||||
if ( null != str ) {
|
||||
if ( SHOW_NUM ) {
|
||||
str = String.format( "%1$5d %2$s", position, str );
|
||||
}
|
||||
text.setText( str );
|
||||
text.setOnClickListener( DictBrowseDelegate.this );
|
||||
}
|
||||
|
@ -114,7 +171,7 @@ public class DictBrowseDelegate extends DelegateBase
|
|||
public long getItemId( int position ) { return position; }
|
||||
|
||||
public int getCount() {
|
||||
Assert.assertTrue( 0 != m_dictClosure );
|
||||
Assert.assertTrueNR( m_nWords == XwJNI.di_wordCount( m_diClosure ) );
|
||||
return m_nWords;
|
||||
}
|
||||
|
||||
|
@ -142,15 +199,16 @@ public class DictBrowseDelegate extends DelegateBase
|
|||
@Override
|
||||
public Object[] getSections()
|
||||
{
|
||||
m_prefixes = XwJNI.di_getPrefixes( m_dictClosure );
|
||||
m_indices = XwJNI.di_getIndices( m_dictClosure );
|
||||
m_prefixes = XwJNI.di_getPrefixes( m_diClosure );
|
||||
m_indices = XwJNI.di_getIndices( m_diClosure );
|
||||
return m_prefixes;
|
||||
}
|
||||
}
|
||||
|
||||
protected DictBrowseDelegate( Delegator delegator, Bundle savedInstanceState )
|
||||
protected DictBrowseDelegate( Delegator delegator, Bundle sis )
|
||||
{
|
||||
super( delegator, savedInstanceState, R.layout.dict_browser );
|
||||
super( delegator, sis, R.layout.dict_browser,
|
||||
R.menu.dict_browse_menu );
|
||||
m_activity = delegator.getActivity();
|
||||
}
|
||||
|
||||
|
@ -168,71 +226,63 @@ public class DictBrowseDelegate extends DelegateBase
|
|||
DictUtils.DictLoc.values()[args.getInt( DICT_LOC, 0 )];
|
||||
m_lang = DictLangCache.getDictLangCode( m_activity, name );
|
||||
|
||||
String[] names = { name };
|
||||
DictUtils.DictPairs pairs = DictUtils.openDicts( m_activity, names );
|
||||
m_dictClosure = XwJNI.di_init( pairs.m_bytes[0],
|
||||
name, pairs.m_paths[0] );
|
||||
findTableRows();
|
||||
m_spinnerMin = ((LabeledSpinner)findViewById( R.id.spinner_min ))
|
||||
.getSpinner();
|
||||
m_spinnerMax = ((LabeledSpinner)findViewById( R.id.spinner_max ))
|
||||
.getSpinner();
|
||||
|
||||
String desc = XwJNI.di_getDesc( m_dictClosure );
|
||||
Log.d( TAG, "got desc: %s", desc );
|
||||
loadBrowseState();
|
||||
|
||||
String[] names = { m_name };
|
||||
DictUtils.DictPairs pairs = DictUtils.openDicts( m_activity, names );
|
||||
Assert.assertNotNull( m_browseState );
|
||||
m_dict = XwJNI.makeDict( pairs.m_bytes[0], m_name, pairs.m_paths[0] );
|
||||
|
||||
mDictInfo = new DictInfo();
|
||||
XwJNI.dict_getInfo( m_dict, false, mDictInfo );
|
||||
setTitle( getString( R.string.dict_browse_title_fmt, m_name, mDictInfo.wordCount ) );
|
||||
|
||||
ExpandImageButton eib = (ExpandImageButton)findViewById( R.id.expander );
|
||||
eib.setOnExpandChangedListener( new ExpandChangeListener() {
|
||||
@Override
|
||||
public void expandedChanged( boolean nowExpanded )
|
||||
{
|
||||
m_browseState.m_expanded = nowExpanded;
|
||||
setShowConfig();
|
||||
}
|
||||
} )
|
||||
.setExpanded( m_browseState.m_expanded );
|
||||
|
||||
String desc = XwJNI.dict_getDesc( m_dict );
|
||||
if ( null != desc ) {
|
||||
TextView view = (TextView)findViewById( R.id.desc );
|
||||
Assert.assertNotNull( view );
|
||||
view.setVisibility( View.VISIBLE );
|
||||
view.setText( desc );
|
||||
}
|
||||
|
||||
m_browseState = DBUtils.dictsGetOffset( m_activity, name, m_loc );
|
||||
boolean newState = null == m_browseState;
|
||||
if ( newState ) {
|
||||
m_browseState = new DBUtils.DictBrowseState();
|
||||
m_browseState.m_pos = 0;
|
||||
m_browseState.m_top = 0;
|
||||
}
|
||||
if ( null == m_browseState.m_counts ) {
|
||||
m_browseState.m_counts = XwJNI.di_getCounts( m_dictClosure );
|
||||
int[] ids = { R.id.button_useconfig, R.id.button_addBlank, };
|
||||
for ( int id : ids ) {
|
||||
findViewById( id ).setOnClickListener(this);
|
||||
}
|
||||
|
||||
if ( null == m_browseState.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 = getString( R.string.alert_empty_dict_fmt, name );
|
||||
makeOkOnlyBuilder(msg).setAction(Action.FINISH_ACTION).show();
|
||||
} else {
|
||||
figureMinMax( m_browseState.m_counts );
|
||||
if ( newState ) {
|
||||
m_browseState.m_minShown = m_minAvail;
|
||||
m_browseState.m_maxShown = m_maxAvail;
|
||||
}
|
||||
|
||||
Button button = (Button)findViewById( R.id.search_button );
|
||||
button.setOnClickListener( new View.OnClickListener() {
|
||||
public void onClick( View view )
|
||||
{
|
||||
findButtonClicked();
|
||||
}
|
||||
} );
|
||||
|
||||
setUpSpinners();
|
||||
|
||||
initList();
|
||||
}
|
||||
setShowConfig();
|
||||
replaceIter( true );
|
||||
}
|
||||
} // init
|
||||
|
||||
protected void onPause()
|
||||
{
|
||||
if ( null != m_browseState // already saved?
|
||||
&& null != m_list ) { // there are words? (don't NPE on empty dict)
|
||||
m_browseState.m_pos = m_list.getFirstVisiblePosition();
|
||||
View view = m_list.getChildAt( 0 );
|
||||
m_browseState.m_top = (view == null) ? 0 : view.getTop();
|
||||
m_browseState.m_prefix = getFindText();
|
||||
DBUtils.dictsSetOffset( m_activity, m_name, m_loc, m_browseState );
|
||||
m_browseState = null;
|
||||
}
|
||||
scrapeBrowseState();
|
||||
storeBrowseState();
|
||||
// if ( null != m_browseState ) {
|
||||
// if ( null != m_list ) { // there are words? (don't NPE on empty dict)
|
||||
// m_browseState.m_pos = m_list.getFirstVisiblePosition();
|
||||
// View view = m_list.getChildAt( 0 );
|
||||
// m_browseState.m_top = (view == null) ? 0 : view.getTop();
|
||||
// }
|
||||
// storeBrowseState();
|
||||
// }
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
|
@ -240,30 +290,12 @@ public class DictBrowseDelegate extends DelegateBase
|
|||
protected void onResume()
|
||||
{
|
||||
super.onResume();
|
||||
if ( null == m_browseState ) {
|
||||
m_browseState = DBUtils.dictsGetOffset( m_activity, m_name, m_loc );
|
||||
}
|
||||
setFindText( m_browseState.m_prefix );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy()
|
||||
{
|
||||
XwJNI.di_destroy( m_dictClosure );
|
||||
m_dictClosure = 0;
|
||||
}
|
||||
|
||||
// Just in case onDestroy didn't get called....
|
||||
@Override
|
||||
public void finalize()
|
||||
{
|
||||
Assert.assertTrueNR( m_dictClosure == 0 );
|
||||
XwJNI.di_destroy( m_dictClosure );
|
||||
try {
|
||||
super.finalize();
|
||||
} catch ( java.lang.Throwable err ){
|
||||
Log.i( TAG, "%s", err.toString() );
|
||||
}
|
||||
loadBrowseState();
|
||||
// if ( null == m_browseState ) {
|
||||
// m_browseState = DBUtils.dictsGetOffset( m_activity, m_name, m_loc );
|
||||
// here
|
||||
// }
|
||||
setFindPats( m_browseState.m_pats );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -276,7 +308,7 @@ public class DictBrowseDelegate extends DelegateBase
|
|||
final byte[][] choices = (byte[][])params[0];
|
||||
final String[] strs = new String[choices.length];
|
||||
for ( int ii = 0; ii < choices.length; ++ii ) {
|
||||
strs[ii] = XwJNI.di_tilesToStr( m_dictClosure, choices[ii], DELIM );
|
||||
strs[ii] = XwJNI.dict_tilesToStr( m_dict, choices[ii], DELIM );
|
||||
}
|
||||
final int[] chosen = {0};
|
||||
dialog = makeAlertBuilder()
|
||||
|
@ -293,14 +325,26 @@ public class DictBrowseDelegate extends DelegateBase
|
|||
public void onClick( DialogInterface dialog, int which )
|
||||
{
|
||||
if ( 0 <= chosen[0] ) {
|
||||
byte[][] theOne = {choices[chosen[0]]};
|
||||
showPrefix( theOne, DELIM );
|
||||
Assert.failDbg();
|
||||
}
|
||||
}
|
||||
} )
|
||||
.setTitle( R.string.pick_tiles_title )
|
||||
.create();
|
||||
break;
|
||||
case SHOW_TILES:
|
||||
String info = (String)params[0];
|
||||
View tilesView = inflate( R.layout.tiles_table );
|
||||
addTileRows( tilesView, info );
|
||||
|
||||
String langName = DictLangCache.getLangName( m_activity, m_lang );
|
||||
String title = getString( R.string.show_tiles_title_fmt, langName );
|
||||
dialog = makeAlertBuilder()
|
||||
.setView( tilesView )
|
||||
.setPositiveButton( android.R.string.ok, null )
|
||||
.setTitle( title )
|
||||
.create();
|
||||
break;
|
||||
default:
|
||||
dialog = super.makeDialog( alert, params );
|
||||
break;
|
||||
|
@ -308,48 +352,42 @@ public class DictBrowseDelegate extends DelegateBase
|
|||
return dialog;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected( MenuItem item )
|
||||
{
|
||||
boolean handled = true;
|
||||
|
||||
switch ( item.getItemId() ) {
|
||||
case R.id.dicts_showtiles:
|
||||
showTiles();
|
||||
break;
|
||||
default:
|
||||
handled = false;
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
// View.OnClickListener interface
|
||||
//////////////////////////////////////////////////
|
||||
@Override
|
||||
public void onClick( View view )
|
||||
{
|
||||
TextView text = (TextView)view;
|
||||
String[] words = { text.getText().toString() };
|
||||
launchLookup( words, m_lang, true );
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
// AdapterView.OnItemSelectedListener interface
|
||||
//////////////////////////////////////////////////
|
||||
@Override
|
||||
public void onItemSelected( AdapterView<?> parent, View view,
|
||||
int position, long id )
|
||||
{
|
||||
TextView text = (TextView)view;
|
||||
// null text seems to have generated at least one google play report
|
||||
if ( null != text && null != m_browseState ) {
|
||||
int newval = Integer.parseInt( text.getText().toString() );
|
||||
switch ( parent.getId() ) {
|
||||
case R.id.wordlen_min:
|
||||
if ( newval != m_browseState.m_minShown ) {
|
||||
setMinMax( newval, m_browseState.m_maxShown );
|
||||
}
|
||||
break;
|
||||
case R.id.wordlen_max:
|
||||
if ( newval != m_browseState.m_maxShown ) {
|
||||
setMinMax( m_browseState.m_minShown, newval );
|
||||
}
|
||||
break;
|
||||
}
|
||||
switch ( view.getId() ) {
|
||||
case R.id.button_useconfig:
|
||||
useButtonClicked();
|
||||
break;
|
||||
case R.id.button_addBlank:
|
||||
addBlankButtonClicked();
|
||||
break;
|
||||
default:
|
||||
TextView text = (TextView)view;
|
||||
String[] words = { text.getText().toString() };
|
||||
launchLookup( words, m_lang, true );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected( AdapterView<?> parent )
|
||||
{
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
// DlgDelegate.DlgClickNotify interface
|
||||
//////////////////////////////////////////////////
|
||||
|
@ -362,6 +400,9 @@ public class DictBrowseDelegate extends DelegateBase
|
|||
handled = true;
|
||||
finish();
|
||||
break;
|
||||
case SHOW_TILES:
|
||||
showTiles();
|
||||
break;
|
||||
default:
|
||||
handled = super.onPosButton( action, params );
|
||||
break;
|
||||
|
@ -369,70 +410,209 @@ public class DictBrowseDelegate extends DelegateBase
|
|||
return handled;
|
||||
}
|
||||
|
||||
private void findButtonClicked()
|
||||
private void scrapeBrowseState()
|
||||
{
|
||||
String text = getFindText();
|
||||
if ( null != text && 0 < text.length() ) {
|
||||
m_browseState.m_prefix = text;
|
||||
Assert.assertTrueNR( null != m_browseState );
|
||||
m_browseState.m_chosenMin = MIN_LEN + m_spinnerMin.getSelectedItemPosition();
|
||||
m_browseState.m_chosenMax = MIN_LEN + m_spinnerMax.getSelectedItemPosition();
|
||||
if ( null != m_list ) { // there are words? (don't NPE on empty dict)
|
||||
m_browseState.m_pos = m_list.getFirstVisiblePosition();
|
||||
View view = m_list.getChildAt( 0 );
|
||||
m_browseState.m_top = (view == null) ? 0 : view.getTop();
|
||||
}
|
||||
|
||||
byte[][] choices = XwJNI.di_strToTiles( m_dictClosure, text );
|
||||
if ( null == choices || 0 == choices.length ) {
|
||||
String msg = getString( R.string.no_tiles_exist, text, m_name );
|
||||
makeOkOnlyBuilder( msg ).show();
|
||||
} else if ( 1 == choices.length || !XwJNI.di_hasDuplicates(m_dictClosure) ) {
|
||||
showPrefix( choices, null );
|
||||
} else {
|
||||
showDialogFragment( DlgID.CHOOSE_TILES, (Object)choices );
|
||||
// Get the strings (not bytes) from the rows
|
||||
for ( int ii = 0; ii < m_rows.length; ++ii ) {
|
||||
m_rows[ii].getToDesc(m_browseState.m_pats[ii]);
|
||||
// .updateFrom( desc );
|
||||
}
|
||||
}
|
||||
|
||||
private static final int[] sTileRowIDs = {R.id.face, R.id.count, R.id.value };
|
||||
private void addTileRows( View view, String info )
|
||||
{
|
||||
ViewGroup table = view.findViewById( R.id.table );
|
||||
if ( null != table ) {
|
||||
String[] tiles = TextUtils.split( info, "\n" );
|
||||
for ( String row : tiles ) {
|
||||
String[] fields = TextUtils.split( row, "\t" );
|
||||
if ( 3 == fields.length ) {
|
||||
ViewGroup rowView = (ViewGroup)inflate( R.layout.tiles_row );
|
||||
for ( int ii = 0; ii < sTileRowIDs.length; ++ii ) {
|
||||
TextView tv = (TextView)rowView.findViewById( sTileRowIDs[ii] );
|
||||
tv.setText( fields[ii] );
|
||||
}
|
||||
table.addView( rowView );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String getFindText()
|
||||
private void showTiles()
|
||||
{
|
||||
EditWClear edit = (EditWClear)findViewById( R.id.word_edit );
|
||||
return edit.getText().toString();
|
||||
String info = XwJNI.getTilesInfo( m_dict );
|
||||
showDialogFragment( DlgID.SHOW_TILES, info );
|
||||
}
|
||||
|
||||
private void setFindText( String text )
|
||||
private String m_stateKey = null;
|
||||
private String getStateKey()
|
||||
{
|
||||
EditWClear edit = (EditWClear)findViewById( R.id.word_edit );
|
||||
edit.setText( text );
|
||||
if ( null == m_stateKey ) {
|
||||
m_stateKey = String.format( "KEY_%s_%d", m_name, m_loc.ordinal() );
|
||||
}
|
||||
return m_stateKey;
|
||||
}
|
||||
|
||||
private void showPrefix( byte[][] prefix, String delim )
|
||||
private void findTableRows()
|
||||
{
|
||||
if ( null != prefix && 0 < prefix.length && 0 < prefix[0].length ) {
|
||||
int pos = XwJNI.di_getStartsWith( m_dictClosure, prefix );
|
||||
if ( 0 <= pos ) {
|
||||
m_list.setSelection( pos );
|
||||
} else {
|
||||
String text = XwJNI.di_tilesToStr( m_dictClosure, prefix[0], delim );
|
||||
DbgUtils.showf( m_activity, R.string.dict_browse_nowords_fmt,
|
||||
m_name, text );
|
||||
ViewGroup table = (ViewGroup)findViewById( R.id.config );
|
||||
int count = table.getChildCount();
|
||||
int nFound = 0;
|
||||
for ( int ii = 0; ii < count && nFound < m_rows.length; ++ii ) {
|
||||
View child = table.getChildAt( ii );
|
||||
if ( child instanceof PatTableRow ) {
|
||||
m_rows[nFound++] = (PatTableRow)child;
|
||||
}
|
||||
}
|
||||
Assert.assertTrueNR( nFound == m_rows.length );
|
||||
}
|
||||
|
||||
private void loadBrowseState()
|
||||
{
|
||||
boolean newState = false;
|
||||
if ( null == m_browseState ) {
|
||||
Serializable obj = DBUtils.getSerializableFor( m_activity, getStateKey() );
|
||||
if ( null != obj && obj instanceof DictBrowseState ) {
|
||||
m_browseState = (DictBrowseState)obj;
|
||||
if ( null == m_browseState.m_pats ) {
|
||||
m_browseState = null;
|
||||
}
|
||||
}
|
||||
if ( null == m_browseState ) {
|
||||
m_browseState = new DictBrowseState();
|
||||
}
|
||||
}
|
||||
Log.d( TAG, "loadBrowseState() => %s", m_browseState );
|
||||
}
|
||||
|
||||
private void storeBrowseState()
|
||||
{
|
||||
if ( null != m_browseState ) {
|
||||
DBUtils.setSerializableFor( m_activity, getStateKey(), m_browseState );
|
||||
}
|
||||
}
|
||||
|
||||
private void useButtonClicked()
|
||||
{
|
||||
scrapeBrowseState();
|
||||
Log.d( TAG, "useButtonClicked(): m_browseState: %s", m_browseState );
|
||||
|
||||
boolean pending = false;
|
||||
|
||||
if ( m_browseState.m_chosenMin > m_browseState.m_chosenMax ) {
|
||||
pending = true;
|
||||
makeOkOnlyBuilder( R.string.error_min_gt_max ).show();
|
||||
}
|
||||
|
||||
PatDesc[] pats = m_browseState.m_pats;
|
||||
for ( int ii = 0; ii < pats.length && !pending; ++ii ) {
|
||||
String strPat = pats[ii].strPat;
|
||||
if ( null != strPat && 0 < strPat.length() ) {
|
||||
byte[][] choices = XwJNI.dict_strToTiles( m_dict, strPat );
|
||||
if ( null == choices || 0 == choices.length ) {
|
||||
String langName = DictLangCache.getLangName( m_activity, m_lang );
|
||||
String msg = getString( R.string.no_tiles_exist, strPat, langName );
|
||||
makeOkOnlyBuilder( msg )
|
||||
.setActionPair( Action.SHOW_TILES, R.string.show_tiles_button )
|
||||
.show();
|
||||
pending = true;
|
||||
} else if ( 1 == choices.length
|
||||
|| !XwJNI.dict_hasDuplicates( m_dict ) ) {
|
||||
pats[ii].tilePat = choices[0];
|
||||
} else {
|
||||
showDialogFragment( DlgID.CHOOSE_TILES, (Object)choices );
|
||||
pending = true;
|
||||
}
|
||||
} else {
|
||||
pats[ii].tilePat = null;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !pending ) {
|
||||
storeBrowseState();
|
||||
replaceIter( false );
|
||||
}
|
||||
}
|
||||
|
||||
private void addBlankButtonClicked()
|
||||
{
|
||||
boolean handled = false;
|
||||
for ( PatTableRow row : m_rows ) {
|
||||
handled = handled || row.addBlankToFocussed( "_" );
|
||||
}
|
||||
if ( !handled ) {
|
||||
makeNotAgainBuilder( R.string.blank_button_expl,
|
||||
R.string.key_na_addBlankButton )
|
||||
.setTitle(null)
|
||||
.show();
|
||||
}
|
||||
}
|
||||
|
||||
private void setShowConfig()
|
||||
{
|
||||
findViewById(R.id.config).setVisibility( m_browseState.m_expanded
|
||||
? View.VISIBLE : View.GONE );
|
||||
}
|
||||
|
||||
private void setFindPats( PatDesc[] descs )
|
||||
{
|
||||
if ( null != descs && descs.length == m_rows.length ) {
|
||||
for ( int ii = 0; ii < m_rows.length; ++ii ) {
|
||||
m_rows[ii].setFromDesc( descs[ii] );
|
||||
}
|
||||
}
|
||||
setUpSpinners();
|
||||
}
|
||||
|
||||
private String formatPats( PatDesc[] pats, String delim )
|
||||
{
|
||||
Assert.assertTrueNR( null != m_diClosure );
|
||||
List<String> strs = new ArrayList<>();
|
||||
for ( int ii = 0; ii < pats.length; ++ii ) {
|
||||
PatDesc desc = pats[ii];
|
||||
String str = desc.strPat;
|
||||
if ( null == str && (ii == 0 || ii == pats.length - 1) ) {
|
||||
str = "";
|
||||
}
|
||||
if ( null != str ) {
|
||||
strs.add(str);
|
||||
}
|
||||
}
|
||||
String result = TextUtils.join( "…", strs );
|
||||
// Log.d( TAG, "formatPats() => %s", result );
|
||||
return result;
|
||||
}
|
||||
|
||||
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 recognize a changed dataset. So, as a
|
||||
// workaround, relaunch the activity with different parameters.
|
||||
if ( m_browseState.m_minShown != min ||
|
||||
m_browseState.m_maxShown != max ) {
|
||||
// if ( m_browseState.m_minShown != min ||
|
||||
// m_browseState.m_maxShown != max ) {
|
||||
|
||||
m_browseState.m_pos = 0;
|
||||
m_browseState.m_top = 0;
|
||||
m_browseState.m_minShown = min;
|
||||
m_browseState.m_maxShown = max;
|
||||
m_browseState.m_prefix = getFindText();
|
||||
DBUtils.dictsSetOffset( m_activity, m_name, m_loc, m_browseState );
|
||||
// m_browseState.m_pos = 0;
|
||||
// m_browseState.m_top = 0;
|
||||
// m_browseState.m_minShown = min;
|
||||
// m_browseState.m_maxShown = max;
|
||||
// m_browseState.m_pats = getFindText();
|
||||
// DBUtils.dictsSetOffset( m_activity, m_name, m_loc, m_browseState );
|
||||
|
||||
setUpSpinners();
|
||||
// setUpSpinners();
|
||||
|
||||
initList();
|
||||
}
|
||||
// initList();
|
||||
// }
|
||||
}
|
||||
|
||||
private void figureMinMax( int[] counts )
|
||||
|
@ -448,55 +628,106 @@ public class DictBrowseDelegate extends DelegateBase
|
|||
}
|
||||
}
|
||||
|
||||
private void makeSpinnerAdapter( int resID, int min, int max, int cur )
|
||||
private String[] m_nums;
|
||||
private void makeSpinnerAdapter( Spinner spinner, int curVal )
|
||||
{
|
||||
Spinner spinner = (Spinner)findViewById( resID );
|
||||
Assert.assertTrue( min <= max );
|
||||
|
||||
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<String> adapter = new
|
||||
ArrayAdapter<String>( m_activity,
|
||||
//android.R.layout.simple_spinner_dropdown_item,
|
||||
android.R.layout.simple_spinner_item,
|
||||
nums );
|
||||
m_nums );
|
||||
adapter.setDropDownViewResource( android.R.layout.
|
||||
simple_spinner_dropdown_item );
|
||||
spinner.setAdapter( adapter );
|
||||
spinner.setSelection( sel );
|
||||
spinner.setOnItemSelectedListener( this );
|
||||
spinner.setSelection( curVal - MIN_LEN );
|
||||
// spinner.setOnItemSelectedListener( this );
|
||||
}
|
||||
|
||||
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.
|
||||
makeSpinnerAdapter( R.id.wordlen_min, m_minAvail,
|
||||
m_browseState.m_maxShown, m_browseState.m_minShown );
|
||||
makeSpinnerAdapter( R.id.wordlen_max, m_browseState.m_minShown,
|
||||
m_maxAvail, m_browseState.m_maxShown );
|
||||
if ( null == m_nums ) {
|
||||
m_nums = new String[MAX_LEN - MIN_LEN + 1];
|
||||
for ( int ii = MIN_LEN; ii <= MAX_LEN; ++ii ) {
|
||||
m_nums[ii - MIN_LEN] = String.format( "%d", ii );
|
||||
}
|
||||
}
|
||||
|
||||
makeSpinnerAdapter( m_spinnerMin, m_browseState.m_chosenMin );
|
||||
makeSpinnerAdapter( m_spinnerMax, m_browseState.m_chosenMax );
|
||||
}
|
||||
|
||||
private void initList()
|
||||
private FrameLayout removeList()
|
||||
{
|
||||
m_list = null;
|
||||
FrameLayout parent = (FrameLayout)findViewById(R.id.list_container);
|
||||
parent.removeAllViews();
|
||||
|
||||
return parent;
|
||||
}
|
||||
|
||||
private void replaceIter( boolean useOldVals )
|
||||
{
|
||||
Assert.assertNotNull( m_browseState );
|
||||
Assert.assertNotNull( m_dict );
|
||||
int min = useOldVals ? m_browseState.m_passedMin : m_browseState.m_chosenMin;
|
||||
int max = useOldVals ? m_browseState.m_passedMax : m_browseState.m_chosenMax;
|
||||
|
||||
String title = getString( R.string.filter_title_fmt, m_name );
|
||||
String msg = getString( R.string.filter_progress_fmt, mDictInfo.wordCount );
|
||||
startProgress( title, msg );
|
||||
|
||||
XwJNI.di_init( m_dict, m_browseState.m_pats, min, max,
|
||||
new XwJNI.DictIterProcs() {
|
||||
@Override
|
||||
public void onIterReady( final IterWrapper wrapper )
|
||||
{
|
||||
runOnUiThread( new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
stopProgress();
|
||||
|
||||
m_browseState.onFilterAccepted( m_dict, null );
|
||||
initList( wrapper );
|
||||
setFindPats( m_browseState.m_pats );
|
||||
}
|
||||
} );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
private void initList( IterWrapper newIter )
|
||||
{
|
||||
FrameLayout parent = removeList();
|
||||
|
||||
m_list = (ListView)inflate( R.layout.dict_browser_list );
|
||||
m_list.setAdapter( new DictListAdapter() );
|
||||
|
||||
Assert.assertNotNull( m_browseState );
|
||||
Assert.assertNotNull( m_dict );
|
||||
m_diClosure = newIter;
|
||||
|
||||
DictListAdapter dla = new DictListAdapter();
|
||||
|
||||
m_list.setAdapter( dla );
|
||||
m_list.setFastScrollEnabled( true );
|
||||
m_list.setSelectionFromTop( m_browseState.m_pos, m_browseState.m_top );
|
||||
|
||||
parent.addView( m_list );
|
||||
|
||||
updateFilterString();
|
||||
}
|
||||
|
||||
private void updateFilterString()
|
||||
{
|
||||
PatDesc[] pats = m_browseState.m_pats;
|
||||
Assert.assertNotNull( pats );
|
||||
String summary;
|
||||
String pat = formatPats( pats, null );
|
||||
int nWords = XwJNI.di_wordCount( m_diClosure );
|
||||
int[] minMax = XwJNI.di_getMinMax( m_diClosure );
|
||||
summary = getString( R.string.filter_sum_pat_fmt, pat,
|
||||
minMax[0], minMax[1],
|
||||
nWords );
|
||||
TextView tv = (TextView)findViewById( R.id.filter_summary );
|
||||
tv.setText( summary );
|
||||
}
|
||||
|
||||
private static void launch( Delegator delegator, Bundle bundle )
|
||||
|
|
|
@ -90,6 +90,7 @@ public class DlgDelegate {
|
|||
DELETE_DICT_ACTION,
|
||||
UPDATE_DICTS_ACTION,
|
||||
MOVE_CONFIRMED,
|
||||
SHOW_TILES,
|
||||
|
||||
// Game configs
|
||||
LOCKED_CHANGE_ACTION,
|
||||
|
@ -198,7 +199,13 @@ public class DlgDelegate {
|
|||
|
||||
Builder setTitle( int strID )
|
||||
{
|
||||
mState.setTitle( strID );
|
||||
mState.setTitle( getString(strID) );
|
||||
return this;
|
||||
}
|
||||
|
||||
Builder setTitle( String str )
|
||||
{
|
||||
mState.setTitle( str );
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -407,6 +414,11 @@ public class DlgDelegate {
|
|||
public void startProgress( int titleID, String msg, OnCancelListener lstnr )
|
||||
{
|
||||
String title = getString( titleID );
|
||||
startProgress( title, msg, lstnr );
|
||||
}
|
||||
|
||||
public void startProgress( String title, String msg, OnCancelListener lstnr )
|
||||
{
|
||||
m_progress = ProgressDialog.show( m_activity, title, msg, true, true );
|
||||
|
||||
if ( null != lstnr ) {
|
||||
|
|
|
@ -116,8 +116,8 @@ public class DlgDelegateAlert extends XWDialogFragment {
|
|||
|
||||
AlertDialog.Builder builder = LocUtils.makeAlertBuilder( context );
|
||||
|
||||
if ( 0 != state.m_titleId ) {
|
||||
builder.setTitle( state.m_titleId );
|
||||
if ( null != state.m_title ) {
|
||||
builder.setTitle( state.m_title );
|
||||
}
|
||||
|
||||
populateBuilder( context, state, builder );
|
||||
|
|
|
@ -69,6 +69,7 @@ public enum DlgID {
|
|||
, GAMES_LIST_NAME_REMATCH
|
||||
, ASK_DUP_PAUSE
|
||||
, CHOOSE_TILES
|
||||
, SHOW_TILES
|
||||
;
|
||||
|
||||
private boolean m_addToStack;
|
||||
|
|
|
@ -46,7 +46,7 @@ public class DlgState implements Parcelable {
|
|||
public int m_prefsNAKey;
|
||||
// These can't be serialized!!!!
|
||||
public Object[] m_params;
|
||||
public int m_titleId;
|
||||
public String m_title;
|
||||
|
||||
public DlgState( DlgID dlgID )
|
||||
{
|
||||
|
@ -79,8 +79,8 @@ public class DlgState implements Parcelable {
|
|||
{ m_posButton = id; return this; }
|
||||
public DlgState setNegButton( int id )
|
||||
{ m_negButton = id; return this; }
|
||||
public DlgState setTitle( int id )
|
||||
{ m_titleId = id; return this; }
|
||||
public DlgState setTitle( String title )
|
||||
{ m_title = title; return this; }
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
|
@ -103,7 +103,7 @@ public class DlgState implements Parcelable {
|
|||
.append(", pair ").append(m_pair)
|
||||
.append(", pos: ").append(m_posButton)
|
||||
.append(", neg: ").append(m_negButton)
|
||||
.append(", title: ").append(m_titleId)
|
||||
.append(", title: ").append(m_title)
|
||||
.append(", params: [").append(params)
|
||||
.append("]}")
|
||||
.toString();
|
||||
|
@ -124,14 +124,15 @@ public class DlgState implements Parcelable {
|
|||
DlgState other = (DlgState)it;
|
||||
result = other != null
|
||||
&& m_id.equals(other.m_id)
|
||||
&& ((null == m_msg) ? (null == other.m_msg) : m_msg.equals(other.m_msg))
|
||||
&& TextUtils.equals( m_msg, other.m_msg)
|
||||
&& m_posButton == other.m_posButton
|
||||
&& m_negButton == other.m_negButton
|
||||
&& m_action == other.m_action
|
||||
&& ((null == m_pair) ? (null == other.m_pair) : m_pair.equals(other.m_pair))
|
||||
&& m_prefsNAKey == other.m_prefsNAKey
|
||||
&& Arrays.deepEquals( m_params, other.m_params )
|
||||
&& m_titleId == other.m_titleId;
|
||||
&& TextUtils.equals( m_title,other.m_title)
|
||||
;
|
||||
}
|
||||
} else {
|
||||
result = super.equals( it );
|
||||
|
@ -164,7 +165,7 @@ public class DlgState implements Parcelable {
|
|||
out.writeInt( m_negButton );
|
||||
out.writeInt( null == m_action ? -1 : m_action.ordinal() );
|
||||
out.writeInt( m_prefsNAKey );
|
||||
out.writeInt( m_titleId );
|
||||
out.writeString( m_title );
|
||||
out.writeString( m_msg );
|
||||
out.writeSerializable( m_params );
|
||||
out.writeSerializable( m_pair );
|
||||
|
@ -196,7 +197,7 @@ public class DlgState implements Parcelable {
|
|||
int tmp = in.readInt();
|
||||
Action action = 0 > tmp ? null : Action.values()[tmp];
|
||||
int prefsKey = in.readInt();
|
||||
int titleId = in.readInt();
|
||||
String title = in.readString();
|
||||
String msg = in.readString();
|
||||
Object[] params = (Object[])in.readSerializable();
|
||||
ActionPair pair = (ActionPair)in.readSerializable();
|
||||
|
@ -206,7 +207,7 @@ public class DlgState implements Parcelable {
|
|||
.setNegButton( negButton )
|
||||
.setAction( action )
|
||||
.setPrefsNAKey( prefsKey )
|
||||
.setTitle(titleId)
|
||||
.setTitle(title)
|
||||
.setParams(params)
|
||||
.setActionPair(pair)
|
||||
;
|
||||
|
|
|
@ -19,9 +19,10 @@
|
|||
|
||||
package org.eehouse.android.xw4;
|
||||
|
||||
import android.widget.SearchView;
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.EditText;
|
||||
import android.widget.SearchView;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
@ -31,6 +32,7 @@ public class EditWClear extends SearchView
|
|||
private static final String TAG = EditWClear.class.getSimpleName();
|
||||
|
||||
private Set<TextWatcher> mWatchers;
|
||||
private EditText mEdit;
|
||||
|
||||
public interface TextWatcher {
|
||||
void onTextChanged( String newText );
|
||||
|
@ -41,6 +43,12 @@ public class EditWClear extends SearchView
|
|||
super( context, as );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate()
|
||||
{
|
||||
mEdit = (EditText)Utils.getChildInstanceOf( this, EditText.class );
|
||||
}
|
||||
|
||||
synchronized void addTextChangedListener( TextWatcher proc )
|
||||
{
|
||||
if ( null == mWatchers ) {
|
||||
|
@ -60,6 +68,17 @@ public class EditWClear extends SearchView
|
|||
return super.getQuery();
|
||||
}
|
||||
|
||||
void insertBlank( String blank )
|
||||
{
|
||||
// I'm not confident I'll always be able to get the edittext, so to be
|
||||
// safe....
|
||||
if ( null == mEdit ) {
|
||||
setQuery( getQuery() + blank, false );
|
||||
} else {
|
||||
mEdit.getText().insert(mEdit.getSelectionStart(), blank );
|
||||
}
|
||||
}
|
||||
|
||||
// from SearchView.OnQueryTextListener
|
||||
@Override
|
||||
public synchronized boolean onQueryTextChange( String newText )
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
/* -*- compile-command: "find-and-gradle.sh inXw4dDeb"; -*- */
|
||||
/*
|
||||
* Copyright 2009 - 2020 by Eric House (xwords@eehouse.org). All rights
|
||||
* reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package org.eehouse.android.xw4;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.widget.ImageButton;
|
||||
|
||||
public class ExpandImageButton extends ImageButton {
|
||||
private boolean m_expanded;
|
||||
|
||||
public interface ExpandChangeListener {
|
||||
public void expandedChanged( boolean nowExpanded );
|
||||
}
|
||||
|
||||
public ExpandImageButton( Context context, AttributeSet as )
|
||||
{
|
||||
super( context, as );
|
||||
}
|
||||
|
||||
public ExpandImageButton setExpanded( boolean expanded )
|
||||
{
|
||||
m_expanded = expanded;
|
||||
|
||||
setImageResource( expanded ?
|
||||
R.drawable.expander_ic_maximized :
|
||||
R.drawable.expander_ic_minimized);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ExpandImageButton setOnExpandChangedListener( final ExpandChangeListener listener )
|
||||
{
|
||||
setOnClickListener( new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick( View view )
|
||||
{
|
||||
m_expanded = ! m_expanded;
|
||||
setExpanded( m_expanded );
|
||||
listener.expandedChanged( m_expanded );
|
||||
}
|
||||
} );
|
||||
return this;
|
||||
}
|
||||
}
|
|
@ -377,8 +377,8 @@ public class GameConfigDelegate extends DelegateBase
|
|||
} else {
|
||||
dictLabel.setVisibility( View.GONE );
|
||||
}
|
||||
m_playerDictSpinner = (Spinner)
|
||||
playerView.findViewById( R.id.dict_spinner );
|
||||
m_playerDictSpinner = ((LabeledSpinner)playerView.findViewById( R.id.player_dict_spinner ))
|
||||
.getSpinner();
|
||||
if ( localOnlyGame() ) {
|
||||
configDictSpinner( m_playerDictSpinner, m_gi.dictLang, m_gi.dictName(lp) );
|
||||
} else {
|
||||
|
@ -429,11 +429,6 @@ public class GameConfigDelegate extends DelegateBase
|
|||
lp.password = Utils.getText( dialog, R.id.password_edit );
|
||||
|
||||
if ( localOnlyGame() ) {
|
||||
{
|
||||
Spinner spinner =
|
||||
(Spinner)((Dialog)di).findViewById( R.id.dict_spinner );
|
||||
Assert.assertTrue( m_playerDictSpinner == spinner );
|
||||
}
|
||||
int position = m_playerDictSpinner.getSelectedItemPosition();
|
||||
SpinnerAdapter adapter = m_playerDictSpinner.getAdapter();
|
||||
|
||||
|
@ -475,9 +470,13 @@ public class GameConfigDelegate extends DelegateBase
|
|||
findViewById( R.id.play_button ).setOnClickListener( this );
|
||||
|
||||
m_playerLayout = (LinearLayout)findViewById( R.id.player_list );
|
||||
m_phoniesSpinner = (Spinner)findViewById( R.id.phonies_spinner );
|
||||
m_boardsizeSpinner = (Spinner)findViewById( R.id.boardsize_spinner );
|
||||
m_smartnessSpinner = (Spinner)findViewById( R.id.smart_robot );
|
||||
|
||||
m_phoniesSpinner = ((LabeledSpinner)findViewById( R.id.phonies_spinner ))
|
||||
.getSpinner();
|
||||
m_boardsizeSpinner = ((LabeledSpinner)findViewById( R.id.boardsize_spinner ))
|
||||
.getSpinner();
|
||||
m_smartnessSpinner = ((LabeledSpinner)findViewById( R.id.smart_robot ))
|
||||
.getSpinner();
|
||||
|
||||
m_connLabel = (TextView)findViewById( R.id.conns_label );
|
||||
} // init
|
||||
|
|
|
@ -43,7 +43,8 @@ import java.util.HashSet;
|
|||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
public class GameListItem extends LinearLayout
|
||||
implements View.OnClickListener, SelectableItem.LongClickHandler {
|
||||
implements View.OnClickListener, SelectableItem.LongClickHandler,
|
||||
ExpandImageButton.ExpandChangeListener {
|
||||
private static final String TAG = GameListItem.class.getSimpleName();
|
||||
|
||||
private static final int SUMMARY_WAIT_MSECS = 1000;
|
||||
|
@ -67,7 +68,7 @@ public class GameListItem extends LinearLayout
|
|||
|
||||
private boolean m_expanded, m_haveTurn, m_haveTurnLocal;
|
||||
private long m_lastMoveTime;
|
||||
private ImageButton m_expandButton;
|
||||
private ExpandImageButton m_expandButton;
|
||||
private Handler m_handler;
|
||||
private GameSummary m_summary;
|
||||
private SelectableItem m_cb;
|
||||
|
@ -165,15 +166,6 @@ public class GameListItem extends LinearLayout
|
|||
{
|
||||
int id = view.getId();
|
||||
switch ( id ) {
|
||||
case R.id.expander:
|
||||
m_expanded = !m_expanded;
|
||||
DBUtils.setExpanded( m_rowid, m_expanded );
|
||||
|
||||
makeThumbnailIf( m_expanded );
|
||||
|
||||
showHide();
|
||||
break;
|
||||
|
||||
case R.id.view_loaded:
|
||||
toggleSelected();
|
||||
break;
|
||||
|
@ -189,12 +181,24 @@ public class GameListItem extends LinearLayout
|
|||
}
|
||||
}
|
||||
|
||||
// ExpandImageButton.ExpandChangeListener
|
||||
@Override
|
||||
public void expandedChanged( boolean nowExpanded )
|
||||
{
|
||||
m_expanded = nowExpanded;
|
||||
DBUtils.setExpanded( m_rowid, m_expanded );
|
||||
|
||||
makeThumbnailIf( m_expanded );
|
||||
|
||||
showHide();
|
||||
}
|
||||
|
||||
private void findViews()
|
||||
{
|
||||
m_hideable = (LinearLayout)findViewById( R.id.hideable );
|
||||
m_name = (ExpiringTextView)findViewById( R.id.game_name );
|
||||
m_expandButton = (ImageButton)findViewById( R.id.expander );
|
||||
m_expandButton.setOnClickListener( this );
|
||||
m_expandButton = (ExpandImageButton)findViewById( R.id.expander );
|
||||
m_expandButton.setOnExpandChangedListener( this );
|
||||
m_viewUnloaded = (TextView)findViewById( R.id.view_unloaded );
|
||||
m_viewLoaded = findViewById( R.id.view_loaded );
|
||||
m_viewLoaded.setOnClickListener( this );
|
||||
|
@ -225,9 +229,7 @@ public class GameListItem extends LinearLayout
|
|||
|
||||
private void showHide()
|
||||
{
|
||||
m_expandButton.setImageResource( m_expanded ?
|
||||
R.drawable.expander_ic_maximized :
|
||||
R.drawable.expander_ic_minimized);
|
||||
m_expandButton.setExpanded( m_expanded );
|
||||
m_hideable.setVisibility( m_expanded? View.VISIBLE : View.GONE );
|
||||
|
||||
int vis = m_expanded && XWPrefs.getThumbEnabled( m_context )
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
/* -*- compile-command: "find-and-gradle.sh inXw4dDeb"; -*- */
|
||||
/*
|
||||
* Copyright 2020 by Eric House (xwords@eehouse.org). All
|
||||
* rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package org.eehouse.android.xw4;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
|
||||
|
||||
/**
|
||||
* This class's purpose is to link a spinner with a textview that's its label
|
||||
* such that clicking on the label is the same as clicking on the spinner.
|
||||
*/
|
||||
|
||||
public class LabeledSpinner extends LinearLayout {
|
||||
private Spinner mSpinner;
|
||||
|
||||
public LabeledSpinner( Context context, AttributeSet as ) {
|
||||
super( context, as );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate()
|
||||
{
|
||||
mSpinner = (Spinner)Utils.getChildInstanceOf( this, Spinner.class );
|
||||
|
||||
TextView tv = (TextView)Utils.getChildInstanceOf( this, TextView.class );
|
||||
tv.setOnClickListener( new OnClickListener() {
|
||||
@Override
|
||||
public void onClick( View target )
|
||||
{
|
||||
mSpinner.performClick();
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
public Spinner getSpinner()
|
||||
{
|
||||
Assert.assertNotNull( mSpinner );
|
||||
return mSpinner;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
/* -*- compile-command: "find-and-gradle.sh inXw4dDeb"; -*- */
|
||||
/*
|
||||
* Copyright 2020 by Eric House (xwords@eehouse.org). All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package org.eehouse.android.xw4;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.TableRow;
|
||||
|
||||
import org.eehouse.android.xw4.jni.XwJNI.PatDesc;
|
||||
|
||||
public class PatTableRow extends TableRow {
|
||||
private static final String TAG = PatTableRow.class.getSimpleName();
|
||||
private EditWClear mEdit;
|
||||
private CheckBox mCheck;
|
||||
|
||||
public PatTableRow( Context context, AttributeSet as )
|
||||
{
|
||||
super( context, as );
|
||||
}
|
||||
|
||||
public void getToDesc( PatDesc out )
|
||||
{
|
||||
getFields();
|
||||
|
||||
// PatDesc result = null;
|
||||
String strPat = mEdit.getText().toString();
|
||||
out.strPat = strPat;
|
||||
out.anyOrderOk = mCheck.isChecked();
|
||||
// if ( null != strPat && 0 < strPat.length() ) {
|
||||
// result = new PatDesc();
|
||||
// result.strPat = strPat;
|
||||
// result.anyOrderOk = mCheck.isChecked();
|
||||
// }
|
||||
// return result;
|
||||
}
|
||||
|
||||
public void setFromDesc( PatDesc desc )
|
||||
{
|
||||
getFields();
|
||||
|
||||
mEdit.setText(desc.strPat);
|
||||
mCheck.setChecked(desc.anyOrderOk);
|
||||
}
|
||||
|
||||
public boolean addBlankToFocussed( String blank )
|
||||
{
|
||||
getFields();
|
||||
|
||||
boolean handled = mEdit.hasFocus();
|
||||
if ( handled ) {
|
||||
mEdit.insertBlank( blank );
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
|
||||
private void getFields()
|
||||
{
|
||||
for ( int ii = 0;
|
||||
(null == mEdit || null == mCheck) && ii < getChildCount();
|
||||
++ii ) {
|
||||
View view = getChildAt( ii );
|
||||
if ( view instanceof EditWClear ) {
|
||||
mEdit = (EditWClear)view;
|
||||
} else if ( view instanceof CheckBox ) {
|
||||
mCheck = (CheckBox)view;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -59,7 +59,7 @@ public class StudyListDelegate extends ListDelegateBase
|
|||
|
||||
private Activity m_activity;
|
||||
private Spinner m_spinner;
|
||||
private View m_pickView; // LinearLayout, actually
|
||||
private LabeledSpinner m_pickView;
|
||||
private int[] m_langCodes;
|
||||
private String[] m_words;
|
||||
private Set<String> m_checkeds;
|
||||
|
@ -79,8 +79,8 @@ public class StudyListDelegate extends ListDelegateBase
|
|||
{
|
||||
m_list = (ListView)findViewById( android.R.id.list );
|
||||
|
||||
m_spinner = (Spinner)findViewById( R.id.pick_lang_spinner );
|
||||
m_pickView = findViewById( R.id.pick_lang );
|
||||
m_pickView = (LabeledSpinner)findViewById( R.id.pick_lang );
|
||||
m_spinner = m_pickView.getSpinner();
|
||||
m_checkeds = new HashSet<>();
|
||||
m_words = new String[0];
|
||||
|
||||
|
|
|
@ -23,7 +23,6 @@ package org.eehouse.android.xw4;
|
|||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.CompoundButton.OnCheckedChangeListener;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
|
|
@ -48,6 +48,7 @@ import android.util.Base64;
|
|||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
|
@ -690,6 +691,21 @@ public class Utils {
|
|||
return Looper.getMainLooper().equals(Looper.myLooper());
|
||||
}
|
||||
|
||||
public static View getChildInstanceOf( ViewGroup parent, Class clazz )
|
||||
{
|
||||
View result = null;
|
||||
for ( int ii = 0; null == result && ii < parent.getChildCount(); ++ii ) {
|
||||
View child = parent.getChildAt( ii );
|
||||
if ( clazz.isInstance(child) ) {
|
||||
result = child;
|
||||
break;
|
||||
} else if ( child instanceof ViewGroup ) {
|
||||
result = getChildInstanceOf( (ViewGroup)child, clazz );
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// But see hexArray above
|
||||
private static final String HEX_CHARS = "0123456789ABCDEF";
|
||||
private static char[] HEX_CHARS_ARRAY = HEX_CHARS.toCharArray();
|
||||
|
|
|
@ -22,6 +22,7 @@ package org.eehouse.android.xw4.jni;
|
|||
|
||||
import android.graphics.Rect;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.eehouse.android.xw4.Assert;
|
||||
|
@ -531,29 +532,130 @@ public class XwJNI {
|
|||
public static boolean dict_getInfo( byte[] dict, String name, String path,
|
||||
boolean check, DictInfo info )
|
||||
{
|
||||
return dict_getInfo( getJNI().m_ptrGlobals, dict, name, path, check, info );
|
||||
DictWrapper wrapper = makeDict( dict, name, path );
|
||||
return dict_getInfo( wrapper, check, info );
|
||||
}
|
||||
|
||||
public static boolean dict_getInfo( DictWrapper dict, boolean check, DictInfo info )
|
||||
{
|
||||
return dict_getInfo( getJNI().m_ptrGlobals, dict.getDictPtr(),
|
||||
check, info );
|
||||
}
|
||||
|
||||
public static String dict_getDesc( DictWrapper dict )
|
||||
{
|
||||
return dict_getDesc( dict.getDictPtr() );
|
||||
}
|
||||
|
||||
public static String dict_tilesToStr( DictWrapper dict, byte[] tiles, String delim )
|
||||
{
|
||||
return dict_tilesToStr( dict.getDictPtr(), tiles, delim );
|
||||
}
|
||||
|
||||
public static byte[][] dict_strToTiles( DictWrapper dict, String str )
|
||||
{
|
||||
return dict_strToTiles( dict.getDictPtr(), str );
|
||||
}
|
||||
|
||||
public static boolean dict_hasDuplicates( DictWrapper dict )
|
||||
{
|
||||
return dict_hasDuplicates( dict.getDictPtr() );
|
||||
}
|
||||
|
||||
public static String getTilesInfo( DictWrapper dict )
|
||||
{
|
||||
return dict_getTilesInfo( getJNI().m_ptrGlobals, dict.getDictPtr() );
|
||||
}
|
||||
|
||||
public static native int dict_getTileValue( long dictPtr, int tile );
|
||||
|
||||
// Dict iterator
|
||||
public final static int MAX_COLS_DICT = 15; // from dictiter.h
|
||||
public static long di_init( byte[] dict, String name, String path )
|
||||
public static DictWrapper makeDict( byte[] bytes, String name, String path )
|
||||
{
|
||||
return di_init( getJNI().m_ptrGlobals, dict, name, path );
|
||||
long dict = dict_make( getJNI().m_ptrGlobals, bytes, name, path );
|
||||
return new DictWrapper( dict );
|
||||
}
|
||||
public static native void di_setMinMax( long closure, int min, int max );
|
||||
public static native void di_destroy( long closure );
|
||||
public static native int di_wordCount( long closure );
|
||||
public static native int[] di_getCounts( long closure );
|
||||
public static native String di_nthWord( long closure, int nn, String delim );
|
||||
public static native String[] di_getPrefixes( long closure );
|
||||
public static native int[] di_getIndices( long closure );
|
||||
public static native byte[][] di_strToTiles( long closure, String str );
|
||||
public static native int di_getStartsWith( long closure, byte[][] prefix );
|
||||
public static native String di_getDesc( long closure );
|
||||
public static native String di_tilesToStr( long closure, byte[] tiles, String delim );
|
||||
public static native boolean di_hasDuplicates( long closure );
|
||||
|
||||
public static class PatDesc implements Serializable {
|
||||
public String strPat;
|
||||
public byte[] tilePat;
|
||||
public boolean anyOrderOk;
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format( "{str: %s; nTiles: %d; anyOrderOk: %b}",
|
||||
strPat, null == tilePat ? 0 : tilePat.length,
|
||||
anyOrderOk );
|
||||
}
|
||||
}
|
||||
|
||||
public static class IterWrapper {
|
||||
private long iterRef;
|
||||
|
||||
private IterWrapper(long ref) { this.iterRef = ref; }
|
||||
|
||||
private long getRef() { return this.iterRef; }
|
||||
|
||||
@Override
|
||||
public void finalize() throws java.lang.Throwable
|
||||
{
|
||||
di_destroy( iterRef );
|
||||
super.finalize();
|
||||
}
|
||||
}
|
||||
|
||||
public interface DictIterProcs {
|
||||
void onIterReady( IterWrapper iterRef );
|
||||
}
|
||||
|
||||
public static void di_init( DictWrapper dict, final PatDesc[] pats,
|
||||
final int minLen, final int maxLen,
|
||||
final DictIterProcs callback )
|
||||
{
|
||||
final long jniState = getJNI().m_ptrGlobals;
|
||||
final long dictPtr = dict.getDictPtr();
|
||||
new Thread( new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
long iterPtr = di_init( jniState, dictPtr, pats,
|
||||
minLen, maxLen );
|
||||
callback.onIterReady( new IterWrapper(iterPtr) );
|
||||
}
|
||||
} ).start();
|
||||
}
|
||||
|
||||
public static int di_wordCount( IterWrapper iter )
|
||||
{
|
||||
return di_wordCount( iter.getRef() );
|
||||
}
|
||||
|
||||
public static String di_nthWord( IterWrapper iter, int nn, String delim )
|
||||
{
|
||||
return di_nthWord( iter.getRef(), nn, delim );
|
||||
}
|
||||
|
||||
public static int[] di_getMinMax( IterWrapper iter ) {
|
||||
return di_getMinMax( iter.getRef() );
|
||||
}
|
||||
|
||||
public static String[] di_getPrefixes( IterWrapper iter )
|
||||
{
|
||||
return di_getPrefixes( iter.getRef() );
|
||||
}
|
||||
|
||||
public static int[] di_getIndices( IterWrapper iter )
|
||||
{
|
||||
return di_getIndices( iter.getRef() );
|
||||
}
|
||||
|
||||
private static native void di_destroy( long closure );
|
||||
private static native int di_wordCount( long closure );
|
||||
private static native String di_nthWord( long closure, int nn, String delim );
|
||||
private static native int[] di_getMinMax( long closure );
|
||||
private static native String[] di_getPrefixes( long closure );
|
||||
private static native int[] di_getIndices( long closure );
|
||||
|
||||
// Private methods -- called only here
|
||||
private static native long initGlobals( DUtilCtxt dutil, JNIUtils jniu );
|
||||
|
@ -575,14 +677,18 @@ public class XwJNI {
|
|||
byte[] stream );
|
||||
private static native long initGameJNI( long jniState, int seed );
|
||||
private static native void envDone( long globals );
|
||||
private static native long dict_make( long jniState, byte[] dict, String name, String path );
|
||||
private static native void dict_ref( long dictPtr );
|
||||
private static native void dict_unref( long dictPtr );
|
||||
private static native boolean dict_getInfo( long jniState, byte[] dict,
|
||||
String name, String path,
|
||||
boolean check,
|
||||
DictInfo info );
|
||||
private static native long di_init( long jniState, byte[] dict,
|
||||
String name, String path );
|
||||
private static native byte[][] dict_strToTiles( long dictPtr, String str );
|
||||
private static native String dict_tilesToStr( long dictPtr, byte[] tiles, String delim );
|
||||
private static native boolean dict_hasDuplicates( long dictPtr );
|
||||
private static native String dict_getTilesInfo( long jniState, long dictPtr );
|
||||
private static native boolean dict_getInfo( long jniState, long dictPtr,
|
||||
boolean check, DictInfo info );
|
||||
private static native String dict_getDesc( long dictPtr );
|
||||
private static native long di_init( long jniState, long dictPtr,
|
||||
PatDesc[] pats, int minLen, int maxLen );
|
||||
|
||||
private static native byte[][]
|
||||
smsproto_prepOutbound( long jniState, SMS_CMD cmd, int gameID, byte[] buf,
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="8dp"
|
||||
android:paddingRight="8dp"
|
||||
android:focusableInTouchMode="true"
|
||||
|
@ -13,73 +14,151 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_width="fill_parent"
|
||||
android:visibility="gone"
|
||||
android:layout_alignParentTop="true"
|
||||
/>
|
||||
|
||||
<LinearLayout android:id="@+id/search"
|
||||
android:orientation="horizontal"
|
||||
<!-- A summary followed by a hideable filter-config section -->
|
||||
<LinearLayout android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="0"
|
||||
android:layout_below="@id/desc"
|
||||
>
|
||||
<!-- Here's the summary -->
|
||||
<LinearLayout android:orientation="horizontal"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
>
|
||||
<TextView android:id="@+id/filter_summary"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_weight="1"
|
||||
/>
|
||||
<org.eehouse.android.xw4.ExpandImageButton
|
||||
android:id="@+id/expander"
|
||||
style="@style/expander_button"
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
||||
<org.eehouse.android.xw4.EditWClear
|
||||
android:id="@+id/word_edit"
|
||||
style="@style/edit_w_clear"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxLines="1"
|
||||
android:inputType="text"
|
||||
android:layout_weight="1"
|
||||
android:hint="@string/word_search_hint"
|
||||
android:capitalize="characters"
|
||||
/>
|
||||
|
||||
<Button android:id="@+id/search_button"
|
||||
android:layout_width="wrap_content"
|
||||
<!-- Config panel. A vertical array of fields with button at
|
||||
bottom. Can be hidden -->
|
||||
<TableLayout android:id="@+id/config"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:background="#FF1F1F1F"
|
||||
android:visibility="gone"
|
||||
android:paddingLeft="8dp"
|
||||
android:paddingRight="8dp"
|
||||
>
|
||||
<TableRow
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
>
|
||||
<View android:layout_width="5dp"
|
||||
android:layout_height="5dp"
|
||||
android:layout_span="2"
|
||||
/>
|
||||
<TextView android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/pat_col_anyorder"
|
||||
/>
|
||||
</TableRow>
|
||||
<org.eehouse.android.xw4.PatTableRow
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
>
|
||||
<TextView style="@style/pat_table_label"
|
||||
android:text="@string/pat_starts_with"
|
||||
/>
|
||||
<org.eehouse.android.xw4.EditWClear
|
||||
style="@style/pat_table_edit"
|
||||
/>
|
||||
<CheckBox style="@style/pat_table_check"
|
||||
/>
|
||||
</org.eehouse.android.xw4.PatTableRow>
|
||||
<org.eehouse.android.xw4.PatTableRow
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
>
|
||||
<TextView style="@style/pat_table_label"
|
||||
android:text="@string/pat_contains"
|
||||
/>
|
||||
<org.eehouse.android.xw4.EditWClear
|
||||
style="@style/pat_table_edit"
|
||||
/>
|
||||
<CheckBox style="@style/pat_table_check"
|
||||
/>
|
||||
</org.eehouse.android.xw4.PatTableRow>
|
||||
<org.eehouse.android.xw4.PatTableRow
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
>
|
||||
<TextView style="@style/pat_table_label"
|
||||
android:text="@string/pat_ends_with"
|
||||
/>
|
||||
<org.eehouse.android.xw4.EditWClear
|
||||
style="@style/pat_table_edit"
|
||||
/>
|
||||
<CheckBox style="@style/pat_table_check"
|
||||
/>
|
||||
</org.eehouse.android.xw4.PatTableRow>
|
||||
<TableRow android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
>
|
||||
<Button android:id="@+id/button_addBlank"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:text="@string/button_addBlank"
|
||||
android:layout_span="1"
|
||||
/>
|
||||
</TableRow>
|
||||
<LinearLayout android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
>
|
||||
<org.eehouse.android.xw4.LabeledSpinner
|
||||
android:id="@+id/spinner_min"
|
||||
android:orientation="horizontal"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/button_search"
|
||||
android:layout_weight="0"
|
||||
/>
|
||||
android:layout_width="wrap_content"
|
||||
>
|
||||
<TextView style="@style/config_spinner_label"
|
||||
android:text="@string/min_len"
|
||||
/>
|
||||
<Spinner android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:drawSelectorOnTop="true"
|
||||
android:label="@string/title_langs_list"
|
||||
/>
|
||||
</org.eehouse.android.xw4.LabeledSpinner>
|
||||
<org.eehouse.android.xw4.LabeledSpinner
|
||||
android:id="@+id/spinner_max"
|
||||
android:orientation="horizontal"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
>
|
||||
<TextView style="@style/config_spinner_label"
|
||||
android:text="@string/max_len"
|
||||
/>
|
||||
<Spinner android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:drawSelectorOnTop="true"
|
||||
android:label="@string/title_langs_list"
|
||||
/>
|
||||
</org.eehouse.android.xw4.LabeledSpinner>
|
||||
</LinearLayout>
|
||||
<Button android:id="@+id/button_useconfig"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:text="@string/button_useconfig"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_span="2"
|
||||
/>
|
||||
</TableLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout android:id="@+id/sizes"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="0"
|
||||
android:layout_alignParentBottom="true"
|
||||
>
|
||||
<TextView android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:text="@string/min_len"
|
||||
/>
|
||||
<Spinner android:id="@+id/wordlen_min"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:drawSelectorOnTop="true"
|
||||
android:prompt="@string/prompt_min_len"
|
||||
/>
|
||||
<TextView android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:text="@string/max_len"
|
||||
/>
|
||||
<Spinner android:id="@+id/wordlen_max"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:drawSelectorOnTop="true"
|
||||
android:prompt="@string/prompt_max_len"
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
||||
<!-- This goes in the middle but gets listed here because stuff it's
|
||||
relative to must be defined first. -->
|
||||
<FrameLayout android:id="@+id/list_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_below="@id/search"
|
||||
android:layout_above="@id/sizes"
|
||||
android:layout_weight="1"
|
||||
/>
|
||||
</RelativeLayout>
|
||||
</LinearLayout>
|
||||
|
|
|
@ -235,29 +235,30 @@
|
|||
android:text="@string/hints_allowed"
|
||||
/>
|
||||
|
||||
<LinearLayout style="@style/config_spinner_container"
|
||||
>
|
||||
<org.eehouse.android.xw4.LabeledSpinner
|
||||
android:id="@+id/smart_robot"
|
||||
style="@style/config_spinner_container"
|
||||
>
|
||||
<TextView style="@style/config_spinner_label"
|
||||
android:text="@string/robot_iq_label"
|
||||
/>
|
||||
<Spinner style="@style/config_spinner_spinner"
|
||||
android:id="@+id/smart_robot"
|
||||
android:prompt="@string/robot_spinner_prompt"
|
||||
android:entries="@array/robot_levels"
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout style="@style/config_spinner_container"
|
||||
>
|
||||
</org.eehouse.android.xw4.LabeledSpinner>
|
||||
<org.eehouse.android.xw4.LabeledSpinner
|
||||
style="@style/config_spinner_container"
|
||||
android:id="@+id/phonies_spinner"
|
||||
>
|
||||
<TextView style="@style/config_spinner_label"
|
||||
android:text="@string/phonies_label"
|
||||
/>
|
||||
<Spinner style="@style/config_spinner_spinner"
|
||||
android:id="@+id/phonies_spinner"
|
||||
android:prompt="@string/phonies_spinner_prompt"
|
||||
android:entries="@array/phony_names"
|
||||
/>
|
||||
</LinearLayout>
|
||||
</org.eehouse.android.xw4.LabeledSpinner>
|
||||
|
||||
<CheckBox android:id="@+id/pick_faceup"
|
||||
android:layout_width="fill_parent"
|
||||
|
@ -265,17 +266,18 @@
|
|||
android:text="@string/pick_faceup"
|
||||
/>
|
||||
|
||||
<LinearLayout style="@style/config_spinner_container"
|
||||
>
|
||||
<org.eehouse.android.xw4.LabeledSpinner
|
||||
style="@style/config_spinner_container"
|
||||
android:id="@+id/boardsize_spinner"
|
||||
>
|
||||
<TextView style="@style/config_spinner_label"
|
||||
android:text="@string/board_size"
|
||||
/>
|
||||
<Spinner style="@style/config_spinner_spinner"
|
||||
android:id="@+id/boardsize_spinner"
|
||||
android:prompt="@string/board_size"
|
||||
android:entries="@array/board_sizes"
|
||||
/>
|
||||
</LinearLayout>
|
||||
</org.eehouse.android.xw4.LabeledSpinner>
|
||||
|
||||
<LinearLayout android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- -*- compile-command: "cd ../../; ant install"; -*- -->
|
||||
|
||||
<!-- top-level layout is hozontal, with an image and another layout -->
|
||||
<org.eehouse.android.xw4.GameListItem
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
|
@ -99,9 +97,10 @@
|
|||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
/>
|
||||
|
||||
<ImageButton android:id="@+id/expander"
|
||||
style="@style/expander_button"
|
||||
/>
|
||||
<org.eehouse.android.xw4.ExpandImageButton
|
||||
android:id="@+id/expander"
|
||||
style="@style/expander_button"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
|
|
@ -63,10 +63,13 @@
|
|||
/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout android:orientation="horizontal"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="fill_parent"
|
||||
>
|
||||
<!-- And here -->
|
||||
<org.eehouse.android.xw4.LabeledSpinner
|
||||
android:id="@+id/player_dict_spinner"
|
||||
android:orientation="horizontal"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="fill_parent"
|
||||
>
|
||||
<TextView android:id="@+id/dict_label"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
|
@ -75,12 +78,11 @@
|
|||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
/>
|
||||
|
||||
<Spinner android:id="@+id/dict_spinner"
|
||||
android:layout_width="fill_parent"
|
||||
<Spinner android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:drawSelectorOnTop="true"
|
||||
/>
|
||||
</LinearLayout>
|
||||
</org.eehouse.android.xw4.LabeledSpinner>
|
||||
|
||||
<CheckBox android:id="@+id/robot_check"
|
||||
android:layout_width="wrap_content"
|
||||
|
|
|
@ -9,28 +9,26 @@
|
|||
android:paddingRight="8dp"
|
||||
>
|
||||
|
||||
<LinearLayout android:id="@+id/pick_lang"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
>
|
||||
<TextView android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:text="@string/study_langpick"
|
||||
/>
|
||||
|
||||
<Spinner android:id="@+id/pick_lang_spinner"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:drawSelectorOnTop="true"
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
||||
<ListView android:id="@id/android:list"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_weight="1"
|
||||
android:drawSelectorOnTop="false"
|
||||
<org.eehouse.android.xw4.LabeledSpinner
|
||||
android:id="@+id/pick_lang"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
>
|
||||
<TextView android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:text="@string/study_langpick"
|
||||
/>
|
||||
<Spinner android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:drawSelectorOnTop="true"
|
||||
/>
|
||||
</org.eehouse.android.xw4.LabeledSpinner>
|
||||
|
||||
<ListView android:id="@id/android:list"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_weight="1"
|
||||
android:drawSelectorOnTop="false"
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
|
16
xwords4/android/app/src/main/res/layout/tiles_row.xml
Normal file
16
xwords4/android/app/src/main/res/layout/tiles_row.xml
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<TableRow xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
>
|
||||
<TextView android:id="@+id/face"
|
||||
style="@style/tiles_table_row"
|
||||
/>
|
||||
<TextView android:id="@+id/count"
|
||||
style="@style/tiles_table_row"
|
||||
/>
|
||||
<TextView android:id="@+id/value"
|
||||
style="@style/tiles_table_row"
|
||||
/>
|
||||
</TableRow>
|
35
xwords4/android/app/src/main/res/layout/tiles_table.xml
Normal file
35
xwords4/android/app/src/main/res/layout/tiles_table.xml
Normal file
|
@ -0,0 +1,35 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="8dp"
|
||||
android:paddingRight="8dp"
|
||||
>
|
||||
<TableRow android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="8dp"
|
||||
>
|
||||
<TextView android:text="@string/tiles_header_face"
|
||||
style="@style/tiles_table_row"
|
||||
/>
|
||||
<TextView android:text="@string/tiles_header_count"
|
||||
style="@style/tiles_table_row"
|
||||
/>
|
||||
<TextView android:text="@string/tiles_header_value"
|
||||
style="@style/tiles_table_row"
|
||||
/>
|
||||
</TableRow>
|
||||
<ScrollView android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:orientation="vertical"
|
||||
>
|
||||
<LinearLayout android:id="@+id/table"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
/>
|
||||
</ScrollView>
|
||||
</TableLayout>
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<item android:id="@+id/dicts_showtiles"
|
||||
android:title="@string/show_tiles_menu"
|
||||
/>
|
||||
</menu>
|
|
@ -155,6 +155,7 @@
|
|||
<string name="key_na_sms_banned">key_na_sms_banned</string>
|
||||
<string name="key_na_longtap_lookup">key_na_longtap_lookup</string>
|
||||
<string name="key_na_perms_phonestate">key_na_perms_phonestate</string>
|
||||
<string name="key_na_addBlankButton">key_na_addBlankButton</string>
|
||||
|
||||
<string name="key_na_dupstatus_host">key_na_dupstatus_host</string>
|
||||
<string name="key_na_dupstatus_guest">key_na_dupstatus_guest</string>
|
||||
|
|
|
@ -1539,10 +1539,52 @@
|
|||
<!-- -->
|
||||
<string name="button_move">Move</string>
|
||||
<string name="button_newgroup">New group</string>
|
||||
<!-- -->
|
||||
<string name="button_search">Find</string>
|
||||
<!-- -->
|
||||
<string name="word_search_hint">First letters</string>
|
||||
|
||||
<!-- For user to confirm/apply wordlist filter -->
|
||||
<string name="button_useconfig">Apply Filter</string>
|
||||
<!-- Button in wordlist filter: keep it short!!!! -->
|
||||
<string name="button_addBlank">+Blank</string>
|
||||
<!-- String showing user what filter is in use. Substitutions are
|
||||
1) the filter pattern, 2) minimum and 3) maximum lengths, and
|
||||
4) number of words in the filtered list. -->
|
||||
<string name="filter_sum_pat_fmt">Showing: %1$s, lengths %2$d-%3$d
|
||||
(%4$d words)</string>
|
||||
<!-- Shown when user "misspells" a pattern using a combination not
|
||||
legal in the language, e.g. Q alone in Spanish or Catalan -->
|
||||
<string name="show_tiles_button">Show Tiles</string>
|
||||
<!-- Menuitem in dict browser -->
|
||||
<string name="show_tiles_menu">\u200CShow Tiles</string>
|
||||
<!-- title of dialog showing the list of tiles. Passed language
|
||||
name, e.g. Tiles for English -->
|
||||
<string name="show_tiles_title_fmt">Tiles for %1$s</string>
|
||||
|
||||
<!-- Shown when user uses the +Blank button in wordlist browser
|
||||
but nothing can be done because there's not focussed text
|
||||
field -->
|
||||
<string name="blank_button_expl">This button inserts a blank at
|
||||
the active text field\'s cursor, but there is no cursor
|
||||
now.</string>
|
||||
|
||||
<!-- Label for first field in wordlist browser filter -->
|
||||
<string name="pat_starts_with">Starts with</string>
|
||||
<!-- Label for middle field in wordlist browser filter -->
|
||||
<string name="pat_contains">Contains</string>
|
||||
<!-- Label for last field in wordlist browser filter -->
|
||||
<string name="pat_ends_with">Ends with</string>
|
||||
<!-- Column head for checkboxes that cause the tiles to be
|
||||
accepted in any order. E.g. "ends with: ING" will also accept
|
||||
words ending in GIN if the box under this head is
|
||||
checked-->
|
||||
<string name="pat_col_anyorder">Any Order</string>
|
||||
|
||||
<!-- Headers for columns in tiles table: 1: letter on tile -->
|
||||
<string name="tiles_header_face">Letter</string>
|
||||
<!-- Headers for columns in tiles table: 2: Number of tiles with
|
||||
that letter -->
|
||||
<string name="tiles_header_count">Number</string>
|
||||
<!-- Headers for columns in tiles table: 3: Value of each tile -->
|
||||
<string name="tiles_header_value">Value</string>
|
||||
|
||||
<!-- -->
|
||||
<string name="tilepick_all_fmt">Pick %1$d for me</string>
|
||||
<!-- -->
|
||||
|
@ -1550,14 +1592,7 @@
|
|||
<!-- This is for debug builds only! A setting for testing networking -->
|
||||
<string name="disableds_title">Disabled address types</string>
|
||||
<!-- -->
|
||||
<string name="dict_browse_title_fmt">%1$s (%2$d words using %3$d-%4$d
|
||||
tiles)</string>
|
||||
<!-- -->
|
||||
<string name="dict_browse_title1_fmt">%1$s (%2$d words using %3$d
|
||||
tiles)</string>
|
||||
<!-- -->
|
||||
<string name="dict_browse_nowords_fmt">No word in %1$s starts with
|
||||
%2$s.</string>
|
||||
<string name="dict_browse_title_fmt">%1$s (%2$d words total)</string>
|
||||
<!-- -->
|
||||
<string name="not_again_browse">This button opens the wordlist
|
||||
browser on the current player\'s wordlist.</string>
|
||||
|
@ -1576,6 +1611,17 @@
|
|||
<!-- -->
|
||||
<string name="prompt_max_len">Words no longer than</string>
|
||||
<!-- -->
|
||||
|
||||
<!-- Shown when user tries to make a wordlist filter where max < min -->
|
||||
<string name="error_min_gt_max">The minimum length value cannot be
|
||||
greater than the maximum value.</string>
|
||||
|
||||
<!-- Title of progress alert shown while wordlist is loading. For
|
||||
huge lists like Polish this can take a few seconds. -->
|
||||
<string name="filter_title_fmt">Loading %1$s…</string>
|
||||
<!-- Message in progress alert shown while wordlist is loading -->
|
||||
<string name="filter_progress_fmt">Processing %1$d words</string>
|
||||
|
||||
<string name="board_menu_file_email">Email author</string>
|
||||
<!-- -->
|
||||
<string name="email_author_subject">Comment about CrossWords</string>
|
||||
|
@ -2553,8 +2599,17 @@
|
|||
<string name="logstore_clear_confirm">Are you sure you want to
|
||||
erase your debug logs? This action cannot be undone.</string>
|
||||
|
||||
<!-- Shown when there's more than one sequence of tiles with which
|
||||
to "spell" the string a user has entered in the wordlist
|
||||
browser. Displayed below are the possible
|
||||
spellings. Currently this can only happen with Hungarian
|
||||
wordlists. -->
|
||||
<string name="pick_tiles_title">Pick a tile \"spelling\"</string>
|
||||
<string name="no_tiles_exist">\"%1$s\" cannot be spelled with tiles in %2$s.</string>
|
||||
<!-- Shown when user types a string that contains non-tiles,
|
||||
e.g. a Q alone when the langauge has only QU. First
|
||||
substituted is user's string; second substitution is name of
|
||||
language -->
|
||||
<string name="no_tiles_exist">\"%1$s\" cannot be spelled with %2$s tiles.</string>
|
||||
|
||||
<!-- MQTT stuff. May not see the light of day -->
|
||||
<string name="invite_choice_mqtt">Internet/MQTT</string>
|
||||
|
|
|
@ -112,6 +112,34 @@
|
|||
<item name="android:searchHintIcon">@null</item>
|
||||
</style>
|
||||
|
||||
<!-- Columns for the dict browser pattern editor -->
|
||||
<style name="pat_table_label">
|
||||
<item name="android:layout_width">wrap_content</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
<item name="android:layout_gravity">center_vertical</item>
|
||||
</style>
|
||||
|
||||
<style name="pat_table_edit" parent="edit_w_clear">
|
||||
<item name="android:layout_width">200dp</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
<item name="android:maxLines">1</item>
|
||||
<item name="android:inputType">text</item>
|
||||
</style>
|
||||
|
||||
<style name="pat_table_check">
|
||||
<item name="android:layout_width">wrap_content</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
<item name="android:layout_gravity">center</item>
|
||||
</style>
|
||||
|
||||
<style name="tiles_table_row">
|
||||
<item name="android:layout_width">match_parent</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
<item name="android:layout_weight">1</item>
|
||||
<item name="android:textSize">14dp</item>
|
||||
<item name="android:gravity">center_horizontal</item>
|
||||
</style>
|
||||
|
||||
<style name="config_spinner_container">
|
||||
<item name="android:layout_width">fill_parent</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "comtypes.h"
|
||||
#include "xwstream.h"
|
||||
#include "strutils.h"
|
||||
#include "dbgutil.h"
|
||||
|
||||
void
|
||||
and_assert( const char* test, int line, const char* file, const char* func )
|
||||
|
@ -268,10 +269,10 @@ getObject( JNIEnv* env, jobject obj, const char* name, const char* sig,
|
|||
jfieldID fid = (*env)->GetFieldID( env, cls, name, sig );
|
||||
XP_ASSERT( !!fid );
|
||||
*ret = (*env)->GetObjectField( env, obj, fid );
|
||||
XP_ASSERT( !!*ret );
|
||||
bool result = !!*ret;
|
||||
|
||||
deleteLocalRef( env, cls );
|
||||
return true;
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* -*- compile-command: "find-and-gradle.sh insXw4Deb"; -*- */
|
||||
/* -*- compile-command: "find-and-gradle.sh inXw4dDeb"; -*- */
|
||||
/*
|
||||
* Copyright 2001 - 2017 by Eric House (xwords@eehouse.org). All rights
|
||||
* Copyright 2001 - 2020 by Eric House (xwords@eehouse.org). All rights
|
||||
* reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
|
@ -398,7 +398,7 @@ and_util_makeEmptyDict( XW_UtilCtxt* uc, XWEnv xwe )
|
|||
DictionaryCtxt* result =
|
||||
and_dictionary_make_empty( MPPARM( ((AndUtil*)uc)->util.mpool )
|
||||
globals->jniutil );
|
||||
return dict_ref( result, xwe );
|
||||
return (DictionaryCtxt*)dict_ref( result, xwe );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -879,6 +879,23 @@ Java_org_eehouse_android_xw4_jni_XwJNI_comms_1getUUID
|
|||
return jstr;
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_org_eehouse_android_xw4_jni_XwJNI_dict_1make
|
||||
( JNIEnv* env, jclass C, jlong jniGlobalPtr, jbyteArray jDictBytes,
|
||||
jstring jname, jstring jpath )
|
||||
{
|
||||
JNIGlobalState* globalState = (JNIGlobalState*)jniGlobalPtr;
|
||||
#ifdef MEM_DEBUG
|
||||
MemPoolCtx* mpool = GETMPOOL( globalState );
|
||||
#endif
|
||||
|
||||
/* makeDict calls dict_ref() */
|
||||
DictionaryCtxt* dictPtr = makeDict( MPPARM(mpool) env, TI_IF(&globalState->ti)
|
||||
globalState->dictMgr,globalState->jniutil,
|
||||
jname, jDictBytes, jpath, NULL, false );
|
||||
return (jlong)dictPtr;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_eehouse_android_xw4_jni_XwJNI_dict_1ref
|
||||
( JNIEnv* env, jclass C, jlong dictPtr )
|
||||
|
@ -899,36 +916,141 @@ Java_org_eehouse_android_xw4_jni_XwJNI_dict_1unref
|
|||
}
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_org_eehouse_android_xw4_jni_XwJNI_dict_1getInfo
|
||||
( JNIEnv* env, jclass C, jlong jniGlobalPtr, jbyteArray jDictBytes,
|
||||
jstring jname, jstring jpath, jboolean check, jobject jinfo )
|
||||
{
|
||||
jboolean result = false;
|
||||
JNIGlobalState* globalState = (JNIGlobalState*)jniGlobalPtr;
|
||||
MAP_THREAD( &globalState->ti, env );
|
||||
typedef struct _FTData {
|
||||
JNIEnv* env;
|
||||
jbyteArray arrays[16];
|
||||
int nArrays;
|
||||
} FTData;
|
||||
|
||||
static XP_Bool
|
||||
onFoundTiles( void* closure, const Tile* tiles, int nTiles )
|
||||
{
|
||||
FTData* ftd = (FTData*)closure;
|
||||
ftd->arrays[ftd->nArrays++] = makeByteArray( ftd->env, nTiles,
|
||||
(const jbyte*)tiles );
|
||||
return ftd->nArrays < VSIZE(ftd->arrays); /* still have room? */
|
||||
}
|
||||
|
||||
JNIEXPORT jobjectArray JNICALL
|
||||
Java_org_eehouse_android_xw4_jni_XwJNI_dict_1strToTiles
|
||||
( JNIEnv* env, jclass C, jlong dictPtr, jstring jstr )
|
||||
{
|
||||
jobjectArray result = NULL;
|
||||
DictionaryCtxt* dict = (DictionaryCtxt*)dictPtr;
|
||||
const char* str = (*env)->GetStringUTFChars( env, jstr, NULL );
|
||||
|
||||
FTData ftd = { .env = env, };
|
||||
dict_tilesForString( dict, str, 0, onFoundTiles, &ftd );
|
||||
|
||||
if ( ftd.nArrays > 0 ) {
|
||||
result = makeByteArrayArray( env, ftd.nArrays );
|
||||
for ( int ii = 0; ii < ftd.nArrays; ++ii ) {
|
||||
(*env)->SetObjectArrayElement( env, result, ii, ftd.arrays[ii] );
|
||||
deleteLocalRef( env, ftd.arrays[ii] );
|
||||
}
|
||||
}
|
||||
|
||||
(*env)->ReleaseStringUTFChars( env, jstr, str );
|
||||
return result;
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_org_eehouse_android_xw4_jni_XwJNI_dict_1hasDuplicates
|
||||
( JNIEnv* env, jclass C, jlong dictPtr )
|
||||
{
|
||||
jboolean result;
|
||||
DictionaryCtxt* dict = (DictionaryCtxt*)dictPtr;
|
||||
result = dict_hasDuplicates( dict );
|
||||
return result;
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_org_eehouse_android_xw4_jni_XwJNI_dict_1getTilesInfo
|
||||
( JNIEnv* env, jclass C, jlong jniGlobalPtr, jlong dictPtr )
|
||||
{
|
||||
jstring result = NULL;
|
||||
JNIGlobalState* globalState = (JNIGlobalState*)jniGlobalPtr;
|
||||
#ifdef MEM_DEBUG
|
||||
MemPoolCtx* mpool = GETMPOOL( globalState );
|
||||
#endif
|
||||
DictionaryCtxt* dict = (DictionaryCtxt*)dictPtr;
|
||||
XWStreamCtxt* stream = mem_stream_make( MPPARM(mpool) globalState->vtMgr,
|
||||
NULL, 0, NULL );
|
||||
dict_writeTilesInfo( dict, stream );
|
||||
result = streamToJString( env, stream );
|
||||
stream_destroy( stream, env );
|
||||
|
||||
DictionaryCtxt* dict = makeDict( MPPARM(mpool) env, TI_IF(&globalState->ti)
|
||||
globalState->dictMgr,
|
||||
globalState->jniutil, jname, jDictBytes, jpath,
|
||||
NULL, check );
|
||||
return result;
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_org_eehouse_android_xw4_jni_XwJNI_dict_1tilesToStr
|
||||
( JNIEnv* env, jclass C, jlong dictPtr, jbyteArray jtiles, jstring jdelim )
|
||||
{
|
||||
jstring result = NULL;
|
||||
DictionaryCtxt* dict = (DictionaryCtxt*)dictPtr;
|
||||
if ( !!jtiles && !!dict ) {
|
||||
XP_UCHAR buf[64];
|
||||
const XP_UCHAR* delim = NULL;
|
||||
if ( !!jdelim ) {
|
||||
delim = (*env)->GetStringUTFChars( env, jdelim, NULL );
|
||||
}
|
||||
|
||||
XP_U16 nTiles = (*env)->GetArrayLength( env, jtiles );
|
||||
jbyte* tiles = (*env)->GetByteArrayElements( env, jtiles, NULL );
|
||||
|
||||
XP_U16 strLen = dict_tilesToString( dict, (Tile*)tiles, nTiles,
|
||||
buf, VSIZE(buf), delim );
|
||||
if ( 0 < strLen ) {
|
||||
buf[strLen] = '\0';
|
||||
result = (*env)->NewStringUTF( env, buf );
|
||||
}
|
||||
|
||||
if ( !!jdelim ) {
|
||||
(*env)->ReleaseStringUTFChars( env, jdelim, delim );
|
||||
}
|
||||
(*env)->ReleaseByteArrayElements( env, jtiles, tiles, 0 );
|
||||
} else {
|
||||
XP_LOGFF( "null jtiles array" );
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_org_eehouse_android_xw4_jni_XwJNI_dict_1getInfo
|
||||
( JNIEnv* env, jclass C, jlong jniGlobalPtr, jlong dictPtr,
|
||||
jboolean check, jobject jinfo )
|
||||
{
|
||||
jboolean result = false;
|
||||
#ifdef MAP_THREAD_TO_ENV
|
||||
JNIGlobalState* globalState = (JNIGlobalState*)jniGlobalPtr;
|
||||
MAP_THREAD( &globalState->ti, env );
|
||||
#endif
|
||||
DictionaryCtxt* dict = (DictionaryCtxt*)dictPtr;
|
||||
if ( NULL != dict ) {
|
||||
if ( NULL != jinfo ) {
|
||||
XP_LangCode code = dict_getLangCode( dict );
|
||||
XP_ASSERT( 0 < code );
|
||||
setInt( env, jinfo, "langCode", code );
|
||||
setInt( env, jinfo, "wordCount", dict_getWordCount( dict ) );
|
||||
setInt( env, jinfo, "wordCount", dict_getWordCount( dict, env ) );
|
||||
setString( env, jinfo, "md5Sum", dict_getMd5Sum( dict ) );
|
||||
}
|
||||
dict_unref( dict, env );
|
||||
result = true;
|
||||
}
|
||||
|
||||
releaseMPool( globalState );
|
||||
return result;
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_org_eehouse_android_xw4_jni_XwJNI_dict_1getDesc
|
||||
( JNIEnv* env, jclass C, jlong dictPtr )
|
||||
{
|
||||
jstring result = NULL;
|
||||
DictionaryCtxt* dict = (DictionaryCtxt*)dictPtr;
|
||||
const XP_UCHAR* disc = dict_getDesc( dict );
|
||||
if ( NULL != disc && '\0' != disc[0] ) {
|
||||
result = (*env)->NewStringUTF( env, disc );
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -2509,11 +2631,12 @@ Java_org_eehouse_android_xw4_jni_XwJNI_board_1sendChat
|
|||
|
||||
typedef struct _DictIterData {
|
||||
JNIGlobalState* globalState;
|
||||
DictionaryCtxt* dict;
|
||||
DictIter iter;
|
||||
const DictionaryCtxt* dict;
|
||||
DictIter* iter;
|
||||
IndexData idata;
|
||||
XP_U16 depth;
|
||||
#ifdef DEBUG
|
||||
pthread_t lastUser;
|
||||
XP_U32 guard;
|
||||
#endif
|
||||
} DictIterData;
|
||||
|
@ -2524,65 +2647,103 @@ static void freeIndices( DictIterData* data );
|
|||
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_org_eehouse_android_xw4_jni_XwJNI_di_1init
|
||||
( JNIEnv* env, jclass C, jlong jniGlobalPtr, jbyteArray jDictBytes,
|
||||
jstring jname, jstring jpath )
|
||||
( JNIEnv* env, jclass C, jlong jniGlobalPtr, jlong dictPtr,
|
||||
jobjectArray jPatsArr, jint minLen, jint maxLen )
|
||||
{
|
||||
jlong closure = 0;
|
||||
JNIGlobalState* globalState = (JNIGlobalState*)jniGlobalPtr;
|
||||
MAP_THREAD( &globalState->ti, env );
|
||||
|
||||
DictionaryCtxt* dict = makeDict( MPPARM(globalState->mpool) env,
|
||||
TI_IF(&globalState->ti)
|
||||
globalState->dictMgr, globalState->jniutil,
|
||||
jname, jDictBytes, jpath, NULL, false );
|
||||
DictionaryCtxt* dict = (DictionaryCtxt*)dictPtr;
|
||||
if ( !!dict ) {
|
||||
DictIterData* data = XP_CALLOC( globalState->mpool, sizeof(*data) );
|
||||
data->globalState = globalState;
|
||||
data->dict = dict;
|
||||
data->dict = dict_ref( dict, env );
|
||||
data->depth = 2;
|
||||
#ifdef DEBUG
|
||||
data->guard = GI_GUARD;
|
||||
#endif
|
||||
|
||||
jobject jdescs[3];
|
||||
PatDesc patDescs[3] = {{0}};
|
||||
jbyteArray jtiles[3];
|
||||
|
||||
int len = 0;
|
||||
if ( !!jPatsArr ) {
|
||||
len = (*env)->GetArrayLength( env, jPatsArr );
|
||||
XP_ASSERT( len == 3 );
|
||||
for ( int ii = 0; ii < len ; ++ii ) {
|
||||
jdescs[ii] = (*env)->GetObjectArrayElement( env, jPatsArr, ii );
|
||||
if ( !!jdescs[ii] ) {
|
||||
if ( getObject( env, jdescs[ii], "tilePat", "[B", &jtiles[ii] ) ) {
|
||||
patDescs[ii].nTiles = (*env)->GetArrayLength( env, jtiles[ii] );
|
||||
patDescs[ii].tiles = (Tile*)
|
||||
(*env)->GetByteArrayElements( env, jtiles[ii], NULL );
|
||||
patDescs[ii].anyOrderOk = getBool( env, jdescs[ii], "anyOrderOk" );
|
||||
}
|
||||
} else {
|
||||
jtiles[ii] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DIMinMax mm = { .min = minLen, .max = maxLen };
|
||||
data->iter = di_makeIter( data->dict, env, &mm, NULL, 0,
|
||||
!!jPatsArr ? patDescs : NULL, VSIZE(patDescs) );
|
||||
|
||||
for ( int ii = 0; ii < len ; ++ii ) {
|
||||
if ( !!jtiles[ii] ) {
|
||||
(*env)->ReleaseByteArrayElements( env, jtiles[ii],
|
||||
(jbyte*)patDescs[ii].tiles, 0 );
|
||||
deleteLocalRef( env, jtiles[ii] );
|
||||
}
|
||||
}
|
||||
|
||||
makeIndex( data );
|
||||
(void)di_firstWord( data->iter );
|
||||
|
||||
closure = (jlong)data;
|
||||
}
|
||||
return closure;
|
||||
}
|
||||
|
||||
|
||||
#define DI_HEADER() { \
|
||||
#ifdef DEBUG
|
||||
# define DI_HEADER(THREAD_CHECK) { \
|
||||
DictIterData* data = (DictIterData*)closure; \
|
||||
XP_ASSERT( NULL == data || data->guard == GI_GUARD ); \
|
||||
if ( THREAD_CHECK && !!data ) { \
|
||||
if ( 0 == data->lastUser ) { \
|
||||
data->lastUser = pthread_self(); \
|
||||
} else { \
|
||||
XP_ASSERT( data->lastUser == pthread_self() ); \
|
||||
} \
|
||||
} \
|
||||
|
||||
#else
|
||||
# define DI_HEADER(THREAD_CHECK) { \
|
||||
DictIterData* data = (DictIterData*)closure; \
|
||||
|
||||
#endif
|
||||
|
||||
#define DI_HEADER_END() \
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_eehouse_android_xw4_jni_XwJNI_di_1setMinMax
|
||||
( JNIEnv* env, jclass C, jlong closure, jint min, jint max )
|
||||
{
|
||||
DI_HEADER();
|
||||
if ( NULL != data ) {
|
||||
di_initIter( &data->iter, data->dict, min, max );
|
||||
makeIndex( data );
|
||||
(void)di_firstWord( &data->iter );
|
||||
}
|
||||
DI_HEADER_END();
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_eehouse_android_xw4_jni_XwJNI_di_1destroy
|
||||
( JNIEnv* env, jclass C, jlong closure )
|
||||
{
|
||||
DI_HEADER();
|
||||
DI_HEADER(XP_FALSE);
|
||||
if ( NULL != data ) {
|
||||
#ifdef MEM_DEBUG
|
||||
MemPoolCtx* mpool = data->globalState->mpool;
|
||||
#endif
|
||||
dict_unref( data->dict, env );
|
||||
|
||||
freeIndices( data );
|
||||
|
||||
MAP_REMOVE( &data->globalState->ti, env );
|
||||
|
||||
di_freeIter( data->iter, env);
|
||||
dict_unref( data->dict, env );
|
||||
XP_FREE( mpool, data );
|
||||
}
|
||||
DI_HEADER_END();
|
||||
|
@ -2593,31 +2754,25 @@ Java_org_eehouse_android_xw4_jni_XwJNI_di_1wordCount
|
|||
(JNIEnv* env, jclass C, jlong closure )
|
||||
{
|
||||
jint result = 0;
|
||||
DI_HEADER();
|
||||
DI_HEADER(XP_TRUE);
|
||||
if ( NULL != data ) {
|
||||
result = data->iter.nWords;
|
||||
result = di_getNWords( data->iter );
|
||||
}
|
||||
DI_HEADER_END();
|
||||
return result;
|
||||
}
|
||||
|
||||
JNIEXPORT jintArray JNICALL
|
||||
Java_org_eehouse_android_xw4_jni_XwJNI_di_1getCounts
|
||||
(JNIEnv* env, jclass C, jlong closure )
|
||||
Java_org_eehouse_android_xw4_jni_XwJNI_di_1getMinMax
|
||||
( JNIEnv* env, jclass C, jlong closure )
|
||||
{
|
||||
jintArray result = NULL;
|
||||
DI_HEADER();
|
||||
if ( NULL != data ) {
|
||||
DictIter iter;
|
||||
di_initIter( &iter, data->dict, 0, MAX_COLS_DICT );
|
||||
DI_HEADER(XP_TRUE);
|
||||
XP_U16 vals[2];
|
||||
di_getMinMax( data->iter, &vals[0], &vals[1] );
|
||||
|
||||
result = makeIntArray( env, VSIZE(vals), vals, sizeof(vals[0]) );
|
||||
|
||||
LengthsArray lens;
|
||||
if ( 0 < di_countWords( &iter, &lens ) ) {
|
||||
XP_ASSERT( sizeof(jint) == sizeof(lens.lens[0]) );
|
||||
result = makeIntArray( env, VSIZE(lens.lens), (jint*)&lens.lens,
|
||||
sizeof(lens.lens[0]) );
|
||||
}
|
||||
}
|
||||
DI_HEADER_END();
|
||||
return result;
|
||||
}
|
||||
|
@ -2627,7 +2782,7 @@ Java_org_eehouse_android_xw4_jni_XwJNI_di_1getPrefixes
|
|||
( JNIEnv* env, jclass C, jlong closure )
|
||||
{
|
||||
jobjectArray result = NULL;
|
||||
DI_HEADER();
|
||||
DI_HEADER(XP_TRUE);
|
||||
if ( NULL != data && NULL != data->idata.prefixes ) {
|
||||
result = makeStringArray( env, data->idata.count, NULL );
|
||||
|
||||
|
@ -2651,13 +2806,14 @@ Java_org_eehouse_android_xw4_jni_XwJNI_di_1getIndices
|
|||
( JNIEnv* env, jclass C, jlong closure )
|
||||
{
|
||||
jintArray jindices = NULL;
|
||||
DI_HEADER();
|
||||
DI_HEADER(XP_TRUE);
|
||||
if ( NULL != data ) {
|
||||
XP_ASSERT( !!data->idata.indices );
|
||||
XP_ASSERT( sizeof(jint) == sizeof(data->idata.indices[0]) );
|
||||
jindices = makeIntArray( env, data->idata.count,
|
||||
(jint*)data->idata.indices,
|
||||
sizeof(data->idata.indices[0]) );
|
||||
if ( !!data->idata.indices ) { /* filters-block-all case */
|
||||
XP_ASSERT( sizeof(jint) == sizeof(data->idata.indices[0]) );
|
||||
jindices = makeIntArray( env, data->idata.count,
|
||||
(jint*)data->idata.indices,
|
||||
sizeof(data->idata.indices[0]) );
|
||||
}
|
||||
}
|
||||
DI_HEADER_END();
|
||||
return jindices;
|
||||
|
@ -2668,13 +2824,13 @@ Java_org_eehouse_android_xw4_jni_XwJNI_di_1nthWord
|
|||
( JNIEnv* env, jclass C, jlong closure, jint nn, jstring jdelim )
|
||||
{
|
||||
jstring result = NULL;
|
||||
DI_HEADER();
|
||||
DI_HEADER(XP_TRUE);
|
||||
if ( NULL != data ) {
|
||||
if ( di_getNthWord( &data->iter, nn, data->depth, &data->idata ) ) {
|
||||
if ( di_getNthWord( data->iter, env, nn, data->depth, &data->idata ) ) {
|
||||
XP_UCHAR buf[64];
|
||||
const XP_UCHAR* delim = NULL == jdelim ? NULL
|
||||
: (*env)->GetStringUTFChars( env, jdelim, NULL );
|
||||
di_wordToString( &data->iter, buf, VSIZE(buf), delim );
|
||||
di_wordToString( data->iter, buf, VSIZE(buf), delim );
|
||||
result = (*env)->NewStringUTF( env, buf );
|
||||
if ( !!delim ) {
|
||||
(*env)->ReleaseStringUTFChars( env, jdelim, delim );
|
||||
|
@ -2685,137 +2841,19 @@ Java_org_eehouse_android_xw4_jni_XwJNI_di_1nthWord
|
|||
return result;
|
||||
}
|
||||
|
||||
typedef struct _FTData {
|
||||
JNIEnv* env;
|
||||
jbyteArray arrays[16];
|
||||
int nArrays;
|
||||
} FTData;
|
||||
|
||||
static XP_Bool
|
||||
onFoundTiles( void* closure, const Tile* tiles, int nTiles )
|
||||
{
|
||||
FTData* ftd = (FTData*)closure;
|
||||
ftd->arrays[ftd->nArrays++] = makeByteArray( ftd->env, nTiles,
|
||||
(const jbyte*)tiles );
|
||||
return ftd->nArrays < VSIZE(ftd->arrays); /* still have room? */
|
||||
}
|
||||
|
||||
JNIEXPORT jobjectArray JNICALL
|
||||
Java_org_eehouse_android_xw4_jni_XwJNI_di_1strToTiles
|
||||
( JNIEnv* env, jclass C, jlong closure, jstring jstr )
|
||||
{
|
||||
jobjectArray result = NULL;
|
||||
DI_HEADER();
|
||||
const char* str = (*env)->GetStringUTFChars( env, jstr, NULL );
|
||||
|
||||
FTData ftd = { .env = env, };
|
||||
dict_tilesForString( data->dict, str, onFoundTiles, &ftd );
|
||||
|
||||
if ( ftd.nArrays > 0 ) {
|
||||
result = makeByteArrayArray( env, ftd.nArrays );
|
||||
for ( int ii = 0; ii < ftd.nArrays; ++ii ) {
|
||||
(*env)->SetObjectArrayElement( env, result, ii, ftd.arrays[ii] );
|
||||
deleteLocalRef( env, ftd.arrays[ii] );
|
||||
}
|
||||
}
|
||||
|
||||
(*env)->ReleaseStringUTFChars( env, jstr, str );
|
||||
DI_HEADER_END();
|
||||
return result;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_org_eehouse_android_xw4_jni_XwJNI_di_1getStartsWith
|
||||
( JNIEnv* env, jclass C, jlong closure, jobjectArray jtilesArr )
|
||||
{
|
||||
jint result = -1;
|
||||
DI_HEADER();
|
||||
|
||||
int len = (*env)->GetArrayLength( env, jtilesArr );
|
||||
for ( int ii = 0; ii < len && -1 == result ; ++ii ) {
|
||||
jbyteArray jtiles = (*env)->GetObjectArrayElement( env, jtilesArr, ii );
|
||||
XP_U16 nTiles = (*env)->GetArrayLength( env, jtiles );
|
||||
jbyte* tiles = (*env)->GetByteArrayElements( env, jtiles, NULL );
|
||||
|
||||
if ( 0 <= di_findStartsWith( &data->iter, (Tile*)tiles, nTiles ) ) {
|
||||
result = di_getPosition( &data->iter );
|
||||
}
|
||||
(*env)->ReleaseByteArrayElements( env, jtiles, tiles, 0 );
|
||||
deleteLocalRef( env, jtiles );
|
||||
}
|
||||
|
||||
DI_HEADER_END();
|
||||
return result;
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_org_eehouse_android_xw4_jni_XwJNI_di_1tilesToStr
|
||||
( JNIEnv* env, jclass C, jlong closure, jbyteArray jtiles, jstring jdelim )
|
||||
{
|
||||
jstring result = NULL;
|
||||
DI_HEADER();
|
||||
XP_UCHAR buf[64];
|
||||
const XP_UCHAR* delim = NULL;
|
||||
if ( !!jdelim ) {
|
||||
delim = (*env)->GetStringUTFChars( env, jdelim, NULL );
|
||||
}
|
||||
|
||||
XP_U16 nTiles = (*env)->GetArrayLength( env, jtiles );
|
||||
jbyte* tiles = (*env)->GetByteArrayElements( env, jtiles, NULL );
|
||||
|
||||
XP_U16 strLen = dict_tilesToString( data->dict, (Tile*)tiles, nTiles,
|
||||
buf, VSIZE(buf), delim );
|
||||
if ( 0 < strLen ) {
|
||||
buf[strLen] = '\0';
|
||||
result = (*env)->NewStringUTF( env, buf );
|
||||
}
|
||||
|
||||
if ( !!jdelim ) {
|
||||
(*env)->ReleaseStringUTFChars( env, jdelim, delim );
|
||||
}
|
||||
(*env)->ReleaseByteArrayElements( env, jtiles, tiles, 0 );
|
||||
DI_HEADER_END();
|
||||
return result;
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_org_eehouse_android_xw4_jni_XwJNI_di_1hasDuplicates
|
||||
( JNIEnv* env, jclass C, jlong closure )
|
||||
{
|
||||
jboolean result;
|
||||
DI_HEADER();
|
||||
result = dict_hasDuplicates( data->dict );
|
||||
DI_HEADER_END();
|
||||
return result;
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_org_eehouse_android_xw4_jni_XwJNI_di_1getDesc
|
||||
( JNIEnv* env, jclass C, jlong closure )
|
||||
{
|
||||
jstring result = NULL;
|
||||
DI_HEADER();
|
||||
if ( NULL != data ) {
|
||||
const XP_UCHAR* disc = dict_getDesc( data->dict );
|
||||
if ( NULL != disc && '\0' != disc[0] ) {
|
||||
result = (*env)->NewStringUTF( env, disc );
|
||||
}
|
||||
}
|
||||
DI_HEADER_END();
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
freeIndices( DictIterData* data )
|
||||
{
|
||||
IndexData* idata = &data->idata;
|
||||
if ( !!idata->prefixes ) {
|
||||
XP_FREE( data->globalState->mpool, idata->prefixes );
|
||||
idata->prefixes = NULL;
|
||||
}
|
||||
if( !!idata->indices ) {
|
||||
XP_FREE( data->globalState->mpool, idata->indices );
|
||||
idata->indices = NULL;
|
||||
if ( !!data ) {
|
||||
IndexData* idata = &data->idata;
|
||||
if ( !!idata->prefixes ) {
|
||||
XP_FREE( data->globalState->mpool, idata->prefixes );
|
||||
idata->prefixes = NULL;
|
||||
}
|
||||
if( !!idata->indices ) {
|
||||
XP_FREE( data->globalState->mpool, idata->indices );
|
||||
idata->indices = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2840,7 +2878,7 @@ makeIndex( DictIterData* data )
|
|||
idata->indices = XP_MALLOC( mpool, count * sizeof(*idata->indices) );
|
||||
idata->count = count;
|
||||
|
||||
di_makeIndex( &data->iter, data->depth, idata );
|
||||
di_makeIndex( data->iter, data->depth, idata );
|
||||
if ( 0 < idata->count ) {
|
||||
idata->prefixes = XP_REALLOC( mpool, idata->prefixes,
|
||||
idata->count * data->depth *
|
||||
|
|
|
@ -375,7 +375,7 @@ Introduïu el vostre nom aquí. S\'usarà en crear partides noves. (Podreu
|
|||
<string name="button_search">Cerca</string>
|
||||
<string name="word_search_hint">Primeres lletres</string>
|
||||
<string name="pick_faceup">Tria les fitxes cara amunt</string>
|
||||
<string name="dict_browse_title_fmt">%1$s (%2$d paraules usant %3$d-%4$d fitxes)</string>
|
||||
<string name="dict_browse_title_fmt">%1$s (%2$d paraules)</string>
|
||||
<string name="dict_browse_title1_fmt">%1$s (%2$d paraules usant %3$d fitxes)</string>
|
||||
<string name="dict_browse_nowords_fmt">No hi ha cap paraula a %1$s que comenci amb %2$s.</string>
|
||||
<string name="not_again_browse">Aquest botó obre l\'explorador de diccionaris en el diccionari actual del jugador.</string>
|
||||
|
|
|
@ -375,7 +375,7 @@
|
|||
<string name="tilepick_all_fmt">%1$d für mich auswählen</string>
|
||||
<string name="pick_faceup">Spielsteine aufgedeckt auswählen</string>
|
||||
<string name="disableds_title">Deaktivierte Adresstypen</string>
|
||||
<string name="dict_browse_title_fmt">%1$s (%2$d Wörter mit %3$d-%4$d Spielsteinen)</string>
|
||||
<string name="dict_browse_title_fmt">%1$s (%2$d Wörter)</string>
|
||||
<string name="dict_browse_title1_fmt">%1$s (%2$d Wörter mit %3$d Spielsteinen)</string>
|
||||
<string name="dict_browse_nowords_fmt">Kein Wort in %1$s beginnt mit %2$s.</string>
|
||||
<string name="not_again_browse">Dieser Button öffnet den Wortlisten-Browser mit der Wortliste des gegenwärtigen Spielers.</string>
|
||||
|
|
|
@ -1879,8 +1879,7 @@ ligne, les mots qui viennent d\'être joués.</string>
|
|||
tiles)</string>-->
|
||||
<!--<string name="dict_browse_title_fmt">%1$s (%2$d mots utilisant de %3$d à
|
||||
%4$d jetons)</string>-->
|
||||
<string name="dict_browse_title_fmt">%1$s (%2$d mots utilisant de
|
||||
%3$d à %4$d jetons)</string>
|
||||
<string name="dict_browse_title_fmt">%1$s (%2$d mots)</string>
|
||||
<!-- -->
|
||||
<!--<string name="dict_browse_title1_fmt">%1$s (%2$d words using %3$d
|
||||
tiles)</string>-->
|
||||
|
|
|
@ -352,7 +352,7 @@
|
|||
<string name="button_search">検索</string>
|
||||
<string name="word_search_hint">最初の文字</string>
|
||||
<string name="pick_faceup">タイル面を選択</string>
|
||||
<string name="dict_browse_title_fmt">%1$s (%2$d 単語 %3$d-%4$d タイル使用)</string>
|
||||
<string name="dict_browse_title_fmt">%1$s (%2$d 単語)</string>
|
||||
<string name="dict_browse_title1_fmt">%1$s (%2$d 単語 %3$d タイル使用)</string>
|
||||
<string name="dict_browse_nowords_fmt">%1$s に %2$s で開始する単語はありません。</string>
|
||||
<string name="not_again_browse">このボタンは、現在のプレイヤーの単語リストで、単語リスト ブラウザーを開きます。</string>
|
||||
|
|
|
@ -223,7 +223,7 @@
|
|||
<string name="word_search_hint">Første bokstaver</string>
|
||||
<string name="tilepick_all_fmt">Plukk %1$d for meg</string>
|
||||
<string name="disableds_title">Avskrudde adressetyper</string>
|
||||
<string name="dict_browse_title_fmt">%1$s (%2$d ord ved bruk av %3$d-%4$d flis)</string>
|
||||
<string name="dict_browse_title_fmt">%1$s (%2$d ord)</string>
|
||||
<string name="dict_browse_title1_fmt">%1$s (%2$d ord ved bruk av %3$d flis</string>
|
||||
<string name="dict_browse_nowords_fmt">Ingen ord i %1$s starter med %2$s.</string>
|
||||
<string name="not_again_browse">Denne knappen åpner ordlisteutforskeren i gjeldende spillers ordliste.</string>
|
||||
|
|
|
@ -354,8 +354,7 @@
|
|||
<string name="button_search">Vind</string>
|
||||
<string name="word_search_hint">Eerste letters</string>
|
||||
<string name="pick_faceup">Pak letters met de letter naar boven</string>
|
||||
<string name="dict_browse_title_fmt">%1$s (%2$d woorden met %3$d-%4$d letters)</string>
|
||||
<string name="dict_browse_title1_fmt">%1$s (%2$d woorden met %3$d letters)</string>
|
||||
<string name="dict_browse_title_fmt">%1$s (%2$d woorden)</string>
|
||||
<string name="dict_browse_nowords_fmt">Geen woord in %1$s begint met %2$s.</string>
|
||||
<string name="not_again_browse">Deze knop opent de woordenlijst browser voor de woordenlijst van de speler die aan de beurt is.</string>
|
||||
<string name="not_again_browseall">Deze knop opent de woordenlijst browser voor de woordenlijst van jouw keuze.</string>
|
||||
|
|
|
@ -460,7 +460,7 @@
|
|||
\n(Usunięcie grupy Archiwum jest bezpieczne, ponieważ zostanie ona utworzona na nowo, gdy będzie potrzebna.)</string>
|
||||
<string name="button_move">Rusz się.</string>
|
||||
<string name="tilepick_all_fmt">Wybierz %1$d dla mnie</string>
|
||||
<string name="dict_browse_title_fmt">"%1$s (%2$d słów przy użyciu %3$d-%4$d kafelków)"</string>
|
||||
<string name="dict_browse_title_fmt">"%1$s (%2$d słów)"</string>
|
||||
<string name="dict_browse_title1_fmt">%1$s (%2$d wyrazy przy użyciu %3$d kafelków)</string>
|
||||
<string name="dict_browse_nowords_fmt">Żadne słowo w %1$s nie zaczyna się od %2$s.</string>
|
||||
<string name="not_again_browse">Ten przycisk otwiera przeglądarkę listy słów na liście słów bieżącego gracza.</string>
|
||||
|
|
|
@ -1175,12 +1175,6 @@
|
|||
<string name="dict_browse_nowords_fmt">XLATE ME: No word in %1$s starts with
|
||||
%2$s.</string>
|
||||
<!-- -->
|
||||
<string name="dict_browse_title1_fmt">XLATE ME: %1$s (%2$d words using %3$d
|
||||
tiles)</string>
|
||||
<!-- -->
|
||||
<string name="dict_browse_title_fmt">XLATE ME: %1$s (%2$d words using %3$d-%4$d
|
||||
tiles)</string>
|
||||
<!-- -->
|
||||
<string name="pick_faceup">XLATE ME: Pick tiles face-up</string>
|
||||
<!-- -->
|
||||
<!-- -->
|
||||
|
|
|
@ -300,7 +300,7 @@ board_setDraw( BoardCtxt* board, XWEnv xwe, DrawCtx* draw )
|
|||
{
|
||||
board->draw = draw;
|
||||
if ( !!draw ) {
|
||||
DictionaryCtxt* langDict = model_getDictionary( board->model );
|
||||
const DictionaryCtxt* langDict = model_getDictionary( board->model );
|
||||
draw_dictChanged( draw, xwe, -1, langDict );
|
||||
}
|
||||
}
|
||||
|
@ -1058,7 +1058,7 @@ boardNotifyTrade( BoardCtxt* board, XWEnv xwe, const TrayTileSet* tiles )
|
|||
{
|
||||
const XP_UCHAR* tfaces[MAX_TRAY_TILES];
|
||||
XP_U16 ii;
|
||||
DictionaryCtxt* dict = model_getDictionary( board->model );
|
||||
const DictionaryCtxt* dict = model_getDictionary( board->model );
|
||||
|
||||
for ( ii = 0; ii < tiles->nTiles; ++ii ) {
|
||||
tfaces[ii] = dict_getTileString( dict, tiles->tiles[ii] );
|
||||
|
@ -3733,7 +3733,7 @@ typedef struct _FTData {
|
|||
} FTData;
|
||||
|
||||
static XP_Bool
|
||||
foundTiles( void* closure, const Tile* tiles, int len )
|
||||
foundTiles( void* closure, const Tile* tiles, int XP_UNUSED_DBG(len) )
|
||||
{
|
||||
XP_ASSERT( 1 == len );
|
||||
FTData* ftp = (FTData*)closure;
|
||||
|
@ -3758,12 +3758,12 @@ keyToIndex( BoardCtxt* board, XP_Key key, Tile* blankFace )
|
|||
# endif
|
||||
|
||||
if ( tileIndex < 0 ) {
|
||||
DictionaryCtxt* dict = model_getDictionary( model );
|
||||
const DictionaryCtxt* dict = model_getDictionary( model );
|
||||
XP_UCHAR buf[2] = { key, '\0' };
|
||||
|
||||
/* Figure out if we have the tile in the tray */
|
||||
FTData ftd = {0};
|
||||
dict_tilesForString( dict, buf, foundTiles, &ftd );
|
||||
dict_tilesForString( dict, buf, 0, foundTiles, &ftd );
|
||||
if ( ftd.found ) {
|
||||
XP_S16 turn = board->selPlayer;
|
||||
tileIndex = model_trayContains( model, turn, ftd.tile );
|
||||
|
|
|
@ -377,7 +377,7 @@ drawCell( BoardCtxt* board, XWEnv xwe, const XP_U16 col,
|
|||
XP_Bool isBlank, isEmpty, pending = XP_FALSE;
|
||||
XWBonusType bonus;
|
||||
ModelCtxt* model = board->model;
|
||||
DictionaryCtxt* dict = model_getDictionary( model );
|
||||
const DictionaryCtxt* dict = model_getDictionary( model );
|
||||
XP_U16 modelCol, modelRow;
|
||||
|
||||
if ( dict != NULL && getCellRect( board, col, row, &cellRect ) ) {
|
||||
|
|
|
@ -243,7 +243,7 @@ typedef struct CommonPrefs {
|
|||
} CommonPrefs;
|
||||
|
||||
typedef struct _PlayerDicts {
|
||||
DictionaryCtxt* dicts[MAX_NUM_PLAYERS];
|
||||
const DictionaryCtxt* dicts[MAX_NUM_PLAYERS];
|
||||
} PlayerDicts;
|
||||
|
||||
typedef uint64_t MQTTDevID;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -37,21 +37,6 @@ extern "C" {
|
|||
|
||||
/* 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
|
||||
const DictionaryCtxt* dict;
|
||||
XP_U32 nWords;
|
||||
|
||||
DictPosition position;
|
||||
} DictIter;
|
||||
|
||||
typedef struct _IndexData {
|
||||
DictPosition* indices;
|
||||
|
@ -63,19 +48,68 @@ typedef struct _LengthsArray {
|
|||
XP_U32 lens[MAX_COLS_DICT+1];
|
||||
} LengthsArray;
|
||||
|
||||
void di_initIter( DictIter* iter, const DictionaryCtxt* dict,
|
||||
XP_U16 min, XP_U16 max );
|
||||
typedef struct DictIter DictIter;
|
||||
|
||||
/* A pattern is a list of Tiles (that must be contained in the wordlist) plus
|
||||
* regex meta-characters. Tiles are optionally delimited by '.' (to deal with
|
||||
* the Hungarian case) Supported are:
|
||||
*
|
||||
* tile sets (e.g. [A.B.C]); also [^A.B.C] means NOT these, and [+A.B.C] means
|
||||
* use at most once [+A.B.C]{3} would mean "use all of them once each"
|
||||
*
|
||||
* '?' (meaning anything, same as '.' in most regex languages),
|
||||
*
|
||||
* '*' meaning 0 or more of what's before
|
||||
*
|
||||
* '+' meaning 1 or more of what's before
|
||||
*
|
||||
* '{m[,n]}' meaning between m and n of what's before, so ?{2,15} matches
|
||||
* everything
|
||||
*
|
||||
* '()' also required to express word length: (AB_*CD){2,15} is "an word
|
||||
* beginning with AB and ending with CD from 2 to 15 letters long.
|
||||
*
|
||||
* '^' and '$' matching beginning and end of word (not required, so not yet)
|
||||
*/
|
||||
|
||||
/* di_makeIter: It's either-or: provide the pattern as a reg-ex string, or as
|
||||
* an array of three tile-strings representing starts-with, contains, and
|
||||
* ends-with. The first is more powerful but I'm not sure it'll ever be part
|
||||
* of a shipping UI.*/
|
||||
typedef struct _PatDesc {
|
||||
const Tile* tiles;
|
||||
XP_U16 nTiles;
|
||||
XP_Bool anyOrderOk;
|
||||
} PatDesc;
|
||||
|
||||
typedef struct _DIMinMax {
|
||||
XP_U16 min;
|
||||
XP_U16 max;
|
||||
} DIMinMax;
|
||||
|
||||
DictIter* di_makeIter( const DictionaryCtxt* dict, XWEnv xwe,
|
||||
const DIMinMax* lens, /* NULL means use defaults */
|
||||
const XP_UCHAR** strPats, XP_U16 nStrPats,
|
||||
const PatDesc* pats, XP_U16 nPatDescs );
|
||||
void di_freeIter( DictIter* iter, XWEnv xwe );
|
||||
|
||||
#ifdef XWFEATURE_TESTPATSTR
|
||||
XP_Bool di_stringMatches( DictIter* iter, const XP_UCHAR* string );
|
||||
#endif
|
||||
|
||||
XP_U32 di_countWords( const DictIter* iter, LengthsArray* lens );
|
||||
void di_makeIndex( const DictIter* iter, XP_U16 depth, IndexData* data );
|
||||
XP_Bool di_firstWord( DictIter* iter );
|
||||
XP_Bool di_lastWord( DictIter* iter );
|
||||
XP_Bool di_getNextWord( DictIter* iter );
|
||||
XP_Bool di_getPrevWord( DictIter* iter );
|
||||
XP_Bool di_getNthWord( DictIter* iter, DictPosition position, XP_U16 depth,
|
||||
XP_Bool di_getNthWord( DictIter* iter, XWEnv xwe, DictPosition position, XP_U16 depth,
|
||||
const IndexData* data );
|
||||
XP_U32 di_getNWords( const DictIter* iter );
|
||||
void di_getMinMax( const DictIter* iter, XP_U16* min, XP_U16* max );
|
||||
|
||||
void di_wordToString( const DictIter* iter, XP_UCHAR* buf, XP_U16 buflen,
|
||||
const XP_UCHAR* delim );
|
||||
XP_S16 di_findStartsWith( DictIter* iter, const Tile* prefix, XP_U16 nTiles );
|
||||
void di_stringToTiles( const XP_UCHAR* str, Tile out[], XP_U16* nTiles );
|
||||
DictPosition di_getPosition( const DictIter* iter );
|
||||
#ifdef CPLUS
|
||||
|
|
|
@ -39,7 +39,7 @@ extern "C" {
|
|||
|
||||
typedef struct _DictPair {
|
||||
XP_UCHAR* key;
|
||||
DictionaryCtxt* dict;
|
||||
const DictionaryCtxt* dict;
|
||||
} DictPair;
|
||||
|
||||
struct DictMgrCtxt {
|
||||
|
@ -81,10 +81,10 @@ dmgr_destroy( DictMgrCtxt* dmgr, XWEnv xwe )
|
|||
XP_FREE( dmgr->mpool, dmgr );
|
||||
}
|
||||
|
||||
DictionaryCtxt*
|
||||
const DictionaryCtxt*
|
||||
dmgr_get( DictMgrCtxt* dmgr, XWEnv xwe, const XP_UCHAR* key )
|
||||
{
|
||||
DictionaryCtxt* result = NULL;
|
||||
const DictionaryCtxt* result = NULL;
|
||||
|
||||
pthread_mutex_lock( &dmgr->mutex );
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ DictMgrCtxt* dmgr_make( MPFORMAL_NOCOMMA );
|
|||
void dmgr_destroy( DictMgrCtxt* dmgr, XWEnv xwe );
|
||||
|
||||
void dmgr_put( DictMgrCtxt* dmgr, XWEnv xwe, const XP_UCHAR* key, DictionaryCtxt* dict );
|
||||
DictionaryCtxt* dmgr_get( DictMgrCtxt* dmgr, XWEnv xwe, const XP_UCHAR* key );
|
||||
const DictionaryCtxt* dmgr_get( DictMgrCtxt* dmgr, XWEnv xwe, const XP_UCHAR* key );
|
||||
|
||||
#ifdef CPLUS
|
||||
}
|
||||
|
|
|
@ -42,44 +42,46 @@ extern "C" {
|
|||
|
||||
static XP_Bool makeBitmap( XP_U8 const** ptrp, const XP_U8* end );
|
||||
|
||||
DictionaryCtxt*
|
||||
p_dict_ref( DictionaryCtxt* dict, XWEnv XP_UNUSED(xwe)
|
||||
const DictionaryCtxt*
|
||||
p_dict_ref( const DictionaryCtxt* dict, XWEnv XP_UNUSED(xwe)
|
||||
#ifdef DEBUG_REF
|
||||
,const char* func, const char* file, int line
|
||||
#endif
|
||||
)
|
||||
{
|
||||
if ( !!dict ) {
|
||||
pthread_mutex_lock( &dict->mutex );
|
||||
++dict->refCount;
|
||||
DictionaryCtxt* _dict = (DictionaryCtxt*)dict;
|
||||
pthread_mutex_lock( &_dict->mutex );
|
||||
++_dict->refCount;
|
||||
#ifdef DEBUG_REF
|
||||
XP_LOGF( "%s(dict=%p): refCount now %d (from line %d of %s() in %s)",
|
||||
__func__, dict, dict->refCount, line, func, file );
|
||||
#endif
|
||||
pthread_mutex_unlock( &dict->mutex );
|
||||
pthread_mutex_unlock( &_dict->mutex );
|
||||
}
|
||||
return dict;
|
||||
}
|
||||
|
||||
void
|
||||
p_dict_unref( DictionaryCtxt* dict, XWEnv xwe
|
||||
p_dict_unref( const DictionaryCtxt* dict, XWEnv xwe
|
||||
#ifdef DEBUG_REF
|
||||
,const char* func, const char* file, int line
|
||||
#endif
|
||||
)
|
||||
{
|
||||
if ( !!dict ) {
|
||||
pthread_mutex_lock( &dict->mutex );
|
||||
--dict->refCount;
|
||||
XP_ASSERT( 0 <= dict->refCount );
|
||||
DictionaryCtxt* _dict = (DictionaryCtxt*)dict;
|
||||
pthread_mutex_lock( &_dict->mutex );
|
||||
--_dict->refCount;
|
||||
XP_ASSERT( 0 <= _dict->refCount );
|
||||
#ifdef DEBUG_REF
|
||||
XP_LOGF( "%s(dict=%p): refCount now %d (from line %d of %s() in %s)",
|
||||
__func__, dict, dict->refCount, line, func, file );
|
||||
#endif
|
||||
pthread_mutex_unlock( &dict->mutex );
|
||||
if ( 0 == dict->refCount ) {
|
||||
pthread_mutex_destroy( &dict->mutex );
|
||||
(*dict->destructor)( dict, xwe );
|
||||
pthread_mutex_unlock( &_dict->mutex );
|
||||
if ( 0 == _dict->refCount ) {
|
||||
pthread_mutex_destroy( &_dict->mutex );
|
||||
(*dict->destructor)( _dict, xwe );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -531,12 +533,13 @@ dict_tilesToString( const DictionaryCtxt* dict, const Tile* tiles,
|
|||
*/
|
||||
|
||||
static XP_Bool
|
||||
tilesForStringImpl( const DictionaryCtxt* dict, const XP_UCHAR* str,
|
||||
tilesForStringImpl( const DictionaryCtxt* dict,
|
||||
const XP_UCHAR* str, XP_U16 strLen,
|
||||
Tile* tiles, XP_U16 nTiles, XP_U16 nFound,
|
||||
OnFoundTiles proc, void* closure )
|
||||
{
|
||||
XP_Bool goOn;
|
||||
if ( nFound == nTiles || '\0' == str[0] ) {
|
||||
if ( nFound == nTiles || 0 == strLen ) {
|
||||
/* We've recursed to the end and have found a tile! */
|
||||
goOn = (*proc)( closure, tiles, nFound );
|
||||
} else {
|
||||
|
@ -544,20 +547,19 @@ tilesForStringImpl( const DictionaryCtxt* dict, const XP_UCHAR* str,
|
|||
|
||||
XP_U16 nFaces = dict_numTileFaces( dict );
|
||||
for ( Tile tile = 0; goOn && tile < nFaces; ++tile ) {
|
||||
if ( tile != dict->blankTile ) {
|
||||
for ( const XP_UCHAR* facep = NULL; ; ) {
|
||||
facep = dict_getNextTileString( dict, tile, facep );
|
||||
if ( !facep ) {
|
||||
break;
|
||||
}
|
||||
XP_U16 faceLen = XP_STRLEN( facep );
|
||||
if ( 0 == XP_STRNCMP( facep, str, faceLen ) ) {
|
||||
tiles[nFound] = tile;
|
||||
goOn = tilesForStringImpl( dict, str + faceLen,
|
||||
tiles, nTiles, nFound + 1,
|
||||
proc, closure );
|
||||
break; /* impossible to have than one match per tile */
|
||||
}
|
||||
for ( const XP_UCHAR* facep = NULL; ; ) {
|
||||
facep = dict_getNextTileString( dict, tile, facep );
|
||||
if ( !facep ) {
|
||||
break;
|
||||
}
|
||||
XP_U16 faceLen = XP_STRLEN( facep );
|
||||
if ( 0 == XP_STRNCMP( facep, str, faceLen ) ) {
|
||||
tiles[nFound] = tile;
|
||||
goOn = tilesForStringImpl( dict, str + faceLen,
|
||||
strLen - faceLen,
|
||||
tiles, nTiles, nFound + 1,
|
||||
proc, closure );
|
||||
break; /* impossible to have than one match per tile */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -567,10 +569,13 @@ tilesForStringImpl( const DictionaryCtxt* dict, const XP_UCHAR* str,
|
|||
|
||||
void
|
||||
dict_tilesForString( const DictionaryCtxt* dict, const XP_UCHAR* str,
|
||||
OnFoundTiles proc, void* closure )
|
||||
XP_U16 strLen, OnFoundTiles proc, void* closure )
|
||||
{
|
||||
Tile tiles[32];
|
||||
tilesForStringImpl( dict, str, tiles, VSIZE(tiles), 0, proc, closure );
|
||||
if ( 0 == strLen ) {
|
||||
strLen = XP_STRLEN( str );
|
||||
}
|
||||
tilesForStringImpl( dict, str, strLen, tiles, VSIZE(tiles), 0, proc, closure );
|
||||
} /* dict_tilesForString */
|
||||
|
||||
XP_Bool
|
||||
|
@ -638,6 +643,21 @@ ucharsToNarrow( const DictionaryCtxt* dict, XP_UCHAR* buf, XP_U16* bufsizep )
|
|||
*bufsizep = nUsed;
|
||||
}
|
||||
|
||||
/* Summarize tile info in a way it can be presented to users */
|
||||
void
|
||||
dict_writeTilesInfo( const DictionaryCtxt* dict, XWStreamCtxt* stream )
|
||||
{
|
||||
XP_U16 nFaces = dict_numTileFaces( dict );
|
||||
for ( Tile tile = 0; tile < nFaces; ++tile ) {
|
||||
XP_U16 val = dict_getTileValue( dict, tile );
|
||||
XP_U16 count = dict_numTiles( dict, tile );
|
||||
const XP_UCHAR* face = dict_getTileString( dict, tile );
|
||||
XP_UCHAR buf[32];
|
||||
XP_SNPRINTF( buf, VSIZE(buf), "%s\t%d\t%d\n", face, count, val );
|
||||
stream_catString( stream, buf );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
dict_writeToStream( const DictionaryCtxt* dict, XWStreamCtxt* stream )
|
||||
{
|
||||
|
@ -862,14 +882,14 @@ dict_getLangCode( const DictionaryCtxt* dict )
|
|||
}
|
||||
|
||||
XP_U32
|
||||
dict_getWordCount( const DictionaryCtxt* dict )
|
||||
dict_getWordCount( const DictionaryCtxt* dict, XWEnv xwe )
|
||||
{
|
||||
XP_U32 nWords = dict->nWords;
|
||||
#ifdef XWFEATURE_WALKDICT
|
||||
if ( 0 == nWords ) {
|
||||
DictIter iter;
|
||||
di_initIter( &iter, dict, 0, MAX_COLS_DICT );
|
||||
nWords = di_countWords( &iter, NULL );
|
||||
DictIter* iter = di_makeIter( dict, xwe, NULL, NULL, 0, NULL, 0 );
|
||||
nWords = di_countWords( iter, NULL );
|
||||
di_freeIter( iter, xwe );
|
||||
}
|
||||
#endif
|
||||
return nWords;
|
||||
|
|
|
@ -146,18 +146,18 @@ struct DictionaryCtxt {
|
|||
((ACCEPTINGMASK_NEW & ((array_edge_old*)(e))->bits) != 0)
|
||||
#define IS_LAST_EDGE(d,e) \
|
||||
((LASTEDGEMASK_NEW & ((array_edge_old*)(e))->bits) != 0)
|
||||
#define EDGETILE(d,edge) \
|
||||
#define EDGETILE(dict,edge) \
|
||||
((Tile)(((array_edge_old*)(edge))->bits & \
|
||||
((d)->is_4_byte?LETTERMASK_NEW_4:LETTERMASK_NEW_3)))
|
||||
((dict)->is_4_byte?LETTERMASK_NEW_4:LETTERMASK_NEW_3)))
|
||||
|
||||
DictionaryCtxt* p_dict_ref( DictionaryCtxt* dict, XWEnv xwe
|
||||
const DictionaryCtxt* p_dict_ref( const DictionaryCtxt* dict, XWEnv xwe
|
||||
#ifdef DEBUG_REF
|
||||
,const char* func, const char* file, int line
|
||||
,const char* func, const char* file, int line
|
||||
#endif
|
||||
);
|
||||
void p_dict_unref( DictionaryCtxt* dict, XWEnv xwe
|
||||
void p_dict_unref( const DictionaryCtxt* dict, XWEnv xwe
|
||||
#ifdef DEBUG_REF
|
||||
,const char* func, const char* file, int line
|
||||
,const char* func, const char* file, int line
|
||||
#endif
|
||||
);
|
||||
void dict_unref_all( PlayerDicts* dicts, XWEnv xwe );
|
||||
|
@ -191,20 +191,22 @@ const XP_UCHAR* dict_getLangName(const DictionaryCtxt* ctxt );
|
|||
XP_Bool dict_isUTF8( const DictionaryCtxt* ctxt );
|
||||
|
||||
typedef XP_Bool (*OnFoundTiles)(void* closure, const Tile* tiles, int len);
|
||||
void dict_tilesForString( const DictionaryCtxt* dict, const XP_UCHAR* key,
|
||||
OnFoundTiles proc, void* closure );
|
||||
void dict_tilesForString( const DictionaryCtxt* dict, const XP_UCHAR* str,
|
||||
XP_U16 strLen, OnFoundTiles proc, void* closure );
|
||||
|
||||
XP_Bool dict_faceIsBitmap( const DictionaryCtxt* dict, Tile tile );
|
||||
void dict_getFaceBitmaps( const DictionaryCtxt* dict, Tile tile,
|
||||
XP_Bitmaps* bmps );
|
||||
|
||||
XP_LangCode dict_getLangCode( const DictionaryCtxt* dict );
|
||||
XP_U32 dict_getWordCount( const DictionaryCtxt* dict );
|
||||
XP_U32 dict_getWordCount( const DictionaryCtxt* dict, XWEnv xwe );
|
||||
|
||||
const XP_UCHAR* dict_getDesc( const DictionaryCtxt* dict );
|
||||
const XP_UCHAR* dict_getMd5Sum( const DictionaryCtxt* dict );
|
||||
XP_Bool dict_hasDuplicates( const DictionaryCtxt* dict );
|
||||
|
||||
void dict_writeTilesInfo( const DictionaryCtxt* ctxt, XWStreamCtxt* stream );
|
||||
|
||||
void dict_writeToStream( const DictionaryCtxt* ctxt, XWStreamCtxt* stream );
|
||||
void dict_loadFromStream( DictionaryCtxt* dict, XWEnv xwe, XWStreamCtxt* stream );
|
||||
|
||||
|
|
|
@ -757,7 +757,7 @@ figureCrosschecks( EngineCtxt* engine, XP_U16 x, XP_U16 y, XP_U16* scoreP,
|
|||
} /* figureCrosschecks */
|
||||
|
||||
XP_Bool
|
||||
engine_check( DictionaryCtxt* dict, Tile* tiles, XP_U16 nTiles )
|
||||
engine_check( const DictionaryCtxt* dict, Tile* tiles, XP_U16 nTiles )
|
||||
{
|
||||
array_edge* in_edge = dict_getTopEdge( dict );
|
||||
|
||||
|
|
|
@ -63,7 +63,7 @@ XP_Bool engine_findMove( EngineCtxt* ctxt, XWEnv xwe, const ModelCtxt* model, XP
|
|||
#endif
|
||||
XP_U16 robotIQ, XP_Bool* canMove,
|
||||
MoveInfo* result, XP_U16* score );
|
||||
XP_Bool engine_check( DictionaryCtxt* dict, Tile* buf, XP_U16 buflen );
|
||||
XP_Bool engine_check( const DictionaryCtxt* dict, Tile* buf, XP_U16 buflen );
|
||||
|
||||
#ifdef CPLUS
|
||||
}
|
||||
|
|
|
@ -51,8 +51,8 @@ static void notifyBoardListeners( ModelCtxt* model, XWEnv xwe, XP_U16 turn,
|
|||
static void notifyTrayListeners( ModelCtxt* model, XP_U16 turn,
|
||||
XP_S16 index1, XP_S16 index2 );
|
||||
static void notifyDictListeners( ModelCtxt* model, XWEnv xwe, XP_S16 playerNum,
|
||||
DictionaryCtxt* oldDict,
|
||||
DictionaryCtxt* newDict );
|
||||
const DictionaryCtxt* oldDict,
|
||||
const DictionaryCtxt* newDict );
|
||||
static void model_unrefDicts( ModelCtxt* model, XWEnv xwe );
|
||||
|
||||
static CellTile getModelTileRaw( const ModelCtxt* model, XP_U16 col,
|
||||
|
@ -91,8 +91,8 @@ static void assertDiffTurn( ModelCtxt* model, XWEnv xwe, XP_U16 turn,
|
|||
*
|
||||
****************************************************************************/
|
||||
ModelCtxt*
|
||||
model_make( MPFORMAL XWEnv xwe, DictionaryCtxt* dict, const PlayerDicts* dicts,
|
||||
XW_UtilCtxt* util, XP_U16 nCols )
|
||||
model_make( MPFORMAL XWEnv xwe, const DictionaryCtxt* dict,
|
||||
const PlayerDicts* dicts, XW_UtilCtxt* util, XP_U16 nCols )
|
||||
{
|
||||
ModelCtxt* result = (ModelCtxt*)XP_MALLOC( mpool, sizeof( *result ) );
|
||||
if ( result != NULL ) {
|
||||
|
@ -118,7 +118,7 @@ model_make( MPFORMAL XWEnv xwe, DictionaryCtxt* dict, const PlayerDicts* dicts,
|
|||
|
||||
ModelCtxt*
|
||||
model_makeFromStream( MPFORMAL XWEnv xwe, XWStreamCtxt* stream,
|
||||
DictionaryCtxt* dict, const PlayerDicts* dicts,
|
||||
const DictionaryCtxt* dict, const PlayerDicts* dicts,
|
||||
XW_UtilCtxt* util )
|
||||
{
|
||||
ModelCtxt* model;
|
||||
|
@ -574,9 +574,9 @@ setStackBits( ModelCtxt* model, const DictionaryCtxt* dict )
|
|||
}
|
||||
|
||||
void
|
||||
model_setDictionary( ModelCtxt* model, XWEnv xwe, DictionaryCtxt* dict )
|
||||
model_setDictionary( ModelCtxt* model, XWEnv xwe, const DictionaryCtxt* dict )
|
||||
{
|
||||
DictionaryCtxt* oldDict = model->vol.dict;
|
||||
const DictionaryCtxt* oldDict = model->vol.dict;
|
||||
model->vol.dict = dict_ref( dict, xwe );
|
||||
|
||||
if ( !!dict ) {
|
||||
|
@ -593,11 +593,11 @@ model_setPlayerDicts( ModelCtxt* model, XWEnv xwe, const PlayerDicts* dicts )
|
|||
if ( !!dicts ) {
|
||||
XP_U16 ii;
|
||||
#ifdef DEBUG
|
||||
DictionaryCtxt* gameDict = model_getDictionary( model );
|
||||
const DictionaryCtxt* gameDict = model_getDictionary( model );
|
||||
#endif
|
||||
for ( ii = 0; ii < VSIZE(dicts->dicts); ++ii ) {
|
||||
DictionaryCtxt* oldDict = model->vol.dicts.dicts[ii];
|
||||
DictionaryCtxt* newDict = dicts->dicts[ii];
|
||||
const DictionaryCtxt* oldDict = model->vol.dicts.dicts[ii];
|
||||
const DictionaryCtxt* newDict = dicts->dicts[ii];
|
||||
if ( oldDict != newDict ) {
|
||||
XP_ASSERT( NULL == newDict || NULL == gameDict
|
||||
|| dict_tilesAreSame( gameDict, newDict ) );
|
||||
|
@ -612,21 +612,21 @@ model_setPlayerDicts( ModelCtxt* model, XWEnv xwe, const PlayerDicts* dicts )
|
|||
}
|
||||
}
|
||||
|
||||
DictionaryCtxt*
|
||||
const DictionaryCtxt*
|
||||
model_getDictionary( const ModelCtxt* model )
|
||||
{
|
||||
XP_U16 ii;
|
||||
DictionaryCtxt* result = model->vol.dict;
|
||||
const DictionaryCtxt* result = model->vol.dict;
|
||||
for ( ii = 0; !result && ii < VSIZE(model->vol.dicts.dicts); ++ii ) {
|
||||
result = model->vol.dicts.dicts[ii];
|
||||
}
|
||||
return result;
|
||||
} /* model_getDictionary */
|
||||
|
||||
DictionaryCtxt*
|
||||
const DictionaryCtxt*
|
||||
model_getPlayerDict( const ModelCtxt* model, XP_S16 playerNum )
|
||||
{
|
||||
DictionaryCtxt* dict = NULL;
|
||||
const DictionaryCtxt* dict = NULL;
|
||||
if ( 0 <= playerNum && playerNum < VSIZE(model->vol.dicts.dicts) ) {
|
||||
dict = model->vol.dicts.dicts[playerNum];
|
||||
}
|
||||
|
@ -1474,7 +1474,7 @@ model_packTilesUtil( ModelCtxt* model, PoolContext* pool,
|
|||
XP_U16* nUsed, const XP_UCHAR** texts,
|
||||
Tile* tiles )
|
||||
{
|
||||
DictionaryCtxt* dict = model_getDictionary(model);
|
||||
const DictionaryCtxt* dict = model_getDictionary(model);
|
||||
XP_U16 nFaces = dict_numTileFaces( dict );
|
||||
Tile blankFace = dict_getBlankTile( dict );
|
||||
Tile tile;
|
||||
|
@ -2219,7 +2219,7 @@ notifyTrayListeners( ModelCtxt* model, XP_U16 turn, XP_S16 index1,
|
|||
|
||||
static void
|
||||
notifyDictListeners( ModelCtxt* model, XWEnv xwe, XP_S16 playerNum,
|
||||
DictionaryCtxt* oldDict, DictionaryCtxt* newDict )
|
||||
const DictionaryCtxt* oldDict, const DictionaryCtxt* newDict )
|
||||
{
|
||||
if ( model->vol.dictListenerFunc != NULL ) {
|
||||
(*model->vol.dictListenerFunc)( model->vol.dictListenerData, xwe,
|
||||
|
@ -2234,8 +2234,8 @@ printString( XWStreamCtxt* stream, const XP_UCHAR* str )
|
|||
} /* printString */
|
||||
|
||||
static XP_UCHAR*
|
||||
formatTray( const TrayTileSet* tiles, DictionaryCtxt* dict, XP_UCHAR* buf,
|
||||
XP_U16 bufSize, XP_Bool keepHidden )
|
||||
formatTray( const TrayTileSet* tiles, const DictionaryCtxt* dict,
|
||||
XP_UCHAR* buf, XP_U16 bufSize, XP_Bool keepHidden )
|
||||
{
|
||||
if ( keepHidden ) {
|
||||
XP_U16 ii;
|
||||
|
@ -2253,7 +2253,7 @@ formatTray( const TrayTileSet* tiles, DictionaryCtxt* dict, XP_UCHAR* buf,
|
|||
|
||||
typedef struct MovePrintClosure {
|
||||
XWStreamCtxt* stream;
|
||||
DictionaryCtxt* dict;
|
||||
const DictionaryCtxt* dict;
|
||||
XP_U16 nPrinted;
|
||||
XP_Bool keepHidden;
|
||||
XP_U32 lastPauseWhen;
|
||||
|
@ -2339,7 +2339,7 @@ printMovePost( ModelCtxt* model, XWEnv xwe, XP_U16 XP_UNUSED(moveN),
|
|||
if ( entry->moveType != ASSIGN_TYPE ) {
|
||||
MovePrintClosure* closure = (MovePrintClosure*)p_closure;
|
||||
XWStreamCtxt* stream = closure->stream;
|
||||
DictionaryCtxt* dict = closure->dict;
|
||||
const DictionaryCtxt* dict = closure->dict;
|
||||
const XP_UCHAR* format;
|
||||
XP_U16 nTiles;
|
||||
|
||||
|
|
|
@ -74,11 +74,11 @@ typedef XP_U8 TileBit; /* bits indicating selection of tiles in tray */
|
|||
only */
|
||||
|
||||
|
||||
ModelCtxt* model_make( MPFORMAL XWEnv xwe, DictionaryCtxt* dict,
|
||||
ModelCtxt* model_make( MPFORMAL XWEnv xwe, const DictionaryCtxt* dict,
|
||||
const PlayerDicts* dicts, XW_UtilCtxt* util, XP_U16 nCols );
|
||||
|
||||
ModelCtxt* model_makeFromStream( MPFORMAL XWEnv xwe, XWStreamCtxt* stream,
|
||||
DictionaryCtxt* dict, const PlayerDicts* dicts,
|
||||
const DictionaryCtxt* dict, const PlayerDicts* dicts,
|
||||
XW_UtilCtxt* util );
|
||||
|
||||
void model_writeToStream( const ModelCtxt* model, XWStreamCtxt* stream );
|
||||
|
@ -97,11 +97,11 @@ XP_Bool model_popToHash( ModelCtxt* model, XWEnv xwe, const XP_U32 hash,
|
|||
void model_setNPlayers( ModelCtxt* model, XP_U16 numPlayers );
|
||||
XP_U16 model_getNPlayers( const ModelCtxt* model );
|
||||
|
||||
void model_setDictionary( ModelCtxt* model, XWEnv xwe, DictionaryCtxt* dict );
|
||||
DictionaryCtxt* model_getDictionary( const ModelCtxt* model );
|
||||
void model_setDictionary( ModelCtxt* model, XWEnv xwe, const DictionaryCtxt* dict );
|
||||
const DictionaryCtxt* model_getDictionary( const ModelCtxt* model );
|
||||
|
||||
void model_setPlayerDicts( ModelCtxt* model, XWEnv xwe, const PlayerDicts* dicts );
|
||||
DictionaryCtxt* model_getPlayerDict( const ModelCtxt* model, XP_S16 playerNum );
|
||||
const DictionaryCtxt* model_getPlayerDict( const ModelCtxt* model, XP_S16 playerNum );
|
||||
|
||||
XP_Bool model_getTile( const ModelCtxt* model, XP_U16 col, XP_U16 row,
|
||||
XP_Bool getPending, XP_S16 turn,
|
||||
|
|
|
@ -54,7 +54,7 @@ typedef struct ModelVolatiles {
|
|||
XW_DUtilCtxt* dutil;
|
||||
XW_UtilCtxt* util;
|
||||
struct CurGameInfo* gi;
|
||||
DictionaryCtxt* dict;
|
||||
const DictionaryCtxt* dict;
|
||||
PlayerDicts dicts;
|
||||
StackCtxt* stack;
|
||||
BoardListener boardListenerFunc;
|
||||
|
|
|
@ -52,7 +52,7 @@ static XP_U16 scoreWord( const ModelCtxt* model, XWEnv xwe, XP_U16 turn,
|
|||
as little impact as possible on the speed when the robot's looking for FAST
|
||||
scoring */
|
||||
typedef struct WordScoreFormatter {
|
||||
DictionaryCtxt* dict;
|
||||
const DictionaryCtxt* dict;
|
||||
|
||||
XP_UCHAR fullBuf[80];
|
||||
XP_UCHAR wordBuf[MAX_ROWS+1];
|
||||
|
@ -61,7 +61,7 @@ typedef struct WordScoreFormatter {
|
|||
XP_Bool firstPass;
|
||||
} WordScoreFormatter;
|
||||
static void wordScoreFormatterInit( WordScoreFormatter* fmtr,
|
||||
DictionaryCtxt* dict );
|
||||
const DictionaryCtxt* dict );
|
||||
static void wordScoreFormatterAddTile( WordScoreFormatter* fmtr, Tile tile,
|
||||
XP_U16 tileMultiplier,
|
||||
XP_Bool isBlank );
|
||||
|
@ -166,7 +166,7 @@ model_figureFinalScores( ModelCtxt* model, ScoresArray* finalScoresP,
|
|||
XP_S16 firstDoneIndex = -1; /* not set unless FIRST_DONE_BONUS is set */
|
||||
const TrayTileSet* tray;
|
||||
PlayerCtxt* player;
|
||||
DictionaryCtxt* dict = model_getDictionary( model );
|
||||
const DictionaryCtxt* dict = model_getDictionary( model );
|
||||
CurGameInfo* gi = model->vol.gi;
|
||||
|
||||
if ( !!finalScoresP ) {
|
||||
|
@ -298,7 +298,7 @@ checkScoreMove( ModelCtxt* model, XWEnv xwe, XP_S16 turn, EngineCtxt* engine,
|
|||
if ( checkDict && 0 < bcs.nBadWords ) {
|
||||
if ( !silent ) {
|
||||
XP_ASSERT( !!bcs.stream );
|
||||
DictionaryCtxt* dict = model_getPlayerDict( model, turn );
|
||||
const DictionaryCtxt* dict = model_getPlayerDict( model, turn );
|
||||
util_informWordsBlocked( model->vol.util, xwe, bcs.nBadWords,
|
||||
bcs.stream, dict_getName( dict ) );
|
||||
stream_destroy( bcs.stream, xwe );
|
||||
|
@ -647,7 +647,7 @@ scoreWord( const ModelCtxt* model, XWEnv xwe, XP_U16 turn,
|
|||
XP_U16 col, row;
|
||||
const MoveInfoTile* tiles = movei->tiles;
|
||||
XP_U16 firstCoord = tiles->varCoord;
|
||||
DictionaryCtxt* dict = model_getPlayerDict( model, turn );
|
||||
const DictionaryCtxt* dict = model_getPlayerDict( model, turn );
|
||||
|
||||
assertSorted( movei );
|
||||
|
||||
|
@ -831,7 +831,7 @@ find_end( const ModelCtxt* model, XP_U16 col, XP_U16 row,
|
|||
} /* find_end */
|
||||
|
||||
static void
|
||||
wordScoreFormatterInit( WordScoreFormatter* fmtr, DictionaryCtxt* dict )
|
||||
wordScoreFormatterInit( WordScoreFormatter* fmtr, const DictionaryCtxt* dict )
|
||||
{
|
||||
XP_MEMSET( fmtr, 0, sizeof(*fmtr) );
|
||||
|
||||
|
|
|
@ -242,7 +242,7 @@ pool_getNTilesLeftFor( const PoolContext* pool, Tile tile )
|
|||
} /* pool_remainingTileCount */
|
||||
|
||||
void
|
||||
pool_initFromDict( PoolContext* pool, DictionaryCtxt* dict )
|
||||
pool_initFromDict( PoolContext* pool, const DictionaryCtxt* dict )
|
||||
{
|
||||
const XP_U16 numFaces = dict_numTileFaces( dict );
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ XP_U16 pool_getNTilesLeftFor( const PoolContext* pool, Tile tile );
|
|||
PoolContext* pool_make( MPFORMAL_NOCOMMA );
|
||||
|
||||
void pool_destroy( PoolContext* pool );
|
||||
void pool_initFromDict( PoolContext* pool, DictionaryCtxt* dict );
|
||||
void pool_initFromDict( PoolContext* pool, const DictionaryCtxt* dict );
|
||||
|
||||
void pool_writeToStream( PoolContext* pool, XWStreamCtxt* stream );
|
||||
PoolContext* pool_makeFromStream( MPFORMAL XWStreamCtxt* stream );
|
||||
|
|
|
@ -895,7 +895,7 @@ static XP_U16
|
|||
bitsPerTile( ServerCtxt* server )
|
||||
{
|
||||
if ( 0 == server->vol.bitsPerTile ) {
|
||||
DictionaryCtxt* dict = model_getDictionary( server->vol.model );
|
||||
const DictionaryCtxt* dict = model_getDictionary( server->vol.model );
|
||||
XP_U16 nFaces = dict_numTileFaces( dict );
|
||||
server->vol.bitsPerTile = nFaces <= 32? 5 : 6;
|
||||
}
|
||||
|
@ -1537,7 +1537,7 @@ informNeedPickTiles( ServerCtxt* server, XWEnv xwe, XP_Bool initial,
|
|||
XP_U16 turn, XP_U16 nToPick )
|
||||
{
|
||||
ModelCtxt* model = server->vol.model;
|
||||
DictionaryCtxt* dict = model_getDictionary(model);
|
||||
const DictionaryCtxt* dict = model_getDictionary(model);
|
||||
XP_U16 nFaces = dict_numTileFaces( dict );
|
||||
XP_U16 counts[MAX_UNIQUE_TILES];
|
||||
const XP_UCHAR* faces[MAX_UNIQUE_TILES];
|
||||
|
@ -1864,7 +1864,7 @@ client_readInitialMessage( ServerCtxt* server, XWEnv xwe, XWStreamCtxt* stream )
|
|||
gi->nPlayers = nPlayers;
|
||||
model_setNPlayers( model, nPlayers );
|
||||
|
||||
DictionaryCtxt* curDict = model_getDictionary( model );
|
||||
const DictionaryCtxt* curDict = model_getDictionary( model );
|
||||
|
||||
XP_ASSERT( !!newDict );
|
||||
|
||||
|
@ -1997,7 +1997,7 @@ sendInitialMessage( ServerCtxt* server, XWEnv xwe )
|
|||
makeSendableGICopy( server, &localGI, deviceIndex );
|
||||
gi_writeToStream( stream, &localGI );
|
||||
|
||||
DictionaryCtxt* dict = model_getDictionary( model );
|
||||
const DictionaryCtxt* dict = model_getDictionary( model );
|
||||
dict_writeToStream( dict, stream );
|
||||
#ifdef STREAM_VERS_BIGBOARD
|
||||
if ( STREAM_VERS_DICTNAME <= streamVersion ) {
|
||||
|
@ -2202,7 +2202,7 @@ makeNotAVowel( ServerCtxt* server, Tile* newTile )
|
|||
Tile tile = *newTile;
|
||||
PoolContext* pool = server->pool;
|
||||
TrayTileSet set;
|
||||
DictionaryCtxt* dict = model_getDictionary( server->vol.model );
|
||||
const DictionaryCtxt* dict = model_getDictionary( server->vol.model );
|
||||
XP_U8 numGot = 1;
|
||||
|
||||
set.nTiles = 1;
|
||||
|
@ -2240,7 +2240,7 @@ curTrayAsTexts( ServerCtxt* server, XP_U16 turn, const TrayTileSet* notInTray,
|
|||
XP_U16* nUsedP, const XP_UCHAR** curTrayText )
|
||||
{
|
||||
const TrayTileSet* tileSet = model_getPlayerTiles( server->vol.model, turn );
|
||||
DictionaryCtxt* dict = model_getDictionary( server->vol.model );
|
||||
const DictionaryCtxt* dict = model_getDictionary( server->vol.model );
|
||||
XP_U16 ii, jj;
|
||||
XP_U16 size = tileSet->nTiles;
|
||||
const Tile* tp = tileSet->tiles;
|
||||
|
@ -2354,7 +2354,7 @@ fetchTiles( ServerCtxt* server, XWEnv xwe, XP_U16 playerNum, XP_U16 nToFetch,
|
|||
PoolContext* pool = server->pool;
|
||||
const XP_UCHAR* curTray[MAX_TRAY_TILES];
|
||||
#ifdef FEATURE_TRAY_EDIT
|
||||
DictionaryCtxt* dict = model_getDictionary( server->vol.model );
|
||||
const DictionaryCtxt* dict = model_getDictionary( server->vol.model );
|
||||
#endif
|
||||
|
||||
XP_ASSERT( !!pool );
|
||||
|
@ -4184,7 +4184,7 @@ void
|
|||
server_formatDictCounts( ServerCtxt* server, XWEnv xwe, XWStreamCtxt* stream,
|
||||
XP_U16 nCols, XP_Bool allFaces )
|
||||
{
|
||||
DictionaryCtxt* dict;
|
||||
const DictionaryCtxt* dict;
|
||||
Tile tile;
|
||||
XP_U16 nChars, nPrinted;
|
||||
XP_UCHAR buf[48];
|
||||
|
@ -4249,7 +4249,7 @@ server_formatRemainingTiles( ServerCtxt* server, XWEnv xwe, XWStreamCtxt* stream
|
|||
PoolContext* pool = server->pool;
|
||||
if ( !!pool ) {
|
||||
XP_UCHAR buf[128];
|
||||
DictionaryCtxt* dict = model_getDictionary( server->vol.model );
|
||||
const DictionaryCtxt* dict = model_getDictionary( server->vol.model );
|
||||
Tile tile;
|
||||
XP_U16 nChars = dict_numTileFaces( dict );
|
||||
XP_U16 offset;
|
||||
|
|
|
@ -142,7 +142,7 @@ drawTray( BoardCtxt* board, XWEnv xwe )
|
|||
|
||||
if ( draw_trayBegin( board->draw, xwe, &board->trayBounds, turn,
|
||||
turnScore, dfsFor( board, OBJ_TRAY ) ) ) {
|
||||
DictionaryCtxt* dictionary = model_getDictionary( board->model );
|
||||
const DictionaryCtxt* dictionary = model_getDictionary( board->model );
|
||||
XP_U16 trayInvalBits = board->trayInvalBits;
|
||||
XP_S16 cursorBits = 0;
|
||||
XP_Bool cursorOnDivider = XP_FALSE;
|
||||
|
@ -278,7 +278,7 @@ getTileDrawInfo( const BoardCtxt* board, Tile tile, XP_Bool isBlank,
|
|||
XP_Bitmaps* bitmaps, XP_S16* value )
|
||||
{
|
||||
const XP_UCHAR* face = NULL;
|
||||
DictionaryCtxt* dict = model_getDictionary( board->model );
|
||||
const DictionaryCtxt* dict = model_getDictionary( board->model );
|
||||
if ( isBlank ) {
|
||||
tile = dict_getBlankTile( dict );
|
||||
} else {
|
||||
|
|
|
@ -44,7 +44,7 @@ LANG_SPECIAL_INFO = \
|
|||
|
||||
include ../Makefile.langcommon
|
||||
|
||||
SOURCEDICT ?= $(XWDICTPATH)/Catalan/DISC2-LP.dict
|
||||
SOURCEDICT ?= $(XWDICTPATH)/Catalan/DISC2-LP.txt
|
||||
|
||||
$(XWLANG)Main.dict.gz: $(SOURCEDICT) $(MAKEFILE)
|
||||
cat $< \
|
||||
|
|
|
@ -194,12 +194,13 @@ byodbins: table.bin charcount.bin values.bin frankspecials.bin info.txt
|
|||
else
|
||||
ifeq ($(TARGET_TYPE),WINCE)
|
||||
|
||||
byodbins: table.bin charcount.bin values.bin frankspecials.bin info.txt
|
||||
|
||||
### WINCE section here ###
|
||||
all: $(XWLANG)2to8.xwd $(XWLANG)2to9.xwd $(XWLANG)2to15.xwd
|
||||
../mkxwdcab.pl -f $<
|
||||
empty: $(XWLANG)0to0.xwd
|
||||
|
||||
byodbins: table.bin charcount.bin values.bin frankspecials.bin info.txt
|
||||
|
||||
else
|
||||
(Need to define TARGET_TYPE if get error pointing to this line)
|
||||
endif #ifeq ($(TARGET_TYPE),FRANK)
|
||||
|
|
|
@ -110,6 +110,7 @@ DEFINES += -DDISABLE_TILE_SEL
|
|||
# DEFINES += -DSET_GAMESEED
|
||||
DEFINES += -DTEXT_MODEL
|
||||
DEFINES += -DXWFEATURE_WALKDICT
|
||||
DEFINES += -DXWFEATURE_TESTPATSTR
|
||||
DEFINES += -DXWFEATURE_WALKDICT_FILTER
|
||||
DEFINES += -DXWFEATURE_DICTSANITY
|
||||
DEFINES += -DHASH_STREAM
|
||||
|
|
|
@ -826,6 +826,11 @@ typedef enum {
|
|||
,CMD_TESTDICT
|
||||
,CMD_TESTPRFX
|
||||
,CMD_TESTMINMAX
|
||||
#endif
|
||||
,CMD_DELIM
|
||||
#ifdef XWFEATURE_TESTPATSTR
|
||||
,CMD_TESTPAT
|
||||
,CMD_TESTSTR
|
||||
#endif
|
||||
,CMD_DICTDIR
|
||||
,CMD_PLAYERDICT
|
||||
|
@ -959,6 +964,12 @@ static CmdInfoRec CmdInfoRecs[] = {
|
|||
,{ 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_DELIM, true, "test-delim", "string (should be one char) printed between tile faces" }
|
||||
#ifdef XWFEATURE_TESTPATSTR
|
||||
,{ CMD_TESTPAT, true, "test-pat", "pattern: e.g. 'ABC' or 'A[+BC]_{2,5}' (can repeat)" }
|
||||
,{ CMD_TESTSTR, true, "test-string",
|
||||
"string to be tested against test-pat; exit with non-0 if doesn't match" }
|
||||
#endif
|
||||
,{ CMD_DICTDIR, true, "dict-dir", "path to dir in which dicts will be sought" }
|
||||
,{ CMD_PLAYERDICT, true, "player-dict", "dictionary name for player (in sequence)" }
|
||||
|
@ -1914,6 +1925,8 @@ parsePair( const char* optarg, XP_U16* min, XP_U16* max )
|
|||
*min = intmin;
|
||||
*max = intmax;
|
||||
success = true;
|
||||
} else {
|
||||
XP_LOGFF( "bad len params: %d <= %d expected", intmin, intmax );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1929,43 +1942,81 @@ tmp_noop_sigintterm( int XP_UNUSED(sig) )
|
|||
}
|
||||
|
||||
#ifdef XWFEATURE_WALKDICT
|
||||
//# define PRINT_ALL
|
||||
static void
|
||||
testGetNthWord( const DictionaryCtxt* dict, char** XP_UNUSED_DBG(words),
|
||||
XP_U16 depth, IndexData* data, XP_U16 min, XP_U16 max )
|
||||
static DictIter*
|
||||
patsParamsToIter( const LaunchParams* params, const DictionaryCtxt* dict )
|
||||
{
|
||||
XP_UCHAR buf[64];
|
||||
XP_U32 ii, jj;
|
||||
DictIter iter;
|
||||
const XP_UCHAR** strPats = NULL;
|
||||
const XP_UCHAR* _strPats[4];
|
||||
XP_U16 nStrPats = 0;
|
||||
const PatDesc* pats = NULL;
|
||||
XP_U16 nPatDescs = 0;
|
||||
|
||||
di_initIter( &iter, dict, min, max );
|
||||
XP_U32 half = di_countWords( &iter, NULL ) / 2;
|
||||
if ( !!params->iterTestPats ) {
|
||||
nStrPats = g_slist_length( params->iterTestPats );
|
||||
strPats = &_strPats[0];
|
||||
GSList* iter;
|
||||
int ii;
|
||||
for ( ii = 0, iter = params->iterTestPats;
|
||||
!!iter && ii < nStrPats;
|
||||
++ii, iter = iter->next ) {
|
||||
strPats[ii] = iter->data;
|
||||
}
|
||||
} else if ( !!params->patStartW || !!params->patContains || !!params->patEndsW ) {
|
||||
XP_ASSERT(0);
|
||||
/* and what about the boolean? */
|
||||
}
|
||||
|
||||
DIMinMax dimm;
|
||||
DIMinMax* dimmp = NULL;
|
||||
if ( !!params->testMinMax && parsePair( params->testMinMax, &dimm.min, &dimm.max ) ) {
|
||||
dimmp = &dimm;
|
||||
}
|
||||
|
||||
DictIter* iter = di_makeIter( dict, NULL_XWE, dimmp, strPats, nStrPats,
|
||||
pats, nPatDescs );
|
||||
return iter;
|
||||
}
|
||||
|
||||
# define PRINT_ALL
|
||||
static void
|
||||
testGetNthWord( const LaunchParams* params, const DictionaryCtxt* dict,
|
||||
char** XP_UNUSED_DBG(words), XP_U16 depth,
|
||||
const IndexData* data )
|
||||
{
|
||||
DictIter* iter = patsParamsToIter( params, dict );
|
||||
XP_U32 half = di_countWords( iter, NULL ) / 2;
|
||||
XP_U32 interval = half / 100;
|
||||
const XP_UCHAR* delim = params->dumpDelim; /* NULL is ok */
|
||||
if ( interval == 0 ) {
|
||||
++interval;
|
||||
}
|
||||
|
||||
XP_UCHAR buf[64];
|
||||
int ii, jj;
|
||||
for ( ii = 0, jj = half; ii < half; ii += interval, jj += interval ) {
|
||||
if ( di_getNthWord( &iter, ii, depth, data ) ) {
|
||||
di_wordToString( &iter, buf, VSIZE(buf), "." );
|
||||
if ( di_getNthWord( iter, NULL_XWE, ii, depth, data ) ) {
|
||||
XP_UCHAR buf[64];
|
||||
di_wordToString( iter, buf, VSIZE(buf), delim );
|
||||
XP_ASSERT( 0 == strcmp( buf, words[ii] ) );
|
||||
# ifdef PRINT_ALL
|
||||
XP_LOGF( "%s: word[%ld]: %s", __func__, ii, buf );
|
||||
XP_LOGFF( "word[%d]: %s", ii, buf );
|
||||
# endif
|
||||
} else {
|
||||
XP_ASSERT( 0 );
|
||||
}
|
||||
if ( di_getNthWord( &iter, jj, depth, data ) ) {
|
||||
di_wordToString( &iter, buf, VSIZE(buf), "." );
|
||||
if ( di_getNthWord( iter, NULL_XWE, jj, depth, data ) ) {
|
||||
di_wordToString( iter, buf, VSIZE(buf), delim );
|
||||
XP_ASSERT( 0 == strcmp( buf, words[jj] ) );
|
||||
# ifdef PRINT_ALL
|
||||
XP_LOGF( "%s: word[%ld]: %s", __func__, jj, buf );
|
||||
XP_LOGFF( "word[%d]: %s", jj, buf );
|
||||
# endif
|
||||
} else {
|
||||
XP_ASSERT( 0 );
|
||||
}
|
||||
}
|
||||
di_freeIter( iter, NULL_XWE );
|
||||
}
|
||||
|
||||
typedef struct _FTData {
|
||||
DictIter* iter;
|
||||
IndexData* data;
|
||||
|
@ -1975,72 +2026,71 @@ typedef struct _FTData {
|
|||
} FTData;
|
||||
|
||||
static XP_Bool
|
||||
onFoundTiles( void* closure, const Tile* tiles, int nTiles )
|
||||
onFoundTiles( void* XP_UNUSED(closure), const Tile* XP_UNUSED(tiles),
|
||||
int XP_UNUSED(nTiles) )
|
||||
{
|
||||
FTData* ftp = (FTData*)closure;
|
||||
XP_S16 lenMatched = di_findStartsWith( ftp->iter, tiles, nTiles );
|
||||
if ( 0 <= lenMatched ) {
|
||||
XP_UCHAR buf[32];
|
||||
XP_UCHAR bufPrev[32] = {0};
|
||||
di_wordToString( ftp->iter, buf, VSIZE(buf), "." );
|
||||
XP_LOGFF( "Not doing anything as di_findStartsWith is gone" );
|
||||
/* FTData* ftp = (FTData*)closure; */
|
||||
/* XP_S16 lenMatched = di_findStartsWith( ftp->iter, tiles, nTiles ); */
|
||||
/* if ( 0 <= lenMatched ) { */
|
||||
/* XP_UCHAR buf[32]; */
|
||||
/* XP_UCHAR bufPrev[32] = {0}; */
|
||||
/* di_wordToString( ftp->iter, buf, VSIZE(buf), "." ); */
|
||||
|
||||
/* This doesn't work with synonyms like "L-L" for "L·L" */
|
||||
// XP_ASSERT( 0 == strncasecmp( buf, prefix, lenMatched ) );
|
||||
/* /\* This doesn't work with synonyms like "L-L" for "L·L" *\/ */
|
||||
/* // XP_ASSERT( 0 == strncasecmp( buf, prefix, lenMatched ) ); */
|
||||
|
||||
DictPosition pos = di_getPosition( ftp->iter );
|
||||
XP_ASSERT( 0 == strcmp( buf, ftp->words[pos] ) );
|
||||
if ( pos > 0 ) {
|
||||
if ( !di_getNthWord( ftp->iter, pos-1, ftp->depth, ftp->data ) ) {
|
||||
XP_ASSERT( 0 );
|
||||
}
|
||||
di_wordToString( ftp->iter, bufPrev, VSIZE(bufPrev), "." );
|
||||
XP_ASSERT( 0 == strcmp( bufPrev, ftp->words[pos-1] ) );
|
||||
}
|
||||
XP_LOGF( "di_getStartsWith(%s) => %s (prev=%s)",
|
||||
ftp->prefix, buf, bufPrev );
|
||||
} else {
|
||||
XP_LOGFF( "nothing starts with %s", ftp->prefix );
|
||||
}
|
||||
/* DictPosition pos = di_getPosition( ftp->iter ); */
|
||||
/* XP_ASSERT( 0 == strcmp( buf, ftp->words[pos] ) ); */
|
||||
/* if ( pos > 0 ) { */
|
||||
/* if ( !di_getNthWord( ftp->iter, pos-1, ftp->depth, ftp->data ) ) { */
|
||||
/* XP_ASSERT( 0 ); */
|
||||
/* } */
|
||||
/* di_wordToString( ftp->iter, bufPrev, VSIZE(bufPrev), "." ); */
|
||||
/* XP_ASSERT( 0 == strcmp( bufPrev, ftp->words[pos-1] ) ); */
|
||||
/* } */
|
||||
/* XP_LOGF( "di_getStartsWith(%s) => %s (prev=%s)", */
|
||||
/* ftp->prefix, buf, bufPrev ); */
|
||||
/* } else { */
|
||||
/* XP_LOGFF( "nothing starts with %s", ftp->prefix ); */
|
||||
/* } */
|
||||
return XP_TRUE;
|
||||
}
|
||||
|
||||
/** walk_dict_test()
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
static void
|
||||
walk_dict_test( MPFORMAL const DictionaryCtxt* dict,
|
||||
GSList* testPrefixes, const char* testMinMax )
|
||||
walk_dict_test( MPFORMAL const LaunchParams* params, const DictionaryCtxt* dict,
|
||||
GSList* testPrefixes )
|
||||
{
|
||||
/* 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. */
|
||||
DictIter iter;
|
||||
long jj;
|
||||
XP_Bool gotOne;
|
||||
|
||||
XP_U16 min, max;
|
||||
if ( !testMinMax || !parsePair( testMinMax, &min, &max ) ) {
|
||||
min = 0;
|
||||
max = MAX_COLS_DICT;
|
||||
}
|
||||
|
||||
di_initIter( &iter, dict, min, max );
|
||||
DictIter* iter = patsParamsToIter( params, dict );
|
||||
LengthsArray lens;
|
||||
XP_U32 count = di_countWords( &iter, &lens );
|
||||
XP_U32 count = di_countWords( iter, &lens );
|
||||
|
||||
XP_U32 sum = 0;
|
||||
for ( jj = 0; jj < VSIZE(lens.lens); ++jj ) {
|
||||
sum += lens.lens[jj];
|
||||
XP_LOGF( "%d words of length %ld", lens.lens[jj], jj );
|
||||
for ( long ii = 0; ii < VSIZE(lens.lens); ++ii ) {
|
||||
XP_LOGF( "%d words of length %ld", lens.lens[ii], ii );
|
||||
sum += lens.lens[ii];
|
||||
}
|
||||
XP_ASSERT( sum == count );
|
||||
|
||||
if ( count > 0 ) {
|
||||
const XP_UCHAR* delim = params->dumpDelim;
|
||||
XP_Bool gotOne;
|
||||
long jj;
|
||||
char** words = g_malloc( count * sizeof(char*) );
|
||||
XP_ASSERT( !!words );
|
||||
|
||||
for ( jj = 0, gotOne = di_firstWord( &iter );
|
||||
for ( jj = 0, gotOne = di_firstWord( iter );
|
||||
gotOne;
|
||||
gotOne = di_getNextWord( &iter ) ) {
|
||||
XP_ASSERT( di_getPosition( &iter ) == jj );
|
||||
gotOne = di_getNextWord( iter ) ) {
|
||||
XP_ASSERT( di_getPosition( iter ) == jj );
|
||||
XP_UCHAR buf[64];
|
||||
di_wordToString( &iter, buf, VSIZE(buf), "." );
|
||||
di_wordToString( iter, buf, VSIZE(buf), delim );
|
||||
# ifdef PRINT_ALL
|
||||
fprintf( stderr, "%.6ld: %s\n", jj, buf );
|
||||
# endif
|
||||
|
@ -2051,12 +2101,13 @@ walk_dict_test( MPFORMAL const DictionaryCtxt* dict,
|
|||
}
|
||||
XP_ASSERT( count == jj );
|
||||
|
||||
for ( jj = 0, gotOne = di_lastWord( &iter );
|
||||
XP_LOGFF( "comparing runs in both directions" );
|
||||
for ( jj = 0, gotOne = di_lastWord( iter );
|
||||
gotOne;
|
||||
++jj, gotOne = di_getPrevWord( &iter ) ) {
|
||||
XP_ASSERT( di_getPosition(&iter) == count-jj-1 );
|
||||
++jj, gotOne = di_getPrevWord( iter ) ) {
|
||||
XP_ASSERT( di_getPosition(iter) == count-jj-1 );
|
||||
XP_UCHAR buf[64];
|
||||
di_wordToString( &iter, buf, VSIZE(buf), "." );
|
||||
di_wordToString( iter, buf, VSIZE(buf), delim );
|
||||
# ifdef PRINT_ALL
|
||||
fprintf( stderr, "%.6ld: %s\n", jj, buf );
|
||||
# endif
|
||||
|
@ -2069,24 +2120,26 @@ walk_dict_test( MPFORMAL const DictionaryCtxt* dict,
|
|||
}
|
||||
}
|
||||
XP_ASSERT( count == jj );
|
||||
XP_LOGF( "finished comparing runs in both directions" );
|
||||
XP_LOGFF( "FINISHED comparing runs in both directions" );
|
||||
|
||||
XP_LOGF( "testing getNth" );
|
||||
testGetNthWord( dict, words, 0, NULL, min, max );
|
||||
XP_LOGFF( "testing getNth" );
|
||||
testGetNthWord( params, dict, words, 0, NULL );
|
||||
XP_LOGFF( "FINISHED testing getNth" );
|
||||
|
||||
XP_U16 depth = 2;
|
||||
XP_U16 maxCount = dict_numTileFaces( dict );
|
||||
IndexData data;
|
||||
data.count = maxCount * maxCount;
|
||||
data.count = maxCount * maxCount; /* squared because depth == 2! */
|
||||
data.indices = XP_MALLOC( mpool,
|
||||
data.count * depth * sizeof(data.indices[0]) );
|
||||
data.prefixes = XP_MALLOC( mpool,
|
||||
depth * data.count * sizeof(data.prefixes[0]) );
|
||||
|
||||
XP_LOGF( "making index..." );
|
||||
di_makeIndex( &iter, depth, &data );
|
||||
XP_LOGF( "DONE making index" );
|
||||
di_makeIndex( iter, depth, &data );
|
||||
XP_LOGF( "DONE making index (have %d indices)", data.count );
|
||||
|
||||
/* Resize 'em in case not all slots filled */
|
||||
data.indices = XP_REALLOC( mpool, data.indices,
|
||||
data.count * depth * sizeof(*data.indices) );
|
||||
data.prefixes = XP_REALLOC( mpool, data.prefixes,
|
||||
|
@ -2098,10 +2151,10 @@ walk_dict_test( MPFORMAL const DictionaryCtxt* dict,
|
|||
}
|
||||
XP_ASSERT( word.index == indices[ii] );
|
||||
XP_UCHAR buf1[64];
|
||||
dict_wordToString( dict, &word, buf1, VSIZE(buf1), "." );
|
||||
dict_wordToString( dict, &word, buf1, VSIZE(buf1), delim );
|
||||
XP_UCHAR buf2[64] = {0};
|
||||
if ( ii > 0 && dict_getNthWord( dict, &word, indices[ii]-1 ) ) {
|
||||
dict_wordToString( dict, &word, buf2, VSIZE(buf2), "." );
|
||||
dict_wordToString( dict, &word, buf2, VSIZE(buf2), delim );
|
||||
}
|
||||
char prfx[8];
|
||||
dict_tilesToString( dict, &prefixes[depth*ii], depth, prfx,
|
||||
|
@ -2112,7 +2165,8 @@ walk_dict_test( MPFORMAL const DictionaryCtxt* dict,
|
|||
#endif
|
||||
|
||||
XP_LOGFF( "testing getNth WITH INDEXING" );
|
||||
testGetNthWord( dict, words, depth, &data, min, max );
|
||||
testGetNthWord( params, dict, words, depth, &data );
|
||||
XP_LOGFF( "DONE testing getNth WITH INDEXING" );
|
||||
|
||||
if ( !!testPrefixes ) {
|
||||
int ii;
|
||||
|
@ -2121,21 +2175,22 @@ walk_dict_test( MPFORMAL const DictionaryCtxt* dict,
|
|||
gchar* prefix = (gchar*)g_slist_nth_data( testPrefixes, ii );
|
||||
XP_LOGFF( "prefix %d: %s", ii, prefix );
|
||||
|
||||
FTData foundTilesData = { .iter = &iter, .words = words,
|
||||
FTData foundTilesData = { .iter = iter, .words = words,
|
||||
.depth = depth, .data = &data,
|
||||
.prefix = prefix, };
|
||||
dict_tilesForString( dict, prefix, onFoundTiles, &foundTilesData );
|
||||
dict_tilesForString( dict, prefix, 0, onFoundTiles, &foundTilesData );
|
||||
}
|
||||
}
|
||||
XP_FREE( mpool, data.indices );
|
||||
XP_FREE( mpool, data.prefixes );
|
||||
}
|
||||
di_freeIter( iter, NULL_XWE );
|
||||
XP_LOGF( "done" );
|
||||
}
|
||||
|
||||
static void
|
||||
walk_dict_test_all( MPFORMAL const LaunchParams* params, GSList* testDicts,
|
||||
GSList* testPrefixes, const char* testMinMax )
|
||||
GSList* testPrefixes )
|
||||
{
|
||||
int ii;
|
||||
guint count = g_slist_length( testDicts );
|
||||
|
@ -2146,7 +2201,7 @@ walk_dict_test_all( MPFORMAL const LaunchParams* params, GSList* testDicts,
|
|||
params->useMmap );
|
||||
if ( NULL != dict ) {
|
||||
XP_LOGF( "walk_dict_test(%s)", name );
|
||||
walk_dict_test( MPPARM(mpool) dict, testPrefixes, testMinMax );
|
||||
walk_dict_test( MPPARM(mpool) params, dict, testPrefixes );
|
||||
dict_unref( dict, NULL_XWE );
|
||||
}
|
||||
}
|
||||
|
@ -2154,17 +2209,18 @@ walk_dict_test_all( MPFORMAL const LaunchParams* params, GSList* testDicts,
|
|||
#endif
|
||||
|
||||
static void
|
||||
dumpDict( DictionaryCtxt* dict )
|
||||
dumpDict( const LaunchParams* params, DictionaryCtxt* dict )
|
||||
{
|
||||
DictIter iter;
|
||||
di_initIter( &iter, dict, 0, MAX_COLS_DICT );
|
||||
for ( XP_Bool result = di_firstWord( &iter );
|
||||
DictIter* iter = patsParamsToIter( params, dict );
|
||||
const XP_UCHAR* delim = params->dumpDelim; /* NULL is ok */
|
||||
for ( XP_Bool result = di_firstWord( iter );
|
||||
result;
|
||||
result = di_getNextWord( &iter ) ) {
|
||||
result = di_getNextWord( iter ) ) {
|
||||
XP_UCHAR buf[32];
|
||||
di_wordToString( &iter, buf, VSIZE(buf), "." );
|
||||
di_wordToString( iter, buf, VSIZE(buf), delim );
|
||||
fprintf( stdout, "%s\n", buf );
|
||||
}
|
||||
di_freeIter( iter, NULL_XWE );
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -2545,13 +2601,36 @@ dawg2dict( const LaunchParams* params, GSList* testDicts )
|
|||
g_slist_nth_data( testDicts, ii ),
|
||||
params->useMmap );
|
||||
if ( NULL != dict ) {
|
||||
dumpDict( dict );
|
||||
dumpDict( params, dict );
|
||||
dict_unref( dict, NULL_XWE );
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef XWFEATURE_TESTPATSTR
|
||||
static int
|
||||
testOneString( const LaunchParams* params, GSList* testDicts )
|
||||
{
|
||||
int result = 0;
|
||||
guint count = g_slist_length( testDicts );
|
||||
for ( int ii = 0; 0 == result && ii < count; ++ii ) {
|
||||
DictionaryCtxt* dict =
|
||||
linux_dictionary_make( MPPARM(params->mpool) NULL_XWE, params,
|
||||
g_slist_nth_data( testDicts, ii ),
|
||||
params->useMmap );
|
||||
if ( NULL != dict ) {
|
||||
DictIter* iter = patsParamsToIter( params, dict );
|
||||
if ( ! di_stringMatches( iter, params->iterTestPatStr ) ) {
|
||||
result = 1;
|
||||
}
|
||||
di_freeIter( iter, NULL_XWE );
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
main( int argc, char** argv )
|
||||
{
|
||||
|
@ -2570,7 +2649,6 @@ main( int argc, char** argv )
|
|||
#ifdef XWFEATURE_WALKDICT
|
||||
GSList* testDicts = NULL;
|
||||
GSList* testPrefixes = NULL;
|
||||
char* testMinMax = NULL;
|
||||
#endif
|
||||
char dictbuf[256];
|
||||
char* dict;
|
||||
|
@ -2730,7 +2808,18 @@ main( int argc, char** argv )
|
|||
testPrefixes = g_slist_prepend( testPrefixes, g_strdup(optarg) );
|
||||
break;
|
||||
case CMD_TESTMINMAX:
|
||||
testMinMax = optarg;
|
||||
mainParams.testMinMax = optarg;
|
||||
break;
|
||||
#endif
|
||||
case CMD_DELIM:
|
||||
mainParams.dumpDelim = optarg;
|
||||
break;
|
||||
#ifdef XWFEATURE_TESTPATSTR
|
||||
case CMD_TESTPAT:
|
||||
mainParams.iterTestPats = g_slist_append( mainParams.iterTestPats, optarg );
|
||||
break;
|
||||
case CMD_TESTSTR:
|
||||
mainParams.iterTestPatStr = optarg;
|
||||
break;
|
||||
#endif
|
||||
case CMD_DICTDIR:
|
||||
|
@ -3104,18 +3193,22 @@ main( int argc, char** argv )
|
|||
}
|
||||
}
|
||||
|
||||
/* add cur dir if dict search dir path is empty */
|
||||
if ( !mainParams.dictDirs ) {
|
||||
mainParams.dictDirs = g_slist_append( mainParams.dictDirs, "./" );
|
||||
}
|
||||
|
||||
int result = 0;
|
||||
if ( g_str_has_suffix( argv[0], "dawg2dict" ) ) {
|
||||
result = dawg2dict( &mainParams, testDicts );
|
||||
#ifdef XWFEATURE_TESTPATSTR
|
||||
} else if ( !!mainParams.iterTestPatStr ) {
|
||||
result = testOneString( &mainParams, testDicts );
|
||||
#endif
|
||||
} else {
|
||||
XP_ASSERT( mainParams.pgi.nPlayers == mainParams.nLocalPlayers
|
||||
+ mainParams.info.serverInfo.nRemotePlayers );
|
||||
|
||||
/* add cur dir if dict search dir path is empty */
|
||||
if ( !mainParams.dictDirs ) {
|
||||
mainParams.dictDirs = g_slist_append( mainParams.dictDirs, "./" );
|
||||
}
|
||||
|
||||
if ( mainParams.info.serverInfo.nRemotePlayers == 0 ) {
|
||||
mainParams.pgi.serverRole = SERVER_STANDALONE;
|
||||
} else if ( isServer ) {
|
||||
|
@ -3199,8 +3292,7 @@ main( int argc, char** argv )
|
|||
/* } */
|
||||
#ifdef XWFEATURE_WALKDICT
|
||||
if ( !!testDicts ) {
|
||||
walk_dict_test_all( MPPARM(mainParams.mpool) &mainParams, testDicts,
|
||||
testPrefixes, testMinMax );
|
||||
walk_dict_test_all( MPPARM(mainParams.mpool) &mainParams, testDicts, testPrefixes );
|
||||
exit( 0 );
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -140,6 +140,18 @@ typedef struct _LaunchParams {
|
|||
|
||||
DeviceRole serverRole;
|
||||
|
||||
const XP_UCHAR* testMinMax;
|
||||
const XP_UCHAR* dumpDelim;
|
||||
|
||||
GSList* iterTestPats;
|
||||
/* These three aren't used yet */
|
||||
const XP_UCHAR* patStartW;
|
||||
const XP_UCHAR* patContains;
|
||||
const XP_UCHAR* patEndsW;
|
||||
#ifdef XWFEATURE_TESTPATSTR
|
||||
const XP_UCHAR* iterTestPatStr;
|
||||
#endif
|
||||
|
||||
CommsAddrRec addr;
|
||||
struct {
|
||||
XP_U16 inviteeCounts[MAX_NUM_PLAYERS];
|
||||
|
|
|
@ -57,7 +57,7 @@ loadClientID( LaunchParams* params, MQTTConStorage* storage )
|
|||
}
|
||||
|
||||
static void
|
||||
onMessageReceived( struct mosquitto *mosq, void *userdata,
|
||||
onMessageReceived( struct mosquitto* XP_UNUSED_DBG(mosq), void *userdata,
|
||||
const struct mosquitto_message* message )
|
||||
{
|
||||
XP_LOGFF( "(len=%d)", message->payloadlen );
|
||||
|
@ -74,7 +74,7 @@ onMessageReceived( struct mosquitto *mosq, void *userdata,
|
|||
}
|
||||
|
||||
static void
|
||||
connect_callback( struct mosquitto *mosq, void *userdata, int err )
|
||||
connect_callback( struct mosquitto *mosq, void *userdata, int XP_UNUSED_DBG(err) )
|
||||
{
|
||||
XP_LOGFF( "(err=%s)", mosquitto_strerror(err) );
|
||||
XP_USE(mosq);
|
||||
|
@ -104,7 +104,8 @@ subscribe_callback( struct mosquitto *mosq, void *userdata, int mid,
|
|||
}
|
||||
|
||||
static void
|
||||
log_callback( struct mosquitto *mosq, void *userdata, int level, const char *str )
|
||||
log_callback( struct mosquitto *mosq, void *userdata, int level,
|
||||
const char* XP_UNUSED_DBG(str) )
|
||||
{
|
||||
XP_USE(mosq);
|
||||
XP_USE(userdata);
|
||||
|
@ -122,11 +123,17 @@ handle_gotmsg( GIOChannel* source, GIOCondition XP_UNUSED(condition), gpointer d
|
|||
int pipe = g_io_channel_unix_get_fd( source );
|
||||
XP_ASSERT( pipe == storage->msgPipe[0] );
|
||||
short len;
|
||||
ssize_t nRead = read( pipe, &len, sizeof(len) );
|
||||
#ifdef DEBUG
|
||||
ssize_t nRead =
|
||||
#endif
|
||||
read( pipe, &len, sizeof(len) );
|
||||
XP_ASSERT( nRead == sizeof(len) );
|
||||
len = ntohs(len);
|
||||
XP_U8 buf[len];
|
||||
nRead = read( pipe, buf, len );
|
||||
#ifdef DEBUG
|
||||
nRead =
|
||||
#endif
|
||||
read( pipe, buf, len );
|
||||
XP_ASSERT( nRead == len );
|
||||
|
||||
dvc_parseMQTTPacket( storage->params->dutil, NULL_XWE, buf, len );
|
||||
|
@ -167,8 +174,10 @@ mqttc_init( LaunchParams* params )
|
|||
storage->params = params;
|
||||
|
||||
loadClientID( params, storage );
|
||||
|
||||
int res = pipe( storage->msgPipe );
|
||||
#ifdef DEBUG
|
||||
int res =
|
||||
#endif
|
||||
pipe( storage->msgPipe );
|
||||
XP_ASSERT( !res );
|
||||
ADD_SOCKET( storage, storage->msgPipe[0], handle_gotmsg );
|
||||
|
||||
|
@ -209,8 +218,10 @@ void
|
|||
mqttc_cleanup( LaunchParams* params )
|
||||
{
|
||||
MQTTConStorage* storage = getStorage( params );
|
||||
|
||||
int err = mosquitto_loop_stop( storage->mosq, true ); /* blocks until thread dies */
|
||||
#ifdef DEBUG
|
||||
int err =
|
||||
#endif
|
||||
mosquitto_loop_stop( storage->mosq, true ); /* blocks until thread dies */
|
||||
XP_LOGFF( "mosquitto_loop_stop() => %s", mosquitto_strerror(err) );
|
||||
mosquitto_destroy( storage->mosq );
|
||||
storage->mosq = NULL;
|
||||
|
@ -239,9 +250,11 @@ void
|
|||
mqttc_invite( LaunchParams* params, NetLaunchInfo* nli, const MQTTDevID* invitee )
|
||||
{
|
||||
MQTTConStorage* storage = getStorage( params );
|
||||
#ifdef DEBUG
|
||||
gchar buf[32];
|
||||
XP_LOGFF( "need to send to %s", formatMQTTDevID(invitee, buf, sizeof(buf) ) );
|
||||
XP_ASSERT( 16 == strlen(buf) );
|
||||
#endif
|
||||
|
||||
XWStreamCtxt* stream = mem_stream_make_raw( MPPARM(params->mpool)
|
||||
params->vtMgr );
|
||||
|
|
92
xwords4/linux/scripts/regex-test.py
Executable file
92
xwords4/linux/scripts/regex-test.py
Executable file
|
@ -0,0 +1,92 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import argparse, subprocess
|
||||
|
||||
g_pairs = [
|
||||
(['_*ING'], [('RINGER', False)]),
|
||||
(['_{2}ING'], [('RING', False), ('DOING', True), ('SPRING', False)]),
|
||||
(['_{2}'], [('DO', True)]),
|
||||
(['D_{1,2}'], [('DOG', True), ('DO', True), ('D', False)]),
|
||||
(['A_*'], [('ABLE', True), ('BALL', False),]),
|
||||
(['B_*'], [('BALL', True), ('APPLE', False), ('CAT', False),],),
|
||||
(['ABC'], [('ABC', True), ('CBA', False)]),
|
||||
(['_*'], [('ABC', True)]),
|
||||
(['_*Z'], [('ABC', False), ('AB', False)]),
|
||||
(['_*C'], [('ABC', True)]),
|
||||
(['_*B'], [('AB', True)]),
|
||||
(['B_*'], [('AB', False), ('BA', True)]),
|
||||
|
||||
(['A*'], [('A', True)]),
|
||||
(['A*A*'], [('A', True), ('AA', True), ('AAA', True), ('AAAA', True), ('AABA', False)]),
|
||||
(['A*A*B'], [('B', True), ('C', False)]),
|
||||
|
||||
(['A{3}'], [('AAA', True)]),
|
||||
(['A{1}A{1}A{1}'], [('AAA', True),('AA', False),('AAAA', False)]),
|
||||
(['A*A*A*'], [('A', True),('AA', True),('AAA', True),('AAAA', True), ('ABAA', False)]),
|
||||
|
||||
(['AB*'], [('A', True)]),
|
||||
|
||||
(['A{2,4}'], [('A', False), ('AA', True), ('AAAA', True), ('AAAAA', False)]),
|
||||
(['_*ING'], [('RINGER', False)]),
|
||||
(['R_*'], [('RINGER', True)]),
|
||||
(['R_*', '_*ING'], [('RING', True), ('ROLLING', True), ('SPRING', False), ('INGER', False), ('RINGER', False)]),
|
||||
(['A', '_*'], [('ABC', False), ('CBA', False), ('A', True)]),
|
||||
(['ABC', '_*'], [('ABC', True)]),
|
||||
|
||||
(['[ABC]{3}'], [('ABC', True), ('CBA', True), ('AAA', True), ('BBB', True)]),
|
||||
(['[+ABC]{3}'], [('ABC', True), ('CBA', True), ('AAA', False), ('AA', False), ]),
|
||||
(['[+ABC]{3}_*'], [('ABC', True), ('CBA', True), ('AAA', False), ('AA', False), ]),
|
||||
(['AA[+ABC]{3}ZZ'], [('AAABCZZ', True), ('AACBAZZ', True), ('AAAAAZZ', False), ]),
|
||||
|
||||
(['[+AAB]{3}'], [('AAB', True), ('ABA', True), ('ABB', False), ('AB', False),
|
||||
('ABBA', False),]),
|
||||
(['[+AB_]{3}'], [('AAB', True), ('ABA', True), ('ABB', True), ('ABC', True),
|
||||
('AB', False), ('ABBA', False),]),
|
||||
(['[+_AB]{3}'], [('AAB', True), ('ABA', True), ('ABB', True), ('ABC', True),
|
||||
('AB', False), ('ABBA', False),]),
|
||||
]
|
||||
|
||||
g_dict = '../android/app/src/main/assets/BasEnglish2to8.xwd'
|
||||
|
||||
def doTest( pats, pair, stderr ):
|
||||
# print('pair: {}'.format(pair))
|
||||
(word, expect) = pair
|
||||
args = ['./obj_linux_memdbg/xwords', '--test-dict', g_dict, '--test-string', word ]
|
||||
for pat in pats:
|
||||
args += ['--test-pat', pat]
|
||||
result = subprocess.run(args, stderr=stderr)
|
||||
passed = (0 == result.returncode) == expect
|
||||
return passed
|
||||
|
||||
def main():
|
||||
stderr = subprocess.DEVNULL
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--with-stderr', dest = 'STDERR', action = 'store_true',
|
||||
help = 'don\'t discard stderr')
|
||||
parser.add_argument('--do-only', dest = 'SPECIFIED', type = int, action = 'append',
|
||||
help = 'do this test case only')
|
||||
parser.add_argument('--show-all', dest = 'PRINT_ALL', action = 'store_true', default = False,
|
||||
help = 'print successes in addition to failures')
|
||||
|
||||
args = parser.parse_args()
|
||||
if args.STDERR: stderr = None
|
||||
|
||||
ii = 0
|
||||
counts = { False: 0, True: 0 }
|
||||
for cases in g_pairs:
|
||||
(pats, rest) = cases
|
||||
for one in rest:
|
||||
if not args.SPECIFIED or ii in args.SPECIFIED:
|
||||
success = doTest(pats, one, stderr)
|
||||
note = success and 'passed' or 'FAILED'
|
||||
if args.PRINT_ALL or not success:
|
||||
print( '{:2d} {}: {} {}'.format(ii, note, pats, one))
|
||||
counts[success] += 1
|
||||
ii += 1
|
||||
|
||||
print('Successes: {}'.format(counts[True]))
|
||||
print('Failures: {}'.format(counts[False]))
|
||||
|
||||
##############################################################################
|
||||
if __name__ == '__main__':
|
||||
main()
|
Loading…
Reference in a new issue