扫雷4Android(附源码)

  最近由于项目需要学习了一下Android ,感觉汗不错。做了一个Android版的扫雷游戏。

游戏简介

 在此游戏中,我们使用一个块的网格,其中有一些随机的地雷

下面是效果图

 

一、应用程序布局

使用TableLayout布局控件。设置3行。

<?xml version="1.0" encoding="utf-8"?>
<TableLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:background="@drawable/back">
 
  <TableRow>
  <TextView android:id="@+id/timer" android:layout_column="0"
   android:layout_width="fill_parent" android:layout_height="48px"
   android:gravity="center_horizontal" android:padding="5dip"
   android:textColor="#FFFFFF" android:textSize="35sp"
      android:text=" 0" />
  <ImageButton android:id="@+id/smiley"
   android:layout_column="1" android:scaleType="center" android:padding="5dip"
   android:layout_width="48px" android:background="@drawable/smiley_button_states"
   android:layout_height="48px" />
  <TextView android:id="@+id/minecount" android:layout_column="2"
   android:layout_width="fill_parent" android:layout_height="48px"
   android:gravity="center_horizontal" android:padding="5dip"
   android:textColor="#FFFFFF" android:textSize="35sp" android:text="000" />
 </TableRow>
 
 <TableRow>
  <TextView android:layout_column="0" android:layout_height="50px"
   android:layout_width="fill_parent" android:layout_span="3"
   android:padding="10dip" />
 </TableRow>
 
 <TableRow>
  <TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:id="@+id/minefield" android:layout_width="260px"
   android:layout_height="260px" android:gravity="bottom"
   android:stretchColumns="*" android:layout_span="3" android:padding="5dip">
  </TableLayout>
 </TableRow>
</TableLayout>

二、地雷块

Block.java


/**
 * 地雷的块,继承自Button
 * @author 记忆的永恒
 *
 */
public class Block extends Button {
 private boolean isCovered; // 块是否覆盖
 private boolean isMined; // 下个块
 private boolean isFlagged; // 是否将该块标记为一个潜在的地雷
 private boolean isQuestionMarked; // 是否是块的问题标记
 private boolean isClickable; // 是否可以单击
 private int numberOfMinesInSurrounding; // 在附近的地雷数量块

 public Block(Context context) {
  super(context);
  // TODO Auto-generated constructor stub
 }

 public Block(Context context, AttributeSet attrs) {
  super(context, attrs);
  // TODO Auto-generated constructor stub
 }
 
 public Block(Context context, AttributeSet attrs, int defStyle)
     {
      super(context, attrs, defStyle);
     }


 /**
  * 设置默认参数
  */
 public void setDefaults() {
  isCovered = true;
  isMined = false;
  isFlagged = false;
  isQuestionMarked = false;
  isClickable = true;
  numberOfMinesInSurrounding = 0;
  
  this.setBackgroundResource(R.drawable.square_blue);
  setBoldFont();
 }

 public void setNumberOfSurroundingMines(int number) {
  this.setBackgroundResource(R.drawable.square_grey);
  updateNumber(number);
 }

 public void setMineIcon(boolean enabled) {
  this.setText("M");
  if (!enabled) {
   this.setBackgroundResource(R.drawable.square_grey);
   this.setTextColor(Color.RED);
  }

  else {
   this.setTextColor(Color.BLACK);
  }
 }

 public void setFlagIcon(boolean enabled) {
  this.setText("F");
  if (!enabled) {
   this.setBackgroundResource(R.drawable.square_grey);
   this.setTextColor(Color.RED);
  }

  else {
   this.setTextColor(Color.BLACK);
  }
 }

 public void setQuestionMarkIcon(boolean enabled) {
  this.setText("?");
  if (!enabled) {
   this.setBackgroundResource(R.drawable.square_grey);
   this.setTextColor(Color.RED);
  }

  else {
   this.setTextColor(Color.BLACK);
  }
 }

