Merge branch 'android_branch' of ssh://xwords.git.sourceforge.net/gitroot/xwords/xwords into android_branch

This commit is contained in:
Eric House 2010-07-27 20:47:42 -07:00
commit ad1be65236
53 changed files with 1210 additions and 400 deletions

View file

@ -22,7 +22,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.eehouse.android.xw4"
android:versionCode="6"
android:versionName="4.4 beta 12"
android:versionName="4.4 beta 13"
>
<uses-permission android:name="android.permission.INTERNET" />

View file

@ -15,8 +15,9 @@ local_DEFINES += \
$(local_DEBUG) \
-DXWFEATURE_RELAY \
-DXWFEATURE_TURNCHANGENOTIFY \
-DXWFEATURE_CROSSHAIRS \
-DSHOW_PROGRESS \
-DKEY_SUPPORT \
-DXWFEATURE_CROSSHAIRS \
-DPOINTER_SUPPORT \
-DSCROLL_DRAG_THRESHHOLD=1 \
-DDROP_BITMAPS \

View file

@ -197,10 +197,12 @@ and_util_yOffsetChange(XW_UtilCtxt* uc, XP_U16 maxOffset,
static void
and_util_turnChanged(XW_UtilCtxt* uc)
{
/* don't log; this is getting called a lot */
UTIL_CBK_HEADER( "turnChanged", "()V" );
(*env)->CallVoidMethod( env, util->jutil, mid );
UTIL_CBK_TAIL();
}
#endif
static void
and_util_notifyGameOver( XW_UtilCtxt* uc )
{
@ -378,13 +380,17 @@ and_util_getTraySearchLimits(XW_UtilCtxt* uc, XP_U16* min, XP_U16* max )
static void
and_util_engineStarting( XW_UtilCtxt* uc, XP_U16 nBlanks )
{
LOG_FUNC();
UTIL_CBK_HEADER("engineStarting", "(I)V" );
(*env)->CallVoidMethod( env, util->jutil, mid, nBlanks );
UTIL_CBK_TAIL();
}
static void
and_util_engineStopping( XW_UtilCtxt* uc )
{
LOG_FUNC();
UTIL_CBK_HEADER("engineStopping", "()V" );
(*env)->CallVoidMethod( env, util->jutil, mid );
UTIL_CBK_TAIL();
}
#endif

View file

@ -160,6 +160,7 @@ loadCommonPrefs( JNIEnv* env, CommonPrefs* cp, jobject j_cp )
cp->skipCommitConfirm = getBool( env, j_cp, "skipCommitConfirm" );
cp->showColors = getBool( env, j_cp, "showColors" );
cp->sortNewTiles = getBool( env, j_cp, "sortNewTiles" );
cp->allowPeek = getBool( env, j_cp, "allowPeek" );
}
static XWStreamCtxt*
@ -694,6 +695,17 @@ Java_org_eehouse_android_xw4_jni_XwJNI_board_1replaceTiles
return result;
}
JNIEXPORT jboolean JNICALL
Java_org_eehouse_android_xw4_jni_XwJNI_board_1redoReplacedTiles
( JNIEnv* env, jclass C, jint gamePtr )
{
jboolean result;
XWJNI_START();
result = board_redoReplacedTiles( state->game.board );
XWJNI_END();
return result;
}
JNIEXPORT void JNICALL
Java_org_eehouse_android_xw4_jni_XwJNI_server_1handleUndo
(JNIEnv* env, jclass C, jint gamePtr)
@ -726,7 +738,7 @@ Java_org_eehouse_android_xw4_jni_XwJNI_board_1resetEngine
JNIEXPORT jboolean JNICALL
Java_org_eehouse_android_xw4_jni_XwJNI_board_1requestHint
( JNIEnv* env, jclass C, jint gamePtr, jboolean useLimits,
jbooleanArray workRemains )
jboolean goBack, jbooleanArray workRemains )
{
jboolean result;
XWJNI_START();
@ -735,7 +747,7 @@ Java_org_eehouse_android_xw4_jni_XwJNI_board_1requestHint
#ifdef XWFEATURE_SEARCHLIMIT
useLimits,
#endif
&tmpbool );
goBack, &tmpbool );
/* If passed need to do workRemains[0] = tmpbool */
if ( workRemains ) {
jboolean jbool = tmpbool;
@ -1024,6 +1036,51 @@ Java_org_eehouse_android_xw4_jni_XwJNI_board_1focusChanged
}
#endif
JNIEXPORT jint JNICALL
Java_org_eehouse_android_xw4_jni_XwJNI_board_1visTileCount
( JNIEnv* env, jclass C, jint gamePtr )
{
jint result;
XWJNI_START();
result = board_visTileCount( state->game.board );
XWJNI_END();
return result;
}
JNIEXPORT jboolean JNICALL
Java_org_eehouse_android_xw4_jni_XwJNI_board_1canHint
( JNIEnv* env, jclass C, jint gamePtr )
{
jboolean result;
XWJNI_START();
result = board_canHint( state->game.board );
XWJNI_END();
return result;
}
JNIEXPORT jboolean JNICALL
Java_org_eehouse_android_xw4_jni_XwJNI_board_1canShuffle
( JNIEnv* env, jclass C, jint gamePtr )
{
jboolean result;
XWJNI_START();
result = board_canShuffle( state->game.board );
XWJNI_END();
return result;
}
JNIEXPORT jboolean JNICALL
Java_org_eehouse_android_xw4_jni_XwJNI_board_1canTogglePending
( JNIEnv* env, jclass C, jint gamePtr )
{
jboolean result;
XWJNI_START();
result = board_canTogglePending( state->game.board );
XWJNI_END();
return result;
}
#ifdef KEYBOARD_NAV
JNIEXPORT jboolean JNICALL
Java_org_eehouse_android_xw4_jni_XwJNI_board_1handleKey
( JNIEnv* env, jclass C, jint gamePtr, jobject jkey, jboolean jup,
@ -1044,6 +1101,7 @@ Java_org_eehouse_android_xw4_jni_XwJNI_board_1handleKey
XWJNI_END();
return result;
}
#endif
JNIEXPORT jboolean JNICALL
Java_org_eehouse_android_xw4_jni_XwJNI_game_1hasComms

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View file

@ -6,38 +6,24 @@
>
<TextView android:id="@+id/version_string"
android:layout_marginLeft="5sp"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textColor="#FFFFFFFF"
style="@style/about_items"
/>
<TextView android:layout_marginLeft="5sp"
android:layout_marginTop="5sp"
android:layout_marginBottom="5sp"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
<TextView style="@style/about_items"
android:text="@string/about_copyright"
android:textColor="#FFFFFFFF"
/>
<TextView android:layout_marginLeft="5sp"
android:layout_marginTop="5sp"
android:layout_marginBottom="5sp"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/about_web"
android:textColor="#FFFFFFFF"
<TextView style="@style/about_items"
android:text="@string/about_web"
android:autoLink="all"
/>
<TextView android:id="@+id/about_xlator"
android:layout_marginLeft="5sp"
android:layout_marginTop="5sp"
android:layout_marginBottom="5sp"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textColor="#FFFFFFFF"
style="@style/about_items"
/>
<TextView style="@style/about_items"
android:text="@string/about_credits"
/>
</LinearLayout>

View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:paddingLeft="3dp"
@ -9,14 +9,90 @@
android:paddingTop="3dp"
>
<org.eehouse.android.xw4.BoardView
android:id="@+id/board_view"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
android:focusable="true"
android:clickable="true"
android:longClickable="true"
android:drawSelectorOnTop="false"/>
<LinearLayout android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
>
<org.eehouse.android.xw4.BoardView
android:id="@+id/board_view"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
android:focusable="true"
android:clickable="true"
android:longClickable="true"
android:drawSelectorOnTop="false"/>
<LinearLayout android:id="@+id/toolbar_horizontal"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
>
<ImageButton android:id="@+id/prevhint_button_horizontal"
style="@style/toolbar_button"
android:src="@drawable/prev_hint"
/>
<ImageButton android:id="@+id/nexthint_button_horizontal"
style="@style/toolbar_button"
android:src="@drawable/next_hint"
/>
<ImageButton android:id="@+id/shuffle_button_horizontal"
style="@style/toolbar_button"
android:src="@drawable/shuffle"
/>
<ImageButton android:id="@+id/flip_button_horizontal"
style="@style/toolbar_button"
android:src="@drawable/flip"
/>
<ImageButton android:id="@+id/zoom_button_horizontal"
style="@style/toolbar_button"
android:src="@drawable/zoom"
/>
<ImageButton android:id="@+id/values_button_horizontal"
style="@style/toolbar_button"
android:src="@drawable/values"
/>
<ImageButton android:id="@+id/undo_button_horizontal"
style="@style/toolbar_button"
android:src="@drawable/undo"
/>
</LinearLayout>
</LinearLayout>
<LinearLayout android:id="@+id/toolbar_vertical"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
>
<ImageButton android:id="@+id/prevhint_button_vertical"
style="@style/toolbar_button"
android:src="@drawable/prev_hint"
/>
<ImageButton android:id="@+id/nexthint_button_vertical"
style="@style/toolbar_button"
android:src="@drawable/next_hint"
/>
<ImageButton android:id="@+id/shuffle_button_vertical"
style="@style/toolbar_button"
android:src="@drawable/shuffle"
/>
<ImageButton android:id="@+id/flip_button_vertical"
style="@style/toolbar_button"
android:src="@drawable/flip"
/>
<ImageButton android:id="@+id/zoom_button_vertical"
style="@style/toolbar_button"
android:src="@drawable/zoom"
/>
<ImageButton android:id="@+id/values_button_vertical"
style="@style/toolbar_button"
android:src="@drawable/values"
/>
<ImageButton android:id="@+id/undo_button_vertical"
style="@style/toolbar_button"
android:src="@drawable/undo"
/>
</LinearLayout>
</LinearLayout>

View file

@ -11,4 +11,20 @@
android:textAppearance="?android:attr/textAppearanceLarge"
android:longClickable="true"
android:background="@android:drawable/list_selector_background"
/>
>
<TextView android:id="@+id/text_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textAppearance="?android:attr/textAppearanceMedium"
/>
<ImageButton android:id="@+id/hint_button_horizontal"
android:layout_width="32dp"
android:layout_height="32dp"
android:src="@android:drawable/ic_delete"
android:visibility="gone"
/>
</org.eehouse.android.xw4.XWListItem>

View file

@ -1,53 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/board_menu_juggle"
android:title="@string/board_menu_juggle"
android:alphabeticShortcut="J"
/>
<item android:id="@+id/board_menu_trade"
android:title="@string/board_menu_trade"
android:alphabeticShortcut="T"
/>
<item android:title="@string/board_submenu_hint">
<menu>
<item android:id="@+id/board_menu_hint_next"
android:title="@string/board_menu_hint_next"
android:alphabeticShortcut="H"
/>
<item android:id="@+id/board_menu_hint"
android:title="@string/board_menu_hint"
/>
<item android:id="@+id/board_menu_values"
android:title="@string/board_menu_values"
android:alphabeticShortcut="V"
/>
</menu>
</item>
<item android:title="@string/board_submenu_undo">
<menu>
<item android:id="@+id/board_menu_undo_current"
android:title="@string/board_menu_undo_current"
/>
<item android:id="@+id/board_menu_undo_last"
android:title="@string/board_menu_undo_last"
android:alphabeticShortcut="U"
/>
</menu>
</item>
<item android:id="@+id/board_menu_tray"
android:title="@string/board_menu_tray"
android:alphabeticShortcut="H"
/>
<!-- <item android:id="@+id/board_menu_juggle" -->
<!-- android:title="@string/board_menu_juggle" -->
<!-- android:alphabeticShortcut="J" -->
<!-- /> -->
<item android:id="@+id/board_menu_done"
android:title="@string/board_menu_done"
android:alphabeticShortcut="D"
/>
<item android:id="@+id/board_menu_flip"
android:title="@string/board_menu_flip"
android:alphabeticShortcut="F"
<item android:id="@+id/board_menu_trade"
android:title="@string/board_menu_trade"
android:alphabeticShortcut="T"
/>
<item android:id="@+id/board_menu_undo_last"
android:title="@string/board_menu_undo_last"
android:alphabeticShortcut="U"
/>
<item android:id="@+id/board_menu_tray"
android:title="@string/board_menu_tray"
android:alphabeticShortcut="H"
/>
<!-- <item android:id="@+id/board_menu_flip" -->
<!-- android:title="@string/board_menu_flip" -->
<!-- android:alphabeticShortcut="F" -->
<!-- /> -->
<item android:id="@+id/board_menu_values"
android:title="@string/board_menu_values"
android:alphabeticShortcut="V"
/>
<item android:title="@string/board_submenu_game">
@ -64,6 +48,19 @@
android:title="@string/board_menu_game_resend" />
</menu>
</item>
<item android:title="@string/board_submenu_hint">
<menu>
<item android:id="@+id/board_menu_hint"
android:title="@string/board_menu_hint"
/>
<item android:id="@+id/board_menu_hint_next"
android:title="@string/board_menu_hint_next"
android:alphabeticShortcut="H"
/>
</menu>
</item>
<item android:id="@+id/board_menu_file_prefs"
android:title="@string/menu_prefs"
android:alphabeticShortcut="P"

View file

@ -4,9 +4,6 @@
<item android:id="@+id/dicts_item_select"
android:title="@string/dicts_item_select"
/>
<item android:id="@+id/dicts_item_delete"
android:title="@string/dicts_item_delete"
/>
<item android:id="@+id/dicts_item_details"
android:title="@string/dicts_item_details"
/>

View file

