Android Open Source - picturepuzzle Picture Puzzle






From Project

Back to project page picturepuzzle.

License

The source code is released under:

GNU General Public License

If you think the Android project picturepuzzle listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package me.crr.picturepuzzle;
/*  w  w w  .  j  av  a 2 s  . c  o m*/
import java.util.Random;

import javax.microedition.khronos.opengles.GL10;

import me.crr.interfaces.InputManagerReceiver;
import me.crr.interfaces.RenderHost;
import me.tempus.picturepuzzle.R;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.SystemClock;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class PicturePuzzle implements Runnable, RenderHost, InputManagerReceiver {

  private final Piece freePiece = new Piece(0, 0, new int[] { 0, 0, 0,
      0 });

  private final Piece[] activePieces = new Piece[4];

  private int rowSize = 3;
  private int columnSize = 3;

  private static boolean pieceSelected = false; //Boolean to keep track if a piece has been selected
  private static Piece piece = null; //To keep a reference to what piece has been touched/selected
  private final PieceTransitionAnimation pieceAnimation;
  private Piece[] pieces;

  private Render render;

  private boolean done = false;

  private long startTime = 0;

  private int pictureID = -1;

  private GameActivity gameActivity;

  private Texture picture;

  private String grid;

  public PicturePuzzle(GameActivity gameActivity, Render render, int rowSize, int columnSize, int pictureID){
    this.render = render;
    this.rowSize = rowSize;
    this.columnSize = columnSize;
    this.pictureID  = pictureID;
    this.gameActivity = gameActivity;
    this.pieceAnimation = new PieceTransitionAnimation(this);
  }

  public PicturePuzzle(GameActivity gameActivity2, Render render2,
      int rowSize2, int columnSize2, String grid,
      int nintendoCharactersNintendo512x512) {
    this(gameActivity2, render2, rowSize2, columnSize2, nintendoCharactersNintendo512x512);
    this.grid = grid;
  }

  public void init() {
  }
  

  public void run() {
    
    init();
    waitThis();
    if(grid != null){
      pieces = loadGrid(grid, picture, render, freePiece, rowSize, columnSize);
    }else{
      setUpGrid(rowSize, columnSize, picture.width, picture.height);
      //shuffPieces(pieces);
    }
    long currentTime = 0;
    long delta = 0;
    while(!done){
      currentTime = SystemClock.currentThreadTimeMillis();
      
      activePieces[0] = getActivePiece(freePiece.i, freePiece.j + 1);
      activePieces[1] = getActivePiece(freePiece.i, freePiece.j - 1);
      activePieces[2] = getActivePiece(freePiece.i + 1, freePiece.j);
      activePieces[3] = getActivePiece(freePiece.i - 1, freePiece.j);
      
      
      InputManager.processInput(this);
      pieceAnimation.update();
      render.addDrawables(pieces);
      //if (render != null)        
      render.beginFrame();
      delta = SystemClock.currentThreadTimeMillis() - currentTime;
      if(delta < 32){ // 32 for 30 frames for second
        try {
          synchronized (this) {
            wait(32 - delta);
          }          
        } catch (InterruptedException e) {}
      }
    }
    render.beginFrame();
  }

  public void setUpButtons(View view) {

    final PicturePuzzle host = this; // Dirty work around for accessing within a button onClick
    
    Button resetButton = (Button) view
        .findViewById(R.id.resestButton);

    resetButton.setOnClickListener(new OnClickListener() {

      @Override
      public void onClick(View v) {
        host.shuffPieces(pieces);
        startTime = SystemClock.uptimeMillis();
      }
    });
  }

  public void preUpdate(GameActivity game, Render render) {
    
  }


  /**
   * Created to prevent array out of bounds when getting the different active
   * pieces
   * 
   * @param i
   * @param j
   * @return The active piece
   */
  public Piece getActivePiece(int i, int j) {
    if(i < 0 || j < 0) return null;
    final int pos = getPositionInArray(i, j, rowSize);
    if (pieces == null)
      return null;
    if (pos >= 0 && pos < pieces.length) {

      return pieces[pos];
    }
    return null;

  }

  /**
   * Sets up the grid of pieces for the image
   * 
   * @param textureWidth
   * @param textureHeight
   */
  private void setUpGrid(int rowPieces, int columnPieces,
      int textureWidth, int textureHeight) {
    pieces = new Piece[rowPieces * columnPieces];
    Piece.setPieceWidth(render.getScreenWidth() / rowPieces);
    Piece.setPieceHeight(render.getScreenHeight() / columnPieces);
    Piece.setxPadding(2);
    Piece.setyPadding(2);
    
    final int tPieceWidth = textureWidth / (rowPieces);
    final int tPieceHeight = textureHeight / (columnPieces);
    
    for (int i = 0; i < rowPieces; i++) {
      for (int j = 0; j < columnPieces; j++) {
        final int position = getPositionInArray(i, j, rowPieces);
        final Piece piece = new Piece(i, j, new int[] {
            i * tPieceWidth, textureHeight - (j * tPieceHeight),
            tPieceWidth, -tPieceHeight });
        pieces[position] = piece;
      }
    }
    pieces[getPositionInArray(0, 0, rowPieces)] = null;
    freePiece.getRect().width = Piece.getPieceWidth();
    freePiece.getRect().height = Piece.getPieceHeight();

    
  }

  /**
   * Loads the game grid given a setup of coordinates
   * @param grid The formatted string so that each position maps a grid position. Free set of cords is the free piece
   * E.G 0 9:1 1 4:3 2 5:4 Meaning that the first position has the last piece in it which belongs in the first position
   */
  private Piece[] loadGrid(String grid, Texture picture, Render render, Piece freePiece, int rowSize, int columnSize) {
    
    setUpGrid(rowSize, columnSize, picture.width, picture.height);
    Piece[] pieces = new Piece[this.pieces.length];
    String[] posistions = grid.split(" ");
    for(int k = 0; k < posistions.length; k++){
      if(posistions[k].length() == 2 && posistions[k].charAt(0) == 'n'){
        int[] cords = getCoordinates(k, rowSize);
        pieces[k] = this.pieces[0];
        freePiece.setI(cords[0]);
        freePiece.setJ(cords[1]);
      }else{
        Piece currentPiece = this.pieces[Integer.parseInt(posistions[k])];
        int[] cords = getCoordinates(k, rowSize);
        pieces[k] = currentPiece;
        currentPiece.setI(cords[0]);
        currentPiece.setJ(cords[1]);
      }
    }
    
    return pieces;
    
  }
  
  /**
   * To check if the pieces are in the correct places The method will take
   * care of the case when the game is won
   * 
   * @param piece Piece array of the current state of the pieces
   */
  private void checkIfComplete(Piece[] pieces) {
    Piece currentPiece = null;
    for (int i = 0; i < pieces.length; i++) {
      currentPiece = pieces[i];
      if (currentPiece != null) {
        if (getPositionInArray(currentPiece.initI, currentPiece.initJ,
            rowSize) != i) {
          return;
        }
      }
    }
    showWinGameDialog();
  }

  //A debugging method to check if the grid is valid
  @SuppressWarnings("unused")
  private boolean validGrid(Piece[] pieces, int rowSize){
    for(int i = 0; i < pieces.length; i++){
      Piece p = pieces[i];
      if(p != null){
        int piecePos = getPositionInArray(p.i, p.j, rowSize);
        if(piecePos == getPositionInArray(freePiece.i, freePiece.j, rowSize)){
          return false;
        }
        for(int k = 0; k < pieces.length; k++){
          
          if(i != k){
            Piece c = pieces[k];
            if(c != null){
              if(piecePos == getPositionInArray(c.i, c.j, rowSize)){
                return false;
              }
            }
          }
        }
      }
    }
    
    return true;
  }
  
  private void showWinGameDialog() {
    final long winGameTime = startTime;
    Runnable winGame = new Runnable() {
      
      @Override
      public void run() {
        AlertDialog.Builder winGameDialog = new AlertDialog.Builder(gameActivity);
        winGameDialog.setTitle(R.string.wingame);
        LayoutInflater inflater = (LayoutInflater)gameActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            View winGameViewContent = inflater.inflate(R.layout.wingamedialog, null);
            
            final TextView nameInput = (TextView) winGameViewContent.findViewById(R.id.enterNameEditText);
        winGameDialog.setView(winGameViewContent);
        winGameDialog.setPositiveButton(R.string.wingamedialogbuttontext, new DialogInterface.OnClickListener() {
          
          @Override
          public void onClick(DialogInterface arg0, int arg1) {
            Intent startStatsActivity = new Intent();
            startStatsActivity.setClass(gameActivity, StatsActivity.class);
            startStatsActivity.putExtra("me.crr.picturepuzzle.winTime", new WinTime(SystemClock.uptimeMillis() - winGameTime, nameInput.getText().toString()));
            
            SharedPreferences prefences = gameActivity.getSharedPreferences(gameActivity.getResources().getString(R.string.sharedPrefencesName), Context.MODE_PRIVATE);
            SharedPreferences.Editor editor = prefences.edit();
            
            editor.putBoolean("me.crr.picturepuzzle.continue", false);
            
            editor.commit();
            
            gameActivity.startActivity(startStatsActivity);
            
          }
        });
        winGameDialog.create().show();
      }
    };
    gameActivity.runOnUiThread(winGame);
  }

  /**
   * 
   * @param piece
   *            The current Piece to move
   * @param i
   *            Row position to move to
   * @param j
   *            Column position to move to
   */
  public void movePieceTo(Piece piece, int i, int j) {
    final int freePos = getPositionInArray(freePiece.i, freePiece.j,
        rowSize);
    final int posTry = getPositionInArray(i, j, rowSize);
    if (posTry == freePos) {
      pieceAnimation.setAnimationData(piece, freePiece, 200);
      checkIfComplete(pieces);
    }
  }

  /**
   * Swap two pieces positions
   * 
   * @param p1
   *            Piece one
   * @param p2
   *            Piece two
   */
  public void swapPiece(Piece p1, Piece p2, Piece[] pieces) {
    if(p1 == null || p2 == null) return;      
    
    final int pos1 = getPositionInArray(p1.i, p1.j, rowSize);
    final int pos2 = getPositionInArray(p2.i, p2.j, rowSize);
    final Piece p = pieces[pos1];
    pieces[pos1] = pieces[pos2];
    pieces[pos2] = p;
    final int i1 = p1.i;
    final int j1 = p1.j;
    p1.setI(p2.i);
    p1.setJ(p2.j);
    p2.setI(i1);
    p2.setJ(j1);
  }

  /**
   * 
   * @param i
   *            Zero indexed row position
   * @param j
   *            Zero indexed Column position
   * @param n
   *            Row size
   * @return The position in the array
   */
  public static int getPositionInArray(int i, int j, int n) {
    return ((n * j) + i);
  }
  
  /**
   * Reverses the process of getPositionInArray
   * @param position
   * @param rowSize
   * @return
   */
  public static int[] getCoordinates(int position, int rowSize){
    int[] cords = new int[2];    
    cords[1] = (int)(position / rowSize);
    cords[0] = position - (rowSize * cords[1]);
    return cords;
  }

  /**
   * Called each frame to process all the touch events the MainActivity thread
   * as given the game thread
   * 
   * @param activePieces
   *            The pieces surrounding the empty slot
   * @param event
   *            The touch event
   * @return A piece if it's being touched
   */
  public Piece processTouchDownEvent(Piece[] activePieces, MotionEvent event) {
    if (event == null) {
      return null;
    }
    final int size = activePieces.length;
    final float x = event.getRawX();
    final float y = render.getRawScreenHeight() - event.getRawY();
    Piece activePiece = null;
    for (int i = 0; i < size; i++) {
      final Piece currentPiece = activePieces[i];
      if (currentPiece != null) {
        if (Rectangle.pointIntersects(x, y,
            currentPiece.getRect())) {
          activePiece = currentPiece;
        }
      }
    }
    return activePiece;
  }

  /**
   * 
   * @param list
   *            The list of objects to be shuffled
   * @return Returns the shuffled version of the list
   */
  public Piece[] shuffPieces(Piece[] list) {

    final Random random = new Random();
    for (int i = list.length - 1; i > 0; i--) {
      final int swapIndex = random.nextInt(i - 1 + 1) + 1;
      if (list[swapIndex] != null && list[i] != null) {
        swapPiece(list[i], list[swapIndex], pieces);
      }
    }

    final int swapIndex = random.nextInt((list.length - 1) - 1 + 1) + 1;
    swapPiece(freePiece, list[swapIndex], pieces);

    return list;
  }

  /**
   * Resets the current game
   * Shuffles the pieces and puts the start time back to current phones uptime
   */
  public void resetGame() {
    //startTime = SystemClock.uptimeMillis(); //Decided not to reset the time. This makes the game more realistic and funnier
    shuffPieces(pieces);
        
  }
  
  @Override
  public void onKeyPressed(KeyEvent event) {

  }

  /**
   * Method to handle touch events being sent to this screen
   */
  public void onTouch(MotionEvent event) {

    switch (event.getAction()) {

    case MotionEvent.ACTION_DOWN:
      if (!pieceSelected) {
        piece = null;
        piece = processTouchDownEvent(activePieces, event);
        if(piece != null){
          pieceSelected = true;
        }
      }
      break;
    case MotionEvent.ACTION_UP:
      pieceSelected = false;      
      
      break;
    case MotionEvent.ACTION_MOVE:
      
      if (pieceSelected) {
        final float x = event.getRawX();
        final float y = render.getRawScreenHeight() - event.getRawY();

        if (Rectangle.pointIntersects(x, y, freePiece.getRect())) {
          movePieceTo(piece, freePiece.i, freePiece.j);
          pieceSelected = false;
        }
        
      }      
      break;
    case MotionEvent.ACTION_CANCEL:
      break;

    }
  }

  @Override
  public void screenChanged(GL10 gl) {    
    
    final Texture picture = Render.loadBitmap(gl, (Context)gameActivity, pictureID);
    this.picture = picture;
    this.notifyThis();
  }

  @Override
  public void screenCreated(GL10 gl) {
    
  }

  @Override
  public void frameStarted(GL10 gl) {
    render.bindTexture(gl, picture.textureID);
  }

  @Override
  public void frameEnded(GL10 gl) {
    
  }

  public long getStartTime() {
    return startTime ;
  }
  
  public int getRowSize() {
    return rowSize;
  }

  public int getColumnSize() {
    return columnSize;
  }
  
  public void setDone(boolean done) {
    this.done = done;    
  }

  public void setStartTime(long startTime) {
    this.startTime = startTime;
  }
  
  /**
   * Creates a string representing the current state of the game's grid. Formated like below
   * E.G 0 9:1 1 4:3 2 5:4 Meaning that the first position has the last piece in it which belongs in the first position
   * @param pieces The list of the current pieces of the game
   * @param freePiece The piece representing the null piece in the list
   * @param rowSize The size of how pieces are in each row of the grid
   * @return A string representing the games grid
   */
  public String getGrid(Piece[] pieces, Piece freePiece, int rowSize) {
    StringBuilder grid = new StringBuilder();
    
    for(int i = 0; i < pieces.length; i++){
      Piece currentPiece = pieces[i];
      if(currentPiece != null){
        grid.append(getPositionInArray(currentPiece.initI, currentPiece.initJ, rowSize)).append(" ");
      }else{
        //Log.d("PicturePuzzle", freePiece.toString());
        grid.append("n").append(getPositionInArray(freePiece.initI, freePiece.initJ, rowSize)).append(" ");
      }
    }
    grid.deleteCharAt(grid.length()-1); //Burns the space put at the end
    return grid.toString();
  }
  

  public Piece[] getPieces() {
    return pieces;
  }

  public Piece getFreePiece() {
    // TODO Auto-generated method stub
    return freePiece;
  }
  
  public String toString() {
    return "PicturePuzzle";
  }
  /**
   * A sync and catch way of waiting the thread. Just cleaner code
   */
  public void waitThis(){
    try{
      synchronized (this) {
        this.wait();
      }
    }catch(Exception e){
      e.printStackTrace();
    }
  }

  /**
   * A sync and catch way of notifying the thread. Just cleaner code
   */
  public void notifyThis(){
    try{
      synchronized (this) {
        this.notify();
      }
    }catch(Exception e){
      e.printStackTrace();
    }
  }  

}




Java Source Code List

me.crr.interfaces.AABB.java
me.crr.interfaces.InputManagerReceiver.java
me.crr.interfaces.RenderHost.java
me.crr.picturepuzzle.Drawable.java
me.crr.picturepuzzle.FixedArray.java
me.crr.picturepuzzle.GameActivity.java
me.crr.picturepuzzle.InputManager.java
me.crr.picturepuzzle.MainMenuActivity.java
me.crr.picturepuzzle.PicturePuzzle.java
me.crr.picturepuzzle.PieceTransitionAnimation.java
me.crr.picturepuzzle.Piece.java
me.crr.picturepuzzle.Rectangle.java
me.crr.picturepuzzle.Render.java
me.crr.picturepuzzle.StatsActivity.java
me.crr.picturepuzzle.Texture.java
me.crr.picturepuzzle.WinTime.java