 public void setBlockAsDisabled(boolean enabled) {
  if (!enabled) {
   this.setBackgroundResource(R.drawable.square_grey);
  }

  else {
   this.setTextColor(R.drawable.square_blue);
  }
 }

 public void clearAllIcons() {
  this.setText("");
 }

 private void setBoldFont() {
  this.setTypeface(null, Typeface.BOLD);
 }

 public void OpenBlock() {
  if (!isCovered) {
   return;
  }

  setBlockAsDisabled(false);
  isCovered = false;

  if (hasMine()) {
   setMineIcon(false);
  }

  else {
   setNumberOfSurroundingMines(numberOfMinesInSurrounding);
  }
 }

 public void updateNumber(int text) {
  if (text != 0) {
   this.setText(Integer.toString(text));
   switch (text) {
   case 1:
    this.setTextColor(Color.BLUE);
    break;
   case 2:
    this.setTextColor(Color.rgb(0, 100, 0));
    break;
   case 3:
    this.setTextColor(Color.RED);
    break;
   case 4:
    this.setTextColor(Color.rgb(85, 26, 139));
    break;
   case 5:
    this.setTextColor(Color.rgb(139, 28, 98));
    break;
   case 6:
    this.setTextColor(Color.rgb(238, 173, 14));
    break;
   case 7:
    this.setTextColor(Color.rgb(47, 79, 79));
    break;
   case 8:
    this.setTextColor(Color.rgb(71, 71, 71));
    break;
   case 9:
    this.setTextColor(Color.rgb(205, 205, 0));
    break;

   }
  }
 }

 public void plantMine() {
  isMined = true;
 }

 public void triggerMine() {
  setMineIcon(true);
  this.setTextColor(Color.RED);
 }

 public boolean isCovered() {
  return isCovered;
 }

 public boolean hasMine() {
  return isMined;
 }

 public void setNumberOfMinesInSurrounding(int number) {
  numberOfMinesInSurrounding = number;
 }

 public int getNumberOfMinesInSorrounding() {
  return numberOfMinesInSurrounding;
 }

 public boolean isFlagged() {
  return isFlagged;
 }

 public void setFlagged(boolean flagged) {
  isFlagged = flagged;
 }

 public boolean isQuestionMarked() {
  return isQuestionMarked;
 }

 public void setQuestionMarked(boolean questionMarked) {
  isQuestionMarked = questionMarked;
 }

 public boolean isClickable() {
  return isClickable;
 }

 public void setClickable(boolean clickable) {
  isClickable = clickable;
 }

}

 

三、主界面

1.TableLayout动态添加行

 mineField = (TableLayout)findViewById(R.id.MineField);

private void showMineField()
{
  for (int row = 1; row < numberOfRowsInMineField + 1; row++)
  {
    TableRow tableRow = new TableRow(this); 
    tableRow.setLayoutParams(new LayoutParams((blockDimension + 2 * blockPadding) *
        numberOfColumnsInMineField, blockDimension + 2 * blockPadding));

    for (int column = 1; column < numberOfColumnsInMineField + 1; column++)
    {
      blocks[row][column].setLayoutParams(new LayoutParams( 
          blockDimension + 2 * blockPadding, 
          blockDimension + 2 * blockPadding));
      blocks[row][column].setPadding(blockPadding, blockPadding, blockPadding, blockPadding);
      tableRow.addView(blocks[row][column]);
    }
    mineField.addView(tableRow,new TableLayout.LayoutParams( 
        (blockDimension + 2 * blockPadding) * numberOfColumnsInMineField, blockDimension + 2 * blockPadding)); 
  }
}

2.定时器Handler

private Handler timer = new Handler();
private int secondsPassed = 0;

public void startTimer(){ if (secondsPassed == 0)
  {
    timer.removeCallbacks(updateTimeElasped);
    // tell timer to run call back after 1 second
    timer.postDelayed(updateTimeElasped, 1000);

  }
}

