/** MineApp.java    David Fourer
  * starts the MineSweep Application.  Gives player options for size
  * and number of games.  Checks for NumberFormatException and other
  * invalid choices.  Launches MineFrame to play.
  */

import java.awt.*;
import java.io.*;
import java.awt.event.*;

public class MineApp extends Frame implements ActionListener {
	private Button b1, b2;							
	private TextField t1, t2, t3;
	private TextArea tArea;
	private Button b3;
	private Color purple = new Color( 100, 20, 100 );
	private int row, col, mine, time=0;
	
	public static void main( String args[ ] ) throws IOException {
		MineApp ma = new MineApp( );
		ma.addWindowListener( new CloseWindowAndExit( ) );
	}
		//__________________________________________________constructor
	MineApp( ) {										

		super( "MineSweep  25 cents to play" );				//frame 
		setFont( new Font( "SansSerif", Font.PLAIN, 16 ) );
		setSize( 180, 420 );

		Panel pControll = new Panel( );					//upper panel
		pControll.setLayout( new GridLayout( 7, 1, 3, 3 ) );

		b1 = new Button( "Start easy game" );			//play buttons
		b2 = new Button( "Start difficult" );
		b1.addActionListener( this );
		b2.addActionListener( this );
		pControll.add( b1 );
		pControll.add( b2 );

		Label l1 = new Label( "across" );				//customize play option
		Label l2 = new Label( "down" );
		Label l3 = new Label( "mines" );
		t1 = new TextField( 5 );							//# across
		t2 = new TextField( 5 );							//# down
		t3 = new TextField( 5 );							//# mines

		Panel pBlank = new Panel( );
		Panel p1 = new Panel( );
		Panel p2 = new Panel( );
		Panel p3 = new Panel( );

		b3 = new Button( "Start custom" );				//custom play button
		b3.addActionListener( this );

		p1.add( l1 );  p1.add( t1 );						//pair components in panels
		p2.add( l2 );  p2.add( t2 );
		p3.add( l3 );  p3.add( t3 );
		pControll.add( pBlank );
		pControll.add( p1 ); pControll.add( p2 ); pControll.add( p3 );
		pControll.add( b3 );
		add( pControll, BorderLayout.NORTH );
													//exceptions and instructions text area
		tArea = new TextArea( "Choose the game you want to play", 4, 18,
														TextArea.SCROLLBARS_NONE );
		tArea.setForeground( purple );
		tArea.setEditable( false );
		add( tArea, BorderLayout.SOUTH );

		setVisible( true );
	}	//_______________________________ launch game__________actionPerformed( )
	public void actionPerformed( ActionEvent e ) {
		if( e.getSource( ) == b1 ) {
			row = 12; col = 12; mine = 18; time = 420;
		}
		if( e.getSource( ) == b2 ){
			row = 18; col = 18; mine = 60; time = 960;
		}
		if( e.getSource( ) == b3 ){
			try {					//Integer.parseInt( ) throws NumberFormatException
				col = Integer.parseInt( t1.getText( ) );
				row = Integer.parseInt( t2.getText( ) );
				mine = Integer.parseInt( t3.getText( ) );
			}
			catch( NumberFormatException nfe ) {
				tArea.setText( "Type an integer number in each box before " +
									"using the custom button" );
			}
			if( col<2 || row<2 || mine<1 ) {
				tArea.setText( "Choose positive values greater than one" );
				return;
			}if( col>32 || row>32 ) {
				tArea.setText( "32 rows or columns is the most that " +
									"fits in the display" );
				return;
			}if( col*row>700 ) {
				tArea.setText( "across X down > 700 boxes crashes my system. " +
									" Choose smaller values " );
				return;
			}if( mine>=col*row ) {
				tArea.setText( "You have chosen too many mines." );
				return;
			}if( col/row > 3 || row/col > 3 ) {
				tArea.setText( "Your game board will not display properly " +
								" Choose more equal values for across and down." );
				return;
			}
		}
		tArea.setText( "Please wait" );						//conclude actionPerformed
		MineFrame f = new MineFrame( row, col, mine, time );
		f.addWindowListener( new CloseWindowAndExit( ) );
		dispose( );				
	}
}

****************************************************************************
****************************************************************************

/** MineFrame.java     MineSweeper game   David Fourer
  * Constructor creates all the buttons, adds event, adds to frame.
  * mousePressed method drives program.
  * GameButton extends Button.
  * 
  * 
  */

import java.awt.*;
import java.awt.event.*;
import java.io.*;

public class MineFrame extends Frame implements MouseListener, ActionListener {

