Android Open Source - DroidSweeper Player






From Project

Back to project page DroidSweeper.

License

The source code is released under:

MIT License

If you think the Android project DroidSweeper 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 de.nisble.droidsweeper.game.replay;
/*  ww  w. ja  v  a 2 s  .  c  o  m*/
import static de.nisble.droidsweeper.config.Constants.TIMER_PERIOD;

import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;

import de.nisble.droidsweeper.config.GameConfig;
import de.nisble.droidsweeper.game.Field;
import de.nisble.droidsweeper.game.Game;
import de.nisble.droidsweeper.game.database.DSDBAdapter;
import de.nisble.droidsweeper.game.jni.FieldListener;
import de.nisble.droidsweeper.game.jni.FieldStatus;
import de.nisble.droidsweeper.utilities.LogDog;
import de.nisble.droidsweeper.utilities.Timer;
import de.nisble.droidsweeper.utilities.Timer.TimerObserver;

/** {@link Replay} player.<br>
 * This class is used to show a game {@link Replay} that was loaded from the
 * database or {@link Recorder recorded} right before. The key feature of this
 * program to update the field widgets directly from native code makes showing a
 * replay a bit tricky.<br>
 * To update the {@link FieldStatus status} of the field widgets this
 * class must know the widgets. Therefore this class holds a matrix of
 * {@link FieldListener interfaces} to the field widgets.<br>
 * It is mandatory for the view to distinguish between a real game and a replay.
 * If its a game the field widgets must be registered in
 * {@link Game#setFieldListener(FieldListener)} else in this class by calling
 * {@link Player#setFieldListener(FieldListener)}.<br>
 * The view should register a {@link PlayerObserver} in this class. After
 * loading a {@link Replay} and while a call to {@link Player#play()} the
 * interface method {@link PlayerObserver#onBuildGrid(GameConfig)} is invoked.
 * Inside this method the view should create the game grid just as if the call
 * comes from {@link Game}. But rather than registering the field widgets in the
 * Game, the widgets should be registered here.
 * @author Moritz Nisbl moritz.nisble@gmx.de
 * @see {@link Recorder} for how to record a replay. */
public class Player implements TimerObserver {
  private final String CLASSNAME = Player.class.getSimpleName();

  private static final int STOPPED = 0;
  private static final int PLAYING = 1;
  private static final int PAUSED = 2;
  private int mState = STOPPED;

  private List<PlayerObserver> mObservers = new ArrayList<PlayerObserver>(1);

  private Timer mTimer = new Timer();

  private Replay mReplay = new Replay();

  private ListIterator<TimeStep> mTsIter;
  private FieldListener[][] mFlMatrix;

  /** Instantiate and initialize a new replay player. */
  public Player() {
    mTimer.addListener(this);
  }

  /** Add an observer.
   * @param l Observer. */
  public void addObserver(PlayerObserver l) {
    // Avoid multiple entries of the same object.
    if (!mObservers.contains(l))
      mObservers.add(l);
  }

  /** Remove an observer.
   * @param l Observer. */
  public void removeObserver(PlayerObserver l) {
    mObservers.remove(l);
  }

  /** Register a field widget for the player to be able to update the status of
   * the widgets.
   * @param l A field widget that implements the {@link FieldListener}
   *            interface.
   * @throws ArrayIndexOutOfBoundsException If a coordinate that the widget
   *             returns in its {@link FieldListener#getPosition()} method is
   *             out of the bounds of the current {@link GameConfig}. */
  public void setFieldListener(FieldListener l) throws ArrayIndexOutOfBoundsException {
    mFlMatrix[l.getPosition().X][l.getPosition().Y] = l;
  }

  /** Load a {@link Replay} by its game ID directly from the database.
   * @param gameID The ID of the game in the database.
   * @throws Exception Multiple exceptions are possible due to errors while
   *             loading from the database of deserialisation of the replay. */
  public void load(long gameID) throws Exception {
    // Stop the current replay
    mState = STOPPED;
    mTimer.stop();

    mReplay = new Replay(DSDBAdapter.INSTANCE.getReplay(gameID));

    mFlMatrix = new FieldListener[mReplay.getGameConfig().X][mReplay.getGameConfig().Y];
  }

  /** Load the given {@link Replay}.
   * @param replay A Replay. */
  public void load(Replay replay) {
    // Stop the current replay
    mState = STOPPED;
    mTimer.stop();

    // Make an internal copy
    mReplay = new Replay(replay);

    mFlMatrix = new FieldListener[mReplay.getGameConfig().X][mReplay.getGameConfig().Y];
  }

  /** Play a previously loaded {@link Replay}.<br>
   * This invokes {@link PlayerObserver#onBuildGrid(GameConfig)} and passes
   * the {@link GameConfig} of the Replay. The view should build the game grid
   * and register the field widgets by passing them to
   * {@link #setFieldListener(FieldListener)} */
  public void play() {
    if (!mReplay.getTimeSteps().isEmpty()) {
      mState = PLAYING;
      mTimer.stop();

      mTsIter = mReplay.getTimeSteps().listIterator(0);

      for (PlayerObserver l : mObservers) {
        l.onTimeUpdate(0);
        l.onRemainingBombsChanged(mReplay.getGameConfig().BOMBS);

        /* Let the view build the game grid. */
        l.onBuildGrid(mReplay.getGameConfig());
      }
      mTimer.start(TIMER_PERIOD);
    }
  }

