最近由于项目需要学习了一下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()");
}
}