	GameButton b[ ][ ];								// subclass of Button
	GameButton bb;									// gets button clicked

	int numberOfMines;
	int rowSize, colSize;						// number of rows and cols
	int minesLeft;
	int notMinesLeft;
	int timeToPlay;
	boolean firstClick;

	Button b1, b2;									// controll panel
	TextField tCount, tCount2;
	TextArea tArea;
	TextField clock;
	Timer timer;
		//__________________________________________________________constructor
	MineFrame( int rows, int cols, int mines, int time) {		
		super( "MineSweeper game" );

		rowSize = rows;
		colSize = cols;
		minesLeft = numberOfMines = mines;
		timeToPlay = time;
		notMinesLeft = rowSize * colSize - mines;
		setSize( 700, 450 );
		setLayout( new BorderLayout( 10, 10 ) );
		Button b1, b2;
		firstClick = true;
		
		Panel p = new Panel( );									// to hold game board
		p.setLayout( new GridLayout( rows, cols, 2, 2 ) );
		setFont( new Font( "SansSerif", Font.PLAIN, 270/rowSize ) );
		controllPanel( );

		tCount.setText( String.valueOf( numberOfMines ) );
		tCount2.setText( String.valueOf( notMinesLeft ) );

		b = new GameButton[ rows ][ cols];					// instantiate array
		for( int i=0; i<rows; i++ )
			for( int j=0; j<cols; j++ ) {
				b[i][j] = new GameButton( " ", i, j );		// instantiate buttons
				b[i][j].addMouseListener( this );
				p.add( b[i][j] );
			}
		add( p, BorderLayout.CENTER );
		setVisible( true );
		
	}	//_____________________________________________________controllPanel( )
	public void controllPanel( ) {
		Panel pControll = new Panel( );
		pControll.setLayout( new GridLayout( 2, 1 ) );

		Panel pAction = new Panel( );
		pAction.setFont( new Font( "SansSerif", Font.PLAIN, 16 ) );
		pAction.setLayout( new GridLayout( 5, 1, 3, 3 ) );

		b1 = new Button( "Start Over" );					//start over and end buttons
		b2 = new Button( "Kill Button" );
		b1.addActionListener( this );
		b2.addActionListener( this );
		pAction.add( b1 );
		pAction.add( b2 );

		Label lCount = new Label( "Mines left" );			//display # mines
		tCount = new TextField( 4 );
		tCount.setEditable( false );
		Panel pCount = new Panel( );
		pCount.add( lCount );  pCount.add( tCount );
		pAction.add( pCount );

		Label lCount2 = new Label( "Safe left" );	//display # safe spaces
		tCount2 = new TextField( 4 );
		tCount2.setEditable( false );
		Panel pCount2 = new Panel( );
		pCount2.add( lCount2 );  pCount2.add( tCount2 );
		pAction.add( pCount2 );

		Label lClock = new Label( "Time" );			//display time left
		clock = new TextField( 8 );
		clock.setEditable( false );
		clock.setFont( new Font( "SansSerif", Font.ITALIC, 20 ) );
		clock.setForeground( Color.red );
		Panel pClock = new Panel( );
		pClock.add( lClock ); pClock.add( clock );
		pAction.add( pClock );

		pControll.add( pAction );

		tArea = new TextArea( "Good Luck", 5, 12, TextArea.SCROLLBARS_NONE );
		tArea.setFont( new Font( "Serif", Font.ITALIC, 28 ) );
		tArea.setBackground( Color.gray );
		tArea.setForeground( Color.red );
		tArea.setEditable( false );
		pControll.add( tArea );
	
		add( pControll, BorderLayout.WEST );
	}	//__________________________for controll panel_________actionPerformed( )
	public void actionPerformed( ActionEvent e ) {		
		if( e.getSource( ) == b1 ) {
			MineApp ma = new MineApp( );
			ma.addWindowListener( new CloseWindowAndExit( ) );
			dispose( );
		}
		if( e.getSource( ) == b2 ) {
			dispose( );
			System.exit(0);
		}
	}	//_____________________________for playing game__________mousePressed( )
	public void mouseClicked( MouseEvent e ){ }
	public void mouseReleased( MouseEvent e ){ }
	public void mouseEntered( MouseEvent e ){ }
	public void mouseExited( MouseEvent e ){ }
	public void mousePressed( MouseEvent e ) {
		bb = (GameButton) e.getSource( );				//get button pressed
		if( firstClick ) {
			setMines( );			//set mines after first button clicked
			tArea.setText( "" );
			timer = new Timer( clock, tArea, timeToPlay );
			timer.start( );									//start clock
		}
		firstClick = false;
										
		if( e.isMetaDown( ) ) {				//right mouse click				
			if( bb.markMine == false ) {	//mark mine or unmark mine
				minesLeft--;
				bb.setLabel( "M" );			//set attribute
				bb.markMine = true;
			}
			else {
				minesLeft++;
				bb.setLabel( " " );
				bb.markMine = false;
			}
		tCount.setText( String.valueOf( minesLeft ) );
		}
		else {									// left mouse click
			int row = bb.row;
			int col = bb.col;
			if( b[row][col].show == false )
				play( row, col );
		}
	testForWin( );
	}	//______________________________initialize game_________setMines( )
	public void setMines( ) {
		for( int n=0, z=0; n<numberOfMines && z<200; z++ ) {
			int i = (int) (Math.random( ) * rowSize);
			int j = (int) (Math.random( ) * colSize);
			if( b[i][j].hasMine == false && bb != b[i][j] ) {
				b[i][j].hasMine = true;
				n++;
			}
		}
	}	//_________________________when mine is hit_____________showMines( )
	public void showMines( ) {						
		tArea.setText( "Game Over  Try Again" );								
		for( int i=0; i<rowSize; i++ )
			for( int j=0; j<colSize; j++ )
				if( b[i][j].hasMine ) 
					b[i][j].setLabel( "@" );
	}	//____________________________________to run game________________play( )
	public void play( int row, int col) {
		--notMinesLeft;							// register count of spaces left
		tCount2.setText( String.valueOf( notMinesLeft ) );
		if( b[row][col].markMine ) {					// if incorrectly marked mine
			b[row][col].setLabel( " " );				// unmark it and change count
			++minesLeft;									// change display
			tCount.setText( String.valueOf( minesLeft ) );
		}
		if( b[row][col].hasMine ) {					// game lost
			showMines( );
			timer.stop( );
			return;
		}
		int countMines = 0;			// determine number of neighboring mines
		for( int i=(-1); i<=1; i++ )
			if( i+row < rowSize && i+row >= 0 )
				for( int j=(-1); j<=1; j++ )
					if( j+col < colSize && j+col >= 0 )
						if( b[i+row][j+col].hasMine )
							countMines++;
		if( countMines == 0 ) {								// found empty button
			b[row][col].setBackground( Color.pink );	// recursion uncovers
			b[row][col].show = true;						// neighbors
			for( int i=(-1); i<=1; i++ )
				if( i+row < rowSize && i+row >= 0 )
					for( int j=(-1); j<=1; j++ )
						if( j+col < colSize && j+col >= 0 )
							if( b[i+row][j+col].show == false )
								play( i+row, j+col );
		}
		else														// mark # neighboring mines
			b[row][col].setLabel( String.valueOf( countMines ) );
			if( countMines == 1 )
				b[row][col].setForeground( Color.black );
			if( countMines == 2 )
				b[row][col].setForeground( Color.blue );
			if( countMines == 3 )
				b[row][col].setForeground( Color.green );
			if( countMines == 4 )
				b[row][col].setForeground( Color.orange );
			if( countMines == 5 )
				b[row][col].setForeground( Color.yellow );
			if( countMines > 5 )
				b[row][col].setForeground( Color.magenta );
			b[row][col].show = true;
	}	//______________________________________________testForWin( )
	public void testForWin( ) {
		if( notMinesLeft == 0 ) {
			tArea.setText( "Well Done, Game Completed" );
			timer.stop( );
		}			
		else if( minesLeft == 0 ) { 
			for( int i=0; i<rowSize; i++ )
				for( int j=0; j<colSize; j++ )
					if( b[i][j].markMine != b[i][j].hasMine )
						return;
			tArea.setText( "Well Done, Game Completed" );
			timer.stop( );
		}
	}
}

***********************************************************************************
***********************************************************************************

/** GameButton.java   for MineSweep game   David Fourer   
  * 
  * data includes status and location of button
  * all data access directly, no methods, since not intended for re-use.
  */

import java.awt.*;
import java.awt.event.*;

 public class GameButton extends Button {

	public boolean hasMine = false;		// all buttons start with these settings
 	public boolean show = false;
 	public boolean markMine = false;
	public int row, col;						// subscripts
	
 	GameButton ( String s, int xx, int yy ) {
		super( s );
		row = xx;
		col = yy;
 	}
}

************************************************************
************************************************************

/** Close Window and Exit    David Fourer
  */
import java.awt.event.*;

public class CloseWindowAndExit extends WindowAdapter {
	public void windowClosing( WindowEvent e ) {
		System.exit( 0 );
	}
}