@ -1,16 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<!-- <item android:id="@+id/list_item_open" -->
<!-- android:title="@string/list_item_open" -->
<!-- /> -->
<item android:id="@+id/player_list_item_delete"
android:title="@string/list_item_delete"
/>
<item android:id="@+id/player_list_item_up"
android:title="@string/list_item_up"
/>
<item android:id="@+id/player_list_item_down"
android:title="@string/list_item_down"
/>
</menu>

View file

@ -19,13 +19,14 @@
<string name="menu_insert">Afegeix una partida</string>
<string name="button_new_game">Afegeix una partida</string>
<string name="list_item_play">Vés a la partida</string>
<string name="list_item_config">Configura</string>
<string name="list_item_hide">Amaga</string>
<string name="list_item_delete">Suprimeix</string>
<string name="list_item_copy">Copia</string>
<string name="list_item_reset">Reinicialitza</string>
<string name="list_item_new_from">Nova des de</string>
<string name="list_item_new_from">Nova</string>
<string name="list_item_move_up">Mou amunt</string>
<string name="list_item_move_down">Mou avall</string>
<string name="list_item_move_to_top">Mou amunt de tot</string>
@ -185,8 +186,18 @@
<string name="explain_robot_summary">Mostra el resum de la jugada dels jugadors robot</string>
<string name="skip_confirm_turn">Omet la confirmació de la jugada</string>
<string name="skip_confirm_turn_summary">No mostra el resum de la jugada dels jugadors humans</string>
<string name="title_sort_tiles">Ordena les fitxes noves</string>
<string name="summary_sort_tiles">Ordena el faristol en agafar noves fitxes</string>
<string name="ringer_zoom">Zoom amb els botons de volum</string>
<string name="ringer_zoom_summary">Apropa o allunya el tauler fent servir les tecles de volum.</string>
<string name="click_launches">Clic per a jugar</string>
<string name="click_launches_summary">obre la partida en fer-hi clic al llistat de partides, en compte d\'obrir un menú d\'opcions</string>
<string name="hide_title">Amaga la capçalera</string>
<string name="hide_title_summary">Permet que el tauler sigui una mica més gran</string>
<string name="show_bonussum">Mostra les bonificacions</string>
<string name="show_bonussum_summary">Mostra el text com "2P" a les caselles bonificadores lliures</string>
<string name="role_standalone">Solitari</string>
<string name="role_host">Amfitrió</string>
@ -215,7 +226,13 @@
<string name="prefs_defaults">Valors predeterminats per a partides noves</string>
<string name="prefs_defaults_summary">Paràmetres predeterminats per a partides noves</string>
<string name="default_dict">Diccionari de la partida</string>
<string name="prefs_appearance">Aspecte</string>
<string name="prefs_appearance_summary">Paràmetres que controlen l\'aspecte</string>
<string name="prefs_behavior">Comportament</string>
<string name="prefs_behavior_summary">Paràmetres que controlen el comportament de l\'aplicació</string>
<string name="default_dict">Diccionari arbitral</string>
<string name="default_phonies">Paraules fora del dicc.</string>
<string name="board_size">Mida del tauler</string>
<string name="default_timerenabled">Usa el rellotge</string>
@ -232,9 +249,15 @@
<string name="bonus_l3x">Triple de lletra</string>
<string name="bonus_w2x">Doble de paraula</string>
<string name="bonus_w3x">Triple de paraula</string>
<string name="bonus_l2x_summary">2L</string>
<string name="bonus_w2x_summary">2P</string>
<string name="bonus_l3x_summary">3L</string>
<string name="bonus_w3x_summary">3P</string>
<string name="pts">pts</string>
<string name="trading_text">Canvi de fitxes. Pitgeu\n\'Fet\' quan hagueu acabat.</string>
<string name="tile_back">Fons de la fitxa</string>
<string name="empty">Cel·la buida/fons</string>
<string name="clr_crosshairs">Creu d\'ubicació</string>
<string name="focus">Color del focus</string>
<string name="advanced">Avançat</string>
<string name="advanced_summary">No hauríeu de necessitar canviar això</string>

View file

@ -9,6 +9,7 @@
<string name="key_explain_robot">key_explain_robot</string>
<string name="key_skip_confirm">key_skip_confirm</string>
<string name="key_sort_tiles">key_sort_tiles</string>
<string name="key_peek_other">key_peek_other</string>
<string name="key_hide_values">key_hide_values</string>
<string name="key_ringer_zoom">key_ringer_zoom</string>
<string name="key_click_launches">key_click_launches</string>

View file

@ -83,7 +83,7 @@
<string name="board_menu_undo_last">Undo last</string>
<string name="board_submenu_hint">Hint</string>
<string name="board_menu_hint_next">Next hint</string>
<string name="board_menu_hint">Hint</string>
<string name="board_menu_hint">First hint</string>
<string name="board_menu_values">Show values</string>
<string name="board_submenu_game">Game</string>
<string name="board_menu_game_counts">Counts and values</string>
@ -135,7 +135,7 @@
<string name="str_too_few_tiles_left_to_trade">Too few tiles left to exchange.</string>
<string name="str_cant_undo_tileassign">Tile assignment can't be undone.</string>
<string name="str_cant_hint_while_disabled">The hint feature is disabled for this game. Enable it for a new game using the Settings dialog.</string>
<string name="str_no_peek_remote_tiles">No peeking at remote players' tiles!</string>
<string name="str_no_peek_remote_tiles">No peeking at remote players\' tiles!</string>
<string name="str_reg_unexpected_user">Refused attempt to register unexpected user[s]</string>
<string name="str_server_dict_wins">Conflict between Host and Guest dictionaries; Host wins.</string>
<string name="str_reg_server_sans_remote">At least one player must be marked \"Remote\" for a game started as Host.</string>
@ -180,6 +180,7 @@
delete all games? This action cannot be undone.</string>
<string name="hints_allowed">Allow hints</string>
<string name="progress_title">Searching for moves</string>
<string name="use_timer">Enable game timer</string>
<string name="color_tiles">Color tiles</string>
<string name="color_tiles_summary">Draw tiles using color of
@ -197,16 +198,16 @@
<string name="summary_sort_tiles">Sort trays whenever new tiles
are added</string>
<string name="ringer_zoom">Volume keys zoom</string>
<string name="ringer_zoom_summary">Zoom board using volume keys
rather than on-screen buttons</string>
<string name="ringer_zoom_summary">Zoom board using volume keys</string>
<string name="click_launches">Tap to play</string>
<string name="click_launches_summary">Tapping on game in games
list opens it rather than dropping a menu</string>
<string name="hide_title">Hide titlebar</string>
<string name="hide_title_summary">Hiding the game name lets the
board be slightly larger</string>
<string name="peek_other">View tiles out-of-turn</string>
<string name="peek_other_summary">Tapping on scoreboard name shows
that player\'s tiles</string>
<string name="show_bonussum">Show bonus values</string>
<string name="show_bonussum_summary">Include text like "2W" on
empty bonus squares</string>
@ -339,6 +340,9 @@
<!-- fill this in other than in English -->
<string name="xlator"></string>
<string name="about_credits">Toolbar icons by Sarah Chu; other
credits pending permission.</string>
<string name="downloading_dictf">Downloading Crosswords
dictionary %s...</string>
<string name="no_dict_title">Dictionary not found</string>

View file

@ -37,5 +37,20 @@
<item name="android:ems">3</item>
</style>
<style name="toolbar_button">
<item name="android:layout_width">48dp</item>
<item name="android:layout_height">48dp</item>
<item name="android:layout_weight">1</item>
</style>
<style name="about_items">
<item name="android:layout_marginLeft">5sp</item>
<item name="android:layout_marginTop">5sp</item>
<item name="android:layout_marginBottom">5sp</item>
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:textColor">#FFFFFFFF</item>
</style>
</resources>

View file

@ -152,6 +152,11 @@
android:summary="@string/click_launches_summary"
android:defaultValue="false"
/>
<CheckBoxPreference android:key="@string/key_peek_other"
android:title="@string/peek_other"
android:summary="@string/peek_other_summary"
android:defaultValue="false"
/>
</PreferenceScreen>
<PreferenceScreen android:title="@string/advanced"

View file

