zoukankan      html  css  js  c++  java
  • 扫雷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()");
     }

    }

    源码下载

  • 相关阅读:
    C#线程池
    C#.Net前台线程与后台线程的区别
    ASP.NET Core 2.1 : 十五.图解路由(2.1 or earler)(转)
    ASP.NET Core 2.1 : 十四.静态文件与访问授权、防盗链(转)
    ASP.NET Core 2.1 : 十三.httpClient.GetAsync 报SSL错误的问题(转)
    ASP.NET Core 2.1 : 十二.内置日志、使用Nlog将日志输出到文件(转)
    ASP.NET Core 2.1 : 十一. 如何在后台运行一个任务(转)
    ASP.NET Core 2.1 : 十.升级现有Core2.0 项目到2.1(转)
    ASP.NET Core 2.0 : 九.从Windows发布到CentOS的跨平台部署(转)
    ASP.NET Core 2.0 : 八.图说管道,唐僧扫塔的故事(转)
  • 原文地址:https://www.cnblogs.com/salam/p/1841650.html
Copyright © 2011-2022 走看看