Missig files from the 'Working Version'.

This commit is contained in:
2013-05-14 09:20:24 +04:00
parent bb6e76009d
commit 821bf0c916
7 changed files with 611 additions and 101 deletions

View File

@@ -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>

View File

@@ -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;

View File

@@ -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>

View File

@@ -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);
}
} }

View File

@@ -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;
} }
} }
@@ -83,11 +185,20 @@ public class SokobanMenu extends Activity
// setContentView(R.layout-l.menu); // setContentView(R.layout-l.menu);
} }
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 );
}
} }
} }

View File

@@ -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;
} }
} }

View File

@@ -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();