package MinePackage;
public class MineTable implements MineConstants
{
private boolean[][] mine; // holds true if spot is a mine
private byte[][] value, // holds number of mines in surrounding spots
state; // holds either unclicked, clicked, or flagged
private short width,
height,
numMines,
numMinesFlagged;
private boolean hasLost, hasWon;
public MineTable() { }
/** Does most of the initialization work for creating or resetting a table */
public void create(int width, int height, int numMines)
{
if (this.width != width || this.height != height) // new dimensions
{
this.width = (short)width;
this.height = (short)height;
mine = new boolean[width][height];
value = new byte[width][height];
state = new byte[width][height];
}
else // reset table
{
for (short y = 0; y < height; y++)
for (short x = 0; x < width; x++)
mine[x][y] = false;
}
this.numMines = (short)numMines;
numMinesFlagged = 0;
hasLost = false;
hasWon = false;
// clear all states to unclicked
for (short y = 0; y < height; y++)
for (short x = 0; x < width; x++)
state[x][y] = UNCLICKED;
}
public short getWidth()
{ return width; }
public short getHeight()
{ return height; }
public short getNumMines()
{ return numMines; }
public short getNumFlagged()
{ return numMinesFlagged; }
public boolean hasWon()
{ return hasWon; }
public boolean hasLost()
{ return hasLost; }
public boolean isUnclicked(int x, int y)
{ return (outOfBounds(x, y) || state[x][y] != UNCLICKED ? false : true); }
public boolean isClicked(int x, int y)
{ return (outOfBounds(x, y) || state[x][y] != CLICKED ? false : true); }
public boolean isFlagged(int x, int y)
{ return (outOfBounds(x, y) || state[x][y] != FLAGGED ? false : true); }
public boolean isMine(int x, int y)
{ return (outOfBounds(x, y) || !mine[x][y] ? false : true); }
/** Returns a 1 if (x,y) is a mine, it returns 0 otherwise, or if out of bounds */
private int mine(int x, int y)
{ return (outOfBounds(x, y) || !mine[x][y] ? 0 : 1); }
public byte getValue(int x, int y)
{ return value[x][y]; }
public byte getState(int x, int y)
{ return state[x][y]; }
public boolean outOfBounds(int x, int y)
{ return (x < 0 || y < 0 || x >= width || y >= height ? true : false); }
/** Finds location for mines and stores values making sure (x,y) is not a mine */
public void firstClick(int x, int y)
{
initMines(x, y);
initValues();
}
public void click(int x, int y, boolean checkWin)
{
if (!isUnclicked(x, y)) // must be unclicked (also checks for out of bounds)
return;
if (mine[x][y]) // if it's a mine then they have lost
{
hasLost = true;
return;
}
state[x][y] = CLICKED;
if (value[x][y] == 0) // if no surrounding mines then call click on all neighbors
{
click(x - 1, y - 1, false);
click(x, y - 1, false);
click(x + 1, y - 1, false);
click(x - 1, y, false);
click(x + 1, y, false);
click(x - 1, y + 1, false);
click(x, y + 1, false);
click(x + 1, y + 1, false);
}
if (checkWin == true) // only the top click() should check for win
checkForWin();
} // end Click()
public void doubleClick(int dx, int dy)
{
int x, y, flagged = 0;
if (!isClicked(dx, dy) || value[dx][dy] == 0) // must be clicked and have a non-zero value
return;
for (y = dy - 1; y <= dy + 1; y++) // count number of surrounding spots that are flagged
for (x = dx - 1; x <= dx + 1; x++)
if (isFlagged(x, y))
flagged++;
if (flagged == value[dx][dy])
{
for (y = dy - 1; y <= dy + 1; y++)
for (x = dx - 1; x <= dx + 1; x++)
click(x, y, false);
}
checkForWin();
} // end doubleClick()
/** Flags the square at (x,y), if already flagged, then unflags it */
public void flag(int x, int y)
{
if (isUnclicked(x, y))
{
state[x][y] = FLAGGED;
numMinesFlagged++;
}
else if (isFlagged(x, y))
{
state[x][y] = UNCLICKED;
numMinesFlagged--;
}
}
// private methods
/** Determines if a mine location is too close to the sent location */
private boolean tooClose(int x, int y, int mx, int my)
{
if (Math.abs(x - mx) <= 1 && Math.abs(y - my) <= 1)
return true;
else
return false;
}
/** Sets random locations for all mines: firstX, firstY will not be immediately surrounded by a mine */
private void initMines(int fx, int fy)
{
short x, y;
for (short i = 0; i < numMines; i++)
{
do // get a random location and make sure there's nothing there
{
x = (short)(Math.random() * width);
y = (short)(Math.random() * height);
}
while (mine[x][y] || tooClose(fx, fy, x, y));
mine[x][y] = true;
}
}
/** Finds the values for each spot, value equals number of surrounding spots with a mine */
private void initValues()
{
for (short y = 0; y < height; y++) {
for (short x = 0; x < width; x++)
{
value[x][y] = (byte)(mine(x - 1, y - 1) + mine(x, y - 1) + mine(x + 1, y - 1));
value[x][y] += mine(x - 1, y) + mine(x + 1, y);
value[x][y] += mine(x - 1, y + 1) + mine(x, y + 1) + mine(x + 1, y + 1);
}
}
}
/** Checks if the player has qualified to win, meaning all squares that do not contain a mine are clicked */
private void checkForWin()
{
for (short y = 0; y < height; y++)
for (short x = 0; x < width; x++)
if (!mine[x][y] && !(state[x][y] == CLICKED))
return;
hasWon = true;
} // end checkForWin()
} // end MineTable class