  /** Stop a {@link Replay}. */
  public void stop() {
    mState = STOPPED;
    mTimer.stop();
  }

  /** Pause a currently running {@link Replay}. The Replay can be resumed by
   * calling {@link #resume()}. */
  public void pause() {
    if (PLAYING == mState) {
      mState = PAUSED;
      mTimer.pause();
    }
  }

  /** Resume a {@link #pause() paused} {@link Replay}. */
  public void resume() {
    if (PAUSED == mState) {
      mState = PLAYING;
      mTimer.resume();
    }
  }

  @Override
  public void onTick(long milliseconds) {
    if (mTsIter.hasNext()) {
      // Get next time step
      TimeStep ts = mTsIter.next();
      if (ts.TIME <= milliseconds) {
        // LogDog.d(CLASSNAME, "HIT @ TimeStep " + ts.TIME + "ms <= " +
        // milliseconds + "ms");

        for (PlayerObserver l : mObservers) {
          l.onRemainingBombsChanged(ts.BOMBS);
        }

        // Get field changes in this time step
        for (Field f : ts.STEPS) {
          // LogDog.v(CLASSNAME, "Changed field: X:" + f.POSITION.X +
          // " Y:" + f.POSITION.Y + " ("
          // + f.ADJACENT_BOMBS + ") to " + f.STATUS.toString());

          try {
            mFlMatrix[f.POSITION.X][f.POSITION.Y].onStatusChanged(f.STATUS, f.ADJACENT_BOMBS);
          } catch (ArrayIndexOutOfBoundsException e) {
            LogDog.e(CLASSNAME, "Out of bounds of FieldListener matrix @ X:" + f.POSITION.X + " Y:"
                + f.POSITION.Y, e);
          }
        }
      } else {
        mTsIter.previous();
      }
    } else {
      mState = STOPPED;
      mTimer.stop();

      for (PlayerObserver l : mObservers) {
        l.onReplayEnded();
      }
    }
  }

  @Override
  public void onSecond(long seconds) {
    for (PlayerObserver l : mObservers) {
      l.onTimeUpdate(seconds * 1000);
    }
  }

  /** @return True if a {@link Replay} is currently {@link #load(long) loaded}. */
  public boolean isLoaded() {
    return !mReplay.getTimeSteps().isEmpty();
  }

  /** @return True if the the {@link Player} is stopped. */
  public boolean isStopped() {
    return (STOPPED == mState);
  }

  /** @return True if the {@link Player} is currently playing. */
  public boolean isPlaying() {
    return PLAYING == mState;
  }

  /** @return True if the {@link Player} is paused. */
  public boolean isPaused() {
    return PAUSED == mState;
  }
}




Java Source Code List

de.nisble.droidsweeper.config.ApplicationConfig.java
de.nisble.droidsweeper.config.Constants.java
de.nisble.droidsweeper.config.GameConfig.java
de.nisble.droidsweeper.config.Level.java
de.nisble.droidsweeper.game.Field.java
de.nisble.droidsweeper.game.GameObserver.java
de.nisble.droidsweeper.game.Game.java
de.nisble.droidsweeper.game.Position.java
de.nisble.droidsweeper.game.database.DSDBAdapter.java
de.nisble.droidsweeper.game.database.DSDBContract.java
de.nisble.droidsweeper.game.database.DSDBGameEntry.java
de.nisble.droidsweeper.game.database.DSDBHelper.java
de.nisble.droidsweeper.game.jni.FieldListener.java
de.nisble.droidsweeper.game.jni.FieldStatus.java
de.nisble.droidsweeper.game.jni.GameStatus.java
de.nisble.droidsweeper.game.jni.MatrixObserver.java
de.nisble.droidsweeper.game.jni.MineSweeperMatrix.java
de.nisble.droidsweeper.game.replay.PlayerObserver.java
de.nisble.droidsweeper.game.replay.Player.java
de.nisble.droidsweeper.game.replay.Recorder.java
de.nisble.droidsweeper.game.replay.Replay.java
de.nisble.droidsweeper.game.replay.TimeStep.java
de.nisble.droidsweeper.gui.DroidSweeperActivity.java
de.nisble.droidsweeper.gui.HighScoreActivity.java
de.nisble.droidsweeper.gui.HighScoreListAdapter.java
de.nisble.droidsweeper.gui.SettingsActivity.java
de.nisble.droidsweeper.gui.grid.FieldDrawables.java
de.nisble.droidsweeper.gui.grid.FieldView.java
de.nisble.droidsweeper.gui.grid.GameGridView.java
de.nisble.droidsweeper.utilities.LogDog.java
de.nisble.droidsweeper.utilities.Timer.java