public void stopTimer()
{
  // disable call backs
  timer.removeCallbacks(updateTimeElasped);

}

// timer call back when timer is ticked
private Runnable updateTimeElasped = new Runnable()

{
  public void run()
  {
    long currentMilliseconds = System.currentTimeMillis();
    ++secondsPassed;
    txtTimer.setText(Integer.toString(secondsPassed));

    // add notification
    timer.postAtTime(this, currentMilliseconds);

    // notify to call back after 1 seconds
    // basically to remain in the timer loop
    timer.postDelayed(updateTimeElasped, 1000);

  }
};

3.第一次点击

private boolean isTimerStarted; // check if timer already started or not
blocks[row][column].setOnClickListener(new OnClickListener()

{
  @Override
  public void onClick(View view)
  {
    // start timer on first click
    if (!isTimerStarted)

    {
      startTimer();
      isTimerStarted = true;
    }
    ...
  }
});

4.第一次点击无雷

private boolean areMinesSet; // check if mines are planted in blocks

blocks[row][column].setOnClickListener(new OnClickListener()
{
  @Override
  public void onClick(View view)
  {
    ...
    // set mines on first click
    if (!areMinesSet)

    {
      areMinesSet = true;
      setMines(currentRow, currentColumn);
    }
  }
});

private void setMines(int currentRow, int currentColumn)
{
  // set mines excluding the location where user clicked
  Random rand = new Random();

  int mineRow, mineColumn;

  for (int row = 0; row < totalNumberOfMines; row++)
  {
    mineRow = rand.nextInt(numberOfColumnsInMineField);
    mineColumn = rand.nextInt(numberOfRowsInMineField);
    if ((mineRow + 1 != currentColumn) || (mineColumn + 1 != currentRow))
    {
      if (blocks[mineColumn + 1][mineRow + 1].hasMine())
      {
        row--; // mine is already there, don't repeat for same block
      }

      // plant mine at this location
      blocks[mineColumn + 1][mineRow + 1].plantMine();

    }
    // exclude the user clicked location
    else

    {
      row--;
    }
  }

  int nearByMineCount;

  // count number of mines in surrounding blocks
  ...

}

5.点击雷块的效果

private void rippleUncover(int rowClicked, int columnClicked)
{
  // don't open flagged or mined rows
  if (blocks[rowClicked][columnClicked].hasMine() || blocks[rowClicked][columnClicked].isFlagged())

  {
    return;
  }

  // open clicked block
  blocks[rowClicked][columnClicked].OpenBlock();


  // if clicked block have nearby mines then don't open further
  if (blocks[rowClicked][columnClicked].getNumberOfMinesInSorrounding() != 0 )

  {
    return;
  }

  // open next 3 rows and 3 columns recursively
  for (int row = 0; row < 3; row++)

  {
    for (int column = 0; column < 3; column++)
    {
      // check all the above checked conditions
      // if met then open subsequent blocks
      if (blocks[rowClicked + row - 1][columnClicked + column - 1].isCovered()

          && (rowClicked + row - 1 > 0) && (columnClicked + column - 1 > 0)
          && (rowClicked + row - 1 < numberOfRowsInMineField + 1)
          && (columnClicked + column - 1 < numberOfColumnsInMineField + 1))
      {
        rippleUncover(rowClicked + row - 1, columnClicked + column - 1 );
      }
    }
  }
  return;
}

6.以问好标记空白

