import java.awt.*;
import java.awt.geom.*;
import javax.swing.*;
import java.util.*;

public class Minesweep{
  public static void main(String args[]){
    Board board=new Board(30,16,99);
    //Board board=new Board(6,6,6);
    JEventQueue events=new JEventQueue();
    View view =new View(board);
    events.listenTo(view.getCanvas(),"canvas");
    events.listenTo(view.getFrame(),"frame");
    events.listenTo(view.getButton(),"newgame");
    events.startTimer(1000,"timer");
    while(true){
       EventObject event=events.waitEvent();
       if(events.isWindowResizing(event))view.update();else
       if(events.getName(event).equals("timer"))view.tickTime();else
       if(events.getName(event).equals("newgame")){board.reset(30,16,99);view.reset();}else
       if(events.isMousePressed(event)){
          int x=view.getX(events.getMouseX(event));
          int y=view.getY(events.getMouseY(event));
          board.check(x,y,events.getMouseButton(event));
          view.update();
       }     
    }
  }
}//Minesweep

class Board{
  private static int random(int i){ return  (int)Math.floor(i*Math.random());   }
  private int mx, my;
  private int[][]board;
  private int bombs=0;
  public int getBombs(){return bombs;}
  public int getMaxX(){return mx;}
  public int getMaxY(){return my;}
  Board(int x,int y,int bombs){ reset(x,y,bombs); }
  public void reset(int x,int y,int bombs){ 
    mx=x;my=y; this.bombs=bombs;
    board=new int[mx][my];
    int cnt=0;
    while(cnt<bombs){ // place bombs
      int i=random(mx),j=random(my);
      if(board[i][j]==0){board[i][j]=-1;cnt++;}   
    }
    for(int i=0;i<mx;i++)
      for(int j=0;j<my;j++)
         if(board[i][j]==0){ // if no bombs, insert neighbour bomb count 
            board[i][j]+=cnt(i-1,j-1); board[i][j]+=cnt(i,j-1); board[i][j]+=cnt(i+1,j-1);
            board[i][j]+=cnt(i-1,j  );                          board[i][j]+=cnt(i+1,j  );
            board[i][j]+=cnt(i-1,j+1); board[i][j]+=cnt(i,j+1); board[i][j]+=cnt(i+1,j+1);
         }
     for(int i=0;i<mx;i++) // cover all bombs
       for(int j=0;j<my;j++)
           board[i][j]+=10;
   }
   public int get(int x,int y){ // field value
      if(x<0||x>=mx||y<0||y>=my)return 0;
      return board[x][y];
   }
   private int cnt(int x,int y){// 1 if bomb in field, 0 otherwixe
      if(x<0||x>=mx||y<0||y>=my)return 0;
      if(board[x][y]<0)return 1; else return 0;
   }
   public void check(int x,int y,int b){ // check a field with mouse button
      if(x<0||x>=mx||y<0||y>=my)return;
      if(board[x][y]<=8)return;
      board[x][y]-=10;
      if(board[x][y]<0)bombs--;
      if(board[x][y]==-1&&b==3)board[x][y]=-2;
      if(board[x][y]!=0)return;
      check(x-1,y-1,b); check(x,y-1,b); check(x+1,y-1,b);
      check(x-1,y,b);               check(x+1,y,b);
      check(x-1,y+1,b); check(x,y+1,b); check(x+1,y+1,b);
   }
}

class View{
  View(Board board){
    this.board=board;
    frame.setSize(800,600);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    JBox top=JBox.hbox(l1,jtime,JBox.hspace(30),button,JBox.hspace(30),l2,jbombs);
    top.setFont(new Font("Arial",Font.BOLD,30));
    top.setMaximumSize(new Dimension(100000,40));
    frame.add(JBox.vbox(top,canvas));
    canvas.setFont(new Font("Arial",Font.BOLD,20));
    frame.setVisible(true);
    update();
  }
  public void reset(){ time=0; update(); }
  //---------------------------
  private Board board;
  private JFrame frame=new JFrame("Minesweep");
  public JFrame getFrame(){return frame;}
  private JCanvas canvas=new JCanvas();
  public JCanvas getCanvas(){return canvas;}
  private JButton button=new JButton("New game");
  public JButton getButton(){return button;}
  private JTextField jtime=new JTextField();
  private JTextField jbombs=new JTextField();
  private JLabel l1=new JLabel("Time"),l2=new JLabel("Bombs");
  //----------------------------
  private int dim=20; //size of Boards on the board
  public int getX(int x){return (x-5)/dim;}// screen to row/col coordinate 
  public int getY(int y){return (y-5)/dim;}// screen to row/col coordinate 
  private int s(int x){return 5+x*dim;}     //row/col to screen coordinate 
  //----------------------------
  private int time=0;
  public void tickTime(){time++;jtime.setText("  "+time);}
  //----------------------------
  private void mark(JCanvas canvas,int i,int j,Color c){ canvas.setPaint(c);
     canvas.fillRect(s(i)+2,s(j)+2,dim-3,dim-3);}
  public void update(){
    //System.out.println("update");
    int mx=board.getMaxX(),my=board.getMaxY();
    int wd=canvas.getBounds().width,ht=canvas.getBounds().height;
    if(wd<=10||ht<=10||mx<=0||my<=0)return;
    dim=Math.min((wd-10)/mx,(ht-10)/my); 
    jbombs.setText("  "+board.getBombs());
    FontMetrics fm=canvas.getFontMetrics();
    canvas.startBuffer();//canvas.clear();
    canvas.setFont(new Font("Arial",Font.BOLD,dim-5));
    canvas.setColor(Color.black); // draw grid
    for(int x=0;x<=mx;x++) canvas.drawLine(s(x),s(0),s(x),s(my));
    for(int y=0;y<=my;y++) canvas.drawLine(s(0),s(y),s(mx),s(y));
    for(int i=0;i<mx;i++)
      for(int j=0;j<my;j++){
        int v=board.get(i,j);
        if(v>8)    mark(canvas,i,j,Color.gray);else
        if(v==-2)  mark(canvas,i,j,Color.blue);else
        if(v==-1)  mark(canvas,i,j,Color.red);else
        if(v==0)   mark(canvas,i,j,Color.white);else
        if(v>0){   canvas.setPaint(Color.red); 
                   canvas.drawString(""+v,s(i)+(dim-fm.stringWidth(""+v))/2,s(j)+dim-4);}
      }
    canvas.endBuffer();    
    canvas.sleep(10);      
  }  
}
