import java.util.Random;
/**
* mathematical model of mine sweeper pattern
* @author jiazhen
*
*/
public class MineSweeper
{
public static final int BLANK = -2;
public static final int MINE = -1;
public static final int RIGHTCLICK = -3;
public static final int LEFTCLICK = -4;
public static final int UNCLICK = -5;
private int[][] mines;
private int boardSize;
private boolean gameOver;
private boolean reveal;
private int numberOfMines;
private boolean start;
private int[][] flag;
/**
* Create a constructor which will initialise the board
* @param boardSize a given size for the board
* @param numberOfMines a given number of the total mines
*/
public MineSweeper(int boardSize, int numberOfMines)
{
this.boardSize = boardSize;
this.mines = new int[boardSize][boardSize];
this.gameOver = false;
this.reveal = false;
this.start = false;
this.numberOfMines = numberOfMines;
this.flag = new int[boardSize][boardSize];
clearFlag();
generateMines(numberOfMines);
generateNeighbouringNumbers();
}
/**
* Get the value in the flag array with a given location
* @param i the row
* @param j the column
* @return -1 means that has been right clicked
* 0 means that has not been clicked
* 1 means that has been left clicked
*/
public int getFlag(int i, int j)
{
return this.flag[i][j];
}
/**
* Clear all of symbal in the flag array
*/
public void clearFlag()
{
for(int i = 0; i < boardSize; i++)
{
for(int j = 0; j < boardSize; j++)
{
flag[i][j] = UNCLICK;
}
}
}
/**
* Generate a given number of mines
* @param numberOfMines the given number of total mines
*/
public void generateMines(int numberOfMines)
{
// initialise the board
for(int i = 0; i < boardSize; i++)
{
for(int j = 0; j < boardSize; j++)
{
mines[i][j] = BLANK;
}
}
// generate random mines
Random random = new Random();
int row = 0;
int column = 0;
while(numberOfMines > 0)
{
// transfer the position into row and column
int position = 1 + random.nextInt(boardSize * boardSize);
for(int i = 0; i < boardSize; i++)
{
if(i*boardSize < position && (i+1)*boardSize >= position)
{
row = i;
column = position - i*boardSize - 1;
}
}
if(mines[row][column] != MINE)
{
mines[row][column] = MINE;
numberOfMines--;
}
}
}
/**
* Get symbol at given location in the board
* @param i the row
* @param j the column
* @return the number at that location
*/
public int getMineLocation(int i, int j)
{
return this.mines[i][j];
}
/**
* Is it the mine? If it was, game over.
* Otherwise open the button.
* And open the adjacent zero button
* @param i the row
* @param j the column
*/
public void leftClicked(int i, int j)
{
if(flag[i][j] != RIGHTCLICK && start)
{
if(mines[i][j] == MINE)
{
flag[i][j] = LEFTCLICK;
gameOver = true;
}
else
{
if(mines[i][j] == 0)
{
flag[i][j] = LEFTCLICK;
showBlankDown(i, j);
showBlankUp(i, j);
}
else
{
flag[i][j] = LEFTCLICK;
}
}
}
}
/**
* generate the total number of mines in neighbouring
*/
public void generateNeighbouringNumbers()
{
for(int i = 0; i < boardSize; i++)
{
for(int j = 0; j < boardSize; j++)
{
if(mines[i][j] == BLANK)
{
int count = 0;
if((i-1) >= 0 && (j-1) >= 0)
{
if(mines[i-1][j-1] == MINE) count++;
}
if((i-1) >= 0)
{
if(mines[i-1][j] == MINE) count++;
}
if((i-1) >= 0 && (j+1) < boardSize)
{
if(mines[i-1][j+1] == MINE) count++;
}
if((j-1) >= 0)
{
if(mines[i][j-1] == MINE) count++;
}
if((j+1) < boardSize)
{
if(mines[i][j+1] == MINE) count++;
}
if((i+1) < boardSize && (j-1) >= 0)
{
if(mines[i+1][j-1] == MINE) count++;
}
if((i+1) < boardSize)
{
if(mines[i+1][j] == MINE) count++;
}
if((i+1) < boardSize && (j+1) < boardSize)
{
if(mines[i+1][j+1] == MINE) count++;
}
mines[i][j] = count;
}
}
}
}
/**
* Detect if the user lose in the game
* @return true if the user lose, false for not
*/
public boolean isGameOver()
{
return this.gameOver;
}
/**
* Get the size of the board
* @return the size of the board
*/
public int getBoardSize()
{
return this.boardSize;
}
/**
* Detect if user asked to reveal the mines
* @return true if user asked to do that, false for not
*/
public boolean isReveal()
{
return this.reveal;
}
/**
* Decide reveal the mines or not
* @param reveal true for revealing, false for not
*/
public void setReveal(boolean reveal)
{
this.reveal = reveal;
}
/**
* Reset a new game
* @param numberOfMines the total number of the mines
*/
public void newGame(int numberOfMines)
{
this.numberOfMines = numberOfMines;
generateMines(numberOfMines);
generateNeighbouringNumbers();
clearFlag();
this.gameOver = false;
}
/**
* Detect whether win or not
* @return true if win, false for not
*/
public boolean isWon()
{
for(int i = 0; i < boardSize; i++)
{
for(int j = 0; j < boardSize; j++)
{
if(mines[i][j] != MINE && flag[i][j] == LEFTCLICK)
{
continue;
}
else if(mines[i][j] != MINE && flag[i][j] == UNCLICK)
{
return false;
}
else if(mines[i][j] != MINE && flag[i][j] == RIGHTCLICK)
{
return false;
}
}
}
return true;
}
/**
* Detect if all of the mines are flagged or not
* @return true if success, false for not
*/
public boolean isFlagedAllMines()
{
int count = 0;
for(int i = 0; i < boardSize; i++)
{
for(int j = 0; j < boardSize; j++)
{
if(flag[i][j] == RIGHTCLICK)
{
count++;
}
if(mines[i][j] == MINE && flag[i][j] == RIGHTCLICK)
{
continue;
}
else if(mines[i][j] == MINE && flag[i][j] == UNCLICK)
{
return false;
}
}
}
return count == numberOfMines;
}
/**
* Open the down adjacent ZERO button
* @param i the row
* @param j the column
*/
private void showBlankDown(int i, int j)
{
if(mines[i][j] != MINE)
{
if(flag[i][j] != RIGHTCLICK)
{
flag[i][j] = LEFTCLICK;
}
if(mines[i][j] == 0)
{
if((j+1) < boardSize)
{
if(mines[i][j+1] == 0)
showBlankDown(i, j+1);
else if(flag[i][j+1] != RIGHTCLICK)
{
flag[i][j+1] = LEFTCLICK;
}
}
if((i+1) < boardSize && (j-1) >= 0)
{
if(mines[i+1][j-1] == 0)
showBlankDown(i+1, j-1);
else if(flag[i+1][j-1] != RIGHTCLICK)
{
flag[i+1][j-1] = LEFTCLICK;
}
}
if((i+1) < boardSize)
{
if(mines[i+1][j] == 0)
showBlankDown(i+1, j);
else if(flag[i+1][j] != RIGHTCLICK)
{
flag[i+1][j] = LEFTCLICK;
}
}
if((i+1) < boardSize && (j+1) < boardSize)
{
if(mines[i+1][j+1] == 0)
showBlankDown(i+1, j+1);
else if(flag[i+1][j+1] != RIGHTCLICK)
{
flag[i+1][j+1] = LEFTCLICK;
}
}
}
}
}
/**
* Open the upper adjacent ZERO button
* @param i the row
* @param j the column
*/
private void showBlankUp(int i, int j)
{
if(mines[i][j] != MINE)
{
if(flag[i][j] != RIGHTCLICK)
{
flag[i][j] = LEFTCLICK;
}
if(mines[i][j] == 0)
{
if((i-1) >= 0 && (j-1) >= 0)
{
if(mines[i-1][j-1] == 0)
showBlankUp(i-1, j-1);
else if(flag[i-1][j-1] != RIGHTCLICK)
{
flag[i-1][j-1] = LEFTCLICK;
}
}
if((i-1) >= 0