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