Merge branch 'android_branch' into send_in_background

Conflicts:
	xwords4/linux/linuxutl.h
This commit is contained in:
Andy2 2011-11-21 22:18:52 -08:00
commit d37424ad7f
96 changed files with 1293 additions and 573 deletions

View file

@ -1,15 +1,19 @@
Here's how I'm building crosswords for Android.
First, my working directory is XWords within this (android/)
directory. And note that local.properties, also there, needs to be
edited so that sdk.dir points to where your sdk is installed.
First, the build process requires a file called local.properties that
must be generated locally. Generate it before your first build by
running ./scripts/setup_local_props.sh.
The working directory is XWords4 within this (android/) directory.
Run the following commands from there.
Build the jni library (the cross-platform code):
# ../scripts/ndkbuild.sh
Then build the app for the emulator
# ant install
Then build the app for the emulator (assuming it's running)
# ant debug install
Build for a device (requires you've set up your keys. I did this too
long ago to remember how but the info's easy to find):
# ant release
(The above command not yet verified for new SDK I installed on 11/19/11)

View file

@ -2,69 +2,86 @@
<project name="XWords4" default="release">
<!-- The local.properties file is created and updated by the 'android' tool.
It contains the path to the SDK. It should *NOT* be checked in in Version
Control Systems. -->
<exec dir=".." executable="./scripts/setup_local_props.sh" output="ant_out.txt" />
<property file="local.properties" />
It contains the path to the SDK. It should *NOT* be checked into
Version Control Systems. -->
<loadproperties srcFile="local.properties" />
<!-- The build.properties file can be created by you and is never touched
by the 'android' tool. This is the place to change some of the default property values
used by the Ant rules.
<!-- The ant.properties file can be created by you. It is only edited by the
'android' tool to add properties to it.
This is the place to change some Ant specific build properties.
Here are some properties you may want to change/update:
application.package
the name of your application package as defined in the manifest. Used by the
'uninstall' rule.
source.dir
the name of the source directory. Default is 'src'.
The name of the source directory. Default is 'src'.
out.dir
the name of the output directory. Default is 'bin'.
The name of the output directory. Default is 'bin'.
Properties related to the SDK location or the project target should be updated
using the 'android' tool with the 'update' action.
For other overridable properties, look at the beginning of the rules
files in the SDK, at tools/ant/build.xml
This file is an integral part of the build system for your application and
should be checked in in Version Control Systems.
Properties related to the SDK location or the project target should
be updated using the 'android' tool with the 'update' action.
This file is an integral part of the build system for your
application and should be checked into Version Control Systems.
-->
<property file="build.properties" />
<property file="ant.properties" />
<!-- The default.properties file is created and updated by the 'android' tool, as well
as ADT.
This file is an integral part of the build system for your application and
should be checked in in Version Control Systems. -->
<property file="default.properties" />
<!-- The project.properties file is created and updated by the 'android'
tool, as well as ADT.
<!-- Custom Android task to deal with the project target, and import the proper rules.
This requires ant 1.6.0 or above. -->
<path id="android.antlibs">
<pathelement path="${sdk.dir}/tools/lib/anttasks.jar" />
<pathelement path="${sdk.dir}/tools/lib/sdklib.jar" />
<pathelement path="${sdk.dir}/tools/lib/androidprefs.jar" />
<pathelement path="${sdk.dir}/tools/lib/apkbuilder.jar" />
<pathelement path="${sdk.dir}/tools/lib/jarutils.jar" />
</path>
This contains project specific properties such as project target, and library
dependencies. Lower level build properties are stored in ant.properties
(or in .classpath for Eclipse projects).
<taskdef name="setup"
classname="com.android.ant.SetupTask"
classpathref="android.antlibs" />
This file is an integral part of the build system for your
application and should be checked into Version Control Systems. -->
<loadproperties srcFile="project.properties" />
<exec dir=".." executable="./scripts/genvers.sh" output="ant_out.txt" />
<!-- quick check on sdk.dir -->
<fail
message="sdk.dir is missing. Make sure to generate local.properties using 'android update project'"
unless="sdk.dir"
/>
<!-- Execute the Android Setup task that will setup some properties specific to the target,
and import the build rules files.
The rules file is imported from
<SDK>/platforms/<target_platform>/templates/android_rules.xml
<!-- extension targets. Uncomment the ones where you want to do custom work
in between standard targets -->
To customize some build steps for your project:
- copy the content of the main node <project> from android_rules.xml
- paste it in this build.xml below the <setup /> task.
- disable the import by changing the setup task below to <setup import="false" />
<target name="-pre-build">
<exec dir=".." executable="./scripts/genvers.sh" output="ant_out.txt" />
</target>
<!--
<target name="-pre-compile">
</target>
This will ensure that the properties are setup correctly but that your customized
build steps are used.
/* This is typically used for code obfuscation.
Compiled code location: ${out.classes.absolute.dir}
If this is not done in place, override ${out.dex.input.absolute.dir} */
<target name="-post-compile">
</target>
-->
<!-- Import the actual build file.
To customize existing targets, there are two options:
- Customize only one target:
- copy/paste the target into this file, *before* the
<import> task.
- customize it to your needs.
- Customize the whole content of build.xml
- copy/paste the content of the rules files (minus the top node)
into this file, replacing the <import> task.
- customize to your needs.
***********************
****** IMPORTANT ******
***********************
In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
in order to avoid having your file be overridden by tools such as "android update project"
-->
<setup />
<!-- version-tag: 1 -->
<import file="${sdk.dir}/tools/ant/build.xml" />
</project>

View file

@ -1,14 +0,0 @@
# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system use,
# "build.properties", and override values to adapt the script to your
# project structure.
# Indicates whether an apk should be generated for each density.
split.density=false
# Project target. 4 == 1.6, but I need that for the SMS APIs. Later
# set it back to android-3 and figure out how to gracefully degrade.
target=android-4

View file

@ -26,12 +26,14 @@ local_DEFINES += \
-DDISABLE_TILE_SEL \
-DXWFEATURE_BOARDWORDS \
-DXWFEATURE_WALKDICT \
-DXWFEATURE_WALKDICT_FILTER \
-DXWFEATURE_DICTSANITY \
-DFEATURE_TRAY_EDIT \
-DNODE_CAN_4 \
-DRELAY_ROOM_DEFAULT=\"\"\
-D__LITTLE_ENDIAN \
local_SRC_FILES += \
xwjni.c \
utilwrapper.c \

View file

@ -1,7 +1,7 @@
/* -*-mode: C; compile-command: "../../scripts/ndkbuild.sh"; -*- */
/* -*- compile-command: "../../scripts/ndkbuild.sh"; -*- */
/*
* Copyright © 2009-2010 by Eric House (xwords@eehouse.org). All
* rights reserved.
* Copyright © 2009 - 2011 by Eric House (xwords@eehouse.org). All rights
* reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@ -45,7 +45,7 @@ typedef struct _AndDictionaryCtxt {
} AndDictionaryCtxt;
#define CHECK_PTR(p,c,e) \
if ( ((p)+(c)) >= (e) ) { \
if ( ((p)+(c)) > (e) ) { \
XP_LOGF( "%s (line %d); out of bytes", __func__, __LINE__ ); \
goto error; \
}
@ -568,14 +568,15 @@ makeDict( MPFORMAL JNIEnv *env, JNIUtilCtxt* jniutil, jstring jname,
XP_U32 numEdges;
XP_Bool parses = parseDict( anddict, (XP_U8*)anddict->bytes,
bytesSize, &numEdges );
if ( !parses || (check && !checkSanity( &anddict->super, numEdges ) ) ) {
if ( !parses || (check && !checkSanity( &anddict->super,
numEdges ) ) ) {
and_dictionary_destroy( (DictionaryCtxt*)anddict );
anddict = NULL;
}
}
return (DictionaryCtxt*)anddict;
}
} /* makeDict */
void
destroyDicts( PlayerDicts* dicts )

View file

@ -77,10 +77,11 @@ and_util_makeStreamFromAddr( XW_UtilCtxt* uc, XP_PlayerAddr channelNo )
}
static XWBonusType and_util_getSquareBonus( XW_UtilCtxt* XP_UNUSED(uc),
const ModelCtxt* XP_UNUSED(model),
XP_U16 boardSize,
XP_U16 col, XP_U16 row )
{
static const int s_buttsBoard[8][8] = {
#define BONUS_DIM 8
static const int s_buttsBoard[BONUS_DIM][BONUS_DIM] = {
{ BONUS_TRIPLE_WORD, BONUS_NONE, BONUS_NONE,BONUS_DOUBLE_LETTER,BONUS_NONE,BONUS_NONE,BONUS_NONE,BONUS_TRIPLE_WORD },
{ BONUS_NONE, BONUS_DOUBLE_WORD, BONUS_NONE,BONUS_NONE,BONUS_NONE,BONUS_TRIPLE_LETTER,BONUS_NONE,BONUS_NONE },
@ -94,10 +95,12 @@ static XWBonusType and_util_getSquareBonus( XW_UtilCtxt* XP_UNUSED(uc),
{ BONUS_TRIPLE_WORD, BONUS_NONE, BONUS_NONE,BONUS_DOUBLE_LETTER,BONUS_NONE,BONUS_NONE,BONUS_NONE,BONUS_DOUBLE_WORD },
}; /* buttsBoard */
int half = 15 / 2; /* remove 15!!!! PENDING */
int half = boardSize / 2;
if ( col > half ) { col = (half*2) - col; }
if ( row > half ) { row = (half*2) - row; }
XP_ASSERT( col < BONUS_DIM && row < BONUS_DIM );
return s_buttsBoard[row][col];
#undef BONUS_DIM
}
static void

View file

@ -1310,13 +1310,11 @@ Java_org_eehouse_android_xw4_jni_XwJNI_dict_1iter_1init
data->vtMgr = make_vtablemgr( MPPARM_NOCOMMA(mpool) );
data->jniutil = jniutil;
data->dict = dict;
data->depth = 2;
#ifdef MEM_DEBUG
data->mpool = mpool;
#endif
closure = (int)data;
dict_initIter( data->dict, &data->iter );
(void)dict_firstWord( &data->iter );
} else {
destroyJNIUtil( &jniutil );
XP_FREE( mpool, data );
@ -1327,6 +1325,63 @@ Java_org_eehouse_android_xw4_jni_XwJNI_dict_1iter_1init
return closure;
}
static void
freeIndices( DictIterData* data )
{
IndexData* idata = &data->idata;
if ( !!idata->prefixes ) {
XP_FREE( data->mpool, idata->prefixes );
idata->prefixes = NULL;
}
if( !!idata->indices ) {
XP_FREE( data->mpool, idata->indices );
idata->indices = NULL;
}
}
static void
makeIndex( DictIterData* data )
{
XP_U16 nFaces = dict_numTileFaces( data->dict );
XP_U16 ii;
XP_U16 count;
for ( count = 1, ii = 0; ii < data->depth; ++ii ) {
count *= nFaces;
}
freeIndices( data );
IndexData* idata = &data->idata;
idata->prefixes = XP_MALLOC( data->mpool, count * data->depth
* sizeof(*idata->prefixes) );
idata->indices = XP_MALLOC( data->mpool,
count * sizeof(*idata->indices) );
idata->count = count;
dict_makeIndex( &data->iter, data->depth, idata );
if ( 0 < idata->count ) {
idata->prefixes = XP_REALLOC( data->mpool, idata->prefixes,
idata->count * data->depth *
sizeof(*idata->prefixes) );
idata->indices = XP_REALLOC( data->mpool, idata->indices,
idata->count * sizeof(*idata->indices) );
} else {
freeIndices( data );
}
} /* makeIndex */
JNIEXPORT void JNICALL
Java_org_eehouse_android_xw4_jni_XwJNI_dict_1iter_1setMinMax
( JNIEnv* env, jclass C, jint closure, jint min, jint max )
{
DictIterData* data = (DictIterData*)closure;
if ( NULL != data ) {
dict_initIter( &data->iter, data->dict, min, max );
makeIndex( data );
(void)dict_firstWord( &data->iter );
}
}
JNIEXPORT void JNICALL
Java_org_eehouse_android_xw4_jni_XwJNI_dict_1iter_1destroy
( JNIEnv* env, jclass C, jint closure )
@ -1338,12 +1393,7 @@ Java_org_eehouse_android_xw4_jni_XwJNI_dict_1iter_1destroy
#endif
dict_destroy( data->dict );
destroyJNIUtil( &data->jniutil );
if ( !!data->idata.indices ) {
XP_FREE( mpool, data->idata.indices );
}
if ( !!data->idata.prefixes ) {
XP_FREE( mpool, data->idata.prefixes );
}
freeIndices( data );
vtmgr_destroy( MPPARM(mpool) data->vtMgr );
XP_FREE( mpool, data );
#ifdef MEM_DEBUG
@ -1364,37 +1414,24 @@ Java_org_eehouse_android_xw4_jni_XwJNI_dict_1iter_1wordCount
return result;
}
JNIEXPORT void JNICALL
Java_org_eehouse_android_xw4_jni_XwJNI_dict_1iter_1makeIndex
( JNIEnv* env, jclass C, jint closure )
JNIEXPORT jintArray JNICALL
Java_org_eehouse_android_xw4_jni_XwJNI_dict_1iter_1getCounts
(JNIEnv* env, jclass C, jint closure )
{
jintArray result = NULL;
DictIterData* data = (DictIterData*)closure;
if ( NULL != data ) {
data->depth = 2; /* for now */
XP_U16 nFaces = dict_numTileFaces( data->dict );
XP_U16 ii;
XP_U16 count;
for ( count = 1, ii = 0; ii < data->depth; ++ii ) {
count *= nFaces;
DictIter iter;
dict_initIter( &iter, data->dict, 0, MAX_COLS_DICT );
LengthsArray lens;
if ( 0 < dict_countWords( &iter, &lens ) ) {
XP_ASSERT( sizeof(jint) == sizeof(lens.lens[0]) );
result = makeIntArray( env, VSIZE(lens.lens), (jint*)&lens.lens );
(*env)->DeleteLocalRef( env, result );
}
IndexData* idata = &data->idata;
XP_ASSERT( !idata->prefixes );
idata->prefixes = XP_MALLOC( data->mpool, count * data->depth
* sizeof(*idata->prefixes) );
XP_ASSERT( !idata->indices );
idata->indices = XP_MALLOC( data->mpool,
count * sizeof(*idata->indices) );
idata->count = count;
dict_makeIndex( &data->iter, data->depth, idata );
idata->prefixes = XP_REALLOC( data->mpool, idata->prefixes,
idata->count * data->depth *
sizeof(*idata->prefixes) );
idata->indices = XP_REALLOC( data->mpool, idata->indices,
idata->count * sizeof(*idata->indices) );
}
return result;
}
JNIEXPORT jobjectArray JNICALL

View file

@ -35,4 +35,30 @@
android:drawSelectorOnTop="false"
/>
<LinearLayout android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
>
<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>
</LinearLayout>

View file

@ -1784,10 +1784,20 @@
<string name="cur_tilesf">Tile picker\n(so far: %s)</string>
<string name="pick_faceup">Pick tiles face-up</string>
<string name="dict_browse_titlef">%1$s (%2$d words)</string>
<string name="dict_browse_titlef">%1$s (%2$d words using %3$d-%4$d
tiles)</string>
<string name="dict_browse_title1f">%1$s (%2$d words using %3$d
tiles)</string>
<string name="dict_browse_nowordsf">No word in %1$s starts with
%2$s.</string>
<string name="not_again_browse">This button opens the wordlist
browser on the current player\'s wordlist.</string>
<string name="alert_empty_dictf">The wordlist %s contains only
tile information. There are no words to browse.</string>
<string name="min_len">Min len</string>
<string name="max_len">Max len</string>
<string name="prompt_min_len">Words no shorter than</string>
<string name="prompt_max_len">Words no longer than</string>
</resources>

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
/*
* Copyright 2009-2011 by Eric House (xwords@eehouse.org). All
* rights reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
/*
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
* rights reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
/*
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
* rights reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
/*
* Copyright 2011 by Eric House (xwords@eehouse.org). All rights
* reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
/*
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
* rights reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
/*
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
* rights reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
/*
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
* rights reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
/*
* Copyright 2009 - 2011 by Eric House (xwords@eehouse.org). All
* rights reserved.
@ -27,12 +27,16 @@ import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListAdapter;
import android.widget.SectionIndexer;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import java.util.Arrays;
import junit.framework.Assert;
@ -41,15 +45,27 @@ import org.eehouse.android.xw4.jni.JNIUtilsImpl;
import org.eehouse.android.xw4.jni.XwJNI;
public class DictBrowseActivity extends XWListActivity
implements View.OnClickListener {
implements View.OnClickListener, OnItemSelectedListener {
public static final String DICT_NAME = "DICT_NAME";
public static final String DICT_MIN = "DICT_MIN";
public static final String DICT_MAX = "DICT_MAX";
public static final String DICT_COUNTS = "DICT_COUNTS";
private static final int MIN_LEN = 2;
private static final int FINISH_ACTION = 1;
private int m_dictClosure = 0;
private int m_lang;
private String m_name;
private int m_nWords;
private float m_textSize;
private Spinner m_minSpinner;
private Spinner m_maxSpinner;
private int m_minShown;
private int m_maxShown;
private int m_minAvail;
private int m_maxAvail;
private int[] m_counts;
// - Steps to reproduce the problem:
// Create ListView, set custom adapter which implements ListAdapter and
@ -62,15 +78,30 @@ public class DictBrowseActivity extends XWListActivity
private String[] m_prefixes;
private int[] m_indices;
private int m_nWords;
public DictListAdapter()
{
super();
XwJNI.dict_iter_setMinMax( m_dictClosure, m_minShown, m_maxShown );
m_nWords = XwJNI.dict_iter_wordCount( m_dictClosure );
int format = m_minShown == m_maxShown ?
R.string.dict_browse_title1f : R.string.dict_browse_titlef;
setTitle( Utils.format( DictBrowseActivity.this, format,
m_name, m_nWords, m_minShown, m_maxShown ));
}
public Object getItem( int position )
{
TextView text = new TextView( DictBrowseActivity.this );
TextView text =
(TextView)Utils.inflate( DictBrowseActivity.this,
android.R.layout.simple_list_item_1 );
String str = XwJNI.dict_iter_nthWord( m_dictClosure, position );
if ( null != str ) {
text.setText( str );
text.setOnClickListener( DictBrowseActivity.this );
text.setTextSize( m_textSize );
}
return text;
}
@ -125,33 +156,44 @@ public class DictBrowseActivity extends XWListActivity
m_name = name;
m_lang = DictLangCache.getDictLangCode( this, name );
m_textSize = 2.0f + new TextView( this ).getTextSize();
String[] names = { name };
DictUtils.DictPairs pairs = DictUtils.openDicts( this, names );
m_dictClosure = XwJNI.dict_iter_init( pairs.m_bytes[0],
pairs.m_paths[0],
JNIUtilsImpl.get() );
m_nWords = XwJNI.dict_iter_wordCount( m_dictClosure );
setTitle( Utils.format( this, R.string.dict_browse_titlef,
name, m_nWords ) );
m_counts = intent.getIntArrayExtra( DICT_COUNTS );
if ( null == m_counts ) {
m_counts = XwJNI.dict_iter_getCounts( m_dictClosure );
}
if ( null == m_counts ) {
// empty dict? Just close down for now. Later if
// this is extended to include tile info -- it should
// be -- then use an empty list elem and disable
// search/minmax stuff.
String msg = Utils.format( this, R.string.alert_empty_dictf,
name );
showOKOnlyDialogThen( msg, FINISH_ACTION );
} else {
figureMinMax();
Utils.logf( "calling makeIndex" );
XwJNI.dict_iter_makeIndex( m_dictClosure );
Utils.logf( "makeIndex done" );
setContentView( R.layout.dict_browser );
setContentView( R.layout.dict_browser );
setListAdapter( new DictListAdapter() );
getListView().setFastScrollEnabled( true );
Button button = (Button)findViewById( R.id.search_button );
button.setOnClickListener( new View.OnClickListener() {
public void onClick( View view )
{
findButtonClicked();
}
} );
Button button = (Button)findViewById( R.id.search_button );
button.setOnClickListener( new View.OnClickListener() {
public void onClick( View view )
{
findButtonClicked();
}
} );
m_minShown = intent.getIntExtra( DICT_MIN, m_minAvail );
m_maxShown = intent.getIntExtra( DICT_MAX, m_maxAvail );
setUpSpinners();
setListAdapter( new DictListAdapter() );
getListView().setFastScrollEnabled( true );
}
}
}
@ -187,6 +229,36 @@ public class DictBrowseActivity extends XWListActivity
launchLookup( words, m_lang, true );
}
//////////////////////////////////////////////////
// AdapterView.OnItemSelectedListener interface
//////////////////////////////////////////////////
public void onItemSelected( AdapterView<?> parent, View view,
int position, long id )
{
TextView text = (TextView)view;
int newval = Integer.parseInt( text.getText().toString() );
if ( parent == m_minSpinner ) {
setMinMax( newval, m_maxShown );
} else if ( parent == m_maxSpinner ) {
setMinMax( m_minShown, newval );
}
}
public void onNothingSelected( AdapterView<?> parent )
{
}
//////////////////////////////////////////////////
// DlgDelegate.DlgClickNotify interface
//////////////////////////////////////////////////
@Override
public void dlgButtonClicked( int id, int which )
{
Assert.assertTrue( FINISH_ACTION == id );
finish();
}
private void findButtonClicked()
{
EditText edit = (EditText)findViewById( R.id.word_edit );
@ -202,6 +274,75 @@ public class DictBrowseActivity extends XWListActivity
}
}
private void setMinMax( int min, int max )
{
// I can't make a second call to setListAdapter() work, nor
// does notifyDataSetChanged do anything toward refreshing the
// adapter/making it recognized a changed dataset. So, as a
// workaround, relaunch the activity with different
// parameters.
if ( m_minShown != min || m_maxShown != max ) {
Intent intent = getIntent();
intent.putExtra( DICT_MIN, min );
intent.putExtra( DICT_MAX, max );
intent.putExtra( DICT_COUNTS, m_counts );
startActivity( intent );
finish();
}
}
private void figureMinMax()
{
Assert.assertTrue( m_counts.length == XwJNI.MAX_COLS_DICT + 1 );
m_minAvail = 0;
while ( 0 == m_counts[m_minAvail] ) {
++m_minAvail;
}
m_maxAvail = XwJNI.MAX_COLS_DICT;
while ( 0 == m_counts[m_maxAvail] ) { //
--m_maxAvail;
}
}
private void makeAdapter( Spinner spinner, int min, int max, int cur )
{
int sel = -1;
String[] nums = new String[max - min + 1];
for ( int ii = 0; ii < nums.length; ++ii ) {
int val = min + ii;
if ( val == cur ) {
sel = ii;
}
nums[ii] = String.format( "%d", min + ii );
}
ArrayAdapter<String> adapter = new
ArrayAdapter<String>( this,
//android.R.layout.simple_spinner_dropdown_item,
android.R.layout.simple_spinner_item,
nums );
adapter.setDropDownViewResource( android.R.layout.
simple_spinner_dropdown_item );
spinner.setAdapter( adapter );
spinner.setSelection( sel );
}
private void setUpSpinners()
{
// Min and max-length spinners. To avoid empty lists,
// don't allow min to exceed max. Do that by making the
// current max the largest min allowed, and the current
// min the smallest max allowed.
m_minSpinner = (Spinner)findViewById( R.id.wordlen_min );
makeAdapter( m_minSpinner, m_minAvail, m_maxShown, m_minShown );
m_minSpinner.setOnItemSelectedListener( this );
m_maxSpinner = (Spinner)findViewById( R.id.wordlen_max );
makeAdapter( m_maxSpinner, m_minShown, m_maxAvail, m_maxShown );
m_maxSpinner.setOnItemSelectedListener( this );
}
public static void launch( Context caller, String name )
{
Intent intent = new Intent( caller, DictBrowseActivity.class );

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
/*
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
* rights reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
/*
* Copyright 2010 by Eric House (xwords@eehouse.org). All rights
* reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
/*
* Copyright 2010 by Eric House (xwords@eehouse.org). All
* rights reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
/*
* Copyright 2009-2011 by Eric House (xwords@eehouse.org). All rights
* reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
/*
* Copyright 2009 - 2011 by Eric House (xwords@eehouse.org). All
* rights reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
/*
* Copyright 2010 by Eric House (xwords@eehouse.org). All rights
* reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
/*
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
* rights reserved.
@ -160,7 +160,7 @@ public class DlgDelegate {
// showNotAgainDlgThen() is called
// FALLTHRU
case DIALOG_OKONLY:
ad.setMessage( m_activity.getString(m_msgID) );
ad.setMessage( m_msg );
break;
case CONFIRM_THEN:
ad.getButton(AlertDialog.BUTTON_POSITIVE).
@ -170,10 +170,19 @@ public class DlgDelegate {
}
}
public void showOKOnlyDialog( String msg, int callbackID )
{
m_msg = msg;
if ( 0 != callbackID ) {
Assert.assertTrue( 0 == m_cbckID );
m_cbckID = callbackID;
}
m_activity.showDialog( DIALOG_OKONLY );
}
public void showOKOnlyDialog( int msgID )
{
m_msgID = msgID;
m_activity.showDialog( DIALOG_OKONLY );
showOKOnlyDialog( m_activity.getString( msgID ), 0 );
}
public void showDictGoneFinish()
@ -289,11 +298,15 @@ public class DlgDelegate {
private Dialog createOKDialog()
{
return new AlertDialog.Builder( m_activity )
Dialog dialog = new AlertDialog.Builder( m_activity )
.setTitle( R.string.info_title )
.setMessage( m_msgID )
.setMessage( m_msg )
.setPositiveButton( R.string.button_ok, null )
.create();
if ( 0 != m_cbckID ) {
dialog = setCallbackDismissListener( dialog );
}
return dialog;
}
private Dialog createNotAgainDialog()

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
/*
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
* rights reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
/*
* Copyright 2010 by Eric House (xwords@eehouse.org). All rights
* reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
/*
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
* rights reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
/*
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
* rights reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
/*
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
* rights reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
/*
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
* rights reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
/*
* Copyright 2009-2011 by Eric House (xwords@eehouse.org). All
* rights reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
/*
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
* rights reserved.

View file

@ -1,4 +1,4 @@
// /* -*- compile-command: "cd ../../../../../; ant install"; -*- */
// /* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
// /*
// * Copyright 2010 by Eric House (xwords@eehouse.org). All rights
// * reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
/*
* Copyright 2009-2011 by Eric House (xwords@eehouse.org). All
* rights reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
/*
* Copyright 2010 by Eric House (xwords@eehouse.org). All rights
* reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
/*
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
* rights reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
/*
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
* rights reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
/*
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
* rights reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
/*
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
* rights reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
/*
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
* rights reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
/*
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
* rights reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
/*
* Copyright 2010 by Eric House (xwords@eehouse.org). All rights
* reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
/*
* Copyright 2010 - 2011 by Eric House (xwords@eehouse.org). All
* rights reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
/*
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
* rights reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
/*
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
* rights reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
/*
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
* rights reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
/*
* Copyright 2010 by Eric House (xwords@eehouse.org). All rights
* reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
/*
* Copyright 2010 - 2011 by Eric House (xwords@eehouse.org). All
* rights reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
/*
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
* rights reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
/*
* Copyright 2010 by Eric House (xwords@eehouse.org). All
* rights reserved.

View file

@ -1,7 +1,7 @@
/* -*- compile-command: "cd ../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
/*
* Copyright 2010 by Eric House (xwords@eehouse.org). All rights
* reserved.
* Copyright 2010 - 2011 by Eric House (xwords@eehouse.org). All
* rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@ -122,6 +122,16 @@ public class XWListActivity extends ListActivity
m_delegate.showNotAgainDlgThen( msgID, prefsKey );
}
protected void showOKOnlyDialogThen( String msg, int action )
{
m_delegate.showOKOnlyDialog( msg, action );
}
protected void showOKOnlyDialog( String msg )
{
m_delegate.showOKOnlyDialog( msg, 0 );
}
protected void showOKOnlyDialog( int msgID )
{
m_delegate.showOKOnlyDialog( msgID );

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
/*
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
* rights reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
/*
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
* rights reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../; ant debug install"; -*- */
/*
* Copyright 2010 - 2011 by Eric House (xwords@eehouse.org). All
* rights reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../../; ant debug install"; -*- */
/*
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
* rights reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../../; ant debug install"; -*- */
/*
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
* rights reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../../; ant debug install"; -*- */
/*
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
* rights reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../../; ant debug install"; -*- */
/*
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
* rights reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../../; ant debug install"; -*- */
/*
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
* rights reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../../; ant debug install"; -*- */
/*
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
* rights reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../../; ant debug install"; -*- */
/*
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
* rights reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../../; ant debug install"; -*- */
/*
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
* rights reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../../; ant debug install"; -*- */
/*
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
* rights reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../../; ant debug install"; -*- */
/*
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
* rights reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../../; ant debug install"; -*- */
/*
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
* rights reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../../; ant debug install"; -*- */
/*
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
* rights reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../../; ant debug install"; -*- */
/*
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
* rights reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../../; ant debug install"; -*- */
/*
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
* rights reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../../; ant debug install"; -*- */
/*
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
* rights reserved.

View file

@ -1,4 +1,4 @@
/* -*- compile-command: "cd ../../../../../../; ant install"; -*- */
/* -*- compile-command: "cd ../../../../../../; ant debug install"; -*- */
/*
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
* rights reserved.
@ -244,12 +244,15 @@ public class XwJNI {
public static native int dict_getTileValue( int dictPtr, int tile );
// Dict iterator
public final static int MAX_COLS_DICT = 15; // from dictiter.h
public static native int dict_iter_init( byte[] dict, String path,
JNIUtils jniu );
public static native void dict_iter_setMinMax( int closure,
int min, int max );
public static native void dict_iter_destroy( int closure );
public static native int dict_iter_wordCount( int closure );
public static native int[] dict_iter_getCounts( int closure );
public static native String dict_iter_nthWord( int closure, int nn );
public static native void dict_iter_makeIndex( int closure );
public static native String[] dict_iter_getPrefixes( int closure );
public static native int[] dict_iter_getIndices( int closure );
public static native int dict_iter_getStartsWith( int closure,

View file

@ -1,14 +1,16 @@
#!/bin/sh
echo $0
cd $(dirname $0)
cd ../XWords4
if [ ! -e local.properties ]; then
ANDROID="$(which android)"
SDK_DIR=$(dirname $ANDROID)
SDK_DIR=$(dirname $SDK_DIR)
echo "# generated by $0" > local.properties
echo "sdk.dir=$SDK_DIR" >> local.properties
fi
# create local.properties for 1.6 sdk (target id 4). Use 'android
# list targets' to get the full set.
android update project --path . --target 4
echo "local.properties looks like this:"
echo ""
cat local.properties
echo ""
exit 0

View file

@ -1002,8 +1002,7 @@ timerFiredForPen( BoardCtxt* board )
#endif
if ( !listWords ) {
XWBonusType bonus;
bonus = util_getSquareBonus( board->util, board->model,
col, row );
bonus = model_getSquareBonus( board->model, col, row );
if ( bonus != BONUS_NONE ) {
#ifdef XWFEATURE_MINIWIN
text = draw_getMiniWText( board->draw,
@ -1198,7 +1197,7 @@ invalPerimeter( BoardCtxt* board )
ScrollData* hsd = &board->sd[SCROLL_H];
XP_U16 firstCol = hsd->offset;
XP_U16 lastCol = hsd->lastVisible;
XP_U16 firstAndLast = (1 << lastCol) | (1 << firstCol);
RowFlags firstAndLast = (1 << lastCol) | (1 << firstCol);
ScrollData* vsd = &board->sd[SCROLL_V];
XP_U16 firstRow = vsd->offset;
XP_U16 lastRow = vsd->lastVisible;
@ -1588,7 +1587,7 @@ invalReflection( BoardCtxt* board )
while ( nRows-- ) {
XP_U16 nCols;
XP_U16 redrawFlag = board->redrawFlags[nRows];
RowFlags redrawFlag = board->redrawFlags[nRows];
if ( !redrawFlag ) {
continue; /* nothing set this row */
}

View file

@ -1,6 +1,6 @@
/* -*-mode: C; fill-column: 78; compile-command: "cd ../linux && make MEMDEBUG=TRUE"; -*- */
/* -*- compile-command: "cd ../linux && make MEMDEBUG=TRUE -j3"; -*- */
/*
* Copyright 1997 - 2010 by Eric House (xwords@eehouse.org). All rights
* Copyright 1997 - 2011 by Eric House (xwords@eehouse.org). All rights
* reserved.
*
* This program is free software; you can redistribute it and/or
@ -299,11 +299,11 @@ drawBoard( BoardCtxt* board )
nVisCols = model_numCols( model ) - board->zoomCount;
for ( row = vsd->offset; row <= vsd->lastVisible; ++row ) {
XP_U16 rowFlags = board->redrawFlags[row];
RowFlags rowFlags = board->redrawFlags[row];
if ( rowFlags != 0 ) {
XP_U16 failedBits = 0;
RowFlags failedBits = 0;
for ( col = 0; col < nVisCols; ++col ) {
XP_U16 colMask = 1 << (col + hsd->offset);
RowFlags colMask = 1 << (col + hsd->offset);
if ( 0 != (rowFlags & colMask) ) {
if ( !drawCell( board, col + hsd->offset,
row, XP_TRUE )) {
@ -331,7 +331,7 @@ drawBoard( BoardCtxt* board )
XWBonusType bonus;
HintAtts hintAtts;
CellFlags flags = CELL_NONE;
bonus = util_getSquareBonus( board->util, model, col, row );
bonus = model_getSquareBonus( model, col, row );
hintAtts = figureHintAtts( board, col, row );
#ifdef KEYBOARD_NAV
if ( cellFocused( board, col, row ) ) {
@ -436,7 +436,7 @@ drawCell( BoardCtxt* board, XP_U16 col, XP_U16 row, XP_Bool skipBlanks )
textP = dict_getTileString( dict, tile );
}
}
bonus = util_getSquareBonus( board->util, model, col, row );
bonus = model_getSquareBonus( model, col, row );
hintAtts = figureHintAtts( board, col, row );
if ( (col==board->star_row) && (row==board->star_row) ) {

View file

@ -157,7 +157,7 @@ struct BoardCtxt {
XP_S16 timerStoppedTurn;
#endif
XP_U16 redrawFlags[MAX_ROWS];
RowFlags redrawFlags[MAX_ROWS];
XP_Rect boardBounds;
XP_U16 heightAsSet;

View file

@ -42,6 +42,37 @@
#define VSIZE(arr) (sizeof(arr)/sizeof(arr[0]))
#if MAX_COLS > 16
# define STREAM_VERS_BIGBOARD 0x12
#endif
#define STREAM_SAVE_PREVWORDS 0x11
#define STREAM_VERS_SERVER_SAVES_TOSHOW 0x10
#define STREAM_VERS_PLAYERDICTS 0x0F
#define STREAM_SAVE_PREVMOVE 0x0E /* server saves prev move explanation */
#define STREAM_VERS_ROBOTIQ STREAM_SAVE_PREVMOVE /* robots have different smarts */
#define STREAM_VERS_DICTLANG 0x0D /* save dict lang code in CurGameInfo */
#define STREAM_VERS_NUNDONE 0x0C /* save undone tile in model */
#define STREAM_VERS_GAMESECONDS 0x0B /* save gameSeconds whether or not
timer's enabled */
#define STREAM_VERS_4YOFFSET 0x0A /* 4 bits for yOffset on board */
#define STREAM_VERS_CHANNELSEED 0x09 /* new short in relay connect must be
saved in comms */
#define STREAM_VERS_UTF8 0x08
#define STREAM_VERS_ALWAYS_MULTI 0x07 /* stream format same for multi and
one-device game builds */
#define STREAM_VERS_MODEL_NO_DICT 0x06
#define STREAM_VERS_BLUETOOTH 0x05
#define STREAM_VERS_KEYNAV 0x04
#define STREAM_VERS_RELAY 0x03
#define STREAM_VERS_41B4 0x02
#define STREAM_VERS_405 0x01
#if MAX_COLS > 16
# define CUR_STREAM_VERS STREAM_VERS_BIGBOARD
#else
# define CUR_STREAM_VERS STREAM_SAVE_PREVWORDS
#endif
typedef struct XP_Rect {
XP_S16 left;
XP_S16 top;
@ -115,7 +146,9 @@ typedef enum {
} XWTimerReason;
#define MAX_NUM_PLAYERS 4
#define MAX_ROWS 16
#ifndef MAX_ROWS
# define MAX_ROWS 16
#endif
#define MAX_COLS MAX_ROWS
#ifdef EIGHT_TILES
# define MAX_TRAY_TILES 8
@ -127,6 +160,24 @@ typedef enum {
#define NPLAYERS_NBITS 3
#define EMPTIED_TRAY_BONUS 50
#if MAX_ROWS <= 16
typedef XP_U16 RowFlags;
#elif MAX_ROWS <= 32
typedef XP_U32 RowFlags;
#else
error
#endif
typedef enum {
BONUS_NONE,
BONUS_DOUBLE_LETTER,
BONUS_DOUBLE_WORD,
BONUS_TRIPLE_LETTER,
BONUS_TRIPLE_WORD,
BONUS_LAST
} XWBonusType;
/* I need a way to communiate prefs to common/ code. For now, though, I'll
* leave storage of these values up to the platforms. First, because I don't
* want to deal with versioning in the common code. Second, becuase they

View file

@ -38,10 +38,33 @@ extern "C" {
#endif
typedef struct _EdgeArray {
array_edge* edges[MAX_COLS];
array_edge* edges[MAX_COLS_DICT];
XP_U16 nEdges;
} EdgeArray;
static XP_Bool prevWord( DictIter* iter );
#ifdef XWFEATURE_WALKDICT_FILTER
#define LENOK( iter, nEdges ) \
(iter)->min <= (nEdges) && (nEdges) <= (iter)->max
static XP_Bool
_isAccepting( DictIter* iter, XP_U16 nEdges )
{
return ISACCEPTING( iter->dict, iter->edges[nEdges-1] )
&& LENOK( iter, nEdges );
}
# define ACCEPT_ITER( iter, nEdges) _isAccepting( iter, nEdges )
# define ACCEPT_NODE( iter, node, nEdges ) \
ISACCEPTING( iter->dict, node ) && LENOK(iter,nEdges)
# define FILTER_TEST(iter,nEdges) ((nEdges) <= (iter)->max)
#else
# define ACCEPT_ITER(iter, nEdges) \
ISACCEPTING( (iter)->dict, (iter)->edges[(nEdges)-1] )
# define ACCEPT_NODE( iter, node, nEdges ) ISACCEPTING( iter->dict, node )
# define FILTER_TEST(iter, nEdges) XP_TRUE
#endif
/* On entry and exit, edge at end of array should be ACCEPTING. The job of
* this function is to iterate from one such edge to the next. Steps are: 1)
* try to follow the edge, to expand to a longer word with the last one as a
@ -53,15 +76,17 @@ static XP_Bool
nextWord( DictIter* iter )
{
const DictionaryCtxt* dict = iter->dict;
XP_U16 nEdges = iter->nEdges;
XP_Bool success = XP_FALSE;
XP_U16 nEdges = iter->nEdges;
while ( 0 < nEdges && ! success ) {
array_edge* next = dict_follow( dict, iter->edges[nEdges-1] );
if ( !!next ) {
iter->edges[nEdges++] = next;
success = ISACCEPTING( dict, next );
continue; /* try with longer word */
}
if ( FILTER_TEST( iter, nEdges ) ) {
array_edge* next = dict_follow( dict, iter->edges[nEdges-1] );
if ( !!next ) {
iter->edges[nEdges++] = next;
success = ACCEPT_NODE( iter, next, nEdges );
continue; /* try with longer word */
}
}
while ( IS_LAST_EDGE( dict, iter->edges[nEdges-1] )
&& 0 < --nEdges ) {
@ -69,10 +94,9 @@ nextWord( DictIter* iter )
if ( 0 < nEdges ) {
iter->edges[nEdges-1] += dict->nodeSize;
success = ISACCEPTING( dict, iter->edges[nEdges-1] );
success = ACCEPT_NODE( iter, iter->edges[nEdges-1], nEdges );
}
}
iter->nEdges = nEdges;
return success;
}
@ -88,48 +112,60 @@ isFirstEdge( const DictionaryCtxt* dict, array_edge* edge )
}
static XP_Bool
lastEdges( DictIter* iter )
lastEdges( DictIter* iter, XP_U16* nEdgesP )
{
const DictionaryCtxt* dict = iter->dict;
array_edge* edge = iter->edges[iter->nEdges-1];
XP_U16 nEdges = *nEdgesP;
array_edge* edge = iter->edges[nEdges-1];
for ( ; ; ) {
while ( !IS_LAST_EDGE( dict, edge ) ) {
edge += dict->nodeSize;
}
iter->edges[iter->nEdges-1] = edge;
iter->edges[nEdges-1] = edge;
edge = dict_follow( dict, edge );
if ( NULL == edge ) {
break;
}
++iter->nEdges;
if ( !FILTER_TEST( iter, nEdges + 1 ) ) {
break;
}
++nEdges;
}
return ISACCEPTING( dict, iter->edges[iter->nEdges-1] );
*nEdgesP = nEdges;
return ACCEPT_ITER( iter, nEdges );
}
static XP_Bool
prevWord( DictIter* iter )
{
const DictionaryCtxt* dict = iter->dict;
XP_U16 nEdges = iter->nEdges;
XP_Bool success = XP_FALSE;
while ( 0 < iter->nEdges && ! success ) {
if ( isFirstEdge( dict, iter->edges[iter->nEdges-1] ) ) {
--iter->nEdges;
success = 0 < iter->nEdges
&& ISACCEPTING( dict, iter->edges[iter->nEdges-1] );
while ( 0 < nEdges && ! success ) {
if ( isFirstEdge( dict, iter->edges[nEdges-1] ) ) {
--nEdges;
success = 0 < nEdges
&& ACCEPT_NODE( iter, iter->edges[nEdges-1], nEdges );
continue;
}
iter->edges[iter->nEdges-1] -= dict->nodeSize;
array_edge* next = dict_follow( dict, iter->edges[iter->nEdges-1] );
if ( NULL != next ) {
iter->edges[iter->nEdges++] = next;
success = lastEdges( iter );
if ( success ) {
continue;
iter->edges[nEdges-1] -= dict->nodeSize;
if ( FILTER_TEST( iter, nEdges ) ) {
array_edge* next = dict_follow( dict, iter->edges[nEdges-1] );
if ( NULL != next ) {
iter->edges[nEdges++] = next;
success = lastEdges( iter, &nEdges );
if ( success ) {
continue;
}
}
}
success = ISACCEPTING( dict, iter->edges[iter->nEdges-1] );
success = ACCEPT_NODE( iter, iter->edges[nEdges-1], nEdges );
}
iter->nEdges = nEdges;
return success;
}
@ -137,19 +173,28 @@ static XP_Bool
findStartsWith( DictIter* iter, const Tile* tiles, XP_U16 nTiles )
{
const DictionaryCtxt* dict = iter->dict;
XP_Bool success = XP_TRUE;
array_edge* edge = dict_getTopEdge( dict );
iter->nEdges = 0;
while ( nTiles-- > 0 ) {
while ( FILTER_TEST( iter, iter->nEdges ) && nTiles > 0 ) {
Tile tile = *tiles++;
edge = dict_edge_with_tile( dict, edge, tile );
if ( NULL == edge ) {
success = XP_FALSE;
break;
}
iter->edges[iter->nEdges++] = edge;
edge = dict_follow( dict, edge );
--nTiles;
}
return 0 == nTiles;
}
static XP_Bool
startsWith( const DictIter* iter, const Tile* tiles, XP_U16 nTiles )
{
XP_Bool success = nTiles <= iter->nEdges;
while ( success && nTiles-- ) {
success = tiles[nTiles] == EDGETILE( iter->dict, iter->edges[nTiles] );
}
return success;
}
@ -159,9 +204,9 @@ findWordStartsWith( DictIter* iter, const Tile* tiles, XP_U16 nTiles )
{
XP_Bool found = XP_FALSE;
if ( findStartsWith( iter, tiles, nTiles ) ) {
found = ISACCEPTING( iter->dict, iter->edges[iter->nEdges-1] );
found = ACCEPT_ITER( iter, iter->nEdges );
if ( !found ) {
found = nextWord( iter );
found = nextWord( iter ) && startsWith( iter, tiles, nTiles );
}
}
return found;
@ -178,38 +223,73 @@ wordsEqual( const DictIter* word1, const DictIter* word2 )
return success;
}
static void
dict_initIterFrom( DictIter* dest, const DictIter* src )
{
dict_initIter( dest, src->dict,
#ifdef XWFEATURE_WALKDICT_FILTER
src->min, src->max
#else
0, 0
#endif
);
}
static XP_Bool
firstWord( DictIter* iter )
{
iter->nEdges = 1;
iter->edges[0] = dict_getTopEdge( iter->dict );
return ISACCEPTING( iter->dict, iter->edges[0] ) || nextWord( iter );
array_edge* top = dict_getTopEdge( iter->dict );
XP_Bool success = !!top;
if ( success ) {
iter->nEdges = 1;
iter->edges[0] = top;
success = ACCEPT_ITER( iter, 1 ) || nextWord( iter );
}
return success;
}
XP_U32
dict_countWords( const DictionaryCtxt* dict )
dict_countWords( const DictIter* iter, LengthsArray* lens )
{
XP_U32 count = 0;
DictIter iter;
dict_initIter( dict, &iter );
DictIter counter;
dict_initIterFrom( &counter, iter );
if ( NULL != lens ) {
XP_MEMSET( lens, 0, sizeof(*lens) );
}
XP_U32 count;
XP_Bool ok;
for ( ok = firstWord( &iter ); ok; ok = nextWord( &iter ) ) {
for ( count = 0, ok = firstWord( &counter );
ok; ok = nextWord( &counter) ) {
++count;
if ( NULL != lens ) {
++lens->lens[counter.nEdges];
}
}
return count;
}
#define GUARD_VALUE 0x12345678
#define ASSERT_INITED( iter ) XP_ASSERT( (iter)->guard == GUARD_VALUE )
void
dict_initIter( const DictionaryCtxt* dict, DictIter* iter )
dict_initIter( DictIter* iter, const DictionaryCtxt* dict,
XP_U16 min, XP_U16 max )
{
XP_MEMSET( iter, 0, sizeof(*iter) );
iter->dict = dict;
#ifdef DEBUG
iter->guard = GUARD_VALUE;
#endif
#ifdef XWFEATURE_WALKDICT_FILTER
iter->min = min;
iter->max = max;
#else
XP_USE( min );
XP_USE( max );
#endif
}
static void
@ -221,7 +301,7 @@ copyIter( DictIter* dest, const DictIter* src )
}
static DictPosition
placeWordClose( DictIter* iter, DictPosition position, XP_U16 depth,
placeWordClose( DictIter* iter, const DictPosition position, XP_U16 depth,
const IndexData* data )
{
XP_S16 low = 0;
@ -283,7 +363,7 @@ indexOne( XP_U16 depth, Tile* tiles, IndexData* data, DictIter* prevIter,
DictPosition* prevIndex )
{
DictIter curIter;
dict_initIter( prevIter->dict, &curIter );
dict_initIterFrom( &curIter, prevIter );
if ( findWordStartsWith( &curIter, tiles, depth ) ) {
while ( !wordsEqual( &curIter, prevIter ) ) {
++*prevIndex;
@ -324,7 +404,7 @@ dict_makeIndex( const DictIter* iter, XP_U16 depth, IndexData* data )
{
ASSERT_INITED( iter );
const DictionaryCtxt* dict = iter->dict;
XP_ASSERT( depth < MAX_COLS );
XP_ASSERT( depth < MAX_COLS_DICT );
XP_U16 ii, needCount;
const XP_U16 nFaces = dict_numTileFaces( dict );
XP_U16 nNonBlankFaces = nFaces;
@ -352,7 +432,7 @@ dict_makeIndex( const DictIter* iter, XP_U16 depth, IndexData* data )
*/
data->count = 0;
DictIter prevIter;
dict_initIter( dict, &prevIter );
dict_initIterFrom( &prevIter, iter );
if ( firstWord( &prevIter ) ) {
DictPosition prevIndex = 0;
Tile prefix[depth];
@ -371,7 +451,7 @@ dict_makeIndex( const DictIter* iter, XP_U16 depth, IndexData* data )
static void
initWord( DictIter* iter )
{
iter->nWords = dict_getWordCount( iter->dict );
iter->nWords = dict_countWords( iter, NULL );
}
XP_Bool
@ -405,7 +485,7 @@ dict_lastWord( DictIter* iter )
iter->nEdges = 1;
iter->edges[0] = dict_getTopEdge( iter->dict );
XP_Bool success = lastEdges( iter );
XP_Bool success = lastEdges( iter, &iter->nEdges ) || prevWord( iter );
if ( success ) {
initWord( iter );
iter->position = iter->nWords - 1;
@ -438,7 +518,7 @@ dict_getNthWord( DictIter* iter, DictPosition position, XP_U16 depth,
XP_Bool validWord = 0 < iter->nEdges;
if ( validWord ) { /* uninitialized */
wordCount = iter->nWords;
XP_ASSERT( wordCount == dict_getWordCount( dict ) );
XP_ASSERT( wordCount == dict_countWords( iter, NULL ) );
} else {
wordCount = dict_getWordCount( dict );
}
@ -516,12 +596,12 @@ dict_findStartsWith( DictIter* iter, const IndexData* data,
XP_LOGF( "%s: not using data", __func__ );
DictIter targetIter;
dict_initIter( iter->dict, &targetIter );
dict_initIterFrom( &targetIter, iter );
if ( findWordStartsWith( &targetIter, prefix, len ) ) {
DictPosition result = 0;
DictIter iterZero;
dict_initIter( iter->dict, &iterZero );
dict_initIterFrom( &iterZero, iter );
if ( !firstWord( &iterZero ) ) {
XP_ASSERT( 0 );
}

View file

@ -33,10 +33,17 @@
extern "C" {
#endif
#define MAX_COLS_DICT 15
/* API for iterating over a dict */
typedef XP_S32 DictPosition;
typedef struct _DictIter {
XP_U16 nEdges;
array_edge* edges[MAX_COLS_DICT];
#ifdef XWFEATURE_WALKDICT_FILTER
XP_U16 min;
XP_U16 max;
#endif
#ifdef DEBUG
XP_U32 guard;
#endif
@ -44,8 +51,6 @@ typedef struct _DictIter {
XP_U32 nWords;
DictPosition position;
XP_U16 nEdges;
array_edge* edges[MAX_COLS];
} DictIter;
typedef struct _IndexData {
@ -54,8 +59,13 @@ typedef struct _IndexData {
XP_U16 count; /* in-out: must indicate others are large enough */
} IndexData;
XP_U32 dict_countWords( const DictionaryCtxt* dict );
void dict_initIter( const DictionaryCtxt* dict, DictIter* iter );
typedef struct _LengthsArray {
XP_U32 lens[MAX_COLS_DICT+1];
} LengthsArray;
void dict_initIter( DictIter* iter, const DictionaryCtxt* dict,
XP_U16 min, XP_U16 max );
XP_U32 dict_countWords( const DictIter* iter, LengthsArray* lens );
void dict_makeIndex( const DictIter* iter, XP_U16 depth, IndexData* data );
XP_Bool dict_firstWord( DictIter* iter );
XP_Bool dict_lastWord( DictIter* iter );

View file

@ -481,7 +481,9 @@ dict_getWordCount( const DictionaryCtxt* dict )
XP_U32 nWords = dict->nWords;
#ifdef XWFEATURE_WALKDICT
if ( 0 == nWords ) {
nWords = dict_countWords( dict );
DictIter iter;
dict_initIter( &iter, dict, 0, MAX_COLS_DICT );
nWords = dict_countWords( &iter, NULL );
}
#endif
return nWords;
@ -705,36 +707,38 @@ checkSanity( DictionaryCtxt* dict, const XP_U32 numEdges )
{
XP_U32 ii;
XP_Bool passed = XP_TRUE;
XP_U16 nFaces = dict_numTileFaces( dict );
array_edge* edge = dict->base;
Tile prevTile = 0;
for ( ii = 0; ii < numEdges && passed; ++ii ) {
Tile tile = EDGETILE( dict, edge );
if ( tile < prevTile || tile >= nFaces ) {
XP_LOGF( "%s: node %ld (out of %ld) has too-large or "
"out-of-order tile", __func__, ii, numEdges );
passed = XP_FALSE;
break;
}
prevTile = tile;
if ( NULL != edge ) { /* not empty dict */
XP_U16 nFaces = dict_numTileFaces( dict );
Tile prevTile = 0;
for ( ii = 0; ii < numEdges && passed; ++ii ) {
Tile tile = EDGETILE( dict, edge );
if ( tile < prevTile || tile >= nFaces ) {
XP_LOGF( "%s: node %ld (out of %ld) has too-large or "
"out-of-order tile", __func__, ii, numEdges );
passed = XP_FALSE;
break;
}
prevTile = tile;
unsigned long index = dict_index_from( dict, edge );
if ( index >= numEdges ) {
XP_LOGF( "%s: node %ld (out of %ld) has too-high index %ld", __func__,
ii, numEdges, index );
passed = XP_FALSE;
break;
unsigned long index = dict_index_from( dict, edge );
if ( index >= numEdges ) {
XP_LOGF( "%s: node %ld (out of %ld) has too-high index %ld",
__func__, ii, numEdges, index );
passed = XP_FALSE;
break;
}
if ( IS_LAST_EDGE( dict, edge ) ) {
prevTile = 0;
}
edge += dict->nodeSize;
}
if ( IS_LAST_EDGE( dict, edge ) ) {
prevTile = 0;
if ( passed ) {
passed = 0 == prevTile; /* last edge seen was a LAST_EDGE */
}
edge += dict->nodeSize;
}
if ( passed ) {
passed = 0 == prevTile; /* last edge seen was a LAST_EDGE */
}
XP_LOGF( "%s(numEdges=%ld)=>%d", __func__, numEdges, passed );

View file

@ -39,16 +39,6 @@ extern "C" {
typedef XP_U8 XP_LangCode;
typedef enum {
BONUS_NONE,
BONUS_DOUBLE_LETTER,
BONUS_DOUBLE_WORD,
BONUS_TRIPLE_LETTER,
BONUS_TRIPLE_WORD,
BONUS_LAST
} XWBonusType;
typedef enum {
INTRADE_MW_TEXT = BONUS_LAST
} XWMiniTextType;

View file

@ -426,13 +426,18 @@ gi_readFromStream( MPFORMAL XWStreamCtxt* stream, CurGameInfo* gi )
XP_U16 ii;
XP_UCHAR* str;
XP_U16 strVersion = stream_getVersion( stream );
#ifdef STREAM_VERS_BIGBOARD
XP_U16 nColsNBits = STREAM_VERS_BIGBOARD > strVersion ? 4 : NUMCOLS_NBITS;
#else
XP_U16 nColsNBits = NUMCOLS_NBITS;
#endif
str = stringFromStream( mpool, stream );
replaceStringIfDifferent( mpool, &gi->dictName, str );
XP_FREEP( mpool, &str );
gi->nPlayers = (XP_U8)stream_getBits( stream, NPLAYERS_NBITS );
gi->boardSize = (XP_U8)stream_getBits( stream, 4 );
gi->boardSize = (XP_U8)stream_getBits( stream, nColsNBits );
gi->serverRole = (DeviceRole)stream_getBits( stream, 2 );
gi->hintsNotAllowed = stream_getBits( stream, 1 );
if ( strVersion < STREAM_VERS_ROBOTIQ ) {
@ -491,10 +496,19 @@ gi_writeToStream( XWStreamCtxt* stream, const CurGameInfo* gi )
const LocalPlayer* pl;
XP_U16 ii;
#ifdef STREAM_VERS_BIGBOARD
XP_U16 strVersion = stream_getVersion( stream );
XP_ASSERT( STREAM_SAVE_PREVWORDS <= strVersion );
XP_U16 nColsNBits = STREAM_VERS_BIGBOARD > strVersion ? 4 : NUMCOLS_NBITS;
#else
XP_U16 nColsNBits = NUMCOLS_NBITS;
#endif
stringToStream( stream, gi->dictName );
stream_putBits( stream, NPLAYERS_NBITS, gi->nPlayers );
stream_putBits( stream, 4, gi->boardSize );
stream_putBits( stream, nColsNBits, gi->boardSize );
stream_putBits( stream, 2, gi->serverRole );
stream_putBits( stream, 1, gi->hintsNotAllowed );
stream_putBits( stream, 2, gi->phoniesAction );

View file

@ -31,30 +31,6 @@
extern "C" {
#endif
#define STREAM_SAVE_PREVWORDS 0x11
#define STREAM_VERS_SERVER_SAVES_TOSHOW 0x10
#define STREAM_VERS_PLAYERDICTS 0x0F
#define STREAM_SAVE_PREVMOVE 0x0E /* server saves prev move explanation */
#define STREAM_VERS_ROBOTIQ STREAM_SAVE_PREVMOVE /* robots have different smarts */
#define STREAM_VERS_DICTLANG 0x0D /* save dict lang code in CurGameInfo */
#define STREAM_VERS_NUNDONE 0x0C /* save undone tile in model */
#define STREAM_VERS_GAMESECONDS 0x0B /* save gameSeconds whether or not
timer's enabled */
#define STREAM_VERS_4YOFFSET 0x0A /* 4 bits for yOffset on board */
#define STREAM_VERS_CHANNELSEED 0x09 /* new short in relay connect must be
saved in comms */
#define STREAM_VERS_UTF8 0x08
#define STREAM_VERS_ALWAYS_MULTI 0x07 /* stream format same for multi and
one-device game builds */
#define STREAM_VERS_MODEL_NO_DICT 0x06
#define STREAM_VERS_BLUETOOTH 0x05
#define STREAM_VERS_KEYNAV 0x04
#define STREAM_VERS_RELAY 0x03
#define STREAM_VERS_41B4 0x02
#define STREAM_VERS_405 0x01
#define CUR_STREAM_VERS STREAM_SAVE_PREVWORDS
typedef struct LocalPlayer {
XP_UCHAR* name;
XP_UCHAR* password;

View file

@ -1,6 +1,7 @@
/* -*- compile-command: "cd ../linux && make -j3 MEMDEBUG=TRUE"; -*- */
/*
* Copyright 2000-2009 by Eric House (xwords@eehouse.org). All rights reserved.
* Copyright 2000-2011 by Eric House (xwords@eehouse.org). All rights
* reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -88,7 +89,9 @@ model_make( MPFORMAL DictionaryCtxt* dict,
const PlayerDicts* dicts, XW_UtilCtxt* util, XP_U16 nCols,
XP_U16 nRows )
{
ModelCtxt* result = (ModelCtxt*)XP_MALLOC( mpool, sizeof( *result ) );
ModelCtxt* result;
XP_U16 size = sizeof(*result) + TILES_SIZE(result, nCols);
result = (ModelCtxt*)XP_MALLOC( mpool, size );
if ( result != NULL ) {
XP_MEMSET( result, 0, sizeof(*result) );
MPASSIGN(result->vol.mpool, mpool);
@ -115,15 +118,21 @@ model_makeFromStream( MPFORMAL XWStreamCtxt* stream, DictionaryCtxt* dict,
{
ModelCtxt* model;
XP_U16 nCols, nRows;
short i;
XP_U16 ii;
XP_Bool hasDict;
XP_U16 nPlayers;
XP_U16 nColsNBits;
XP_U16 version = stream_getVersion( stream );
#ifdef STREAM_VERS_BIGBOARD
nColsNBits = STREAM_VERS_BIGBOARD > version ? 4 : NUMCOLS_NBITS;
#else
nColsNBits = NUMCOLS_NBITS;
#endif
XP_ASSERT( !!dict || !!dicts );
nCols = (XP_U16)stream_getBits( stream, NUMCOLS_NBITS );
nRows = (XP_U16)stream_getBits( stream, NUMCOLS_NBITS );
nCols = (XP_U16)stream_getBits( stream, nColsNBits );
nRows = (XP_U16)stream_getBits( stream, nColsNBits );
hasDict = (version >= STREAM_VERS_MODEL_NO_DICT)
? XP_FALSE : stream_getBits( stream, 1 );
@ -138,6 +147,20 @@ model_makeFromStream( MPFORMAL XWStreamCtxt* stream, DictionaryCtxt* dict,
model = model_make( MPPARM(mpool) dict, dicts, util, nCols, nRows );
model->nPlayers = nPlayers;
#ifdef STREAM_VERS_BIGBOARD
if ( STREAM_VERS_BIGBOARD <= version ) {
model->nBonuses = stream_getBits( stream, 7 );
if ( 0 < model->nBonuses ) {
model->bonuses =
XP_MALLOC( model->vol.mpool,
model->nBonuses * sizeof( model->bonuses[0] ) );
for ( ii = 0; ii < model->nBonuses; ++ii ) {
model->bonuses[ii] = stream_getBits( stream, 4 );
}
}
}
#endif
stack_loadFromStream( model->vol.stack, stream );
buildModelFromStack( model, model->vol.stack, XP_FALSE, 0,
@ -145,10 +168,10 @@ model_makeFromStream( MPFORMAL XWStreamCtxt* stream, DictionaryCtxt* dict,
(MovePrintFuncPre)NULL, (MovePrintFuncPost)NULL,
NULL );
for ( i = 0; i < model->nPlayers; ++i ) {
loadPlayerCtxt( stream, version, &model->players[i] );
setPendingCounts( model, i );
invalidateScore( model, i );
for ( ii = 0; ii < model->nPlayers; ++ii ) {
loadPlayerCtxt( stream, version, &model->players[ii] );
setPendingCounts( model, ii );
invalidateScore( model, ii );
}
return model;
@ -157,7 +180,7 @@ model_makeFromStream( MPFORMAL XWStreamCtxt* stream, DictionaryCtxt* dict,
void
model_writeToStream( ModelCtxt* model, XWStreamCtxt* stream )
{
short i;
XP_U16 ii;
stream_putBits( stream, NUMCOLS_NBITS, model->nCols );
stream_putBits( stream, NUMCOLS_NBITS, model->nRows );
@ -165,10 +188,17 @@ model_writeToStream( ModelCtxt* model, XWStreamCtxt* stream )
/* we have two bits for nPlayers, so range must be 0..3, not 1..4 */
stream_putBits( stream, NPLAYERS_NBITS, model->nPlayers );
#ifdef STREAM_VERS_BIGBOARD
stream_putBits( stream, 7, model->nBonuses );
for ( ii = 0; ii < model->nBonuses; ++ii ) {
stream_putBits( stream, 4, model->bonuses[ii] );
}
#endif
stack_writeToStream( model->vol.stack, stream );
for ( i = 0; i < model->nPlayers; ++i ) {
writePlayerCtxt( stream, &model->players[i] );
for ( ii = 0; ii < model->nPlayers; ++ii ) {
writePlayerCtxt( stream, &model->players[ii] );
}
} /* model_writeToStream */
@ -220,7 +250,7 @@ model_init( ModelCtxt* model, XP_U16 nCols, XP_U16 nRows )
XP_ASSERT( model != NULL );
XP_MEMSET( model, 0, sizeof( *model ) );
XP_MEMSET( &model->tiles, TILE_EMPTY_BIT, sizeof(model->tiles) );
XP_MEMSET( &model->tiles, TILE_EMPTY_BIT, TILES_SIZE(model, nCols) );
model->nCols = nCols;
model->nRows = nRows;
@ -240,9 +270,90 @@ model_destroy( ModelCtxt* model )
{
stack_destroy( model->vol.stack );
/* is this it!? */
if ( !!model->bonuses ) {
XP_FREE( model->vol.mpool, model->bonuses );
}
XP_FREE( model->vol.mpool, model );
} /* model_destroy */
#ifdef STREAM_VERS_BIGBOARD
void
model_setSquareBonuses( ModelCtxt* model, XWBonusType* bonuses, XP_U16 nBonuses )
{
#ifdef DEBUG
XP_U16 nCols = (1 + model_numCols( model )) / 2;
XP_ASSERT( 0 < nCols );
XP_U16 wantLen = 0;
while ( nCols > 0 ) {
wantLen += nCols--;
}
XP_ASSERT( wantLen == nBonuses );
#endif
if ( !!model->bonuses ) {
XP_FREE( model->vol.mpool, model->bonuses );
}
model->bonuses = XP_MALLOC( model->vol.mpool,
nBonuses * sizeof(model->bonuses[0]) );
XP_MEMCPY( model->bonuses, bonuses, nBonuses * sizeof(model->bonuses[0]) );
model->nBonuses = nBonuses;
}
static void
borrowSquareBonuses( ModelCtxt* dest, const ModelCtxt* src )
{
XP_ASSERT( !dest->bonuses );
dest->bonuses = src->bonuses;
dest->nBonuses = src->nBonuses;
}
static void
returnSquareBonuses( ModelCtxt* dest )
{
dest->bonuses = NULL;
dest->nBonuses = 0;
}
#else
# define borrowSquareBonuses(d,s)
# define returnSquareBonuses(d)
#endif
XWBonusType
model_getSquareBonus( const ModelCtxt* model, XP_U16 col, XP_U16 row )
{
XWBonusType result = BONUS_NONE;
if ( 0 ) {
#ifdef STREAM_VERS_BIGBOARD
} else if ( !!model->bonuses ) {
XP_U16 nCols = model_numCols( model );
XP_U16 ii;
if ( col > (nCols/2) ) {
col = nCols - 1 - col;
}
if ( row > (nCols/2) ) {
row = nCols - 1 - row;
}
if ( col > row ) {
XP_U16 tmp = col;
col = row;
row = tmp;
}
for ( ii = 1; ii <= row; ++ii ) {
col += ii;
}
if ( col < model->nBonuses ) {
result = model->bonuses[col];
}
#endif
} else {
result = util_getSquareBonus( model->vol.util, model_numRows(model),
col, row );
}
return result;
}
static void
modelAddEntry( ModelCtxt* model, XP_U16 indx, const StackEntry* entry,
XP_Bool useStack, XWStreamCtxt* stream,
@ -581,17 +692,23 @@ model_getCellOwner( ModelCtxt* model, XP_U16 col, XP_U16 row )
static void
setModelTileRaw( ModelCtxt* model, XP_U16 col, XP_U16 row, CellTile tile )
{
XP_ASSERT( col < MAX_COLS );
XP_ASSERT( row < MAX_ROWS );
model->tiles[col][row] = tile;
XP_ASSERT( col < model->nCols );
XP_ASSERT( row < model->nRows );
model->tiles[(row*model->nCols) + col] = tile;
} /* model_setTile */
static CellTile
getModelTileRaw( const ModelCtxt* model, XP_U16 col, XP_U16 row )
{
XP_ASSERT( col < MAX_COLS );
XP_ASSERT( row < MAX_ROWS );
return model->tiles[col][row];
CellTile tile;
XP_U16 nCols = model->nCols;
XP_ASSERT( model->nRows == nCols );
if ( col < nCols && row < nCols ) {
tile = model->tiles[(row*nCols) + col];
} else {
tile = TILE_EMPTY_BIT;
}
return tile;
} /* getModelTileRaw */
static void
@ -815,6 +932,12 @@ model_currentMoveToStream( ModelCtxt* model, XP_S16 turn,
{
PlayerCtxt* player;
XP_S16 numTiles;
#ifdef STREAM_VERS_BIGBOARD
XP_U16 version = stream_getVersion( stream );
XP_U16 nColsNBits = STREAM_VERS_BIGBOARD > version ? 4 : NUMCOLS_NBITS;
#else
XP_U16 nColsNBits = NUMCOLS_NBITS;
#endif
XP_ASSERT( turn >= 0 );
player = &model->players[turn];
@ -831,8 +954,8 @@ model_currentMoveToStream( ModelCtxt* model, XP_S16 turn,
&col, &row, &isBlank );
XP_ASSERT( numTiles >= 0 );
stream_putBits( stream, TILE_NBITS, tile );
stream_putBits( stream, NUMCOLS_NBITS, col );
stream_putBits( stream, NUMCOLS_NBITS, row );
stream_putBits( stream, nColsNBits, col );
stream_putBits( stream, nColsNBits, row );
stream_putBits( stream, 1, isBlank );
}
} /* model_currentMoveToStream */
@ -847,8 +970,15 @@ void
model_makeTurnFromStream( ModelCtxt* model, XP_U16 playerNum,
XWStreamCtxt* stream )
{
XP_U16 numTiles;
XP_U16 numTiles, ii;
Tile blank = dict_getBlankTile( model_getDictionary(model) );
#ifdef STREAM_VERS_BIGBOARD
XP_U16 version = stream_getVersion( stream );
XP_U16 nColsNBits = STREAM_VERS_BIGBOARD > version ? 4 : NUMCOLS_NBITS;
#else
XP_U16 nColsNBits = NUMCOLS_NBITS;
#endif
model_resetCurrentTurn( model, playerNum );
@ -856,12 +986,12 @@ model_makeTurnFromStream( ModelCtxt* model, XP_U16 playerNum,
XP_LOGF( "%s: numTiles=%d", __func__, numTiles );
while ( numTiles-- ) {
for ( ii = 0; ii < numTiles; ++ii ) {
XP_S16 foundAt;
Tile moveTile;
Tile tileFace = (Tile)stream_getBits( stream, TILE_NBITS );
XP_U16 col = (XP_U16)stream_getBits( stream, NUMCOLS_NBITS );
XP_U16 row = (XP_U16)stream_getBits( stream, NUMCOLS_NBITS );
XP_U16 col = (XP_U16)stream_getBits( stream, nColsNBits );
XP_U16 row = (XP_U16)stream_getBits( stream, nColsNBits );
XP_Bool isBlank = stream_getBits( stream, 1 );
/* This code gets called both for the server, which has all the
@ -1931,6 +2061,7 @@ makeTmpModel( ModelCtxt* model, XWStreamCtxt* stream,
model->vol.util, model_numCols(model),
model_numRows(model));
model_setNPlayers( tmpModel, model->nPlayers );
borrowSquareBonuses( tmpModel, model );
buildModelFromStack( tmpModel, model->vol.stack, XP_FALSE, 0, stream,
(WordNotifierInfo*)NULL, mpf_pre, mpf_post, closure );
@ -1952,6 +2083,7 @@ model_writeGameHistory( ModelCtxt* model, XWStreamCtxt* stream,
tmpModel = makeTmpModel( model, stream, printMovePre, printMovePost,
&closure );
returnSquareBonuses( tmpModel );
model_destroy( tmpModel );
if ( gameOver ) {
@ -2215,6 +2347,11 @@ loadPlayerCtxt( XWStreamCtxt* stream, XP_U16 version, PlayerCtxt* pc )
{
PendingTile* pt;
XP_U16 nTiles;
#ifdef STREAM_VERS_BIGBOARD
XP_U16 nColsNBits = STREAM_VERS_BIGBOARD > version ? 4 : NUMCOLS_NBITS;
#else
XP_U16 nColsNBits = NUMCOLS_NBITS;
#endif
pc->curMoveValid = stream_getBits( stream, 1 );
@ -2230,8 +2367,8 @@ loadPlayerCtxt( XWStreamCtxt* stream, XP_U16 version, PlayerCtxt* pc )
nTiles = pc->nPending + pc->nUndone;
for ( pt = pc->pendingTiles; nTiles-- > 0; ++pt ) {
XP_U16 nBits;
pt->col = (XP_U8)stream_getBits( stream, NUMCOLS_NBITS );
pt->row = (XP_U8)stream_getBits( stream, NUMCOLS_NBITS );
pt->col = (XP_U8)stream_getBits( stream, nColsNBits );
pt->row = (XP_U8)stream_getBits( stream, nColsNBits );
nBits = (version <= STREAM_VERS_RELAY) ? 6 : 7;
pt->tile = (Tile)stream_getBits( stream, nBits );

View file

@ -29,7 +29,11 @@
extern "C" {
#endif
#define NUMCOLS_NBITS 4
#if MAX_COLS <= 16
# define NUMCOLS_NBITS 4
#elif MAX_COLS <= 32
# define NUMCOLS_NBITS 5
#endif
#ifdef EIGHT_TILES
# define NTILES_NBITS 4
@ -265,6 +269,13 @@ void model_listWordsThrough( ModelCtxt* model, XP_U16 col, XP_U16 row,
/* Have there been too many passes (so game should end)? */
XP_Bool model_recentPassCountOk( ModelCtxt* model );
XWBonusType model_getSquareBonus( const ModelCtxt* model,
XP_U16 col, XP_U16 row );
#ifdef STREAM_VERS_BIGBOARD
void model_setSquareBonuses( ModelCtxt* model, XWBonusType* bonuses,
XP_U16 nBonuses );
#endif
XP_Bool model_checkMoveLegal( ModelCtxt* model, XP_S16 player,
XWStreamCtxt* stream,
WordNotifierInfo* notifyInfo );

View file

@ -1,6 +1,7 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
/* -*- compile-command: "cd ../linux && make -j3 MEMDEBUG=TRUE"; -*- */
/*
* Copyright 2000 by Eric House (xwords@eehouse.org). All rights reserved.
* Copyright 2000 - 2011 by Eric House (xwords@eehouse.org). All rights
* reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -70,14 +71,18 @@ struct ModelCtxt {
ModelVolatiles vol;
CellTile tiles[MAX_COLS][MAX_ROWS];
PlayerCtxt players[MAX_NUM_PLAYERS];
XP_U16 nPlayers;
XP_U16 nCols;
XP_U16 nRows;
XP_U16 nBonuses;
XWBonusType* bonuses;
CellTile tiles[];
};
#define TILES_SIZE(m,nc) ((nc) * (nc) * sizeof((m)->tiles[0]))
void invalidateScore( ModelCtxt* model, XP_S16 player );
XP_Bool tilesInLine( ModelCtxt* model, XP_S16 turn, XP_Bool* isHorizontal );
void normalizeMoves( ModelCtxt* model, XP_S16 turn,

View file

@ -526,7 +526,7 @@ figureMoveScore( const ModelCtxt* model, XP_U16 turn, MoveInfo* moveInfo,
static XP_U16
word_multiplier( const ModelCtxt* model, XP_U16 col, XP_U16 row )
{
XWBonusType bonus = util_getSquareBonus( model->vol.util, model, col, row );
XWBonusType bonus = model_getSquareBonus( model, col, row );
switch ( bonus ) {
case BONUS_DOUBLE_WORD:
return 2;
@ -540,8 +540,7 @@ word_multiplier( const ModelCtxt* model, XP_U16 col, XP_U16 row )
static XP_U16
tile_multiplier( const ModelCtxt* model, XP_U16 col, XP_U16 row )
{
XWBonusType bonus = util_getSquareBonus( model->vol.util, model,
col, row );
XWBonusType bonus = model_getSquareBonus( model, col, row );
switch ( bonus ) {
case BONUS_DOUBLE_LETTER:
return 2;

View file

@ -60,6 +60,9 @@ typedef struct ServerPlayer {
typedef struct RemoteAddress {
XP_PlayerAddr channelNo;
#ifdef STREAM_VERS_BIGBOARD
XP_U8 streamVersion;
#endif
} RemoteAddress;
/* These are the parts of the server's state that needs to be preserved
@ -84,6 +87,9 @@ typedef struct ServerNonvolatiles {
XP_U8 pendingRegistrations;
XP_Bool showRobotScores;
XP_Bool sortNewTiles;
#ifdef STREAM_VERS_BIGBOARD
XP_U8 streamVersion;
#endif
#ifdef XWFEATURE_SLOW_ROBOT
XP_U16 robotThinkMin, robotThinkMax; /* not saved (yet) */
#endif
@ -139,12 +145,14 @@ static XWStreamCtxt* messageStreamWithHeader( ServerCtxt* server,
XP_U16 devIndex, XW_Proto code );
static XP_Bool handleRegistrationMsg( ServerCtxt* server,
XWStreamCtxt* stream );
static void registerRemotePlayer( ServerCtxt* server, XWStreamCtxt* stream );
static XP_S8 registerRemotePlayer( ServerCtxt* server, XWStreamCtxt* stream );
static void server_sendInitialMessage( ServerCtxt* server );
static void sendBadWordMsgs( ServerCtxt* server );
static XP_Bool handleIllegalWord( ServerCtxt* server,
XWStreamCtxt* incoming );
static void tellMoveWasLegal( ServerCtxt* server );
static void writeProto( const ServerCtxt* server, XWStreamCtxt* stream,
XW_Proto proto );
#endif
#define PICK_NEXT -1
@ -230,6 +238,9 @@ initServer( ServerCtxt* server )
syncPlayers( server );
server->nv.nDevices = 1; /* local device (0) is always there */
#ifdef STREAM_VERS_BIGBOARD
server->nv.streamVersion = STREAM_SAVE_PREVWORDS; /* default to old */
#endif
} /* initServer */
ServerCtxt*
@ -280,7 +291,18 @@ getNV( XWStreamCtxt* stream, ServerNonvolatiles* nv, XP_U16 nPlayers )
for ( ii = 0; ii < nPlayers; ++ii ) {
nv->addresses[ii].channelNo =
(XP_PlayerAddr)stream_getBits( stream, 16 );
#ifdef STREAM_VERS_BIGBOARD
if ( STREAM_VERS_BIGBOARD <= version ) {
nv->addresses[ii].streamVersion = stream_getBits( stream, 8 );
}
#endif
}
#ifdef STREAM_VERS_BIGBOARD
if ( STREAM_SAVE_PREVWORDS < version ) {
nv->streamVersion = stream_getU8 ( stream );
}
XP_LOGF( "%s: read streamVersion: 0x%x", __func__, nv->streamVersion );
#endif
} /* getNV */
static void
@ -301,7 +323,14 @@ putNV( XWStreamCtxt* stream, ServerNonvolatiles* nv, XP_U16 nPlayers )
for ( ii = 0; ii < nPlayers; ++ii ) {
stream_putBits( stream, 16, nv->addresses[ii].channelNo );
#ifdef STREAM_VERS_BIGBOARD
stream_putBits( stream, 8, nv->addresses[ii].streamVersion );
#endif
}
#ifdef STREAM_VERS_BIGBOARD
stream_putU8( stream, nv->streamVersion );
XP_LOGF( "%s: wrote streamVersion: 0x%x", __func__, nv->streamVersion );
#endif
} /* putNV */
static XWStreamCtxt*
@ -515,7 +544,7 @@ server_initClientConnection( ServerCtxt* server, XWStreamCtxt* stream )
if ( server->nv.gameState == XWSTATE_NONE ) {
stream_open( stream );
stream_putBits( stream, XWPROTO_NBITS, XWPROTO_DEVICE_REGISTRATION );
writeProto( server, stream, XWPROTO_DEVICE_REGISTRATION );
nPlayers = gi->nPlayers;
XP_ASSERT( nPlayers > 0 );
@ -531,8 +560,8 @@ server_initClientConnection( ServerCtxt* server, XWStreamCtxt* stream )
continue;
}
stream_putBits( stream, 1, LP_IS_ROBOT(lp) ); /* better not to send this */
stream_putBits( stream, 1, LP_IS_ROBOT(lp) ); /* better not to
send this */
/* The first nPlayers players are the ones we'll use. The local flag
doesn't matter when for SERVER_ISCLIENT. */
name = emptyStringIfNull(lp->name);
@ -543,6 +572,10 @@ server_initClientConnection( ServerCtxt* server, XWStreamCtxt* stream )
stream_putBits( stream, NAME_LEN_NBITS, len );
stream_putBytes( stream, name, len );
}
#ifdef STREAM_VERS_BIGBOARD
stream_putU8( stream, CUR_STREAM_VERS );
#endif
} else {
XP_LOGF( "%s: wierd state %s; dropping message", __func__,
getStateStr(server->nv.gameState) );
@ -593,11 +626,32 @@ callTurnChangeListener( ServerCtxt* server )
} /* callTurnChangeListener */
#ifndef XWFEATURE_STANDALONE_ONLY
# ifdef STREAM_VERS_BIGBOARD
static void
setStreamVersion( ServerCtxt* server )
{
XP_U16 devIndex;
XP_U8 streamVersion = CUR_STREAM_VERS;
for ( devIndex = 1; devIndex < server->nv.nDevices; ++devIndex ) {
XP_U8 devVersion = server->nv.addresses[devIndex].streamVersion;
if ( devVersion < streamVersion ) {
streamVersion = devVersion;
}
}
XP_LOGF( "%s: setting streamVersion: %d", __func__, streamVersion );
server->nv.streamVersion = streamVersion;
}
# else
# define setStreamVersion(s)
# endif
static XP_Bool
handleRegistrationMsg( ServerCtxt* server, XWStreamCtxt* stream )
{
XP_Bool success = XP_TRUE;
XP_U16 playersInMsg, i;
XP_U16 playersInMsg;
XP_S8 clientIndex;
XP_U16 ii = 0;
LOG_FUNC();
/* code will have already been consumed */
@ -608,21 +662,41 @@ handleRegistrationMsg( ServerCtxt* server, XWStreamCtxt* stream )
util_userError( server->vol.util, ERR_REG_UNEXPECTED_USER );
success = XP_FALSE;
} else {
for ( i = 0; i < playersInMsg; ++i ) {
registerRemotePlayer( server, stream );
XP_S8 prevIndex = -1;
for ( ; ii < playersInMsg; ++ii ) {
clientIndex = registerRemotePlayer( server, stream );
/* This is abusing the semantics of turn change -- at least in the
case where there is another device yet to register -- but we
need to let the board know to redraw the scoreboard with more
players there. */
callTurnChangeListener( server );
XP_ASSERT( ii == 0 || prevIndex == clientIndex );
prevIndex = clientIndex;
}
if ( server->nv.pendingRegistrations == 0 ) {
assignTilesToAll( server );
SETSTATE( server, XWSTATE_RECEIVED_ALL_REG );
}
#ifdef STREAM_VERS_BIGBOARD
if ( 0 < stream_getSize(stream) ) {
XP_U8 streamVersion = stream_getU8( stream );
if ( streamVersion >= STREAM_VERS_BIGBOARD ) {
XP_LOGF( "%s: upping device %d streamVersion to %d",
__func__, clientIndex, streamVersion );
server->nv.addresses[clientIndex].streamVersion = streamVersion;
}
}
#endif
if ( server->nv.pendingRegistrations == 0 ) {
XP_ASSERT( ii == playersInMsg ); /* otherwise malformed */
setStreamVersion( server );
assignTilesToAll( server );
SETSTATE( server, XWSTATE_RECEIVED_ALL_REG );
}
/* now set server's streamVersion if all remote players have the higher one. */
/* But first need to pass it in the strramx */
return success;
} /* handleRegistrationMsg */
#endif
@ -1005,7 +1079,7 @@ findFirstPending( ServerCtxt* server, ServerPlayer** playerP )
return lp;
} /* findFirstPending */
static void
static XP_S8
registerRemotePlayer( ServerCtxt* server, XWStreamCtxt* stream )
{
XP_S8 deviceIndex;
@ -1045,10 +1119,13 @@ registerRemotePlayer( ServerCtxt* server, XWStreamCtxt* stream )
XP_ASSERT( channelNo != 0 );
addr->channelNo = channelNo;
#ifdef STREAM_VERS_BIGBOARD
addr->streamVersion = STREAM_SAVE_PREVWORDS;
#endif
}
player->deviceIndex = deviceIndex;
return deviceIndex;
} /* registerRemotePlayer */
static void
@ -1102,6 +1179,7 @@ client_readInitialMessage( ServerCtxt* server, XWStreamCtxt* stream )
/* version; any dependencies here? */
XP_U8 streamVersion = stream_getU8( stream );
XP_LOGF( "%s: set streamVersion to %d", __func__, streamVersion );
stream_setVersion( stream, streamVersion );
gameID = stream_getU32( stream );
@ -1240,10 +1318,8 @@ server_sendInitialMessage( ServerCtxt* server )
DictionaryCtxt* dict = model_getDictionary(model);
XP_ASSERT( !!stream );
stream_open( stream );
stream_putBits( stream, XWPROTO_NBITS, XWPROTO_CLIENT_SETUP );
writeProto( server, stream, XWPROTO_CLIENT_SETUP );
/* write version for server's benefit; use old version until format
changes */
stream_putU8( stream, CUR_STREAM_VERS );
XP_LOGF( "putting gameID %lx into msg", gameID );
@ -1329,6 +1405,7 @@ printCode(char* intro, XW_Proto code)
caseStr( str, XWPROTO_MOVE_CONFIRM );
caseStr( str, XWPROTO_CLIENT_REQ_END_GAME );
caseStr( str, XWPROTO_END_GAME );
caseStr( str, XWPROTO_NEW_PROTO );
}
XP_STATUSF( "\t%s for %s", intro, str );
@ -1347,9 +1424,11 @@ messageStreamWithHeader( ServerCtxt* server, XP_U16 devIndex, XW_Proto code )
printCode("making", code);
stream = util_makeStreamFromAddr( server->vol.util, channelNo );
#ifdef STREAM_VERS_BIGBOARD
stream_setVersion( stream, server->nv.streamVersion );
#endif
stream_open( stream );
stream_putBits( stream, XWPROTO_NBITS, code );
writeProto( server, stream, code );
return stream;
} /* messageStreamWithHeader */
@ -2446,15 +2525,46 @@ server_handleUndo( ServerCtxt* server )
} /* server_handleUndo */
#ifndef XWFEATURE_STANDALONE_ONLY
static void
writeProto( const ServerCtxt* server, XWStreamCtxt* stream, XW_Proto proto )
{
#ifdef STREAM_VERS_BIGBOARD
XP_ASSERT( server->nv.streamVersion > 0 );
if ( STREAM_SAVE_PREVWORDS < server->nv.streamVersion ) {
stream_putBits( stream, XWPROTO_NBITS, XWPROTO_NEW_PROTO );
stream_putBits( stream, 8, CUR_STREAM_VERS );
}
#else
XP_USE(server);
#endif
stream_putBits( stream, XWPROTO_NBITS, proto );
}
static XW_Proto
readProto( ServerCtxt* server, XWStreamCtxt* stream )
{
XW_Proto proto = (XW_Proto)stream_getBits( stream, XWPROTO_NBITS );
XP_U8 version = STREAM_SAVE_PREVWORDS; /* version prior to fmt change */
#ifdef STREAM_VERS_BIGBOARD
if ( XWPROTO_NEW_PROTO == proto ) {
version = stream_getBits( stream, 8 );
proto = (XW_Proto)stream_getBits( stream, XWPROTO_NBITS );
}
server->nv.streamVersion = version;
#else
XP_USE(server);
#endif
stream_setVersion( stream, version );
return proto;
}
XP_Bool
server_receiveMessage( ServerCtxt* server, XWStreamCtxt* incoming )
{
XW_Proto code;
XP_Bool accepted = XP_FALSE;
XW_Proto code = readProto( server, incoming );
code = (XW_Proto)stream_getBits( incoming, XWPROTO_NBITS );
printCode("Receiving", code);
printCode( "Receiving", code );
if ( code == XWPROTO_DEVICE_REGISTRATION ) {
/* This message is special: doesn't have the header that's possible
@ -2541,7 +2651,8 @@ server_receiveMessage( ServerCtxt* server, XWStreamCtxt* incoming )
accepted = XP_TRUE;
break;
default:
XP_WARNF( "Unknown code on incoming message: %d\n", code );
XP_WARNF( "%s: Unknown code on incoming message: %d\n",
__func__, code );
break;
} /* switch */
}

View file

@ -99,8 +99,7 @@ typedef struct UtilVtable {
XP_PlayerAddr channelNo );
#endif
XWBonusType (*m_util_getSquareBonus)( XW_UtilCtxt* uc,
const ModelCtxt* model,
XWBonusType (*m_util_getSquareBonus)( XW_UtilCtxt* uc, XP_U16 boardSize,
XP_U16 col, XP_U16 row );
void (*m_util_userError)( XW_UtilCtxt* uc, UtilErrID id );
@ -201,8 +200,8 @@ struct XW_UtilCtxt {
#define util_makeStreamFromAddr(uc,a) \
(uc)->vtable->m_util_makeStreamFromAddr((uc),(a))
#define util_getSquareBonus(uc,m,c,r) \
(uc)->vtable->m_util_getSquareBonus((uc),(m),(c),(r))
#define util_getSquareBonus(uc,b,c,r) \
(uc)->vtable->m_util_getSquareBonus((uc),(b),(c),(r))
#define util_userError(uc,err) \
(uc)->vtable->m_util_userError((uc),(err))

View file

@ -44,6 +44,8 @@ typedef enum {
//XWPROTO_MOVEMADE_INFO, /* info about tiles placed and received */
,XWPROTO_CLIENT_REQ_END_GAME /* non-server wants to end the game */
,XWPROTO_END_GAME /* server says to end game */
,XWPROTO_NEW_PROTO
} XW_Proto;
#define XWPROTO_NBITS 4

View file

@ -92,7 +92,9 @@ DEFINES += -DDISABLE_TILE_SEL
DEFINES += -DSET_GAMESEED
DEFINES += -DTEXT_MODEL
DEFINES += -DXWFEATURE_WALKDICT
DEFINES += -DXWFEATURE_WALKDICT_FILTER
DEFINES += -DXWFEATURE_DICTSANITY
#DEFINES += -DMAX_ROWS=32
ifdef CURSES_CELL_HT
DEFINES += -DCURSES_CELL_HT=$(CURSES_CELL_HT)

View file

@ -1570,15 +1570,16 @@ positionSizeStuff( CursesAppGlobals* globals, int width, int height )
XP_U16 cellWidth, cellHt, scoreLeft, scoreWidth;
BoardCtxt* board = globals->cGlobals.game.board;
int remWidth = width;
int nRows = globals->cGlobals.params->gi.boardSize;
cellWidth = CURSES_CELL_WIDTH;
cellHt = CURSES_CELL_HT;
board_setPos( board, BOARD_OFFSET, BOARD_OFFSET,
cellWidth * MAX_COLS, cellHt * MAX_ROWS,
cellWidth * nRows, cellHt * nRows,
cellWidth, XP_FALSE );
/* board_setScale( board, cellWidth, cellHt ); */
scoreLeft = (cellWidth * MAX_COLS);// + BOARD_SCORE_PADDING;
remWidth -= cellWidth * MAX_COLS;
scoreLeft = (cellWidth * nRows);// + BOARD_SCORE_PADDING;
remWidth -= cellWidth * nRows;
/* If the scoreboard will right of the board, put it there. Otherwise try
to fit it below the boards. */
@ -1592,8 +1593,9 @@ positionSizeStuff( CursesAppGlobals* globals, int width, int height )
trayTop = 8;
} else {
trayLeft = BOARD_OFFSET;
trayTop = BOARD_OFFSET + (cellHt * MAX_ROWS);
trayTop = BOARD_OFFSET + (cellHt * nRows);
if ( trayTop + trayHt > height ) {
XP_ASSERT( height > trayTop );
trayHt = height - trayTop;
}
}
@ -1819,7 +1821,7 @@ cursesmain( XP_Bool isServer, LaunchParams* params )
#endif
model_setDictionary( g_globals.cGlobals.game.model, params->dict );
setSquareBonuses( &g_globals.cGlobals );
positionSizeStuff( &g_globals, width, height );
#ifndef XWFEATURE_STANDALONE_ONLY

View file

@ -486,6 +486,7 @@ createOrLoadObjects( GtkAppGlobals* globals )
}
#endif
model_setDictionary( globals->cGlobals.game.model, params->dict );
setSquareBonuses( &globals->cGlobals );
model_setPlayerDicts( globals->cGlobals.game.model, &params->dicts );
#ifdef XWFEATURE_SEARCHLIMIT
@ -528,6 +529,8 @@ configure_event( GtkWidget* widget, GdkEventConfigure* XP_UNUSED(event),
gint trayTop;
gint boardTop = 0;
XP_U16 netStatWidth = 0;
gint nCols = globals->cGlobals.params->gi.boardSize;
gint nRows = nCols;
if ( globals->draw == NULL ) {
createOrLoadObjects( globals );
@ -541,25 +544,23 @@ configure_event( GtkWidget* widget, GdkEventConfigure* XP_UNUSED(event),
bdHeight = widget->allocation.height - (GTK_TOP_MARGIN + GTK_BOTTOM_MARGIN)
- GTK_MIN_TRAY_SCALEV - GTK_BOTTOM_MARGIN;
hscale = bdWidth / GTK_NUM_COLS;
hscale = bdWidth / nCols;
if ( 0 != globals->cGlobals.params->nHidden ) {
vscale = hscale;
} else {
vscale = (bdHeight / (GTK_NUM_ROWS + GTK_TRAY_HT_ROWS)); /* makd tray
height 3x cell
height */
vscale = (bdHeight / (nCols + GTK_TRAY_HT_ROWS)); /* makd tray height
3x cell height */
}
if ( !globals->cGlobals.params->verticalScore ) {
boardTop += GTK_HOR_SCORE_HEIGHT;
}
trayTop = boardTop + (vscale * GTK_NUM_ROWS);
trayTop = boardTop + (vscale * nRows);
/* move tray up if part of board's meant to be hidden */
trayTop -= vscale * globals->cGlobals.params->nHidden;
board_setPos( globals->cGlobals.game.board, GTK_BOARD_LEFT, boardTop,
hscale*GTK_NUM_COLS, vscale * GTK_NUM_ROWS,
hscale * 2, XP_FALSE );
hscale * nCols, vscale * nRows, hscale * 2, XP_FALSE );
/* board_setScale( globals->cGlobals.game.board, hscale, vscale ); */
globals->gridOn = XP_TRUE;
@ -569,16 +570,16 @@ configure_event( GtkWidget* widget, GdkEventConfigure* XP_UNUSED(event),
timerTop = GTK_TIMER_TOP;
if ( globals->cGlobals.params->verticalScore ) {
timerLeft = GTK_BOARD_LEFT + (hscale*GTK_NUM_COLS) + 1;
timerLeft = GTK_BOARD_LEFT + (hscale*nCols) + 1;
board_setScoreboardLoc( globals->cGlobals.game.board,
timerLeft,
GTK_VERT_SCORE_TOP,
GTK_VERT_SCORE_WIDTH,
vscale*GTK_NUM_COLS,
vscale*nCols,
XP_FALSE );
} else {
timerLeft = GTK_BOARD_LEFT + (hscale*GTK_NUM_COLS)
timerLeft = GTK_BOARD_LEFT + (hscale*nCols)
- GTK_TIMER_WIDTH - netStatWidth;
board_setScoreboardLoc( globals->cGlobals.game.board,
GTK_BOARD_LEFT, GTK_HOR_SCORE_TOP,
@ -598,7 +599,7 @@ configure_event( GtkWidget* widget, GdkEventConfigure* XP_UNUSED(event),
GTK_TIMER_WIDTH, GTK_HOR_SCORE_HEIGHT );
board_setTrayLoc( globals->cGlobals.game.board, GTK_TRAY_LEFT, trayTop,
hscale * GTK_NUM_COLS, vscale * GTK_TRAY_HT_ROWS + 10,
hscale * nCols, vscale * GTK_TRAY_HT_ROWS + 10,
GTK_DIVIDER_WIDTH );
setCtrlsForTray( globals );
@ -1251,7 +1252,8 @@ handle_hide_button( GtkWidget* XP_UNUSED(widget), GtkAppGlobals* globals )
XP_Bool draw = XP_FALSE;
if ( globals->cGlobals.params->nHidden > 0 ) {
globals->adjustment->page_size = GTK_NUM_ROWS;
gint nRows = globals->cGlobals.params->gi.boardSize;
globals->adjustment->page_size = nRows;
globals->adjustment->value = 0.0;
gtk_signal_emit_by_name( GTK_OBJECT(globals->adjustment), "changed" );
@ -1341,7 +1343,7 @@ setCtrlsForTray( GtkAppGlobals* XP_UNUSED(globals) )
XP_S16 nHidden = globals->cGlobals.params->nHidden;
if ( nHidden != 0 ) {
XP_U16 pageSize = GTK_NUM_ROWS;
XP_U16 pageSize = nRows;
if ( state == TRAY_HIDDEN ) { /* we recover what tray covers */
nHidden -= GTK_TRAY_HT_ROWS;
@ -1373,7 +1375,8 @@ gtk_util_yOffsetChange( XW_UtilCtxt* uc, XP_U16 maxOffset,
{
GtkAppGlobals* globals = (GtkAppGlobals*)uc->closure;
if ( !!globals->adjustment ) {
globals->adjustment->page_size = GTK_NUM_ROWS - maxOffset;
gint nRows = globals->cGlobals.params->gi.boardSize;
globals->adjustment->page_size = nRows - maxOffset;
globals->adjustment->value = newOffset;
gtk_adjustment_value_changed( GTK_ADJUSTMENT(globals->adjustment) );
}
@ -2317,9 +2320,10 @@ gtkmain( LaunchParams* params, int argc, char *argv[] )
/* install scrollbar even if not needed -- since zooming can make it
needed later */
GtkWidget* vscrollbar;
gint nRows = globals.cGlobals.params->gi.boardSize;
globals.adjustment = (GtkAdjustment*)
gtk_adjustment_new( 0, 0, GTK_NUM_ROWS, 1, 2,
GTK_NUM_ROWS-globals.cGlobals.params->nHidden );
gtk_adjustment_new( 0, 0, nRows, 1, 2,
nRows - globals.cGlobals.params->nHidden );
vscrollbar = gtk_vscrollbar_new( globals.adjustment );
g_signal_connect( GTK_OBJECT(globals.adjustment), "value_changed",
G_CALLBACK(scroll_value_changed), &globals );

View file

@ -132,8 +132,6 @@ typedef struct GtkAppGlobals {
/* DictionaryCtxt* gtk_dictionary_make(); */
int gtkmain( LaunchParams* params, int argc, char *argv[] );
#define GTK_NUM_COLS 15
#define GTK_NUM_ROWS 15
#define GTK_MIN_SCALE 12 /* was 14 */
#define GTK_MIN_TRAY_SCALEH 24
@ -156,7 +154,7 @@ int gtkmain( LaunchParams* params, int argc, char *argv[] );
#define GTK_TIMER_WIDTH 40
#define GTK_NETSTAT_WIDTH 20
#define GTK_TIMER_TOP GTK_HOR_SCORE_TOP
#define GTK_HOR_SCORE_WIDTH ((GTK_MIN_SCALE*MAX_COLS)-GTK_TIMER_PAD)
#define GTK_HOR_SCORE_WIDTH ((GTK_MIN_SCALE*20)-GTK_TIMER_PAD)
#define GTK_VERT_SCORE_WIDTH 40
#define GTK_BOARD_TOP (GTK_SCORE_TOP + GTK_SCORE_HEIGHT \

View file

@ -370,6 +370,7 @@ initFromDictFile( LinuxDictionaryCtxt* dctx, const char* fileName )
} else {
dctx->super.base = NULL;
dctx->super.topEdge = NULL;
numEdges = 0;
}
dctx->super.name = copyString( dctx->super.mpool, fileName );

View file

@ -379,6 +379,7 @@ typedef enum {
#ifdef XWFEATURE_WALKDICT
,CMD_TESTDICT
,CMD_TESTPRFX
,CMD_TESTMINMAX
#endif
,CMD_PLAYERDICT
,CMD_SEED
@ -458,6 +459,7 @@ static CmdInfoRec CmdInfoRecs[] = {
#ifdef XWFEATURE_WALKDICT
,{ CMD_TESTDICT, true, "test-dict", "dictionary to be used for iterator test" }
,{ CMD_TESTPRFX, true, "test-prefix", "list first word starting with this" }
,{ CMD_TESTMINMAX, true, "test-minmax", "M:M -- include only words whose len in range" }
#endif
,{ CMD_PLAYERDICT, true, "player-dict", "dictionary name for player (in sequence)" }
,{ CMD_SEED, true, "seed", "random seed" }
@ -1036,28 +1038,35 @@ tmp_noop_sigintterm( int XP_UNUSED(sig) )
//# define PRINT_ALL
static void
testGetNthWord( const DictionaryCtxt* dict, char** words,
XP_U16 depth, IndexData* data )
XP_U16 depth, IndexData* data, XP_U16 min, XP_U16 max )
{
XP_U32 half = dict_getWordCount( dict ) / 2;
XP_UCHAR buf[64];
XP_U32 ii, jj;
DictIter iter;
XP_U32 interval = 1000;
dict_initIter( dict, &iter );
dict_initIter( &iter, dict, min, max );
XP_U32 half = dict_countWords( &iter, NULL ) / 2;
XP_U32 interval = half / 100;
if ( interval == 0 ) {
++interval;
}
for ( ii = 0, jj = half; ii < half; ii += interval, jj += interval ) {
if ( dict_getNthWord( &iter, ii, depth, data ) ) {
dict_wordToString( &iter, buf, VSIZE(buf) );
XP_ASSERT( 0 == strcmp( buf, words[ii] ) );
// XP_LOGF( "%s: word[%ld]: %s", __func__, ii, buf );
# ifdef PRINT_ALL
XP_LOGF( "%s: word[%ld]: %s", __func__, ii, buf );
# endif
} else {
XP_ASSERT( 0 );
}
if ( dict_getNthWord( &iter, jj, depth, data ) ) {
dict_wordToString( &iter, buf, VSIZE(buf) );
XP_ASSERT( 0 == strcmp( buf, words[jj] ) );
// XP_LOGF( "%s: word[%ld]: %s", __func__, jj, buf );
# ifdef PRINT_ALL
XP_LOGF( "%s: word[%ld]: %s", __func__, jj, buf );
# endif
} else {
XP_ASSERT( 0 );
}
@ -1066,7 +1075,7 @@ testGetNthWord( const DictionaryCtxt* dict, char** words,
static void
walk_dict_test( const LaunchParams* params, const DictionaryCtxt* dict,
GSList* testPrefixes )
GSList* testPrefixes, const char* testMinMax )
{
/* This is just to test that the dict-iterating code works. The words are
meant to be printed e.g. in a scrolling dialog on Android. */
@ -1074,139 +1083,147 @@ walk_dict_test( const LaunchParams* params, const DictionaryCtxt* dict,
long jj;
XP_Bool gotOne;
XP_U32 count = dict_getWordCount( dict );
XP_ASSERT( count > 0 );
XP_ASSERT( count == dict_countWords( dict ) );
char** words = g_malloc( count * sizeof(char*) );
XP_ASSERT( !!words );
/* if ( dict_firstWord( dict, &word ) */
/* && dict_getNextWord( dict, &word ) */
/* && dict_getPrevWord( dict, &word ) ) { */
/* fprintf( stderr, "yay!: dict_getPrevWord returned\n" ); */
/* } */
/* exit( 0 ); */
dict_initIter( dict, &iter );
for ( jj = 0, gotOne = dict_firstWord( &iter );
gotOne;
++jj, gotOne = dict_getNextWord( &iter ) ) {
XP_ASSERT( dict_getPosition( &iter ) == jj );
XP_UCHAR buf[64];
dict_wordToString( &iter, buf, VSIZE(buf) );
# ifdef PRINT_ALL
fprintf( stderr, "%.6ld: %s\n", jj, buf );
# endif
if ( !!words ) {
words[jj] = g_strdup( buf );
}
XP_U16 min, max;
if ( !testMinMax || !parsePair( testMinMax, &min, &max ) ) {
min = 0;
max = MAX_COLS_DICT;
}
XP_ASSERT( count == jj );
for ( jj = 0, gotOne = dict_lastWord( &iter );
gotOne;
++jj, gotOne = dict_getPrevWord( &iter ) ) {
XP_ASSERT( dict_getPosition(&iter) == count-jj-1 );
XP_UCHAR buf[64];
dict_wordToString( &iter, buf, VSIZE(buf) );
dict_initIter( &iter, dict, min, max );
LengthsArray lens;
XP_U32 count = dict_countWords( &iter, &lens );
XP_U32 sum = 0;
for ( jj = 0; jj < VSIZE(lens.lens); ++jj ) {
sum += lens.lens[jj];
XP_LOGF( "%ld words of length %ld", lens.lens[jj], jj );
}
XP_ASSERT( sum == count );
if ( count > 0 ) {
char** words = g_malloc( count * sizeof(char*) );
XP_ASSERT( !!words );
for ( jj = 0, gotOne = dict_firstWord( &iter );
gotOne;
gotOne = dict_getNextWord( &iter ) ) {
XP_ASSERT( dict_getPosition( &iter ) == jj );
XP_UCHAR buf[64];
dict_wordToString( &iter, buf, VSIZE(buf) );
# ifdef PRINT_ALL
fprintf( stderr, "%.6ld: %s\n", jj, buf );
fprintf( stderr, "%.6ld: %s\n", jj, buf );
# endif
if ( !!words ) {
if ( strcmp( buf, words[count-jj-1] ) ) {
fprintf( stderr, "failure at %ld: %s going forward; %s "
"going backward\n", jj, words[count-jj-1], buf );
break;
if ( !!words ) {
words[jj] = g_strdup( buf );
}
++jj;
}
}
XP_ASSERT( count == jj );
XP_LOGF( "finished comparing runs in both directions" );
XP_ASSERT( count == jj );
XP_LOGF( "testing getNth" );
testGetNthWord( dict, words, 0, NULL );
XP_U16 depth = 2;
XP_U16 maxCount = dict_numTileFaces( dict );
IndexData data;
data.count = maxCount * maxCount;
data.indices = XP_MALLOC( params->util->mpool,
data.count * depth * sizeof(data.indices[0]) );
data.prefixes = XP_MALLOC( params->util->mpool,
depth * data.count * sizeof(data.prefixes[0]) );
XP_LOGF( "making index..." );
dict_makeIndex( &iter, depth, &data );
XP_LOGF( "DONE making index" );
data.indices = XP_REALLOC( params->util->mpool, data.indices,
data.count * depth * sizeof(*data.indices) );
data.prefixes = XP_REALLOC( params->util->mpool, data.prefixes,
depth * data.count * sizeof(*data.prefixes) );
#if 0
for ( ii = 0; ii < nIndices; ++ii ) {
if ( !dict_getNthWord( dict, &word, indices[ii] ) ) {
XP_ASSERT( 0 );
}
XP_ASSERT( word.index == indices[ii] );
XP_UCHAR buf1[64];
dict_wordToString( dict, &word, buf1, VSIZE(buf1) );
XP_UCHAR buf2[64] = {0};
if ( ii > 0 && dict_getNthWord( dict, &word, indices[ii]-1 ) ) {
dict_wordToString( dict, &word, buf2, VSIZE(buf2) );
}
char prfx[8];
dict_tilesToString( dict, &prefixes[depth*ii], depth, prfx, VSIZE(prfx) );
fprintf( stderr, "%d: index: %ld; prefix: %s; word: %s (prev: %s)\n",
ii, indices[ii], prfx, buf1, buf2 );
}
#endif
XP_LOGF( "testing getNth WITH INDEXING" );
testGetNthWord( dict, words, depth, &data );
if ( !!testPrefixes ) {
int ii;
guint count = g_slist_length( testPrefixes );
for ( ii = 0; ii < count; ++ii ) {
gchar* prefix = (gchar*)g_slist_nth_data( testPrefixes, ii );
Tile tiles[MAX_COLS];
XP_U16 nTiles = VSIZE(tiles);
if ( dict_tilesForString( dict, prefix, tiles, &nTiles ) ) {
if ( dict_findStartsWith( &iter, NULL, tiles, nTiles ) ) {
XP_UCHAR buf[32];
XP_UCHAR bufPrev[32] = {0};
dict_wordToString( &iter, buf, VSIZE(buf) );
XP_ASSERT( 0 == strncmp( buf, prefix, strlen(prefix) ) );
DictPosition pos = dict_getPosition( &iter );
XP_ASSERT( 0 == strcmp( buf, words[pos] ) );
if ( pos > 0 ) {
if ( !dict_getNthWord( &iter, pos-1, depth, &data ) ) {
XP_ASSERT( 0 );
}
dict_wordToString( &iter, bufPrev, VSIZE(bufPrev) );
XP_ASSERT( 0 == strcmp( bufPrev, words[pos-1] ) );
}
XP_LOGF( "dict_getStartsWith(%s) => %s (prev=%s)",
prefix, buf, bufPrev );
} else {
XP_LOGF( "nothing starts with %s", prefix );
for ( jj = 0, gotOne = dict_lastWord( &iter );
gotOne;
++jj, gotOne = dict_getPrevWord( &iter ) ) {
XP_ASSERT( dict_getPosition(&iter) == count-jj-1 );
XP_UCHAR buf[64];
dict_wordToString( &iter, buf, VSIZE(buf) );
# ifdef PRINT_ALL
fprintf( stderr, "%.6ld: %s\n", jj, buf );
# endif
if ( !!words ) {
if ( strcmp( buf, words[count-jj-1] ) ) {
fprintf( stderr, "failure at %ld: %s going forward; %s "
"going backward\n", jj, words[count-jj-1], buf );
break;
}
}
}
XP_ASSERT( count == jj );
XP_LOGF( "finished comparing runs in both directions" );
XP_LOGF( "testing getNth" );
testGetNthWord( dict, words, 0, NULL, min, max );
XP_U16 depth = 2;
XP_U16 maxCount = dict_numTileFaces( dict );
IndexData data;
data.count = maxCount * maxCount;
data.indices = XP_MALLOC( params->util->mpool,
data.count * depth * sizeof(data.indices[0]) );
data.prefixes = XP_MALLOC( params->util->mpool,
depth * data.count * sizeof(data.prefixes[0]) );
XP_LOGF( "making index..." );
dict_makeIndex( &iter, depth, &data );
XP_LOGF( "DONE making index" );
data.indices = XP_REALLOC( params->util->mpool, data.indices,
data.count * depth * sizeof(*data.indices) );
data.prefixes = XP_REALLOC( params->util->mpool, data.prefixes,
depth * data.count * sizeof(*data.prefixes) );
#if 0
for ( ii = 0; ii < nIndices; ++ii ) {
if ( !dict_getNthWord( dict, &word, indices[ii] ) ) {
XP_ASSERT( 0 );
}
XP_ASSERT( word.index == indices[ii] );
XP_UCHAR buf1[64];
dict_wordToString( dict, &word, buf1, VSIZE(buf1) );
XP_UCHAR buf2[64] = {0};
if ( ii > 0 && dict_getNthWord( dict, &word, indices[ii]-1 ) ) {
dict_wordToString( dict, &word, buf2, VSIZE(buf2) );
}
char prfx[8];
dict_tilesToString( dict, &prefixes[depth*ii], depth, prfx, VSIZE(prfx) );
fprintf( stderr, "%d: index: %ld; prefix: %s; word: %s (prev: %s)\n",
ii, indices[ii], prfx, buf1, buf2 );
}
#endif
XP_LOGF( "testing getNth WITH INDEXING" );
testGetNthWord( dict, words, depth, &data, min, max );
if ( !!testPrefixes ) {
int ii;
guint count = g_slist_length( testPrefixes );
for ( ii = 0; ii < count; ++ii ) {
gchar* prefix = (gchar*)g_slist_nth_data( testPrefixes, ii );
Tile tiles[MAX_COLS_DICT];
XP_U16 nTiles = VSIZE(tiles);
if ( dict_tilesForString( dict, prefix, tiles, &nTiles ) ) {
if ( dict_findStartsWith( &iter, NULL, tiles, nTiles ) ) {
XP_UCHAR buf[32];
XP_UCHAR bufPrev[32] = {0};
dict_wordToString( &iter, buf, VSIZE(buf) );
XP_ASSERT( 0 == strncmp( buf, prefix, strlen(prefix) ) );
DictPosition pos = dict_getPosition( &iter );
XP_ASSERT( 0 == strcmp( buf, words[pos] ) );
if ( pos > 0 ) {
if ( !dict_getNthWord( &iter, pos-1, depth, &data ) ) {
XP_ASSERT( 0 );
}
dict_wordToString( &iter, bufPrev, VSIZE(bufPrev) );
XP_ASSERT( 0 == strcmp( bufPrev, words[pos-1] ) );
}
XP_LOGF( "dict_getStartsWith(%s) => %s (prev=%s)",
prefix, buf, bufPrev );
} else {
XP_LOGF( "nothing starts with %s", prefix );
}
}
}
}
XP_FREE( params->util->mpool, data.indices );
XP_FREE( params->util->mpool, data.prefixes );
}
XP_LOGF( "done" );
XP_FREE( params->util->mpool, data.indices );
XP_FREE( params->util->mpool, data.prefixes );
} /* walk_dict_test */
}
static void
walk_dict_test_all( const LaunchParams* params, GSList* testDicts,
GSList* testPrefixes )
GSList* testPrefixes, const char* testMinMax )
{
int ii;
guint count = g_slist_length( testDicts );
@ -1217,7 +1234,7 @@ walk_dict_test_all( const LaunchParams* params, GSList* testDicts,
params->useMmap );
if ( NULL != dict ) {
XP_LOGF( "walk_dict_test(%s)", name );
walk_dict_test( params, dict, testPrefixes );
walk_dict_test( params, dict, testPrefixes, testMinMax );
dict_destroy( dict );
}
}
@ -1242,6 +1259,7 @@ main( int argc, char** argv )
#ifdef XWFEATURE_WALKDICT
GSList* testDicts = NULL;
GSList* testPrefixes = NULL;
char* testMinMax = NULL;
#endif
/* install a no-op signal handler. Later curses- or gtk-specific code
@ -1366,6 +1384,9 @@ main( int argc, char** argv )
case CMD_TESTPRFX:
testPrefixes = g_slist_prepend( testPrefixes, g_strdup(optarg) );
break;
case CMD_TESTMINMAX:
testMinMax = optarg;
break;
#endif
case CMD_PLAYERDICT:
mainParams.gi.players[nPlayerDicts++].dictName = optarg;
@ -1631,7 +1652,7 @@ main( int argc, char** argv )
/* } */
#ifdef XWFEATURE_WALKDICT
if ( !!testDicts ) {
walk_dict_test_all( &mainParams, testDicts, testPrefixes );
walk_dict_test_all( &mainParams, testDicts, testPrefixes, testMinMax );
exit( 0 );
}
#endif

View file

@ -80,6 +80,63 @@ linux_util_makeEmptyDict( XW_UtilCtxt* XP_UNUSED_DBG(uctx) )
#define TL BONUS_TRIPLE_LETTER
#define TW BONUS_TRIPLE_WORD
static XWBonusType*
bonusesFor( XP_U16 boardSize, XP_U16* len )
{
static XWBonusType scrabbleBoard[] = {
TW,//EM,EM,DL,EM,EM,EM,TW,
EM,DW,//EM,EM,EM,TL,EM,EM,
EM,EM,DW,//EM,EM,EM,DL,EM,
DL,EM,EM,DW,//EM,EM,EM,DL,
EM,EM,EM,EM,DW,//EM,EM,EM,
EM,TL,EM,EM,EM,TL,//EM,EM,
EM,EM,DL,EM,EM,EM,DL,//EM,
TW,EM,EM,DL,EM,EM,EM,DW,
}; /* scrabbleBoard */
static XWBonusType seventeen[] = {
TW,//EM,EM,DL,EM,EM,EM,TW,
EM,DW,//EM,EM,EM,TL,EM,EM,
EM,EM,DW,//EM,EM,EM,DL,EM,
DL,EM,EM,DW,//EM,EM,EM,DL,
EM,EM,EM,EM,DW,//EM,EM,EM,
EM,TL,EM,EM,EM,TL,//EM,EM,
EM,EM,DL,EM,EM,EM,DL,//EM,
TW,EM,EM,DL,EM,EM,EM,DW,
TW,EM,EM,DL,EM,EM,EM,DW,DW,
}; /* scrabbleBoard */
XWBonusType* result = NULL;
if ( boardSize == 15 ) {
result = scrabbleBoard;
*len = VSIZE(scrabbleBoard);
} else if ( boardSize == 17 ) {
result = seventeen;
*len = VSIZE(seventeen);
}
return result;
}
#ifdef STREAM_VERS_BIGBOARD
void
setSquareBonuses( const CommonGlobals* cGlobals )
{
XP_U16 nBonuses;
XWBonusType* bonuses =
bonusesFor( cGlobals->params->gi.boardSize, &nBonuses );
if ( !!bonuses ) {
model_setSquareBonuses( cGlobals->game.model, bonuses, nBonuses );
}
}
#endif
static XWBonusType*
parseBonusFile( XP_U16 nCols, const char* bonusFile )
{
@ -146,14 +203,13 @@ parseBonusFile( XP_U16 nCols, const char* bonusFile )
}
static XWBonusType
linux_util_getSquareBonus( XW_UtilCtxt* uc, const ModelCtxt* model,
linux_util_getSquareBonus( XW_UtilCtxt* uc, XP_U16 nCols,
XP_U16 col, XP_U16 row )
{
static XWBonusType* parsedFile = NULL;
XWBonusType result = EM;
CommonGlobals* cGlobals = (CommonGlobals*)uc->closure;
XP_U16 nCols = model_numCols( model );
if ( NULL == parsedFile && NULL != cGlobals->params->bonusFile ) {
if ( !parsedFile ) {
parsedFile = parseBonusFile( nCols, cGlobals->params->bonusFile );
@ -162,25 +218,12 @@ linux_util_getSquareBonus( XW_UtilCtxt* uc, const ModelCtxt* model,
if ( NULL != parsedFile ) {
result = parsedFile[(row*nCols) + col];
} else {
XP_U16 nEntries;
XWBonusType* scrabbleBoard = bonusesFor( 15, &nEntries );
XP_U16 index, ii;
/* This must be static or won't compile under multilink (for Palm).
Fix! */
static char scrabbleBoard[8*8] = {
TW,//EM,EM,DL,EM,EM,EM,TW,
EM,DW,//EM,EM,EM,TL,EM,EM,
EM,EM,DW,//EM,EM,EM,DL,EM,
DL,EM,EM,DW,//EM,EM,EM,DL,
EM,EM,EM,EM,DW,//EM,EM,EM,
EM,TL,EM,EM,EM,TL,//EM,EM,
EM,EM,DL,EM,EM,EM,DL,//EM,
TW,EM,EM,DL,EM,EM,EM,DW,
}; /* scrabbleBoard */
if ( col > 7 ) col = 14 - col;
if ( row > 7 ) row = 14 - row;
if ( col > (nCols/2) ) col = nCols - 1 - col;
if ( row > (nCols/2) ) row = nCols - 1 - row;
if ( col > row ) {
XP_U16 tmp = col;
col = row;
@ -191,8 +234,8 @@ linux_util_getSquareBonus( XW_UtilCtxt* uc, const ModelCtxt* model,
index += ii;
}
if ( index < VSIZE(scrabbleBoard) ) {
result = (XWBonusType)scrabbleBoard[index];
if ( index < nEntries) {
result = scrabbleBoard[index];
}
}
return result;

View file

@ -1,6 +1,6 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; compile-command: "make MEMDEBUG=TRUE"; -*- */
/* -*- compile-command: "make MEMDEBUG=TRUE -j3"; -*- */
/*
* Copyright 2000-2008 by Eric House (xwords@eehouse.org). All rights
* Copyright 2000 - 2011 by Eric House (xwords@eehouse.org). All rights
* reserved.
*
* This program is free software; you can redistribute it and/or
@ -47,4 +47,10 @@ XP_Bool storeNoConnMsg( CommonGlobals* cGlobals, const XP_U8* msg, XP_U16 len,
const XP_UCHAR* relayID );
void writeNoConnMsgs( CommonGlobals* cGlobals, int fd );
#ifdef STREAM_VERS_BIGBOARD
void setSquareBonuses( const CommonGlobals* cGlobals );
#else
# define setSquareBonuses( cg )
#endif
#endif