Missig files from the 'Working Version'.
This commit is contained in:
@@ -7,19 +7,24 @@
|
|||||||
android:targetSdkVersion="14"/>
|
android:targetSdkVersion="14"/>
|
||||||
<application android:label="@string/app_name"
|
<application android:label="@string/app_name"
|
||||||
android:name="org.dyndns.vahagn.sokoban.App"
|
android:name="org.dyndns.vahagn.sokoban.App"
|
||||||
android:theme="@android:style/Theme.Light">
|
android:icon="@drawable/icon"
|
||||||
<activity android:name="org.dyndns.vahagn.sokoban.SokobanMenu"
|
android:theme="@android:style/Theme">
|
||||||
android:label="@string/app_name">
|
<activity android:name="org.dyndns.vahagn.sokoban.MainMenu"
|
||||||
|
android:label="@string/app_name"
|
||||||
|
android:configChanges="keyboardHidden|orientation"
|
||||||
|
android:screenOrientation="portrait" >
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<activity android:name="org.dyndns.vahagn.sokoban.PlayActivity"
|
<activity android:name="org.dyndns.vahagn.sokoban.play.PlayActivity"
|
||||||
android:label="@string/play_activity">
|
android:label="@string/play_activity"
|
||||||
|
android:configChanges="keyboardHidden|orientation"
|
||||||
|
android:screenOrientation="portrait" >
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value="org.dyndns.vahagn.sokoban.SokobanMenu" />
|
android:value="org.dyndns.vahagn.sokoban.MainMenu" />
|
||||||
</activity>
|
</activity>
|
||||||
</application>
|
</application>
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ protected:
|
|||||||
empty = 0,
|
empty = 0,
|
||||||
wall,
|
wall,
|
||||||
box,
|
box,
|
||||||
hole,
|
goal,
|
||||||
box_in_hole,
|
box_in_goal,
|
||||||
worker
|
worker
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -69,10 +69,10 @@ public:
|
|||||||
*it++ = box;
|
*it++ = box;
|
||||||
break;
|
break;
|
||||||
case '.':
|
case '.':
|
||||||
*it++ = hole;
|
*it++ = goal;
|
||||||
break;
|
break;
|
||||||
case '*':
|
case '*':
|
||||||
*it++ = box_in_hole;
|
*it++ = box_in_goal;
|
||||||
break;
|
break;
|
||||||
case '@':
|
case '@':
|
||||||
*it++ = worker;
|
*it++ = worker;
|
||||||
|
|||||||
@@ -2,10 +2,18 @@
|
|||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="fill_parent"
|
android:layout_height="fill_parent">
|
||||||
android:background="@drawable/splash"
|
|
||||||
>
|
|
||||||
|
|
||||||
|
<GridView
|
||||||
|
android:id="@+id/puzzle_grid"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:horizontalSpacing="2mm"
|
||||||
|
android:verticalSpacing="2mm"
|
||||||
|
android:columnWidth="10mm"
|
||||||
|
android:numColumns="auto_fit"
|
||||||
|
android:stretchMode="columnWidth"
|
||||||
|
android:gravity="center" />
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/btn_start"
|
android:id="@+id/btn_start"
|
||||||
@@ -14,5 +22,6 @@
|
|||||||
android:onClick="onStartCurrentPuzzle"
|
android:onClick="onStartCurrentPuzzle"
|
||||||
android:text="Start" />
|
android:text="Start" />
|
||||||
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,24 @@
|
|||||||
package org.dyndns.vahagn.sokoban;
|
package org.dyndns.vahagn.sokoban;
|
||||||
|
|
||||||
import android.app.Application;
|
import android.app.Application;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
public class App extends Application {
|
public class App extends Application
|
||||||
|
{
|
||||||
|
public static final String TAG = "Sokoban";
|
||||||
|
public static final String PREFS = "org.dyndns.vahagn.sokoban.prefs";
|
||||||
|
static final int MIN_LEVEL = 1;
|
||||||
|
|
||||||
private static App mApp = null;
|
private static App mApp = null;
|
||||||
protected PuzzleContainer pc;
|
protected PuzzleContainer pc;
|
||||||
public int level;
|
protected int current_level;
|
||||||
|
protected int achieved_level;
|
||||||
|
protected int max_level;
|
||||||
|
protected SharedPreferences prefs;
|
||||||
|
protected SharedPreferences.Editor prefsEdit;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
@@ -17,21 +29,82 @@ public class App extends Application {
|
|||||||
super.onCreate();
|
super.onCreate();
|
||||||
mApp = this;
|
mApp = this;
|
||||||
pc = new PuzzleContainer();
|
pc = new PuzzleContainer();
|
||||||
level = 0;
|
prefs = getSharedPreferences(PREFS, MODE_PRIVATE);
|
||||||
|
prefsEdit = prefs.edit();
|
||||||
|
max_level = pc.getCount();
|
||||||
|
current_level = prefs.getInt("current_level", MIN_LEVEL);
|
||||||
|
achieved_level = prefs.getInt("achieved_level", MIN_LEVEL);
|
||||||
}
|
}
|
||||||
|
//
|
||||||
|
// This is a singleton object.
|
||||||
|
//
|
||||||
public static App theApp()
|
public static App theApp()
|
||||||
{
|
{
|
||||||
return mApp;
|
return mApp;
|
||||||
}
|
}
|
||||||
|
//
|
||||||
public PuzzleContainer getPuzzleContainer()
|
// Puzzles.
|
||||||
|
//
|
||||||
|
public Puzzle getPuzzle( int level )
|
||||||
{
|
{
|
||||||
return pc;
|
return pc.getPuzzle( level-1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
public Puzzle getCurrentPuzzle()
|
public Puzzle getCurrentPuzzle()
|
||||||
{
|
{
|
||||||
return getPuzzleContainer().getPuzzle( level );
|
return getPuzzle( getCurrentLevel() );
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// Provide amount of puzzles.
|
||||||
|
//
|
||||||
|
public final int getPuzzleCount()
|
||||||
|
{
|
||||||
|
return max_level;
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// Provide highest solved puzzle.
|
||||||
|
//
|
||||||
|
public final int getAchivedLevel()
|
||||||
|
{
|
||||||
|
return achieved_level;
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// Provide last played puzzle.
|
||||||
|
//
|
||||||
|
public final int getCurrentLevel()
|
||||||
|
{
|
||||||
|
return current_level;
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// Set the current puzzle level. It deons't alter
|
||||||
|
//
|
||||||
|
public void setCurrentLevel( int l )
|
||||||
|
{
|
||||||
|
if ( current_level != l )
|
||||||
|
{
|
||||||
|
current_level = l;
|
||||||
|
prefsEdit.putInt("current_level", current_level);
|
||||||
|
prefsEdit.apply();
|
||||||
|
if ( !prefs.edit().commit() )
|
||||||
|
Log.d(TAG, "prefs.edit().commit() failed.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//
|
||||||
|
// Advances current level. It also reviews achived level if the
|
||||||
|
// new level is bigger than achieved level.
|
||||||
|
//
|
||||||
|
public void advanceCurrentLevel()
|
||||||
|
{
|
||||||
|
int new_level = current_level+1;
|
||||||
|
if ( new_level == max_level )
|
||||||
|
new_level = MIN_LEVEL;
|
||||||
|
if ( new_level > achieved_level )
|
||||||
|
{
|
||||||
|
achieved_level = new_level;
|
||||||
|
prefsEdit.putInt("achieved_level", achieved_level);
|
||||||
|
// Don't call apply() here since the call below
|
||||||
|
// to setCurrentLevel() will do that.
|
||||||
|
}
|
||||||
|
setCurrentLevel(new_level);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,30 +1,132 @@
|
|||||||
package org.dyndns.vahagn.sokoban;
|
package org.dyndns.vahagn.sokoban;
|
||||||
|
|
||||||
|
import org.dyndns.vahagn.sokoban.play.PlayActivity;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.BitmapFactory;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.graphics.Rect;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.util.TypedValue;
|
||||||
|
import android.view.Display;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.view.Window;
|
||||||
|
import android.widget.AdapterView;
|
||||||
|
import android.widget.AdapterView.OnItemClickListener;
|
||||||
|
import android.widget.BaseAdapter;
|
||||||
|
import android.widget.GridView;
|
||||||
|
import android.widget.ImageView;
|
||||||
import static org.dyndns.vahagn.sokoban.App.theApp;
|
import static org.dyndns.vahagn.sokoban.App.theApp;
|
||||||
|
|
||||||
public class SokobanMenu extends Activity
|
public class MainMenu extends Activity
|
||||||
{
|
{
|
||||||
protected final String TAG = "SokobanMenu";
|
protected final String TAG = "SokobanMenu";
|
||||||
protected final String LEVEL= "org.dyndns.vahagn.sokoban.LEVEL";
|
protected final String LEVEL= "org.dyndns.vahagn.sokoban.LEVEL";
|
||||||
|
protected GridView puzzle_grid;
|
||||||
|
|
||||||
/** Called when the activity is first created. */
|
/** Called when the activity is first created. */
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState)
|
public void onCreate(Bundle savedInstanceState)
|
||||||
{
|
{
|
||||||
Log.d(TAG, "onCreate: " + savedInstanceState );
|
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||||
|
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.menu);
|
setContentView(R.layout.menu);
|
||||||
|
|
||||||
try {
|
puzzle_grid = (GridView)findViewById(R.id.puzzle_grid);
|
||||||
} catch (Exception e) {
|
puzzle_grid.setAdapter( new PuzzlesAdapter(this) );
|
||||||
// TODO Auto-generated catch block
|
//puzzle_grid.addView(puzzle_grid);
|
||||||
e.printStackTrace();
|
puzzle_grid.setOnItemClickListener(new OnItemClickListener() {
|
||||||
|
public void onItemClick(AdapterView<?> parent, View v, int position, long id)
|
||||||
|
{
|
||||||
|
onPuzzleClicked(v,(int)id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PuzzlesAdapter extends BaseAdapter
|
||||||
|
{
|
||||||
|
private Context mContext;
|
||||||
|
private int icon_size;
|
||||||
|
private int text_x;
|
||||||
|
private int text_y;
|
||||||
|
private Bitmap lock_icon;
|
||||||
|
private Bitmap unlock_icon;
|
||||||
|
private Paint paint;
|
||||||
|
|
||||||
|
public PuzzlesAdapter(Context c)
|
||||||
|
{
|
||||||
|
mContext = c;
|
||||||
|
icon_size = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_MM, 10, getResources().getDisplayMetrics() );
|
||||||
|
int text_size = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_MM, 4, getResources().getDisplayMetrics() );
|
||||||
|
text_x = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_MM, 9, getResources().getDisplayMetrics() );
|
||||||
|
text_y = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_MM, 9, getResources().getDisplayMetrics() );
|
||||||
|
|
||||||
|
Bitmap lock_icon_tmp = BitmapFactory.decodeResource( getResources(), R.drawable.lock );
|
||||||
|
lock_icon = Bitmap.createBitmap(icon_size,icon_size,Bitmap.Config.ARGB_8888);
|
||||||
|
Canvas lock_canvas = new Canvas(lock_icon);
|
||||||
|
lock_canvas.drawBitmap(lock_icon_tmp,
|
||||||
|
new Rect(0,0,lock_icon_tmp.getWidth()-1,lock_icon_tmp.getHeight()-1),
|
||||||
|
new Rect(0,0,icon_size, icon_size),
|
||||||
|
null);
|
||||||
|
|
||||||
|
Bitmap unlock_icon_tmp = BitmapFactory.decodeResource( getResources(), R.drawable.unlock );
|
||||||
|
unlock_icon = Bitmap.createBitmap(icon_size,icon_size,Bitmap.Config.ARGB_8888);
|
||||||
|
Canvas unlock_canvas = new Canvas(unlock_icon);
|
||||||
|
unlock_canvas.drawBitmap(unlock_icon_tmp,
|
||||||
|
new Rect(0,0,unlock_icon_tmp.getWidth()-1,unlock_icon_tmp.getHeight()-1),
|
||||||
|
new Rect(0,0,icon_size, icon_size),
|
||||||
|
null);
|
||||||
|
|
||||||
|
paint = new Paint();
|
||||||
|
paint.setColor( Color.WHITE );
|
||||||
|
paint.setTextSize( text_size );
|
||||||
|
paint.setTextAlign(Paint.Align.RIGHT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCount()
|
||||||
|
{
|
||||||
|
return theApp().getPuzzleCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getItem(int position)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getItemId(int position)
|
||||||
|
{
|
||||||
|
return position+1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a new ImageView for each item referenced by the Adapter
|
||||||
|
public View getView(int position, View convertView, ViewGroup parent)
|
||||||
|
{
|
||||||
|
ImageView imageView;
|
||||||
|
if (convertView == null)
|
||||||
|
{ // if it's not recycled, initialize some attributes
|
||||||
|
imageView = new ImageView(mContext);
|
||||||
|
imageView.setLayoutParams(new GridView.LayoutParams(icon_size, icon_size));
|
||||||
|
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
|
||||||
|
// imageView.setPadding(8, 8, 8, 8);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
imageView = (ImageView) convertView;
|
||||||
|
|
||||||
|
int id = (int)getItemId(position);
|
||||||
|
Bitmap icon = ( id <= theApp().getAchivedLevel() )
|
||||||
|
? unlock_icon.copy(Bitmap.Config.ARGB_8888,true)
|
||||||
|
: lock_icon.copy(Bitmap.Config.ARGB_8888,true);
|
||||||
|
Canvas canvas = new Canvas(icon);
|
||||||
|
canvas.drawText( Integer.toString(id), text_x, text_y, paint);
|
||||||
|
imageView.setImageBitmap(icon);
|
||||||
|
return imageView;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,8 +188,17 @@ public class SokobanMenu extends Activity
|
|||||||
public void onStartCurrentPuzzle(View v)
|
public void onStartCurrentPuzzle(View v)
|
||||||
{
|
{
|
||||||
Intent intent = new Intent(this, PlayActivity.class);
|
Intent intent = new Intent(this, PlayActivity.class);
|
||||||
|
|
||||||
startActivity( intent );
|
startActivity( intent );
|
||||||
Log.d(TAG, "onStartCurrentPuzzle: " );
|
}
|
||||||
|
|
||||||
|
public void onPuzzleClicked(View v, int level )
|
||||||
|
{
|
||||||
|
if ( level <= theApp().getAchivedLevel() )
|
||||||
|
{
|
||||||
|
theApp().setCurrentLevel(level);
|
||||||
|
|
||||||
|
Intent intent = new Intent(this, PlayActivity.class);
|
||||||
|
startActivity( intent );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,73 +2,51 @@ package org.dyndns.vahagn.sokoban;
|
|||||||
|
|
||||||
//import java.lang.Exception;
|
//import java.lang.Exception;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
import static java.lang.Math.*;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.graphics.Point;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import static org.dyndns.vahagn.sokoban.App.TAG;
|
||||||
|
|
||||||
public class Puzzle
|
public class Puzzle
|
||||||
{
|
{
|
||||||
public enum symbole
|
public final static int FLOOR = 0x0;
|
||||||
{
|
public final static int GOAL = 0x1;
|
||||||
FLOOR,
|
public final static int FLOOR_MASK = ~(GOAL | FLOOR);
|
||||||
WALL,
|
public final static int WALL = 0x2;
|
||||||
BOX,
|
public final static int BOX = 0x4;
|
||||||
HOLE,
|
public final static int BINGO = BOX | GOAL;
|
||||||
BOX_IN_HOLE,
|
public final static int WORKER = 0x8;
|
||||||
WORKER;
|
public final static int WORKER_NORTH = 0x00 | WORKER;
|
||||||
|
public final static int WORKER_SOUTH = 0x10 | WORKER;
|
||||||
|
public final static int WORKER_WEST = 0x20 | WORKER;
|
||||||
|
public final static int WORKER_EAST = 0x30 | WORKER;
|
||||||
|
public final static int WORKER_MASK = WORKER_EAST | WORKER_WEST | WORKER_SOUTH | WORKER_NORTH;
|
||||||
|
public final static int SELECTED = 0x40;
|
||||||
|
public final static int MAX_COUNT = 0x80-1;
|
||||||
|
|
||||||
public static int MAX_COUNT()
|
|
||||||
{
|
|
||||||
return 6;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
protected static final String TAG = "Puzzle";
|
|
||||||
protected int columns;
|
protected int columns;
|
||||||
protected int rows;
|
protected int rows;
|
||||||
protected symbole [] board;
|
protected int box_count;
|
||||||
|
|
||||||
|
protected int [] board;
|
||||||
|
protected int worker_x;
|
||||||
|
protected int worker_y;
|
||||||
|
protected int selected_x;
|
||||||
|
protected int selected_y;
|
||||||
|
protected int bingos;
|
||||||
|
|
||||||
public Puzzle( InputStream is )
|
public Puzzle( InputStream is )
|
||||||
{
|
{
|
||||||
load( is );
|
load( is );
|
||||||
}
|
}
|
||||||
|
|
||||||
private void load( InputStream is )
|
//////////////////////////////////////////////////////////////////////////
|
||||||
{try{
|
//
|
||||||
columns = is.read();
|
// Low level helper functions.
|
||||||
rows = is.read();
|
//
|
||||||
byte [] b = new byte [columns*rows];
|
|
||||||
board = new symbole[columns*rows];
|
|
||||||
is.read( b, 0, columns*rows);
|
|
||||||
for( int i = 0; i < b.length; ++i )
|
|
||||||
{
|
|
||||||
switch( b[i] )
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
board[i] = symbole.FLOOR;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
board[i] = symbole.WALL;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
board[i] = symbole.BOX;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
board[i] = symbole.HOLE;
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
board[i] = symbole.BOX_IN_HOLE;
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
board[i] = symbole.WORKER;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch ( Exception e )
|
|
||||||
{
|
|
||||||
Log.d( TAG, "load()", e);
|
|
||||||
}}
|
|
||||||
|
|
||||||
|
|
||||||
public final int getColumnCount()
|
public final int getColumnCount()
|
||||||
{
|
{
|
||||||
@@ -80,15 +58,347 @@ public class Puzzle
|
|||||||
}
|
}
|
||||||
public static int getSymCount()
|
public static int getSymCount()
|
||||||
{
|
{
|
||||||
return symbole.MAX_COUNT();
|
return MAX_COUNT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
public final int getIndex( int x, int y )
|
||||||
* r- row
|
|
||||||
* c- column
|
|
||||||
*/
|
|
||||||
public final symbole getSym( int r, int c )
|
|
||||||
{
|
{
|
||||||
return board[r*columns+c];
|
return y*columns+x;
|
||||||
|
}
|
||||||
|
public final int getX( int idx )
|
||||||
|
{
|
||||||
|
return idx % columns;
|
||||||
|
}
|
||||||
|
public final int getY( int idx )
|
||||||
|
{
|
||||||
|
return idx / columns;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final int getSym( int x, int y )
|
||||||
|
{
|
||||||
|
return board[getIndex(x,y)];
|
||||||
|
}
|
||||||
|
public void setSym( int x, int y, int v )
|
||||||
|
{
|
||||||
|
board[getIndex(x,y)]=v;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isEmpty( int v )
|
||||||
|
{
|
||||||
|
return (v & FLOOR_MASK) == 0;
|
||||||
|
}
|
||||||
|
public static boolean hasBox( int v )
|
||||||
|
{
|
||||||
|
return (v & BOX) != 0;
|
||||||
|
}
|
||||||
|
public static boolean hasWorker( int v )
|
||||||
|
{
|
||||||
|
return (v & WORKER) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final int getWorkerX()
|
||||||
|
{
|
||||||
|
return worker_x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final int getWorkerY()
|
||||||
|
{
|
||||||
|
return worker_y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final boolean isSelected()
|
||||||
|
{
|
||||||
|
return selected_x != -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final boolean isSelected( int x, int y )
|
||||||
|
{
|
||||||
|
return selected_x == x && selected_y == y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final int getSelectedX()
|
||||||
|
{
|
||||||
|
return selected_x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final int getSelectedY()
|
||||||
|
{
|
||||||
|
return selected_y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final boolean isValid( int x, int y )
|
||||||
|
{
|
||||||
|
return ( 0 <= x && 0 <= y
|
||||||
|
&& x < getColumnCount()
|
||||||
|
&& y < getRowCount() );
|
||||||
|
}
|
||||||
|
|
||||||
|
public final boolean isOneStep( int x, int y )
|
||||||
|
{
|
||||||
|
return isValid(x,y)
|
||||||
|
&& (abs(worker_x-x )+abs(worker_y-y) == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final boolean isDone()
|
||||||
|
{
|
||||||
|
return bingos == box_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Loading.
|
||||||
|
//
|
||||||
|
private void load( InputStream is )
|
||||||
|
{try{
|
||||||
|
columns = is.read();
|
||||||
|
rows = is.read();
|
||||||
|
box_count = 0;
|
||||||
|
bingos = 0;
|
||||||
|
selected_x = -1;
|
||||||
|
selected_y = -1;
|
||||||
|
board = new int[columns*rows];
|
||||||
|
byte [] b = new byte [columns*rows];
|
||||||
|
is.read( b, 0, columns*rows);
|
||||||
|
for( int i = 0; i < b.length; ++i )
|
||||||
|
{
|
||||||
|
switch( b[i] )
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
board[i] = FLOOR;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
board[i] = WALL;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
board[i] = BOX;
|
||||||
|
++box_count;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
board[i] = GOAL;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
board[i] = BINGO;
|
||||||
|
++box_count;
|
||||||
|
++bingos;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
board[i] = WORKER;
|
||||||
|
worker_x = getX(i);
|
||||||
|
worker_y = getY(i);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch ( Exception e )
|
||||||
|
{
|
||||||
|
Log.d( TAG, "load()", e);
|
||||||
|
}}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Move worker.
|
||||||
|
//
|
||||||
|
|
||||||
|
public boolean walk( int x, int y)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// Check that this is one step away.
|
||||||
|
//
|
||||||
|
if ( !isOneStep(x,y) )
|
||||||
|
return false;
|
||||||
|
//
|
||||||
|
// Check that this is empty space.
|
||||||
|
//
|
||||||
|
int v = getSym(x,y);
|
||||||
|
if ( !isEmpty(v) )
|
||||||
|
return false;
|
||||||
|
//
|
||||||
|
// If something is selected then unselect first.
|
||||||
|
//
|
||||||
|
if ( isSelected() )
|
||||||
|
unselect();
|
||||||
|
//
|
||||||
|
// Find direction to move.
|
||||||
|
//
|
||||||
|
int worker;
|
||||||
|
if ( worker_x < x )
|
||||||
|
worker = WORKER_WEST;
|
||||||
|
else if ( worker_x > x )
|
||||||
|
worker = WORKER_EAST;
|
||||||
|
else if ( worker_y > y )
|
||||||
|
worker = WORKER_SOUTH;
|
||||||
|
else
|
||||||
|
worker = WORKER_NORTH;
|
||||||
|
//
|
||||||
|
// Move worker marker from current position to asked position.
|
||||||
|
//
|
||||||
|
setSym(worker_x,worker_y,getSym(worker_x,worker_y)&~WORKER_MASK);
|
||||||
|
worker_x =x;
|
||||||
|
worker_y =y;
|
||||||
|
setSym(worker_x,worker_y,getSym(worker_x,worker_y)|worker);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean select( int x, int y)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// Check that this is one step away.
|
||||||
|
//
|
||||||
|
if ( !isOneStep(x,y) )
|
||||||
|
return false;
|
||||||
|
//
|
||||||
|
// Check that this is empty space.
|
||||||
|
//
|
||||||
|
int v = getSym(x,y);
|
||||||
|
if ( !hasBox(v) )
|
||||||
|
return false;
|
||||||
|
//
|
||||||
|
// If something is selected then unselect first.
|
||||||
|
//
|
||||||
|
if ( isSelected() )
|
||||||
|
unselect();
|
||||||
|
//
|
||||||
|
// Find direction to move.
|
||||||
|
//
|
||||||
|
int worker;
|
||||||
|
if ( worker_x < x )
|
||||||
|
worker = WORKER_WEST;
|
||||||
|
else if ( worker_x > x )
|
||||||
|
worker = WORKER_EAST;
|
||||||
|
else if ( worker_y > y )
|
||||||
|
worker = WORKER_SOUTH;
|
||||||
|
else
|
||||||
|
worker = WORKER_NORTH;
|
||||||
|
//
|
||||||
|
// Move worker marker from current position to asked position.
|
||||||
|
//
|
||||||
|
selected_x =x;
|
||||||
|
selected_y =y;
|
||||||
|
setSym(worker_x,worker_y,getSym(worker_x,worker_y)&~WORKER_MASK|worker|SELECTED);
|
||||||
|
setSym(selected_x,selected_y,getSym(selected_x,selected_y)|SELECTED);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean unselect()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// If not selected then do nothing.
|
||||||
|
//
|
||||||
|
if ( !isSelected() )
|
||||||
|
return false;
|
||||||
|
//
|
||||||
|
// Move worker marker from current position to asked position.
|
||||||
|
//
|
||||||
|
setSym(worker_x,worker_y,getSym(worker_x,worker_y)&~SELECTED);
|
||||||
|
setSym(selected_x,selected_y,getSym(selected_x,selected_y)&~SELECTED);
|
||||||
|
selected_x =-1;
|
||||||
|
selected_y =-1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean push(int x, int y)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// If not selected then do nothing.
|
||||||
|
//
|
||||||
|
if ( !isSelected() )
|
||||||
|
return false;
|
||||||
|
//
|
||||||
|
// Check that we go to the selected direction.
|
||||||
|
//
|
||||||
|
if ( selected_x != x && selected_y != y )
|
||||||
|
return false;
|
||||||
|
//
|
||||||
|
// Check that this is a box that we move.
|
||||||
|
//
|
||||||
|
int v = getSym(x,y);
|
||||||
|
if ( !hasBox(v) )
|
||||||
|
return false;
|
||||||
|
//
|
||||||
|
// Check that the next space to the box is empty.
|
||||||
|
//w - 2*(w-x) = 2x -w
|
||||||
|
int next_x = 2*x - worker_x;
|
||||||
|
int next_y = 2*y - worker_y;
|
||||||
|
int next_v = getSym(next_x,next_y);
|
||||||
|
if ( !isEmpty(next_v) )
|
||||||
|
return false;
|
||||||
|
//
|
||||||
|
// Ok, looks we can move the box. Do it actually.
|
||||||
|
//
|
||||||
|
unselect();
|
||||||
|
setSym(x,y,getSym(x,y)&~BOX);
|
||||||
|
setSym(next_x,next_y,getSym(next_x,next_y)|BOX);
|
||||||
|
walk(x,y);
|
||||||
|
select(next_x,next_y);
|
||||||
|
//
|
||||||
|
// Keep track of box count in place.
|
||||||
|
//
|
||||||
|
if ( (v & GOAL) != 0 )
|
||||||
|
--bingos;
|
||||||
|
if ( (next_v & GOAL) != 0 )
|
||||||
|
++bingos;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Undo/Redo.
|
||||||
|
//
|
||||||
|
|
||||||
|
protected class State
|
||||||
|
{
|
||||||
|
public int [] board;
|
||||||
|
public int worker_x;
|
||||||
|
public int worker_y;
|
||||||
|
public int selected_x;
|
||||||
|
public int selected_y;
|
||||||
|
public int bingos;
|
||||||
|
|
||||||
|
public State(Puzzle puzzle)
|
||||||
|
{
|
||||||
|
board = puzzle.board.clone();
|
||||||
|
worker_x = puzzle.worker_x;
|
||||||
|
worker_y = puzzle.worker_y;
|
||||||
|
selected_x = puzzle.selected_x;
|
||||||
|
selected_y = puzzle.selected_y;
|
||||||
|
bingos = puzzle.bingos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void restore(Puzzle puzzle)
|
||||||
|
{
|
||||||
|
puzzle.board = board;
|
||||||
|
puzzle.worker_x = worker_x;
|
||||||
|
puzzle.worker_y = worker_y;
|
||||||
|
puzzle.selected_x = selected_x;
|
||||||
|
puzzle.selected_y = selected_y;
|
||||||
|
puzzle.bingos = bingos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
protected LinkedList<State> undoStack = new LinkedList<State>();
|
||||||
|
|
||||||
|
//
|
||||||
|
// Save this state to be able to restore later.
|
||||||
|
//
|
||||||
|
public void save()
|
||||||
|
{
|
||||||
|
State s = new State(this);
|
||||||
|
undoStack.addFirst(s);
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// Restore state.
|
||||||
|
//
|
||||||
|
public void restore()
|
||||||
|
{
|
||||||
|
State s = undoStack.removeFirst();
|
||||||
|
if ( s != null )
|
||||||
|
s.restore(this);
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// Check if there are items in the undo stack.
|
||||||
|
//
|
||||||
|
public final boolean isUndoable()
|
||||||
|
{
|
||||||
|
return undoStack.size() != 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,8 +7,6 @@ import android.util.Log;
|
|||||||
|
|
||||||
public class PuzzleContainer
|
public class PuzzleContainer
|
||||||
{
|
{
|
||||||
protected final String TAG = "PuzzleContainer";
|
|
||||||
|
|
||||||
protected int count;
|
protected int count;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -41,11 +39,13 @@ public class PuzzleContainer
|
|||||||
}
|
}
|
||||||
catch ( java.lang.Exception e )
|
catch ( java.lang.Exception e )
|
||||||
{
|
{
|
||||||
Log.d(TAG, "Exception: " + e.getMessage() );
|
//Log.d(TAG, "Exception: " + e.getMessage() );
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
return null;
|
return null;
|
||||||
}}
|
}}
|
||||||
|
//
|
||||||
|
// Retrive amount of puzzles.
|
||||||
|
//
|
||||||
public int getCount()
|
public int getCount()
|
||||||
{try{
|
{try{
|
||||||
if ( count == 0 )
|
if ( count == 0 )
|
||||||
@@ -57,11 +57,13 @@ public class PuzzleContainer
|
|||||||
}
|
}
|
||||||
catch ( java.lang.Exception e )
|
catch ( java.lang.Exception e )
|
||||||
{
|
{
|
||||||
Log.d(TAG, "Exception: " + e.getMessage() );
|
//Log.d(TAG, "Exception: " + e.getMessage() );
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
return 0;
|
return 0;
|
||||||
}}
|
}}
|
||||||
|
//
|
||||||
|
// Helper function to read little endian 32bit integer.
|
||||||
|
//
|
||||||
protected int read_i32( InputStream is ) throws IOException
|
protected int read_i32( InputStream is ) throws IOException
|
||||||
{
|
{
|
||||||
int i = is.read();
|
int i = is.read();
|
||||||
|
|||||||
Reference in New Issue
Block a user