@ -22,6 +22,7 @@ package org.eehouse.android.xw4;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MenuInflater;
@ -35,7 +36,9 @@ import java.util.concurrent.Semaphore;
import android.net.Uri;
import android.app.Dialog;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.widget.ImageButton;
import android.widget.Toast;
import android.widget.EditText;
import android.widget.TextView;
@ -67,6 +70,7 @@ public class BoardActivity extends Activity implements UtilCtxt {
private TimerRunnable[] m_timers;
private String m_path;
private int m_currentOrient;
private Toolbar m_toolbar;
private String m_dlgBytes = null;
private EditText m_passwdEdit = null;
@ -84,6 +88,8 @@ public class BoardActivity extends Activity implements UtilCtxt {
private Thread m_blockingThread;
private JNIThread m_jniThread;
private ProgressDialog m_progress;
public class TimerRunnable implements Runnable {
private int m_why;
private int m_when;
@ -253,7 +259,6 @@ public class BoardActivity extends Activity implements UtilCtxt {
m_view = (BoardView)findViewById( R.id.board_view );
m_volKeysZoom = CommonPrefs.getVolKeysZoom( this );
m_view.setUseZoomControl( !m_volKeysZoom );
Intent intent = getIntent();
Uri uri = intent.getData();
@ -343,7 +348,6 @@ public class BoardActivity extends Activity implements UtilCtxt {
m_jniThread.handle( JNIThread.JNICmd.CMD_PREFS_CHANGE );
}
}
m_view.setUseZoomControl( !m_volKeysZoom );
}
}
@ -351,6 +355,11 @@ public class BoardActivity extends Activity implements UtilCtxt {
public void onConfigurationChanged( Configuration newConfig )
{
m_currentOrient = newConfig.orientation;
if ( null != m_toolbar ) {
boolean landscape =
m_currentOrient == Configuration.ORIENTATION_LANDSCAPE;
m_toolbar.orientChanged( landscape );
}
super.onConfigurationChanged( newConfig );
}
@ -368,7 +377,7 @@ public class BoardActivity extends Activity implements UtilCtxt {
case KeyEvent.KEYCODE_VOLUME_UP:
if ( m_volKeysZoom ) {
int zoomBy = KeyEvent.KEYCODE_VOLUME_DOWN == keyCode
? -1 : 1;
? -2 : 2;
handled = doZoom( zoomBy );
}
break;
@ -406,21 +415,21 @@ public class BoardActivity extends Activity implements UtilCtxt {
case R.id.board_menu_done:
cmd = JNIThread.JNICmd.CMD_COMMIT;
break;
case R.id.board_menu_juggle:
cmd = JNIThread.JNICmd.CMD_JUGGLE;
break;
case R.id.board_menu_flip:
cmd = JNIThread.JNICmd.CMD_FLIP;
break;
// case R.id.board_menu_juggle:
// cmd = JNIThread.JNICmd.CMD_JUGGLE;
// break;
// case R.id.board_menu_flip:
// cmd = JNIThread.JNICmd.CMD_FLIP;
// break;
case R.id.board_menu_trade:
cmd = JNIThread.JNICmd.CMD_TOGGLE_TRADE;
break;
case R.id.board_menu_tray:
cmd = JNIThread.JNICmd.CMD_TOGGLE_TRAY;
break;
case R.id.board_menu_undo_current:
cmd = JNIThread.JNICmd.CMD_UNDO_CUR;
break;
// case R.id.board_menu_undo_current:
// cmd = JNIThread.JNICmd.CMD_UNDO_CUR;
// break;
case R.id.board_menu_undo_last:
cmd = JNIThread.JNICmd.CMD_UNDO_LAST;
break;
@ -687,6 +696,8 @@ public class BoardActivity extends Activity implements UtilCtxt {
case JNIThread.QUERY_ENDGAME:
showDialog( QUERY_ENDGAME );
break;
case JNIThread.TOOLBAR_STATES:
m_toolbar.update( msg.arg1, msg.arg2 );
}
}
} );
@ -698,11 +709,80 @@ public class BoardActivity extends Activity implements UtilCtxt {
}
m_jniThread.handle( JNICmd.CMD_START );
setTitle( GameUtils.gameName( this, m_path ) );
// setTitle( GameUtils.gameName( this, m_path ) );
m_toolbar =
new Toolbar( this, findViewById( R.id.toolbar_horizontal ),
findViewById( R.id.toolbar_vertical ) );
boolean isLandscape =
getResources().getConfiguration().orientation
== Configuration.ORIENTATION_LANDSCAPE;
m_toolbar.orientChanged( isLandscape );
populateToolbar();
}
}
} // loadGame
private void populateToolbar()
{
m_toolbar.setListener( Toolbar.BUTTON_HINT_PREV,
new View.OnClickListener() {
@Override
public void onClick( View view ) {
m_jniThread.handle( JNIThread.JNICmd
.CMD_PREV_HINT );
}
} );
m_toolbar.setListener( Toolbar.BUTTON_HINT_NEXT,
new View.OnClickListener() {
@Override
public void onClick( View view ) {
m_jniThread.handle( JNIThread.JNICmd
.CMD_NEXT_HINT );
}
} );
m_toolbar.setListener( Toolbar.BUTTON_JUGGLE,
new View.OnClickListener() {
@Override
public void onClick( View view ) {
m_jniThread.handle( JNIThread.JNICmd
.CMD_JUGGLE );
}
} );
m_toolbar.setListener( Toolbar.BUTTON_FLIP,
new View.OnClickListener() {
@Override
public void onClick( View view ) {
m_jniThread.handle( JNIThread.JNICmd
.CMD_FLIP );
}
} );
m_toolbar.setListener( Toolbar.BUTTON_ZOOM,
new View.OnClickListener() {
@Override
public void onClick( View view ) {
m_jniThread.handle( JNIThread.JNICmd
.CMD_TOGGLEZOOM );
}
} );
m_toolbar.setListener( Toolbar.BUTTON_UNDO,
new View.OnClickListener() {
@Override
public void onClick( View view ) {
m_jniThread.handle( JNIThread.JNICmd
.CMD_UNDO_CUR );
}
}) ;
m_toolbar.setListener( Toolbar.BUTTON_VALUES,
new View.OnClickListener() {
@Override
public void onClick( View view ) {
m_jniThread.handle( JNIThread.JNICmd
.CMD_VALUES );
}
}) ;
} // populateToolbar
private DialogInterface.OnDismissListener makeODLforBlocking()
{
return new DialogInterface.OnDismissListener() {
@ -794,11 +874,44 @@ public class BoardActivity extends Activity implements UtilCtxt {
return result;
}
public void turnChanged()
{
m_jniThread.handle( JNIThread.JNICmd.CMD_ZOOM, -8 );
}
public boolean engineProgressCallback()
{
return ! m_jniThread.busy();
}
public void engineStarting( int nBlanks )
{
Utils.logf( "engineStarting(%d)", nBlanks );
if ( nBlanks > 0 ) {
m_handler.post( new Runnable() {
public void run() {
String title = getString( R.string.progress_title );
m_progress = ProgressDialog.show( BoardActivity.this,
title, null, true,
true );
}
} );
}
}
public void engineStopping()
{
Utils.logf( "engineStopping" );
m_handler.post( new Runnable() {
public void run() {
if ( null != m_progress ) {
m_progress.cancel();
m_progress = null;
}
}
} );
}
public String getUserString( int stringCode )
{
int id = 0;

View file

@ -33,9 +33,7 @@ import android.view.MotionEvent;
import android.graphics.drawable.Drawable;
import android.content.res.Resources;
import android.graphics.Paint.FontMetricsInt;
import android.widget.ZoomButtonsController;
import android.os.Handler;
import java.util.HashMap;
import java.nio.IntBuffer;
import junit.framework.Assert;
@ -117,9 +115,6 @@ public class BoardView extends View implements DrawCtx, BoardHandler,
private int[] m_playerColors;
private int[] m_otherColors;
private String[] m_bonusSummaries;
private ZoomButtonsController m_zoomButtons;
private boolean m_useZoomControl;
private boolean m_canZoom;
// called when inflating xml
public BoardView( Context context, AttributeSet attrs )
@ -132,15 +127,13 @@ public class BoardView extends View implements DrawCtx, BoardHandler,
{
int action = event.getAction();
int xx = (int)event.getX() - m_left;
int yy = (int)event.getY() - getCurTop();
int yy = (int)event.getY() - m_top;
switch ( action ) {
case MotionEvent.ACTION_DOWN:
enableZoomControlsIf();
m_jniThread.handle( JNIThread.JNICmd.CMD_PEN_DOWN, xx, yy );
break;
case MotionEvent.ACTION_MOVE:
enableZoomControlsIf();
m_jniThread.handle( JNIThread.JNICmd.CMD_PEN_MOVE, xx, yy );
break;
case MotionEvent.ACTION_UP:
@ -160,18 +153,11 @@ public class BoardView extends View implements DrawCtx, BoardHandler,
{
synchronized( this ) {
if ( layoutBoardOnce() ) {
canvas.drawBitmap( m_bitmap, m_left, getCurTop(), m_drawPaint );
canvas.drawBitmap( m_bitmap, m_left, m_top, m_drawPaint );
}
}
}
@Override
protected void onDetachedFromWindow()
{
m_zoomButtons.setVisible( false );
super.onDetachedFromWindow();
}
private void init( Context context )
{
m_context = context;
@ -215,33 +201,6 @@ public class BoardView extends View implements DrawCtx, BoardHandler,
}
m_viewHandler = new Handler();
m_zoomButtons = new ZoomButtonsController( this );
ZoomButtonsController.OnZoomListener lstnr =
new ZoomButtonsController.OnZoomListener(){
public void onVisibilityChanged( boolean visible ){}
public void onZoom( boolean zoomIn )
{
if ( null != m_jniThread ) {
int zoomBy = zoomIn ? 1 : -1;
m_jniThread.handle( JNIThread.JNICmd.CMD_ZOOM, zoomBy );
}
}
};
m_zoomButtons.setOnZoomListener( lstnr );
m_zoomButtons.setZoomSpeed( 100 ); // milliseconds
}
protected void setUseZoomControl( boolean useZoomControl )
{
m_useZoomControl = useZoomControl;
if ( !useZoomControl ) {
m_zoomButtons.setVisible( false );
}
}
private int getCurTop()
{
return m_useZoomControl ? 0 : m_top;
}
private BoardDims figureBoardDims( int width, int height,
@ -309,9 +268,6 @@ public class BoardView extends View implements DrawCtx, BoardHandler,
m_letterRect = null;
m_valRect = null;
// We hide zoom on change in orientation
m_zoomButtons.setVisible( false );
BoardDims dims = figureBoardDims( width, height, m_gi );
m_left = dims.left;
m_top = dims.top;
@ -329,15 +285,6 @@ public class BoardView extends View implements DrawCtx, BoardHandler,
return layoutDone;
} // layoutBoardOnce
private void enableZoomControlsIf()
{
if ( m_useZoomControl && m_canZoom ) {
if ( m_layoutWidth <= m_layoutHeight ) {
m_zoomButtons.setVisible( true );
}
}
}
// BoardHandler interface implementation
public void startHandling( JNIThread thread, int gamePtr, CurGameInfo gi )
{
@ -375,17 +322,6 @@ public class BoardView extends View implements DrawCtx, BoardHandler,
}
}
public void zoomChanged( final boolean[] canZoom )
{
m_viewHandler.post( new Runnable() {
public void run() {
m_zoomButtons.setZoomInEnabled( canZoom[0] );
m_zoomButtons.setZoomOutEnabled( canZoom[1] );
m_canZoom = canZoom[0] || canZoom[1];
}
} );
}
// DrawCtxt interface implementation
public boolean scoreBegin( Rect rect, int numPlayers, int[] scores,
int remCount, int dfs )
@ -550,7 +486,9 @@ public class BoardView extends View implements DrawCtx, BoardHandler,
m_origin.draw( m_canvas );
} else if ( null != bonusStr ) {
m_fillPaint.setColor( GREY );
drawCentered( bonusStr, rect, m_fontDims );
Rect brect = new Rect( rect );
brect.inset( 0, (brect.height() - m_defaultFontHt)/2 );
drawCentered( bonusStr, brect, m_fontDims );
}
} else {
m_fillPaint.setColor( foreColor );

View file

@ -39,7 +39,8 @@ import android.content.SharedPreferences;
import junit.framework.Assert;
public class DictsActivity extends ListActivity
implements View.OnClickListener {
implements View.OnClickListener,
XWListItem.DeleteCallback {
String[] m_dicts;
private class DictListAdapter extends XWListAdapter {
@ -58,6 +59,12 @@ public class DictsActivity extends ListActivity
= (XWListItem)factory.inflate( R.layout.list_item, null );
view.setPosition( position );
view.setText( m_dicts[position] );
if ( !GameUtils.dictIsBuiltin( DictsActivity.this,
m_dicts[position] ) ) {
view.setDeleteCallback( DictsActivity.this );
}
return view;
}
}
@ -88,8 +95,8 @@ public class DictsActivity extends ListActivity
@Override
public void onCreateContextMenu( ContextMenu menu, View view,
ContextMenuInfo menuInfo ) {
ContextMenuInfo menuInfo )
{
super.onCreateContextMenu( menu, view, menuInfo );
MenuInflater inflater = getMenuInflater();
@ -97,12 +104,6 @@ public class DictsActivity extends ListActivity
AdapterView.AdapterContextMenuInfo info
= (AdapterView.AdapterContextMenuInfo)menuInfo;
String dict = m_dicts[info.position];
if ( GameUtils.dictIsBuiltin( this, dict ) ) {
MenuItem item = menu.findItem( R.id.dicts_item_delete );
item.setVisible( false );
}
}
@Override
@ -127,11 +128,6 @@ public class DictsActivity extends ListActivity
editor.putString( key, m_dicts[info.position] );
editor.commit();
break;
case R.id.dicts_item_delete:
GameUtils.deleteDict( this, m_dicts[info.position] );
mkListAdapter();
handled = true;
break;
case R.id.dicts_item_details:
Utils.notImpl( this );
break;
@ -140,6 +136,13 @@ public class DictsActivity extends ListActivity
return handled;
}
// DeleteCallback interface
public void deleteCalled( int myPosition )
{
GameUtils.deleteDict( this, m_dicts[myPosition] );
mkListAdapter();
}
private void mkListAdapter()
{
m_dicts = GameUtils.dictList( this );

View file

@ -41,8 +41,6 @@ import android.content.DialogInterface;
import android.view.LayoutInflater;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.MenuInflater;
import android.view.KeyEvent;
import android.widget.Spinner;
@ -56,7 +54,8 @@ import junit.framework.Assert;
import org.eehouse.android.xw4.jni.*;
import org.eehouse.android.xw4.jni.CurGameInfo.DeviceRole;
public class GameConfig extends Activity implements View.OnClickListener {
public class GameConfig extends Activity implements View.OnClickListener,
XWListItem.DeleteCallback {
private static final int PLAYER_EDIT = 1;
private static final int ROLE_EDIT_RELAY = 2;
@ -453,42 +452,12 @@ public class GameConfig extends Activity implements View.OnClickListener {
setTitle( String.format( fmt, GameUtils.gameName( this, m_path ) ) );
} // onCreate
@Override
public void onCreateContextMenu( ContextMenu menu, View view,
ContextMenuInfo menuInfo ) {
MenuInflater inflater = getMenuInflater();
inflater.inflate( R.menu.players_list_item_menu, menu );
m_whichPlayer = ((XWListItem)view).getPosition();
}
@Override
public boolean onContextItemSelected( MenuItem item )
// DeleteCallback interface
public void deleteCalled( int myPosition )
{
boolean handled = true;
boolean changed = false;
switch (item.getItemId()) {
// case R.id.player_list_item_edit:
// showDialog( PLAYER_EDIT );
// break;
case R.id.player_list_item_delete:
changed = m_gi.delete( m_whichPlayer );
break;
case R.id.player_list_item_up:
changed = m_gi.moveUp( m_whichPlayer );
break;
case R.id.player_list_item_down:
changed = m_gi.moveDown( m_whichPlayer );
break;
default:
handled = false;
}
if ( changed ) {
if ( m_gi.delete( myPosition ) ) {
loadPlayers();
}
return handled;
}
public void onClick( View view )
@ -560,8 +529,11 @@ public class GameConfig extends Activity implements View.OnClickListener {
view.setPosition( ii );
view.setText( names[ii] );
view.setGravity( Gravity.CENTER );
// only enable delete if one will remain
if ( 1 < names.length ) {
view.setDeleteCallback( this );
}
registerForContextMenu( view );
view.setOnClickListener( new View.OnClickListener() {
@Override
public void onClick( View view ) {
@ -576,6 +548,13 @@ public class GameConfig extends Activity implements View.OnClickListener {
m_playerLayout.addView( divider );
}
m_addPlayerButton
.setVisibility( names.length >= CurGameInfo.MAX_NUM_PLAYERS?
View.GONE : View.VISIBLE );
m_jugglePlayersButton
.setVisibility( names.length <= 1 ?
View.GONE : View.VISIBLE );
if ( DeviceRole.SERVER_ISSERVER == m_gi.serverRole
&& 0 == m_gi.remoteCount() ) {
showDialog( FORCE_REMOTE );

View file

@ -0,0 +1,138 @@
/* -*- compile-command: "cd ../../../../../; ant install"; -*- */
/*
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
* rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
package org.eehouse.android.xw4;
import android.app.Activity;
import android.content.Context;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.ImageButton;
//import android.view.LayoutInflater;
//import java.util.HashMap;
//import junit.framework.Assert;
import org.eehouse.android.xw4.jni.*;
public class Toolbar {
private static class TBButtonInfo {
public TBButtonInfo( int... ids ) {
m_ids = ids;
}
public int m_ids[];
}
public static final int BUTTON_HINT_PREV = 0;
public static final int BUTTON_HINT_NEXT = 1;
public static final int BUTTON_FLIP = 2;
public static final int BUTTON_JUGGLE = 3;
public static final int BUTTON_ZOOM = 4;
public static final int BUTTON_UNDO = 5;
public static final int BUTTON_VALUES = 6;
private static TBButtonInfo[] s_buttonInfo = {
// BUTTON_HINT_PREV
new TBButtonInfo(R.id.prevhint_button_horizontal,
R.id.prevhint_button_vertical),
// BUTTON_HINT_NEXT
new TBButtonInfo(R.id.nexthint_button_horizontal,
R.id.nexthint_button_vertical),
// BUTTON_FLIP
new TBButtonInfo(R.id.flip_button_horizontal,
R.id.flip_button_vertical),
// BUTTON_JUGGLE
new TBButtonInfo( R.id.shuffle_button_horizontal,
R.id.shuffle_button_vertical ),
// BUTTON_ZOOM
new TBButtonInfo( R.id.zoom_button_horizontal,
R.id.zoom_button_vertical ),
// BUTTON_UNDO
new TBButtonInfo( R.id.undo_button_horizontal,
R.id.undo_button_vertical ),
// BUTTON_VALUES
new TBButtonInfo( R.id.values_button_horizontal,
R.id.values_button_vertical ),
};
private Activity m_activity;
private LinearLayout m_horLayout;
private LinearLayout m_vertLayout;
private enum ORIENTATION { ORIENT_UNKNOWN,
ORIENT_PORTRAIT,
ORIENT_LANDSCAPE,
};
private ORIENTATION m_curOrient = ORIENTATION.ORIENT_UNKNOWN;
public Toolbar( Activity activity, View horLayout, View vertLayout )
{
m_activity = activity;
m_horLayout = (LinearLayout)horLayout;
m_vertLayout = (LinearLayout)vertLayout;
}
public void setListener( int index, View.OnClickListener listener )
{
TBButtonInfo info = s_buttonInfo[index];
for ( int id : info.m_ids ) {
ImageButton button = (ImageButton)m_activity.findViewById( id );
button.setOnClickListener( listener );
}
}
public void orientChanged( boolean landscape )
{
if ( landscape && m_curOrient == ORIENTATION.ORIENT_LANDSCAPE ) {
// do nothing
} else if ( !landscape && m_curOrient == ORIENTATION.ORIENT_PORTRAIT ) {
// do nothing
} else {
LinearLayout prevLayout, nextLayout;
if ( landscape ) {
m_curOrient = ORIENTATION.ORIENT_LANDSCAPE;
prevLayout = m_horLayout;
nextLayout = m_vertLayout;
} else {
m_curOrient = ORIENTATION.ORIENT_PORTRAIT;
prevLayout = m_vertLayout;
nextLayout = m_horLayout;
}
prevLayout.setVisibility( View.GONE );
nextLayout.setVisibility( View.VISIBLE );
}
}
public void update( int index, int enable )
{
boolean show = enable!=0;
TBButtonInfo info = s_buttonInfo[index];
int vis = enable != 0 ? View.VISIBLE : View.GONE;
ImageButton button;
for ( int id : info.m_ids ) {
button = (ImageButton)m_activity.findViewById( id );
button.setVisibility( vis );
}
}
}

View file

@ -23,5 +23,5 @@ package org.eehouse.android.xw4;
public interface XWConstants {
public static final String GAME_EXTN = ".xwg";
public static final String DICT_EXTN = ".xwd";
public static final String VERSION_STR = "4.4 beta 12";
public static final String VERSION_STR = "4.4 beta 13";
}

View file

@ -20,18 +20,48 @@
package org.eehouse.android.xw4;
import android.widget.LinearLayout;
import android.view.View;
import android.widget.TextView;
import android.widget.ImageButton;
import android.content.Context;
import android.util.AttributeSet;
import android.graphics.Rect;
public class XWListItem extends TextView {
public class XWListItem extends LinearLayout {
private int m_position;
private ImageButton m_button;
private Context m_context;
DeleteCallback m_cb;
public interface DeleteCallback {
void deleteCalled( int myPosition );
}
public XWListItem( Context cx, AttributeSet as ) {
super( cx, as );
m_context = cx;
}
public int getPosition() { return m_position; }
public void setPosition( int indx ) { m_position = indx; }
public void setText( String text )
{
TextView view = (TextView)getChildAt( 0 );
view.setText( text );
}
public void setDeleteCallback( DeleteCallback cb )
{
m_cb = cb;
ImageButton button = (ImageButton)getChildAt( 1 );
button.setOnClickListener( new View.OnClickListener() {
@Override
public void onClick( View view ) {
m_cb.deleteCalled( m_position );
}
} );
button.setVisibility( View.VISIBLE );
}
}

View file

@ -45,6 +45,7 @@ public class CommonPrefs {
public boolean skipCommitConfirm;
public boolean showColors;
public boolean sortNewTiles;
public boolean allowPeek;
public int[] playerColors;
public int[] bonusColors;
@ -78,6 +79,7 @@ public class CommonPrefs {
R.string.key_skip_confirm, false );
showColors = getBoolean( context, sp, R.string.key_color_tiles, true );
sortNewTiles = getBoolean( context, sp, R.string.key_sort_tiles, true );
allowPeek = getBoolean( context, sp, R.string.key_peek_other, false );
int ids[] = { R.string.key_player0,
R.string.key_player1,

View file

@ -34,6 +34,7 @@ import org.eehouse.android.xw4.R;
import org.eehouse.android.xw4.BoardDims;
import org.eehouse.android.xw4.GameUtils;
import org.eehouse.android.xw4.DBUtils;
import org.eehouse.android.xw4.Toolbar;
import org.eehouse.android.xw4.jni.CurGameInfo.DeviceRole;
public class JNIThread extends Thread {
@ -63,6 +64,8 @@ public class JNIThread extends Thread {
CMD_UNDO_LAST,
CMD_HINT,
CMD_ZOOM,
CMD_TOGGLEZOOM,
CMD_PREV_HINT,
CMD_NEXT_HINT,
CMD_VALUES,
CMD_COUNTS_VALUES,
@ -79,6 +82,7 @@ public class JNIThread extends Thread {
public static final int DRAW = 2;
public static final int DIALOG = 3;
public static final int QUERY_ENDGAME = 4;
public static final int TOOLBAR_STATES = 5;
private boolean m_stopped = false;
private int m_jniGamePtr;
@ -196,6 +200,31 @@ public class JNIThread extends Thread {
{
boolean draw = false;
return draw;
} // processKeyEvent
private void checkButtons()
{
int visTileCount = XwJNI.board_visTileCount( m_jniGamePtr );
int canFlip = visTileCount > 1 ? 1 : 0;
Message.obtain( m_handler, TOOLBAR_STATES, Toolbar.BUTTON_FLIP,
canFlip ).sendToTarget();
int canValues = visTileCount > 0 ? 1 : 0;
Message.obtain( m_handler, TOOLBAR_STATES, Toolbar.BUTTON_VALUES,
canValues ).sendToTarget();
int canShuffle = XwJNI.board_canShuffle( m_jniGamePtr ) ? 1 : 0;
Message.obtain( m_handler, TOOLBAR_STATES, Toolbar.BUTTON_JUGGLE,
canShuffle ).sendToTarget();
int canRedo = XwJNI.board_canTogglePending( m_jniGamePtr ) ? 1 : 0;
Message.obtain( m_handler, TOOLBAR_STATES, Toolbar.BUTTON_UNDO,
canRedo ).sendToTarget();
int canHint = XwJNI.board_canHint( m_jniGamePtr ) ? 1 : 0;
Message.obtain( m_handler, TOOLBAR_STATES, Toolbar.BUTTON_HINT_PREV,
canHint ).sendToTarget();
Message.obtain( m_handler, TOOLBAR_STATES, Toolbar.BUTTON_HINT_NEXT,
canHint ).sendToTarget();
}
public void run()
@ -321,7 +350,8 @@ public class JNIThread extends Thread {
draw = XwJNI.board_beginTrade( m_jniGamePtr );
break;
case CMD_UNDO_CUR:
draw = XwJNI.board_replaceTiles( m_jniGamePtr );
draw = XwJNI.board_replaceTiles( m_jniGamePtr )
|| XwJNI.board_redoReplacedTiles( m_jniGamePtr );
break;
case CMD_UNDO_LAST:
XwJNI.server_handleUndo( m_jniGamePtr );
@ -330,19 +360,37 @@ public class JNIThread extends Thread {
case CMD_HINT:
XwJNI.board_resetEngine( m_jniGamePtr );
// fallthru
handle( JNICmd.CMD_NEXT_HINT );
break;
case CMD_NEXT_HINT:
draw = XwJNI.board_requestHint( m_jniGamePtr, false, barr );
case CMD_PREV_HINT:
if ( nextSame( elem.m_cmd ) ) {
continue;
}
draw = XwJNI.board_requestHint( m_jniGamePtr, false,
JNICmd.CMD_PREV_HINT==elem.m_cmd,
barr );
if ( barr[0] ) {
handle( JNICmd.CMD_NEXT_HINT );
handle( elem.m_cmd );
draw = false;
}
break;
case CMD_TOGGLEZOOM:
XwJNI.board_zoom( m_jniGamePtr, 0 , barr );
int zoomBy = 0;
if ( barr[1] ) { // always go out if possible
zoomBy = -4;
} else if ( barr[0] ) {
zoomBy = 4;
}
draw = XwJNI.board_zoom( m_jniGamePtr, zoomBy, barr );
break;
case CMD_ZOOM:
draw = XwJNI.board_zoom( m_jniGamePtr,
((Integer)args[0]).intValue(),
barr );
m_drawer.zoomChanged( barr );
break;
case CMD_VALUES:
@ -433,6 +481,8 @@ public class JNIThread extends Thread {
// main UI thread has to invalidate view as it created
// it.
Message.obtain( m_handler, DRAW ).sendToTarget();
checkButtons();
}
}
Utils.logf( "run exiting" );
@ -444,4 +494,5 @@ public class JNIThread extends Thread {
// Utils.logf( "adding: " + cmd.toString() );
m_queue.add( elem );
}
}

View file

@ -25,5 +25,4 @@ import android.graphics.Rect;
public interface SyncedDraw {
void doJNIDraw();
void doIconDraw( int resID, final Rect rect );
void zoomChanged( boolean[] canZoom );
}

View file

@ -32,8 +32,11 @@ public interface UtilCtxt {
int playerNum, String[] texts );
String askPassword( String name );
void turnChanged();
boolean engineProgressCallback();
void engineStarting( int nBlanks );
void engineStopping();
// Values for why; should be enums
public static final int TIMER_PENDOWN = 1;

View file

@ -137,14 +137,21 @@ public class XwJNI {
public static native boolean board_commitTurn( int gamePtr );
public static native boolean board_flip( int gamePtr );
public static native boolean board_replaceTiles( int gamePtr );
public static native boolean board_redoReplacedTiles( int gamePtr );
public static native void board_resetEngine( int gamePtr );
public static native boolean board_requestHint( int gamePtr,
boolean useTileLimits,
boolean goBackwards,
boolean[] workRemains );
public static native boolean board_beginTrade( int gamePtr );
public static native String board_formatRemainingTiles( int gamePtr );
public static native int board_visTileCount( int gamePtr );
public static native boolean board_canHint( int gamePtr );
public static native boolean board_canShuffle( int gamePtr );
public static native boolean board_canTogglePending( int gamePtr );
public enum XP_Key {
XP_KEY_NONE,
XP_CURSOR_KEY_DOWN,

View file

@ -72,8 +72,6 @@
# define MAX_BOARD_ZOOM 4
#endif
#define BOARD_ZOOMBY 2
#ifdef CPLUS
extern "C" {
#endif
@ -424,6 +422,7 @@ board_prefsChanged( BoardCtxt* board, CommonPrefs* cp )
board->hideValsInTray = cp->hideTileValues;
board->skipCommitConfirm = cp->skipCommitConfirm;
board->showColors = cp->showColors;
board->allowPeek = cp->allowPeek;
if ( showArrowChanged ) {
showArrowChanged = setArrowVisible( board, XP_FALSE );
@ -537,6 +536,38 @@ board_getYOffset( const BoardCtxt* board )
return vsd->offset;
} /* board_getYOffset */
XP_U16
board_visTileCount( const BoardCtxt* board )
{
return model_visTileCount( board->model, board->selPlayer,
TRAY_REVEALED == board->trayVisState );
}
XP_Bool
board_canShuffle( const BoardCtxt* board )
{
return model_canShuffle( board->model, board->selPlayer,
TRAY_REVEALED == board->trayVisState );
}
XP_Bool
board_canTogglePending( const BoardCtxt* board )
{
return TRAY_REVEALED == board->trayVisState
&& model_canTogglePending( board->model, board->selPlayer );
}
XP_Bool
board_canHint( const BoardCtxt* board )
{
XP_Bool canHint = !board->gi->hintsNotAllowed;
if ( canHint ) {
LocalPlayer* lp = &board->gi->players[board->selPlayer];
canHint = lp->isLocal && !lp->isRobot;
}
return canHint;
}
static XP_U16
adjustOffset( XP_U16 curOffset, XP_S16 zoomBy )
{
@ -561,20 +592,13 @@ canZoomIn( const BoardCtxt* board, XP_S16 newCount )
}
XP_Bool
board_zoom( BoardCtxt* board, XP_S16 zoomDir, XP_Bool* canInOut )
board_zoom( BoardCtxt* board, XP_S16 zoomBy, XP_Bool* canInOut )
{
XP_S16 zoomBy = 0;
XP_Bool changed;
XP_S16 zoomCount = board->zoomCount;
ScrollData* hsd = &board->sd[SCROLL_H];
ScrollData* vsd = &board->sd[SCROLL_V];
if ( zoomDir > 0 ) {
zoomBy = BOARD_ZOOMBY;
} else if ( zoomDir < 0 ) {
zoomBy = -BOARD_ZOOMBY;
}
XP_U16 maxCount = model_numCols( board->model ) - MAX_BOARD_ZOOM;
if ( board->boardBounds.width > board->boardBounds.height ) {
XP_U16 ratio = board->boardBounds.width / board->boardBounds.height;
@ -592,8 +616,11 @@ board_zoom( BoardCtxt* board, XP_S16 zoomDir, XP_Bool* canInOut )
/* If we're zooming in, make sure we'll stay inside the limit */
if ( changed && zoomBy > 0 ) {
changed = canZoomIn( board, zoomCount );
while ( zoomCount > 0 && !canZoomIn( board, zoomCount ) ) {
--zoomCount;
}
}
changed = zoomCount != board->zoomCount;
if ( changed ) {
/* Try to distribute the zoom */
@ -788,15 +815,17 @@ board_commitTurn( BoardCtxt* board )
* singletons that may have to be hidden or shown.
*/
static void
selectPlayerImpl( BoardCtxt* board, XP_U16 newPlayer, XP_Bool reveal )
selectPlayerImpl( BoardCtxt* board, XP_U16 newPlayer, XP_Bool reveal,
XP_Bool canPeek )
{
if ( !board->gameOver && server_getCurrentTurn(board->server) < 0 ) {
XP_S16 curTurn = server_getCurrentTurn(board->server);
if ( !board->gameOver && curTurn < 0 ) {
/* game not started yet; do nothing */
} else if ( board->selPlayer == newPlayer ) {
if ( reveal ) {
checkRevealTray( board );
}
} else {
} else if ( canPeek || newPlayer == curTurn ) {
PerTurnInfo* newInfo = &board->pti[newPlayer];
XP_U16 oldPlayer = board->selPlayer;
model_foreachPendingCell( board->model, newPlayer,
@ -846,9 +875,9 @@ selectPlayerImpl( BoardCtxt* board, XP_U16 newPlayer, XP_Bool reveal )
} /* selectPlayerImpl */
void
board_selectPlayer( BoardCtxt* board, XP_U16 newPlayer )
board_selectPlayer( BoardCtxt* board, XP_U16 newPlayer, XP_Bool canSwitch )
{
selectPlayerImpl( board, newPlayer, XP_TRUE );
selectPlayerImpl( board, newPlayer, XP_TRUE, canSwitch );
} /* board_selectPlayer */
void
@ -1577,6 +1606,12 @@ board_replaceTiles( BoardCtxt* board )
return result;
} /* board_replaceTiles */
XP_Bool
board_redoReplacedTiles( BoardCtxt* board )
{
return model_redoPendingTiles( board->model, board->selPlayer );
}
/* There are a few conditions that must be true for any of several actions
to be allowed. Check them here. */
static XP_Bool
@ -1597,7 +1632,7 @@ board_requestHint( BoardCtxt* board,
#ifdef XWFEATURE_SEARCHLIMIT
XP_Bool useTileLimits,
#endif
XP_Bool* workRemainsP )
XP_Bool usePrev, XP_Bool* workRemainsP )
{
XP_Bool result = XP_FALSE;
XP_Bool redraw = XP_FALSE;
@ -1669,7 +1704,7 @@ board_requestHint( BoardCtxt* board,
#endif
searchComplete = engine_findMove(engine, model,
model_getDictionary(model),
tiles, nTiles,
tiles, nTiles, usePrev,
#ifdef XWFEATURE_SEARCHLIMIT
lp, useTileLimits,
#endif
@ -1730,8 +1765,8 @@ figureHScale( BoardCtxt* board )
ScrollData* hsd;
while ( !canZoomIn( board, board->zoomCount ) ) {
XP_ASSERT( board->zoomCount >= BOARD_ZOOMBY );
board->zoomCount -= BOARD_ZOOMBY;
XP_ASSERT( board->zoomCount >= 1 );
--board->zoomCount;
}
nCols = model_numCols( board->model );
@ -3276,7 +3311,7 @@ boardTurnChanged( void* p_board )
nextPlayer = chooseBestSelPlayer( board );
if ( nextPlayer >= 0 ) {
XP_U16 nHumans = gi_countLocalHumans( board->gi );
selectPlayerImpl( board, nextPlayer, nHumans <= 1 );
selectPlayerImpl( board, nextPlayer, nHumans <= 1, XP_TRUE );
}
setTimerIf( board );

View file

@ -78,6 +78,11 @@ void board_reset( BoardCtxt* board );
XP_Bool board_setYOffset( BoardCtxt* board, XP_U16 newOffset );
XP_U16 board_getYOffset( const BoardCtxt* board );
XP_U16 board_visTileCount( const BoardCtxt* board );
XP_Bool board_canShuffle( const BoardCtxt* board );
XP_Bool board_canTogglePending( const BoardCtxt* board );
XP_Bool board_canHint( const BoardCtxt* board );
/* zoomBy: >0: zoom in; < 0: zoom out; 0: query only */
XP_Bool board_zoom( BoardCtxt* board, XP_S16 zoomBy, XP_Bool* canInOut );
@ -98,12 +103,13 @@ XP_Bool board_flip( BoardCtxt* board );
XP_Bool board_get_showValues( const BoardCtxt* board );
XP_Bool board_toggle_showValues( BoardCtxt* board );
XP_Bool board_replaceTiles( BoardCtxt* board );
XP_Bool board_redoReplacedTiles( BoardCtxt* board );
XP_Bool board_requestHint( BoardCtxt* board,
#ifdef XWFEATURE_SEARCHLIMIT
XP_Bool useTileLimits,
#endif
XP_Bool* workRemainsP );
XP_Bool usePrev, XP_Bool* workRemainsP );
XP_Bool board_prefsChanged( BoardCtxt* board, CommonPrefs* cp );

View file

@ -58,11 +58,12 @@ typedef struct _DragState {
DragType dtype;
XP_Bool didMove; /* there was change during the drag; not a
tap */
XP_Bool cellChanged; /* nothing dragged but movement happened */
XP_Bool scrollTimerSet;
XP_Bool isBlank; /* cache rather than lookup in model */
Tile tile; /* cache rather than lookup in model */
DragObjInfo start;
DragObjInfo cur;
DragObjInfo cur; /* where dragged object (not pen) is */
#ifdef XWFEATURE_RAISETILE
XP_U16 yyAdd;
#endif
@ -172,6 +173,7 @@ struct BoardCtxt {
XP_Bool disableArrow;
XP_Bool hideValsInTray;
XP_Bool skipCommitConfirm;
XP_Bool allowPeek; /* Can look at non-turn player's rack */
XP_Bool eraseTray;
XP_Bool boardObscuresTray;
@ -245,7 +247,7 @@ void figureTrayTileRect( BoardCtxt* board, XP_U16 index, XP_Rect* rect );
XP_Bool rectsIntersect( const XP_Rect* rect1, const XP_Rect* rect2 );
XP_S16 pointToTileIndex( BoardCtxt* board, XP_U16 x, XP_U16 y,
XP_Bool* onDividerP );
void board_selectPlayer( BoardCtxt* board, XP_U16 newPlayer );
void board_selectPlayer( BoardCtxt* board, XP_U16 newPlayer, XP_Bool canPeek );
void flipIf( const BoardCtxt* board, XP_U16 col, XP_U16 row,
XP_U16* fCol, XP_U16* fRow );
XP_Bool pointOnSomething( BoardCtxt* board, XP_U16 x, XP_U16 y,

View file

@ -135,6 +135,7 @@ typedef struct CommonPrefs {
XP_U16 robotThinkMin, robotThinkMax;
#endif
XP_Bool showColors; /* applies to all games */
XP_Bool allowPeek; /* applies to all games */
} CommonPrefs;
#ifdef XWFEATURE_BLUETOOTH

View file

@ -63,7 +63,16 @@ dragDropInProgress( const BoardCtxt* board )
XP_Bool
dragDropHasMoved( const BoardCtxt* board )
{
return dragDropInProgress(board) && board->dragState.didMove;
XP_Bool moved = dragDropInProgress( board );
if ( moved ) {
if ( board->dragState.didMove ) {
/* something was dragged; do nothing */
} else {
const DragState* ds = &board->dragState;
moved = ds->cellChanged; /* did non-drag movement happen? */
}
}
return moved;
} /* dragDropHasMoved */
static XP_Bool
@ -490,14 +499,20 @@ dragDropContinueImpl( BoardCtxt* board, XP_U16 xx, XP_U16 yy,
} else if ( ds->dtype == DT_BOARD ) {
if ( newInfo.obj == OBJ_BOARD ) {
XP_S16 diff = newInfo.u.board.col - ds->cur.u.board.col;
if ( !ds->cellChanged && 0 != diff ) {
ds->cellChanged = XP_TRUE;
}
diff /= SCROLL_DRAG_THRESHHOLD;
moving = adjustXOffset( board, diff );
diff = newInfo.u.board.row - ds->cur.u.board.row;
if ( !ds->cellChanged && 0 != diff ) {
ds->cellChanged = XP_TRUE;
}
diff /= SCROLL_DRAG_THRESHHOLD;
moving = adjustYOffset( board, diff ) || moving;
}
} else {
} else if ( ds->dtype == DT_TILE ) {
if ( newInfo.obj == OBJ_BOARD ) {
moving = (newInfo.u.board.col != ds->cur.u.board.col)
|| (newInfo.u.board.row != ds->cur.u.board.row)
@ -537,6 +552,8 @@ dragDropContinueImpl( BoardCtxt* board, XP_U16 xx, XP_U16 yy,
XP_MEMCPY( &ds->cur, &newInfo, sizeof(ds->cur) );
startScrollTimerIf( board );
}
} else {
XP_ASSERT( 0 );
}
if ( moving ) {

View file

@ -31,7 +31,9 @@ extern "C" {
typedef XP_U8 Engine_rack[MAX_UNIQUE_TILES+1];
#define NUM_SAVED_MOVES 10
#ifndef NUM_SAVED_ENGINE_MOVES
# define NUM_SAVED_ENGINE_MOVES 10
#endif
typedef struct BlankTuple {
short col;
@ -48,11 +50,30 @@ typedef struct PossibleMove {
blanks */
} PossibleMove;
/* MoveIterationData is a cache of moves so that next and prev searches don't
* always trigger an actual search. Instead we save up to
* NUM_SAVED_ENGINE_MOVES moves that sort together; then iteration is just
* returning the next or previous in the cache. The cache, savedMoves[], is
* sorted in increasing order, with any unused entries at the low end (since
* they sort as if score == 0). nInMoveCache is the actual number of entries.
* curCacheIndex is the index of the move most recently returned, or outside
* the range if nothing's been returned yet from the current cache.
*
* The cache is empty if nInMoveCache == 0, or if curCacheIndex is in a
* position that, given engine->usePrev, indicates it's been walked through
* the cache already rather than being poised to enter it.
*/
typedef struct MoveIterationData {
PossibleMove savedMoves[NUM_SAVED_MOVES];
XP_U16 lowestSavedScore;
/* savedMoves: if any entries are unused (because result set doesn't fill,
they're at the low end (where sort'll put 'em) */
PossibleMove savedMoves[NUM_SAVED_ENGINE_MOVES];
//XP_U16 lowestSavedScore;
PossibleMove lastSeenMove;
XP_U16 leftInMoveCache;
XP_U16 nInMoveCache; /* num entries,
0 <= nInMoveCache < NUM_SAVED_ENGINE_MOVES */
XP_U16 bottom; /* lowest non-0 entry */
XP_S16 curCacheIndex; /* what we last returned */
} MoveIterationData;
/* one bit per tile that's possible here *\/ */
@ -66,6 +87,7 @@ struct EngineCtxt {
Engine_rack rack;
Tile blankTile;
XP_Bool usePrev;
XP_Bool searchInProgress;
XP_Bool searchHorizontal;
XP_Bool isRobot;
@ -130,7 +152,10 @@ static void considerScoreWordHasBlanks( EngineCtxt* engine, XP_U16 blanksLeft,
BlankTuple* usedBlanks,
XP_U16 usedBlanksCount );
static void saveMoveIfQualifies( EngineCtxt* engine, PossibleMove* posmove );
static XP_Bool move_cache_empty( const EngineCtxt* engine );
static void init_move_cache( EngineCtxt* engine );
static PossibleMove* next_from_cache( EngineCtxt* engine );
static void set_search_limits( EngineCtxt* engine );
#if defined __LITTLE_ENDIAN
@ -221,8 +246,9 @@ engine_makeFromStream( MPFORMAL XWStreamCtxt* XP_UNUSED_DBG(stream),
void
engine_reset( EngineCtxt* engine )
{
XP_MEMSET( &engine->miData, 0, sizeof(engine->miData) );
engine->miData.lastSeenMove.score = 0xffff; /* max possible */
XP_MEMSET( &engine->miData, 0, sizeof(engine->miData) );
/* set last score to max possible */
engine->miData.lastSeenMove.score = engine->usePrev? 0 : 0xffff;
engine->searchInProgress = XP_FALSE;
#ifdef XWFEATURE_SEARCHLIMIT
engine->tileLimitsKnown = XP_FALSE; /* indicates not set */
@ -273,11 +299,33 @@ cmpMoves( PossibleMove* m1, PossibleMove* m2 )
} /* cmpMoves */
#endif
#ifdef DEBUG
static void
print_savedMoves( const EngineCtxt* engine, const char* label )
{
int ii;
int pos = 0;
char buf[(NUM_SAVED_ENGINE_MOVES*10) + 3] = {0};
for ( ii = 0; ii < NUM_SAVED_ENGINE_MOVES; ++ii ) {
if ( 0 < engine->miData.savedMoves[ii].score ) {
pos += XP_SNPRINTF( &buf[pos], VSIZE(buf)-pos, "[%d]: %d; ",
ii, engine->miData.savedMoves[ii].score );
}
}
XP_LOGF( "%s: %s", label, buf );
}
#else
# define print_savedMoves( engine, label )
#endif
static XP_Bool
chooseMove( EngineCtxt* engine, PossibleMove** move )
{
XP_U16 i;
XP_U16 ii;
PossibleMove* chosen;
XP_Bool result;
print_savedMoves( engine, "unsorted moves" );
/* First, sort 'em. Put the higher-scoring moves at the top where they'll
get picked up first. Don't sort if we're working for a robot; we've
@ -286,53 +334,40 @@ chooseMove( EngineCtxt* engine, PossibleMove** move )
if ( engine->isRobot ) {
chosen = &engine->miData.savedMoves[0];
} else {
while ( engine->miData.leftInMoveCache == 0 ) {
XP_Bool done = XP_TRUE;
for ( i = 0; i < NUM_SAVED_MOVES-1; ++i ) {
if ( CMPMOVES( &engine->miData.savedMoves[i],
&engine->miData.savedMoves[i+1]) > 0 ) {
XP_Bool done = !move_cache_empty( engine );
while ( !done ) { /* while so can break */
done = XP_TRUE;
PossibleMove* cur = engine->miData.savedMoves;
for ( ii = 0; ii < NUM_SAVED_ENGINE_MOVES-1; ++ii ) {
PossibleMove* next = cur + 1;
if ( CMPMOVES( cur, next ) > 0 ) {
PossibleMove tmp;
XP_MEMCPY( &tmp, &engine->miData.savedMoves[i],
sizeof(tmp) );
XP_MEMCPY( &engine->miData.savedMoves[i],
&engine->miData.savedMoves[i+1],
sizeof(engine->miData.savedMoves[i]) );
XP_MEMCPY( &engine->miData.savedMoves[i+1], &tmp,
sizeof(engine->miData.savedMoves[i+1]) );
XP_MEMCPY( &tmp, cur, sizeof(tmp) );
XP_MEMCPY( cur, next, sizeof(*cur) );
XP_MEMCPY( next, &tmp, sizeof(*next) );
done = XP_FALSE;
}
cur = next;
}
if ( done ) {
engine->miData.leftInMoveCache = NUM_SAVED_MOVES;
init_move_cache( engine );
print_savedMoves( engine, "sorted moves" );
}
#if 0
XP_DEBUGF( "sorted moves; scores are: " );
for ( i = 0; i < NUM_SAVED_MOVES; ++i ) {
XP_DEBUGF( "%d; ", engine->miData.savedMoves[i].score );
}
XP_DEBUGF( "\n" );
#endif
}
/* now pick the one we're supposed to return */
chosen = &engine->miData.savedMoves[--engine->miData.leftInMoveCache];
chosen = next_from_cache( engine );
}
*move = chosen; /* set either way */
if ( chosen->score > 0 ) {
result = (NULL != chosen) && (chosen->score > 0);
if ( engine->miData.leftInMoveCache == 0 ) {
XP_MEMCPY( &engine->miData.lastSeenMove,
&engine->miData.savedMoves[0],
sizeof(engine->miData.lastSeenMove) );
engine->miData.lowestSavedScore = 0;
}
return XP_TRUE;
} else {
if ( !result ) {
engine_reset( engine );
return XP_FALSE;
}
LOG_RETURNF( "%d", result );
return result;
} /* chooseMove */
/* Return of XP_TRUE means that we ran to completion. XP_FALSE means we were
@ -342,7 +377,7 @@ chooseMove( EngineCtxt* engine, PossibleMove** move )
XP_Bool
engine_findMove( EngineCtxt* engine, const ModelCtxt* model,
const DictionaryCtxt* dict, const Tile* tiles,
XP_U16 nTiles,
XP_U16 nTiles, XP_Bool usePrev,
#ifdef XWFEATURE_SEARCHLIMIT
const BdHintLimits* searchLimits,
XP_Bool useTileLimits,
@ -384,6 +419,7 @@ engine_findMove( EngineCtxt* engine, const ModelCtxt* model,
engine->model = model;
engine->dict = dict;
engine->usePrev = usePrev;
engine->blankTile = dict_getBlankTile( dict );
engine->returnNOW = XP_FALSE;
#ifdef XWFEATURE_SEARCHLIMIT
@ -408,7 +444,8 @@ engine_findMove( EngineCtxt* engine, const ModelCtxt* model,
engine->targetScore = targetScore;
if ( engine->miData.leftInMoveCache == 0 ) {
if ( move_cache_empty( engine ) ) {
set_search_limits( engine );
XP_MEMSET( engine->miData.savedMoves, 0,
sizeof(engine->miData.savedMoves) );
@ -476,12 +513,11 @@ engine_findMove( EngineCtxt* engine, const ModelCtxt* model,
result = XP_FALSE;
} else {
PossibleMove* move;
result = XP_TRUE;
(void)chooseMove( engine, &move );
XP_ASSERT( !!newMove );
XP_MEMCPY( newMove, &move->moveInfo, sizeof(*newMove) );
result = chooseMove( engine, &move );
if ( result ) {
XP_ASSERT( !!newMove );
XP_MEMCPY( newMove, &move->moveInfo, sizeof(*newMove) );
}
}
util_engineStopping( engine->util );
@ -1043,7 +1079,7 @@ considerScoreWordHasBlanks( EngineCtxt* engine, XP_U16 blanksLeft,
XP_U16 lastRow, BlankTuple* usedBlanks,
XP_U16 usedBlanksCount )
{
XP_U16 i;
XP_U16 ii;
if ( blanksLeft == 0 ) {
XP_U16 score;
@ -1059,11 +1095,11 @@ considerScoreWordHasBlanks( EngineCtxt* engine, XP_U16 blanksLeft,
if ( scoreQualifies( engine, score ) ) {
posmove->score = score;
XP_MEMSET( &posmove->blankVals, 0, sizeof(posmove->blankVals) );
for ( i = 0; i < usedBlanksCount; ++i ) {
short col = usedBlanks[i].col;
posmove->blankVals[col] = usedBlanks[i].tile;
for ( ii = 0; ii < usedBlanksCount; ++ii ) {
short col = usedBlanks[ii].col;
posmove->blankVals[col] = usedBlanks[ii].tile;
}
XP_ASSERT( posmove->moveInfo.isHorizontal==
XP_ASSERT( posmove->moveInfo.isHorizontal ==
engine->searchHorizontal );
posmove->moveInfo.commonCoord = (XP_U8)lastRow;
saveMoveIfQualifies( engine, posmove );
@ -1078,18 +1114,18 @@ considerScoreWordHasBlanks( EngineCtxt* engine, XP_U16 blanksLeft,
bt = &usedBlanks[usedBlanksCount++];
/* for each letter for which the blank might be standing in... */
for ( i = 0; i < posmove->moveInfo.nTiles; ++i ) {
CellTile tile = posmove->moveInfo.tiles[i].tile;
for ( ii = 0; ii < posmove->moveInfo.nTiles; ++ii ) {
CellTile tile = posmove->moveInfo.tiles[ii].tile;
if ( (tile & TILE_VALUE_MASK) == bTile && !IS_BLANK(tile) ) {
posmove->moveInfo.tiles[i].tile |= TILE_BLANK_BIT;
bt->col = i;
posmove->moveInfo.tiles[ii].tile |= TILE_BLANK_BIT;
bt->col = ii;
bt->tile = bTile;
considerScoreWordHasBlanks( engine, blanksLeft,
posmove, lastRow,
usedBlanks,
usedBlanksCount );
/* now put things back */
posmove->moveInfo.tiles[i].tile &= ~TILE_BLANK_BIT;
posmove->moveInfo.tiles[ii].tile &= ~TILE_BLANK_BIT;
}
}
}
@ -1098,24 +1134,32 @@ considerScoreWordHasBlanks( EngineCtxt* engine, XP_U16 blanksLeft,
static void
saveMoveIfQualifies( EngineCtxt* engine, PossibleMove* posmove )
{
XP_S16 lowest = 0;
XP_S16 mostest = 0;
XP_S16 cmpVal;
XP_Bool usePrev = engine->usePrev;
XP_Bool foundEmpty = XP_FALSE;
if ( !engine->isRobot ) { /* robot doesn't ask for next hint.... */
mostest = -1;
/* we're not interested if we've seen this */
if ( CMPMOVES( posmove, &engine->miData.lastSeenMove ) >= 0 ) {
lowest = -1;
cmpVal = CMPMOVES( posmove, &engine->miData.lastSeenMove );
if ( !usePrev && cmpVal >= 0 ) {
/* XP_LOGF( "%s: dropping %d: higher than %d", __func__, */
/* posmove->score, engine->miData.lastSeenMove.score ); */
} else if ( usePrev && cmpVal <= 0 ) {
/* XP_LOGF( "%s: dropping %d: lower than %d", __func__, */
/* posmove->score, engine->miData.lastSeenMove.score ); */
} else {
XP_S16 i;
/* terminate i at 1 because lowest starts at 0 */
for ( lowest = NUM_SAVED_MOVES-1, i = lowest - 1; i >= 0; --i ) {
/* Find the lowest value move and overwrite it. Note that
XP_S16 ii;
/* terminate i at 1 because mostest starts at 0 */
for ( ii = 0; ii < NUM_SAVED_ENGINE_MOVES; ++ii ) {
/* Find the mostest value move and overwrite it. Note that
there might not be one, as all may have the same or higher
scores and those that have the same score may compare
higher.
<eeh> can't have this asssertion until I start noting the
lowest saved score (setting miData.lowestSavedScore)
mostest saved score (setting miData.mostestSavedScore)
below. */
/* 1/20/2001 I don't see that this assertion is valid. I
simply don't understand why it isn't tripped all the time
@ -1124,52 +1168,174 @@ saveMoveIfQualifies( EngineCtxt* engine, PossibleMove* posmove )
/* || (engine->miData.savedMoves[i].score */
/* <= posmove->score) ); */
if ( CMPMOVES( &engine->miData.savedMoves[lowest],
&engine->miData.savedMoves[i] ) > 0 ) {
lowest = i;
if ( 0 == engine->miData.savedMoves[ii].score ) {
foundEmpty = XP_TRUE;
mostest = ii;
break;
} else if ( -1 == mostest ) {
mostest = ii;
} else {
cmpVal = CMPMOVES( &engine->miData.savedMoves[mostest],
&engine->miData.savedMoves[ii] );
if ( !usePrev && cmpVal > 0 ) {
mostest = ii;
} else if ( usePrev && cmpVal < 0 ) {
mostest = ii;
}
}
}
}
}
if ( lowest >= 0) {
while ( mostest >= 0 ) { /* while: so we can break */
/* record the score we're dumping. No point in considering any scores
lower than this for the rest of this round. */
engine->miData.lowestSavedScore =
engine->miData.savedMoves[lowest].score;
/* engine->miData.lowestSavedScore = */
/* engine->miData.savedMoves[lowest].score; */
/* XP_DEBUGF( "lowestSavedScore now %d\n", */
/* engine->miData.lowestSavedScore ); */
if ( CMPMOVES( posmove, &engine->miData.savedMoves[lowest]) > 0 ) {
XP_MEMCPY( &engine->miData.savedMoves[lowest], posmove,
sizeof(engine->miData.savedMoves[lowest]) );
/* XP_DEBUGF( "just saved move with score %d\n", */
/* engine->miData.savedMoves[lowest].score ); */
if ( foundEmpty ) {
/* we're good */
} else {
cmpVal = CMPMOVES( posmove, &engine->miData.savedMoves[mostest]);
if ( !usePrev && cmpVal <= 0 ) {
break;
} else if ( usePrev && cmpVal >= 0 ) {
break;
}
}
/* XP_LOGF( "saving move with score %d at %d (replacing %d)\n", */
/* posmove->score, mostest, */
/* engine->miData.savedMoves[mostest].score ); */
XP_MEMCPY( &engine->miData.savedMoves[mostest], posmove,
sizeof(engine->miData.savedMoves[mostest]) );
break;
}
} /* saveMoveIfQualifies */
static void
set_search_limits( EngineCtxt* engine )
{
/* If we're going to be searching backwards we want our highest cached
move as the limit; otherwise the lowest */
if ( 0 < engine->miData.nInMoveCache ) {
XP_U16 srcIndx = engine->usePrev
? NUM_SAVED_ENGINE_MOVES-1 : engine->miData.bottom;
XP_MEMCPY( &engine->miData.lastSeenMove,
&engine->miData.savedMoves[srcIndx],
sizeof(engine->miData.lastSeenMove) );
XP_LOGF( "%s: saved limit move with score: %d", __func__,
engine->miData.lastSeenMove.score );
//engine->miData.lowestSavedScore = 0;
} else {
/* we're doing this for first time */
engine_reset( engine );
}
}
static void
init_move_cache( EngineCtxt* engine )
{
XP_U16 nInMoveCache = NUM_SAVED_ENGINE_MOVES;
XP_U16 ii;
for ( ii = 0; ii < NUM_SAVED_ENGINE_MOVES; ++ii ) {
if ( 0 == engine->miData.savedMoves[ii].score ) {
--nInMoveCache;
} else {
break;
}
}
engine->miData.nInMoveCache = nInMoveCache;
engine->miData.bottom = NUM_SAVED_ENGINE_MOVES - nInMoveCache;
if ( engine->usePrev ) {
engine->miData.curCacheIndex =
NUM_SAVED_ENGINE_MOVES - nInMoveCache - 1;
} else {
engine->miData.curCacheIndex = NUM_SAVED_ENGINE_MOVES;
}
XP_LOGF( "%s: set curCacheIndex to %d", __func__,
engine->miData.curCacheIndex );
}
static PossibleMove*
next_from_cache( EngineCtxt* engine )
{
PossibleMove* move;
if ( move_cache_empty( engine ) ) {
move = NULL;
} else {
if ( engine->usePrev ) {
++engine->miData.curCacheIndex;
} else {
--engine->miData.curCacheIndex;
}
move = &engine->miData.savedMoves[engine->miData.curCacheIndex];
XP_LOGF( "%s: curCacheIndex now %d", __func__,
engine->miData.curCacheIndex );
}
return move;
}
static XP_Bool
move_cache_empty( const EngineCtxt* engine )
{
XP_Bool empty;
const MoveIterationData* miData = &engine->miData;
XP_LOGF( "%s: usePrev: %d; curCacheIndex: %d; nInMoveCache: %d",
__func__, engine->usePrev, miData->curCacheIndex,
miData->nInMoveCache );
if ( 0 == miData->nInMoveCache ) {
empty = XP_TRUE;
} else if ( engine->usePrev ) {
empty = miData->curCacheIndex >= NUM_SAVED_ENGINE_MOVES - 1;
} else {
empty = miData->curCacheIndex <= miData->bottom;
}
LOG_RETURNF( "%d", empty );
return empty;
}
static XP_Bool
scoreQualifies( EngineCtxt* engine, XP_U16 score )
{
XP_Bool qualifies = XP_FALSE;
XP_Bool usePrev = engine->usePrev;
if ( (score > engine->miData.lastSeenMove.score)
|| (score > engine->targetScore)
|| (score < engine->miData.lowestSavedScore) ) {
/* do nothing */
if ( score > engine->targetScore ) {
/* drop it */
} else if ( usePrev && score < engine->miData.lastSeenMove.score ) {
/* drop it */
} else if ( !usePrev && score > engine->miData.lastSeenMove.score
/* || (score < engine->miData.lowestSavedScore) */ ) {
/* drop it */
} else {
XP_S16 i;
XP_S16 ii;
PossibleMove* savedMoves = engine->miData.savedMoves;
/* Look at each saved score, and return true as soon as one's found
with a lower or equal score to this. <eeh> As an optimization,
consider remembering what the lowest score is *once there are
NUM_SAVED_MOVES moves in here* and doing a quick test on that. Or
better, keeping the list in sorted order. */
for ( i = engine->isRobot? 0: NUM_SAVED_MOVES-1; i >= 0; --i ) {
if ( score >= engine->miData.savedMoves[i].score ) {
NUM_SAVED_ENGINE_MOVES moves in here* and doing a quick test on
that. Or better, keeping the list in sorted order. */
for ( ii = 0, savedMoves = engine->miData.savedMoves;
ii < NUM_SAVED_ENGINE_MOVES; ++ii, ++savedMoves ) {
if ( savedMoves->score == 0 ) { /* empty slot */
qualifies = XP_TRUE;
} else if ( usePrev && score <= savedMoves->score ) {
qualifies = XP_TRUE;
break;
} else if ( !usePrev && score >= savedMoves->score ) {
qualifies = XP_TRUE;
break;
}
if ( engine->isRobot ) { /* we look at only one for robot */
break;
}
}
}
//XP_LOGF( "%s(%d)->%d", __func__, score, qualifies );
return qualifies;
} /* scoreQualifies */

View file

@ -51,7 +51,7 @@ void engine_destroy( EngineCtxt* ctxt );
#define NO_SCORE_LIMIT 10000 /* for targetScore */
XP_Bool engine_findMove( EngineCtxt* ctxt, const ModelCtxt* model,
const DictionaryCtxt* dict, const Tile* tiles,
XP_U16 nTiles,
XP_U16 nTiles, XP_Bool usePrev,
#ifdef XWFEATURE_SEARCHLIMIT
const BdHintLimits* boardLimits,
XP_Bool useTileLimits,

View file

@ -31,6 +31,7 @@
extern "C" {
#endif
#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 */
@ -46,7 +47,7 @@ extern "C" {
#define STREAM_VERS_41B4 0x02
#define STREAM_VERS_405 0x01
#define CUR_STREAM_VERS STREAM_VERS_GAMESECONDS
#define CUR_STREAM_VERS STREAM_VERS_NUNDONE
typedef struct LocalPlayer {
XP_UCHAR* name;

View file

@ -70,7 +70,8 @@ static void buildModelFromStack( ModelCtxt* model, StackCtxt* stack,
MovePrintFuncPost mpfpo,
void* closure );
static void setPendingCounts( ModelCtxt* model, XP_S16 turn );
static void loadPlayerCtxt( XWStreamCtxt* stream, PlayerCtxt* pc );
static void loadPlayerCtxt( XWStreamCtxt* stream, XP_U16 version,
PlayerCtxt* pc );
static void writePlayerCtxt( XWStreamCtxt* stream, PlayerCtxt* pc );
static XP_U16 model_getRecentPassCount( ModelCtxt* model );
@ -136,7 +137,7 @@ model_makeFromStream( MPFORMAL XWStreamCtxt* stream, DictionaryCtxt* dict,
(MovePrintFuncPost)NULL, NULL );
for ( i = 0; i < model->nPlayers; ++i ) {
loadPlayerCtxt( stream, &model->players[i] );
loadPlayerCtxt( stream, version, &model->players[i] );
setPendingCounts( model, i );
invalidateScore( model, i );
}
@ -480,13 +481,14 @@ undoFromMoveInfo( ModelCtxt* model, XP_U16 turn, Tile blankTile, MoveInfo* mi )
setModelTileRaw( model, col, row, EMPTY_TILE );
notifyBoardListeners( model, turn, col, row, XP_FALSE );
--model->vol.nTilesOnBoard;
if ( IS_BLANK(tile) ) {
tile = blankTile;
}
model_addPlayerTile( model, turn, -1, tile );
}
XP_LOGF( "%s: %d tiles on board", __func__, model->vol.nTilesOnBoard );
adjustScoreForUndone( model, mi, turn );
} /* undoFromMoveInfo */
@ -842,9 +844,9 @@ model_trayContains( ModelCtxt* model, XP_S16 turn, Tile tile )
} /* model_trayContains */
XP_U16
model_getCurrentMoveCount( ModelCtxt* model, XP_S16 turn )
model_getCurrentMoveCount( const ModelCtxt* model, XP_S16 turn )
{
PlayerCtxt* player;
const PlayerCtxt* player;
XP_ASSERT( turn >= 0 );
player = &model->players[turn];
return player->nPending;
@ -989,6 +991,7 @@ model_moveTrayToBoard( ModelCtxt* model, XP_S16 turn, XP_U16 col, XP_U16 row,
invalLastMove( model );
}
player->nUndone = 0;
pt = &player->pendingTiles[player->nPending++];
XP_ASSERT( player->nPending <= MAX_TRAY_TILES );
@ -1002,6 +1005,40 @@ model_moveTrayToBoard( ModelCtxt* model, XP_S16 turn, XP_U16 col, XP_U16 row,
notifyBoardListeners( model, turn, col, row, XP_TRUE );
} /* model_moveTrayToBoard */
XP_Bool
model_redoPendingTiles( ModelCtxt* model, XP_S16 turn )
{
XP_Bool changed = XP_FALSE;
PlayerCtxt* player = &model->players[turn];
XP_U16 nUndone = player->nUndone;
changed = nUndone > 0;
if ( changed ) {
PendingTile pendingTiles[nUndone];
PendingTile* pt = pendingTiles;
XP_MEMCPY( pendingTiles, &player->pendingTiles[player->nPending],
nUndone * sizeof(pendingTiles[0]) );
/* Now we have info about each tile, but don't know where in the
tray they are. So find 'em. */
for ( pt = pendingTiles; nUndone-- > 0; ++pt ) {
Tile tile = pt->tile;
XP_Bool isBlank = 0 != (tile & TILE_BLANK_BIT);
XP_S16 foundAt;
if ( isBlank ) {
tile = dict_getBlankTile( model->vol.dict );
}
foundAt = model_trayContains( model, turn, tile );
XP_ASSERT( foundAt >= 0 );
model_moveTrayToBoard( model, turn, pt->col, pt->row,
foundAt, pt->tile & ~TILE_BLANK_BIT );
}
}
return changed;
}
void
model_moveBoardToTray( ModelCtxt* model, XP_S16 turn,
XP_U16 col, XP_U16 row, XP_U16 trayOffset )
@ -1024,6 +1061,7 @@ model_moveBoardToTray( ModelCtxt* model, XP_S16 turn,
/* if we're called from putBackOtherPlayersTiles there may be nothing
here */
if ( index < player->nPending ) {
PendingTile tmpPending;
decrPendingTileCountAt( model, col, row );
notifyBoardListeners( model, turn, col, row, XP_FALSE );
@ -1035,9 +1073,14 @@ model_moveBoardToTray( ModelCtxt* model, XP_S16 turn,
model_addPlayerTile( model, turn, trayOffset, tile );
--player->nPending;
tmpPending = player->pendingTiles[index];
for ( i = index; i < player->nPending; ++i ) {
player->pendingTiles[i] = player->pendingTiles[i+1];
}
player->pendingTiles[player->nPending] = tmpPending;
++player->nUndone;
//XP_LOGF( "%s: nUndone(%d): %d", __func__, turn, player->nUndone );
if ( player->nPending == 0 ) {
invalLastMove( model );
@ -1104,6 +1147,30 @@ model_getNMoves( const ModelCtxt* model )
return result;
}
XP_U16
model_visTileCount( const ModelCtxt* model, XP_U16 turn, XP_Bool trayVisible )
{
XP_U16 count = model->vol.nTilesOnBoard;
if ( trayVisible ) {
count += model_getCurrentMoveCount( model, turn );
}
return count;
}
XP_Bool
model_canShuffle( const ModelCtxt* model, XP_U16 turn, XP_Bool trayVisible )
{
return trayVisible
&& model_getPlayerTiles( model, turn )->nTiles > 1;
}
XP_Bool
model_canTogglePending( const ModelCtxt* model, XP_U16 turn )
{
const PlayerCtxt* player = &model->players[turn];
return 0 < player->nPending || 0 < player->nUndone;
}
static void
incrPendingTileCountAt( ModelCtxt* model, XP_U16 col, XP_U16 row )
{
@ -1229,6 +1296,8 @@ commitTurn( ModelCtxt* model, XP_S16 turn, TrayTileSet* newTiles,
setModelTileRaw( model, col, row, tile );
notifyBoardListeners( model, turn, col, row, XP_FALSE );
++model->vol.nTilesOnBoard;
}
(void)getCurrentMoveScoreIfLegal( model, turn, stream, &score );
@ -1241,12 +1310,14 @@ commitTurn( ModelCtxt* model, XP_S16 turn, TrayTileSet* newTiles,
}
player->nPending = 0;
player->nUndone = 0;
newTilesP = newTiles->tiles;
while ( nTiles-- ) {
model_addPlayerTile( model, turn, -1, *newTilesP++ );
}
XP_LOGF( "%s: %d tiles on board", __func__, model->vol.nTilesOnBoard );
return score;
} /* commitTurn */
@ -1303,9 +1374,9 @@ model_getPlayerTile( ModelCtxt* model, XP_S16 turn, XP_S16 index )
} /* model_getPlayerTile */
const TrayTileSet*
model_getPlayerTiles( ModelCtxt* model, XP_S16 turn )
model_getPlayerTiles( const ModelCtxt* model, XP_S16 turn )
{
PlayerCtxt* player = &model->players[turn];
const PlayerCtxt* player = &model->players[turn];
return (const TrayTileSet*)&player->trayTiles;
} /* model_getPlayerTile */
@ -1823,23 +1894,29 @@ model_getPlayersLastScore( ModelCtxt* model, XP_S16 player,
} /* model_getPlayersLastScore */
static void
loadPlayerCtxt( XWStreamCtxt* stream, PlayerCtxt* pc )
loadPlayerCtxt( XWStreamCtxt* stream, XP_U16 version, PlayerCtxt* pc )
{
XP_U16 i;
PendingTile* pt;
XP_U16 nTiles;
pc->curMoveValid = stream_getBits( stream, 1 );
traySetFromStream( stream, &pc->trayTiles );
pc->nPending = (XP_U8)stream_getBits( stream, NTILES_NBITS );
if ( STREAM_VERS_NUNDONE <= version ) {
pc->nUndone = (XP_U8)stream_getBits( stream, NTILES_NBITS );
} else {
XP_ASSERT( 0 == pc->nUndone );
}
for ( i = 0; i < pc->nPending; ++i ) {
PendingTile* pt = &pc->pendingTiles[i];
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 );
nBits = (stream_getVersion( stream ) <= STREAM_VERS_RELAY) ? 6 : 7;
nBits = (version <= STREAM_VERS_RELAY) ? 6 : 7;
pt->tile = (Tile)stream_getBits( stream, nBits );
}
@ -1848,21 +1925,22 @@ loadPlayerCtxt( XWStreamCtxt* stream, PlayerCtxt* pc )
static void
writePlayerCtxt( XWStreamCtxt* stream, PlayerCtxt* pc )
{
XP_U16 i;
XP_U16 nTiles;
PendingTile* pt;
stream_putBits( stream, 1, pc->curMoveValid );
traySetToStream( stream, &pc->trayTiles );
stream_putBits( stream, NTILES_NBITS, pc->nPending );
stream_putBits( stream, NTILES_NBITS, pc->nUndone );
for ( i = 0; i < pc->nPending; ++i ) {
PendingTile* pt = &pc->pendingTiles[i];
nTiles = pc->nPending + pc->nUndone;
for ( pt = pc->pendingTiles; nTiles-- > 0; ++pt ) {
stream_putBits( stream, NUMCOLS_NBITS, pt->col );
stream_putBits( stream, NUMCOLS_NBITS, pt->row );
stream_putBits( stream, 7, pt->tile );
}
} /* writePlayerCtxt */
#ifdef CPLUS

View file

@ -137,7 +137,7 @@ void model_moveTileOnTray( ModelCtxt* model, XP_S16 turn, XP_S16 indexCur,
/* As an optimization, return a pointer to the model's array of tiles for a
player. Don't even think about modifying the array!!!! */
const TrayTileSet* model_getPlayerTiles( ModelCtxt* model, XP_S16 turn );
const TrayTileSet* model_getPlayerTiles( const ModelCtxt* model, XP_S16 turn );
void model_sortTiles( ModelCtxt* model, XP_S16 turn );
XP_U16 model_getNumTilesInTray( ModelCtxt* model, XP_S16 turn );
@ -148,6 +148,8 @@ void model_moveTrayToBoard( ModelCtxt* model, XP_S16 turn, XP_U16 col,
XP_U16 row, XP_S16 tileIndex, Tile blankFace );
XP_Bool model_moveTileOnBoard( ModelCtxt* model, XP_S16 turn, XP_U16 colCur,
XP_U16 rowCur, XP_U16 colNew, XP_U16 rowNew );
XP_Bool model_redoPendingTiles( ModelCtxt* model, XP_S16 turn );
XP_S16 model_trayContains( ModelCtxt* model, XP_S16 turn, Tile tile );
@ -160,7 +162,7 @@ XP_U16 model_numCols( const ModelCtxt* model );
void model_addToCurrentMove( ModelCtxt* model, XP_S16 turn,
XP_U16 col, XP_U16 row,
Tile tile, XP_Bool isBlank );
XP_U16 model_getCurrentMoveCount( ModelCtxt* model, XP_S16 turn );
XP_U16 model_getCurrentMoveCount( const ModelCtxt* model, XP_S16 turn );
void model_getCurrentMoveTile( ModelCtxt* model, XP_S16 turn, XP_S16* index,
Tile* tile, XP_U16* col, XP_U16* row,
@ -190,6 +192,13 @@ void model_makeTurnFromMoveInfo( ModelCtxt* model, XP_U16 playerNum,
void model_resetCurrentTurn( ModelCtxt* model, XP_S16 turn );
XP_S16 model_getNMoves( const ModelCtxt* model );
/* Are there two or more tiles visible */
XP_U16 model_visTileCount( const ModelCtxt* model, XP_U16 turn,
XP_Bool trayVisible );
XP_Bool model_canShuffle( const ModelCtxt* model, XP_U16 turn,
XP_Bool trayVisible );
XP_Bool model_canTogglePending( const ModelCtxt* model, XP_U16 turn );
/********************* notification ********************/
typedef void (*BoardListener)(void* data, XP_U16 turn, XP_U16 col,
XP_U16 row, XP_Bool added );

View file

@ -39,6 +39,7 @@ typedef struct PlayerCtxt {
XP_Bool curMoveValid;
TrayTileSet trayTiles;
XP_U8 nPending; /* still in tray but "on board" */
XP_U8 nUndone; /* tiles above nPending we can reuse */
PendingTile pendingTiles[MAX_TRAY_TILES];
} PlayerCtxt;
@ -53,6 +54,7 @@ typedef struct ModelVolatiles {
void* trayListenerData;
DictListener dictListenerFunc;
void* dictListenerData;
XP_U16 nTilesOnBoard;
MPSLOT
} ModelVolatiles;

View file

@ -324,7 +324,7 @@ handlePenUpScore( BoardCtxt* board, XP_U16 xx, XP_U16 yy )
if ( rectNum == CURSOR_LOC_REM ) {
util_remSelected( board->util );
} else if ( --rectNum >= 0 ) {
board_selectPlayer( board, rectNum );
board_selectPlayer( board, rectNum, board->allowPeek );
} else {
result = XP_FALSE;
}

View file

@ -676,7 +676,7 @@ makeRobotMove( ServerCtxt* server )
XP_ASSERT( !!server_getEngineFor( server, turn ) );
finished = engine_findMove( server_getEngineFor( server, turn ),
model, model_getDictionary( model ),
tileSet->tiles, tileSet->nTiles,
tileSet->tiles, tileSet->nTiles, XP_FALSE,
#ifdef XWFEATURE_SEARCHLIMIT
NULL, XP_FALSE,
#endif

View file

@ -544,7 +544,7 @@ handleHint( CursesAppGlobals* globals )
#ifdef XWFEATURE_SEARCHLIMIT
XP_FALSE,
#endif
&redo );
XP_FALSE, &redo );
return XP_TRUE;
} /* handleHint */

View file

@ -1,4 +1,4 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; compile-command: "make MEMDEBUG=TRUE"; -*- */
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; compile-command: "make MEMDEBUG=TRUE -j3"; -*- */
/*
* Copyright 2000-2009 by Eric House (xwords@eehouse.org). All rights reserved.
*
@ -68,6 +68,7 @@ static void setCtrlsForTray( GtkAppGlobals* globals );
static void new_game( GtkWidget* widget, GtkAppGlobals* globals );
static void new_game_impl( GtkAppGlobals* globals, XP_Bool fireConnDlg );
static void setZoomButtons( GtkAppGlobals* globals, XP_Bool* inOut );
static void disenable_buttons( GtkAppGlobals* globals );
#define GTK_TRAY_HT_ROWS 3
@ -128,6 +129,7 @@ button_press_event( GtkWidget* XP_UNUSED(widget), GdkEventButton *event,
event->x, event->y, &handled );
if ( redraw ) {
board_draw( globals->cGlobals.game.board );
disenable_buttons( globals );
}
}
return 1;
@ -146,6 +148,7 @@ motion_notify_event( GtkWidget* XP_UNUSED(widget), GdkEventMotion *event,
event->y );
if ( handled ) {
board_draw( globals->cGlobals.game.board );
disenable_buttons( globals );
}
} else {
handled = XP_FALSE;
@ -168,6 +171,7 @@ button_release_event( GtkWidget* XP_UNUSED(widget), GdkEventMotion *event,
event->y );
if ( redraw ) {
board_draw( globals->cGlobals.game.board );
disenable_buttons( globals );
}
globals->mouseDown = XP_FALSE;
}
@ -991,6 +995,16 @@ makeMenus( GtkAppGlobals* globals, int XP_UNUSED(argc),
return menubar;
} /* makeMenus */
static void
disenable_buttons( GtkAppGlobals* globals )
{
XP_Bool canFlip = 1 < board_visTileCount( globals->cGlobals.game.board );
gtk_widget_set_sensitive( globals->flip_button, canFlip );
XP_Bool canToggle = board_canTogglePending( globals->cGlobals.game.board );
gtk_widget_set_sensitive( globals->toggle_undo_button, canToggle );
}
static gboolean
handle_flip_button( GtkWidget* XP_UNUSED(widget), gpointer _globals )
{
@ -1012,18 +1026,31 @@ handle_value_button( GtkWidget* XP_UNUSED(widget), gpointer closure )
} /* handle_value_button */
static void
handle_hint_button( GtkWidget* XP_UNUSED(widget), GtkAppGlobals* globals )
handle_hint_button( GtkAppGlobals* globals, XP_Bool prev )
{
XP_Bool redo;
if ( board_requestHint( globals->cGlobals.game.board,
#ifdef XWFEATURE_SEARCHLIMIT
XP_FALSE,
#endif
&redo ) ) {
prev, &redo ) ) {
board_draw( globals->cGlobals.game.board );
disenable_buttons( globals );
}
} /* handle_hint_button */
static void
handle_prevhint_button( GtkWidget* XP_UNUSED(widget), GtkAppGlobals* globals )
{
handle_hint_button( globals, XP_TRUE );
} /* handle_prevhint_button */
static void
handle_nexthint_button( GtkWidget* XP_UNUSED(widget), GtkAppGlobals* globals )
{
handle_hint_button( globals, XP_FALSE );
} /* handle_nexthint_button */
static void
handle_nhint_button( GtkWidget* XP_UNUSED(widget), GtkAppGlobals* globals )
{
@ -1034,7 +1061,7 @@ handle_nhint_button( GtkWidget* XP_UNUSED(widget), GtkAppGlobals* globals )
#ifdef XWFEATURE_SEARCHLIMIT
XP_TRUE,
#endif
&redo ) ) {
XP_FALSE, &redo ) ) {
board_draw( globals->cGlobals.game.board );
}
} /* handle_nhint_button */
@ -1071,6 +1098,16 @@ handle_redo_button( GtkWidget* XP_UNUSED(widget),
{
} /* handle_redo_button */
static void
handle_toggle_undo( GtkWidget* XP_UNUSED(widget),
GtkAppGlobals* globals )
{
BoardCtxt* board = globals->cGlobals.game.board;
if ( board_redoReplacedTiles( board ) || board_replaceTiles( board ) ) {
board_draw( board );
}
}
static void
handle_trade_button( GtkWidget* XP_UNUSED(widget), GtkAppGlobals* globals )
{
@ -1670,13 +1707,17 @@ makeVerticalBar( GtkAppGlobals* globals, GtkWidget* XP_UNUSED(window) )
button = makeShowButtonFromBitmap( globals, "../flip.xpm", "f",
G_CALLBACK(handle_flip_button) );
gtk_box_pack_start( GTK_BOX(vbox), button, FALSE, TRUE, 0 );
globals->flip_button = button;
button = makeShowButtonFromBitmap( globals, "../value.xpm", "v",
G_CALLBACK(handle_value_button) );
gtk_box_pack_start( GTK_BOX(vbox), button, FALSE, TRUE, 0 );
button = makeShowButtonFromBitmap( globals, "../hint.xpm", "?",
G_CALLBACK(handle_hint_button) );
button = makeShowButtonFromBitmap( globals, "../hint.xpm", "?-",
G_CALLBACK(handle_prevhint_button) );
gtk_box_pack_start( GTK_BOX(vbox), button, FALSE, TRUE, 0 );
button = makeShowButtonFromBitmap( globals, "../hint.xpm", "?+",
G_CALLBACK(handle_nexthint_button) );
gtk_box_pack_start( GTK_BOX(vbox), button, FALSE, TRUE, 0 );
button = makeShowButtonFromBitmap( globals, "../hintNum.xpm", "n",
@ -1688,13 +1729,18 @@ makeVerticalBar( GtkAppGlobals* globals, GtkWidget* XP_UNUSED(window) )
gtk_box_pack_start( GTK_BOX(vbox), button, FALSE, TRUE, 0 );
/* undo and redo buttons */
button = makeShowButtonFromBitmap( globals, "../undo.xpm", "u",
button = makeShowButtonFromBitmap( globals, "../undo.xpm", "U",
G_CALLBACK(handle_undo_button) );
gtk_box_pack_start( GTK_BOX(vbox), button, FALSE, TRUE, 0 );
button = makeShowButtonFromBitmap( globals, "../redo.xpm", "r",
button = makeShowButtonFromBitmap( globals, "../redo.xpm", "R",
G_CALLBACK(handle_redo_button) );
gtk_box_pack_start( GTK_BOX(vbox), button, FALSE, TRUE, 0 );
button = makeShowButtonFromBitmap( globals, "", "u/r",
G_CALLBACK(handle_toggle_undo) );
globals->toggle_undo_button = button;
gtk_box_pack_start( GTK_BOX(vbox), button, FALSE, TRUE, 0 );
/* the four buttons that on palm are beside the tray */
button = makeShowButtonFromBitmap( globals, "../juggle.xpm", "j",
G_CALLBACK(handle_juggle_button) );
@ -2058,6 +2104,7 @@ gtkmain( LaunchParams* params, int argc, char *argv[] )
globals.cp.skipCommitConfirm = params->skipCommitConfirm;
globals.cp.sortNewTiles = params->sortNewTiles;
globals.cp.showColors = params->showColors;
globals.cp.allowPeek = params->allowPeek;
globals.cp.showRobotScores = params->showRobotScores;
#ifdef XWFEATURE_SLOW_ROBOT
globals.cp.robotThinkMin = params->robotThinkMin;

View file

@ -87,8 +87,10 @@ typedef struct GtkAppGlobals {
/* GdkPixmap* pixmap; */
GtkWidget* drawing_area;
GtkWidget* flip_button;
GtkWidget* zoomin_button;
GtkWidget* zoomout_button;
GtkWidget* toggle_undo_button;
EngineCtxt* engine;

View file

@ -200,7 +200,7 @@ usage( char* appName, char* msg )
"\t [-k] # ask for parameters via \"new games\" dlg\n"
"\t [-h numRowsHidden] \n"
# ifdef XWFEATURE_SEARCHLIMIT
"\t [-I] # don't support hint rect dragging\n"
"\t [-I] # support hint rect dragging\n"
# endif
#endif
"\t [-f file] # use this file to save/load game\n"
@ -788,10 +788,11 @@ main( int argc, char** argv )
mainParams.nHidden = 0;
mainParams.needsNewGame = XP_FALSE;
#ifdef XWFEATURE_SEARCHLIMIT
mainParams.allowHintRect = XP_TRUE;
mainParams.allowHintRect = XP_FALSE;
#endif
mainParams.skipCommitConfirm = XP_TRUE;
mainParams.showColors = XP_TRUE;
mainParams.allowPeek = XP_TRUE;
/* serverName = mainParams.info.clientInfo.serverName = "localhost"; */
@ -869,7 +870,7 @@ main( int argc, char** argv )
break;
#ifdef XWFEATURE_SEARCHLIMIT
case 'I':
mainParams.allowHintRect = XP_FALSE;
mainParams.allowHintRect = XP_TRUE;
break;
#endif
case 'K':

View file

@ -59,6 +59,7 @@ typedef struct LaunchParams {
XP_Bool verticalScore;
XP_Bool hideValues;
XP_Bool showColors;
XP_Bool allowPeek;
XP_Bool sortNewTiles;
XP_Bool skipCommitConfirm;
XP_Bool needsNewGame;

View file

@ -762,14 +762,21 @@ CookieRef::increasePlayerCounts( const CRefEvent* evt, bool reconn )
if ( reconn ) {
if ( nPlayersS > 0 ) {
if ( 0 != m_nPlayersSought ) {
logf( XW_LOGERROR,
"already have m_nPlayersSought: %d but new value %d",
m_nPlayersSought, nPlayersS );
goto drop;
}
m_nPlayersSought = nPlayersS;
}
m_nPlayersHere += nPlayersH;
if ( 0 != m_nPlayersSought && m_nPlayersHere > m_nPlayersSought ) {
if ( 0 != m_nPlayersSought &&
m_nPlayersHere + nPlayersH > m_nPlayersSought ) {
logf( XW_LOGERROR, "too many new players provided: %d > %d",
m_nPlayersHere + nPlayersH, m_nPlayersSought );
goto drop;
}
m_nPlayersHere += nPlayersH;
if ( m_nPlayersHere == m_nPlayersSought ) {
newevt.type = XWE_ALLHERE;
} else {
@ -777,8 +784,11 @@ CookieRef::increasePlayerCounts( const CRefEvent* evt, bool reconn )
}
addHost = true;
} else if ( nPlayersS > 0 ) { /* a host; init values */
assert( m_nPlayersSought == 0 );
assert( m_nPlayersHere == 0 );
if ( m_nPlayersSought != 0 || m_nPlayersHere != 0 ) {
logf( XW_LOGERROR, "cref in bad state: m_nPlayersSought: %d; "
"m_nPlayersHere: %d", m_nPlayersSought, m_nPlayersHere );
goto drop;
}
m_nPlayersHere = nPlayersH;
m_nPlayersSought = nPlayersS;
addHost = true;