blocks[row][column].setOnLongClickListener(new OnLongClickListener()
{
  public boolean onLongClick(View view)
  {
    // simulate a left-right (middle) click
    // if it is a long click on an opened mine then
    // open all surrounding blocks
    ...


    // if clicked block is enabled, clickable or flagged
    if (blocks[currentRow][currentColumn].isClickable() &&

        (blocks[currentRow][currentColumn].isEnabled() || blocks[currentRow][currentColumn].isFlagged()))
    {

      // for long clicks set:
      // 1. empty blocks to flagged
      // 2. flagged to question mark
      // 3. question mark to blank

      // case 1. set blank block to flagged
      if (!blocks[currentRow][currentColumn].isFlagged() && !blocks[currentRow][currentColumn].isQuestionMarked())

      {
        blocks[currentRow][currentColumn].setBlockAsDisabled(false);
        blocks[currentRow][currentColumn].setFlagIcon(true);
        blocks[currentRow][currentColumn].setFlagged(true);
        minesToFind--; //reduce mine count
        updateMineCountDisplay();

      }
      // case 2. set flagged to question mark
      else if (!blocks[currentRow][currentColumn].isQuestionMarked())

      {
        blocks[currentRow][currentColumn].setBlockAsDisabled(true);
        blocks[currentRow][currentColumn].setQuestionMarkIcon(true);
        blocks[currentRow][currentColumn].setFlagged(false);
        blocks[currentRow][currentColumn].setQuestionMarked(true);
        minesToFind++; // increase mine count
        updateMineCountDisplay();

      }
      // case 3. change to blank square
      else

      {
        blocks[currentRow][currentColumn].setBlockAsDisabled(true);
        blocks[currentRow][currentColumn].clearAllIcons();
        blocks[currentRow][currentColumn].setQuestionMarked(false);
        // if it is flagged then increment mine count
        if (blocks[currentRow][currentColumn].isFlagged())

        {
          minesToFind++; // increase mine count
          updateMineCountDisplay();

        }
        // remove flagged status
        blocks[currentRow][currentColumn].setFlagged(false);

      }
     
      updateMineCountDisplay(); // update mine display
    }


    return true;
  }
});

7.记录胜负

// check status of the game at each step
if (blocks[currentRow + previousRow][currentColumn + previousColumn].hasMine())

{
  // oops game over
  finishGame(currentRow + previousRow, currentColumn + previousColumn);

}

// did we win the game
if (checkGameWin())

{
  // mark game as win
  winGame();

}

private boolean checkGameWin()
{
  for (int row = 1; row < numberOfRowsInMineField + 1; row++)
  {
    for (int column = 1; column < numberOfColumnsInMineField + 1; column++)
    {
      if (!blocks[row][column].hasMine() && blocks[row][column].isCovered())
      {
        return false;
      }
    }
  }
  return true;
}

 

8.完整代码

MinesweeperGame.java

package com.VertexVerveInc.Games;

import java.util.Random;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.TableRow.LayoutParams;

public class MinesweeperGame extends Activity {
 private TextView txtMineCount;
 private TextView txtTimer;
 private ImageButton btnSmile;
 private TableLayout mineField;

 private Block blocks[][]; // blocks for mine field
 private int blockDimension = 24; // width of each block
 private int blockPadding = 2; // padding between blocks

 private int numberOfRowsInMineField = 9;
 private int numberOfColumnsInMineField = 9;
 private int totalNumberOfMines = 10;

 // timer to keep track of time elapsed
 private Handler timer = new Handler();
 private int secondsPassed = 0;

 private boolean isTimerStarted; // check if timer already started or not
 private boolean areMinesSet; // check if mines are planted in blocks
 private boolean isGameOver;
 private int minesToFind; // number of mines yet to be discovered

 /** Called when the activity is first created. */
 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.test);
  
  txtMineCount = (TextView) findViewById(R.id.minecount);
       txtTimer = (TextView) findViewById(R.id.timer);
   
       btnSmile = (ImageButton) findViewById(R.id.smiley);
       btnSmile.setOnClickListener(new OnClickListener()
       {
        @Override
        public void onClick(View view)
        {
         endExistingGame();
         startNewGame();
        }
       });
       
       mineField = (TableLayout)findViewById(R.id.minefield);
       
       showDialog("Click smiley to start New Game", 2000, true, false);
       
 }

 private void startNewGame() {
  createMineField();
  // display all blocks in UI
  showMineField();

  minesToFind = totalNumberOfMines;
  isGameOver = false;
  secondsPassed = 0;

 }

 private void createMineField() {
  // we take one row extra row for each side
  // overall two extra rows and two extra columns
  // first and last row/column are used for calculations purposes only
  // x|xxxxxxxxxxxxxx|x
  // ------------------
  // x| |x
  // x| |x
  // ------------------
  // x|xxxxxxxxxxxxxx|x
  // the row and columns marked as x are just used to keep counts of near
  // by mines

  blocks = new Block[numberOfRowsInMineField + 2][numberOfColumnsInMineField + 2];

  for (int row = 0; row < numberOfColumnsInMineField + 2; row++) {
   for (int column = 0; column < numberOfColumnsInMineField + 2; column++) {
    blocks[row][column] = new Block(this);
    blocks[row][column].setDefaults();

    // pass current row and column number as final int's to event
    // listeners
    // this way we can ensure that each event listener is associated
    // to
    // particular instance of block only
    final int currentRow = row;
    final int currentColumn = column;

    blocks[row][column].setOnClickListener(new OnClickListener() {

     @Override
     public void onClick(View v) {
      // start timer on first click
      if (!isTimerStarted) {
       startTimer();
       isTimerStarted = true;
      }

      // set mines on first click
      if (!areMinesSet) {
       areMinesSet = true;
       setMines(currentRow, currentColumn);
      }

      // this is not first click
      // check if current block is flagged
      // if flagged the don't do anything
      // as that operation is handled by LongClick
      // if block is not flagged then uncover nearby blocks
      // till we get numbered mines
      if (!blocks[currentRow][currentColumn].isFlagged()) {
       // open nearby blocks till we get numbered blocks
       rippleUncover(currentRow, currentColumn);

       // did we clicked a mine
       if (blocks[currentRow][currentColumn].hasMine()) {
        // Oops, game over
        finishGame(currentRow, currentColumn);
       }

       // check if we win the game
       if (checkGameWin()) {
        // mark game as win
        winGame();
       }
      }
     }

    });

    // add Long Click listener
    // this is treated as right mouse click listener
    blocks[row][column]
      .setOnLongClickListener(new OnLongClickListener() {
       public boolean onLongClick(View view) {
        // simulate a left-right (middle) click
        // if it is a long click on an opened mine then
        // open all surrounding blocks
        if (!blocks[currentRow][currentColumn]
          .isCovered()
          && (blocks[currentRow][currentColumn]
            .getNumberOfMinesInSorrounding() > 0)
          && !isGameOver) {
         int nearbyFlaggedBlocks = 0;
         for (int previousRow = -1; previousRow < 2; previousRow++) {
          for (int previousColumn = -1; previousColumn < 2; previousColumn++) {
           if (blocks[currentRow + previousRow][currentColumn
             + previousColumn]
             .isFlagged()) {
            nearbyFlaggedBlocks++;
           }
          }
         }

         // if flagged block count is equal to nearby
         // mine count
         // then open nearby blocks
         if (nearbyFlaggedBlocks == blocks[currentRow][currentColumn]
           .getNumberOfMinesInSorrounding()) {
          for (int previousRow = -1; previousRow < 2; previousRow++) {
           for (int previousColumn = -1; previousColumn < 2; previousColumn++) {
            // don't open flagged blocks
            if (!blocks[currentRow
              + previousRow][currentColumn
              + previousColumn]
              .isFlagged()) {
             // open blocks till we get
             // numbered block
             rippleUncover(
               currentRow
                 + previousRow,
               currentColumn
                 + previousColumn);

             // did we clicked a mine
             if (blocks[currentRow
               + previousRow][currentColumn
               + previousColumn]
               .hasMine()) {
              // oops game over
              finishGame(
                currentRow
                  + previousRow,
                currentColumn
                  + previousColumn);
             }

             // did we win the game
             if (checkGameWin()) {
              // mark game as win
              winGame();
             }
            }
           }
          }
         }

         // as we no longer want to judge this
         // gesture so return
         // not returning from here will actually
         // trigger other action
         // which can be marking as a flag or
         // question mark or blank
         return true;
        }

        // if clicked block is enabled, clickable or
        // flagged
        if (blocks[currentRow][currentColumn]
          .isClickable()
          && (blocks[currentRow][currentColumn]
            .isEnabled() || blocks[currentRow][currentColumn]
            .isFlagged())) {

         // for long clicks set:
         // 1. empty blocks to flagged
         // 2. flagged to question mark
         // 3. question mark to blank

         // case 1. set blank block to flagged
         if (!blocks[currentRow][currentColumn]
           .isFlagged()
           && !blocks[currentRow][currentColumn]
             .isQuestionMarked()) {
          blocks[currentRow][currentColumn]
            .setBlockAsDisabled(false);
          blocks[currentRow][currentColumn]
            .setFlagIcon(true);
          blocks[currentRow][currentColumn]
            .setFlagged(true);
          minesToFind--; // reduce mine count
          updateMineCountDisplay();
         }
         // case 2. set flagged to question mark
         else if (!blocks[currentRow][currentColumn]
           .isQuestionMarked()) {
          blocks[currentRow][currentColumn]
            .setBlockAsDisabled(true);
          blocks[currentRow][currentColumn]
            .setQuestionMarkIcon(true);
          blocks[currentRow][currentColumn]
            .setFlagged(false);
          blocks[currentRow][currentColumn]
            .setQuestionMarked(true);
          minesToFind++; // increase mine count
          updateMineCountDisplay();
         }
         // case 3. change to blank square
         else {
          blocks[currentRow][currentColumn]
            .setBlockAsDisabled(true);
          blocks[currentRow][currentColumn]
            .clearAllIcons();
          blocks[currentRow][currentColumn]
            .setQuestionMarked(false);
          // if it is flagged then increment mine
          // count
          if (blocks[currentRow][currentColumn]
            .isFlagged()) {
           minesToFind++; // increase mine
           // count
           updateMineCountDisplay();
          }
          // remove flagged status
          blocks[currentRow][currentColumn]
            .setFlagged(false);
         }

         updateMineCountDisplay();
         // update mine
         // display
        }

        return true;
       }
      });
   }
  }
 }

 private void showMineField() {
  for (int row = 1; row < numberOfRowsInMineField + 1; row++) {
   TableRow tableRow = new TableRow(this);
   tableRow.setLayoutParams(new LayoutParams(
     (blockDimension + 2 * blockPadding)
       * numberOfColumnsInMineField, blockDimension + 2
       * blockPadding));
   for (int column = 1; column < numberOfColumnsInMineField + 1; column++) {
    blocks[row][column].setLayoutParams(new LayoutParams(
      blockDimension + 2 * blockPadding, blockDimension + 2
        * blockPadding));
    blocks[row][column].setPadding(blockPadding, blockPadding,
      blockPadding, blockPadding);
    tableRow.addView(blocks[row][column]);
   }
   mineField.addView(tableRow, new TableLayout.LayoutParams(
     (blockDimension + 2 * blockPadding)
       * numberOfColumnsInMineField, blockDimension + 2
       * blockPadding));
  }
 }

 private void endExistingGame() {
  stopTimer(); // stop if timer is running
  txtTimer.setText("000"); // revert all text
  txtMineCount.setText("000"); // revert mines count
  btnSmile.setBackgroundResource(R.drawable.smile);

  // remove all rows from mineField TableLayout
  mineField.removeAllViews();

  // set all variables to support end of game
  isTimerStarted = false;
  areMinesSet = false;
  isGameOver = false;
  minesToFind = 0;

 }

 private boolean checkGameWin() {
  for (int row = 1; row < numberOfRowsInMineField + 1; row++) {
   for (int column = 1; column < numberOfColumnsInMineField + 1; column++) {
    if (!blocks[row][column].hasMine()
      && blocks[row][column].isCovered()) {
     return false;
    }
   }
  }
  return true;
 }

 private void updateMineCountDisplay() {
  if (minesToFind < 0) {
   txtMineCount.setText(Integer.toString(minesToFind));
  } else if (minesToFind < 10) {
   txtMineCount.setText("00" + Integer.toString(minesToFind));
  } else if (minesToFind < 100) {
   txtMineCount.setText("0" + Integer.toString(minesToFind));
  } else {
   txtMineCount.setText(Integer.toString(minesToFind));
  }
 }

 private void winGame() {
  stopTimer();
  isTimerStarted = false;
  isGameOver = true;
  minesToFind = 0; // set mine count to 0

  // set icon to cool dude
  btnSmile.setBackgroundResource(R.drawable.cool);

  updateMineCountDisplay(); // update mine count

  // disable all buttons
  // set flagged all un-flagged blocks
  for (int row = 1; row < numberOfRowsInMineField + 1; row++) {
   for (int column = 1; column < numberOfColumnsInMineField + 1; column++) {
    blocks[row][column].setClickable(false);
    if (blocks[row][column].hasMine()) {
     blocks[row][column].setBlockAsDisabled(false);
     blocks[row][column].setFlagIcon(true);
    }
   }
  }

  // show message
  showDialog("You won in " + Integer.toString(secondsPassed)
    + " seconds!", 1000, false, true);
 }

 private void finishGame(int currentRow, int currentColumn) {
  isGameOver = true; // mark game as over
  stopTimer(); // stop timer
  isTimerStarted = false;
  btnSmile.setBackgroundResource(R.drawable.sad);

  // show all mines
  // disable all blocks
  for (int row = 1; row < numberOfRowsInMineField + 1; row++) {
   for (int column = 1; column < numberOfColumnsInMineField + 1; column++) {
    // disable block
    blocks[row][column].setBlockAsDisabled(false);

    // block has mine and is not flagged
    if (blocks[row][column].hasMine()
      && !blocks[row][column].isFlagged()) {
     // set mine icon
     blocks[row][column].setMineIcon(false);
    }

    // block is flagged and doesn't not have mine
    if (!blocks[row][column].hasMine()
      && blocks[row][column].isFlagged()) {
     // set flag icon
     blocks[row][column].setFlagIcon(false);
    }

    // block is flagged
    if (blocks[row][column].isFlagged()) {
     // disable the block
     blocks[row][column].setClickable(false);
    }
   }
  }

  // trigger mine
  blocks[currentRow][currentColumn].triggerMine();

  // show message
  showDialog("You tried for " + Integer.toString(secondsPassed)
    + " seconds!", 1000, false, false);
 }

 private void setMines(int currentRow, int currentColumn) {
  // set mines excluding the location where user clicked
  Random rand = new Random();
  int mineRow, mineColumn;

  for (int row = 0; row < totalNumberOfMines; row++) {
   mineRow = rand.nextInt(numberOfColumnsInMineField);
   mineColumn = rand.nextInt(numberOfRowsInMineField);
   if ((mineRow + 1 != currentColumn)
     || (mineColumn + 1 != currentRow)) {
    if (blocks[mineColumn + 1][mineRow + 1].hasMine()) {
     row--; // mine is already there, don't repeat for same block
    }
    // plant mine at this location
    blocks[mineColumn + 1][mineRow + 1].plantMine();
   }
   // exclude the user clicked location
   else {
    row--;
   }
  }

  int nearByMineCount;

  for (int row = 0; row < numberOfRowsInMineField + 2; row++) {
   for (int column = 0; column < numberOfColumnsInMineField + 2; column++) {
    // for each block find nearby mine count
    nearByMineCount = 0;
    if ((row != 0) && (row != (numberOfRowsInMineField + 1))
      && (column != 0)
      && (column != (numberOfColumnsInMineField + 1))) {
     // check in all nearby blocks
     for (int previousRow = -1; previousRow < 2; previousRow++) {
      for (int previousColumn = -1; previousColumn < 2; previousColumn++) {
       if (blocks[row + previousRow][column
         + previousColumn].hasMine()) {
        // a mine was found so increment the counter
        nearByMineCount++;
       }
      }
     }

     blocks[row][column]
       .setNumberOfMinesInSurrounding(nearByMineCount);
    }
    // for side rows (0th and last row/column)
    // set count as 9 and mark it as opened
    else {
     blocks[row][column].setNumberOfMinesInSurrounding(9);
     blocks[row][column].OpenBlock();
    }
   }
  }
 }

 private void rippleUncover(int rowClicked, int columnClicked) {
  // don't open flagged or mined rows
  if (blocks[rowClicked][columnClicked].hasMine()
    || blocks[rowClicked][columnClicked].isFlagged()) {
   return;
  }

  // open clicked block
  blocks[rowClicked][columnClicked].OpenBlock();

  // if clicked block have nearby mines then don't open further
  if (blocks[rowClicked][columnClicked].getNumberOfMinesInSorrounding() != 0) {
   return;
  }

  // open next 3 rows and 3 columns recursively
  for (int row = 0; row < 3; row++) {
   for (int column = 0; column < 3; column++) {
    // check all the above checked conditions
    // if met then open subsequent blocks
    if (blocks[rowClicked + row - 1][columnClicked + column - 1]
      .isCovered()
      && (rowClicked + row - 1 > 0)
      && (columnClicked + column - 1 > 0)
      && (rowClicked + row - 1 < numberOfRowsInMineField + 1)
      && (columnClicked + column - 1 < numberOfColumnsInMineField + 1)) {
     rippleUncover(rowClicked + row - 1, columnClicked + column
       - 1);
    }
   }
  }
  return;
 }

 public void startTimer() {
  if (secondsPassed == 0) {
   timer.removeCallbacks(updateTimeElasped);
   // tell timer to run call back after 1 second
   timer.postDelayed(updateTimeElasped, 1000);
   Log.i("tag",String.valueOf((timer.postDelayed(updateTimeElasped, 1000))) );
  }
 }

 public void stopTimer() {
  // disable call backs
  timer.removeCallbacks(updateTimeElasped);
 }

 // timer call back when timer is ticked
 private Runnable updateTimeElasped = new Runnable() {
  public void run() {
   long currentMilliseconds = System.currentTimeMillis();
   ++secondsPassed;
   txtTimer.setText(Integer.toString(secondsPassed));

   // add notification
   timer.postAtTime(this, currentMilliseconds);
   // notify to call back after 1 seconds
   // basically to remain in the timer loop
   timer.postDelayed(updateTimeElasped, 1000);
  }
 };

 private void showDialog(String message, int milliseconds,
   boolean useSmileImage, boolean useCoolImage) {
  // show message
  Toast dialog = Toast.makeText(getApplicationContext(), message,
    Toast.LENGTH_LONG);

  dialog.setGravity(Gravity.CENTER, 0, 0);
  LinearLayout dialogView = (LinearLayout) dialog.getView();
  ImageView coolImage = new ImageView(getApplicationContext());
  if (useSmileImage) {
   coolImage.setImageResource(R.drawable.smile);
  } else if (useCoolImage) {
   coolImage.setImageResource(R.drawable.cool);
  } else {
   coolImage.setImageResource(R.drawable.sad);
  }
  dialogView.addView(coolImage, 0);
  dialog.setDuration(milliseconds);
  dialog.show();
  Log.i("tag", "showDialog()");
 }

}

 

源码下载

posted @ 2010-10-03 16:39  ForrestWoo  阅读(10162)  评论(2编辑  收藏  举报