import java.applet.*; 
import java.awt.*; 
import java.awt.event.*; 
import java.io.*; 
import javax.swing.*; 
import javax.swing.filechooser.*; 
import java.util.*; //声明主类 
public class JavaMine{ 
public static void main(String args[]){ 
MainFrame mainWindow=new MainFrame(); 
int h;
mainWindow.show();//显示主窗口 
} 
} /*生成JButton的子类mineSquare,增加三个属性参数作为标志位 
*left用于判断能否用左键按下当前按钮,true表示可以用左键按下 
*sign用于判断当前按钮是否被做标记,true表示已经做了标记 
*lock用于判断在游戏结束后按钮是否锁定,false表示没有锁定 
*/ 
class mineSquare extends JButton{ 
boolean left,sign,locked; 
public mineSquare(){ 
left=true; 
sign=false; 
locked=false;//默认标志位设置 
} 
} /*生成JDialog的子类inputDialog,用于输入自定义雷区的属性 
*有getW()、getH()、getN()三个方法,分别返回雷区的宽度、高度、雷数目 
*/ 
class inputDialog extends JDialog implements ActionListener{ 
private boolean judge;//用于判断输入的有效性,输入是否合法 
private JButton okButton,cancelButton; 
private JPanel panel; 
private JLabel labelWidth,labelHeight,labelNum; 
private JTextField textWidth,textHeight,textNum;//输入雷区尺寸、雷数目的文本框 
private int dataWidth,dataHeight,dataNum;//记录雷区尺寸、雷数目的变量 
private JOptionPane messageBox;//给出提示信息的JOptionPane public inputDialog(JFrame parent){ 
super(parent,"自定义雷区",true); 
panel=new JPanel(); 
this.setSize(320,240); 
this.setResizable(false); 
labelWidth=new JLabel("雷区宽度:"); 
labelHeight=new JLabel("雷区高度:"); 
labelNum=new JLabel("雷数目:"); 
dataWidth=10; 
dataHeight=10; 
dataNum=10; 
textWidth=new JTextField("20"); 
textHeight=new JTextField("20"); 
textNum=new JTextField("10"); 
okButton=new JButton("确定"); 
cancelButton=new JButton("取消"); 
okButton.addActionListener(this); 
cancelButton.addActionListener(this);//增加按钮的监视器 
panel.setLayout(new GridLayout(7,4,2,2)); 
panel.add(new JLabel()); 
panel.add(new JLabel()); 
panel.add(new JLabel()); 
panel.add(new JLabel()); 
panel.add(new JLabel()); 
panel.add(labelWidth); 
panel.add(textWidth); 
panel.add(new JLabel()); 
panel.add(new JLabel()); 
panel.add(labelHeight); 
panel.add(textHeight); 
panel.add(new JLabel()); 
panel.add(new JLabel()); 
panel.add(labelNum); 
panel.add(textNum); 
panel.add(new JLabel()); 
panel.add(new JLabel()); 
panel.add(new JLabel()); 
panel.add(new JLabel()); 
panel.add(new JLabel()); 
panel.add(new JLabel()); 
panel.add(okButton); 
panel.add(cancelButton); 
panel.add(new JLabel()); 
panel.add(new JLabel()); 
panel.add(new JLabel()); 
panel.add(new JLabel()); 
panel.add(new JLabel()); 
this.add(panel);//设置布局 
setVisible(true); 
addWindowListener(new WindowAdapter(){//对话框关闭时的监听器 
public void windowClosing(WindowEvent e) 
{ 
setVisible(false); 
} 
}); 
} //监视按钮的状况,并作有效性判断 
public void actionPerformed(ActionEvent e) { 
if(e.getSource()==okButton){ 
try{ 
dataWidth=Integer.parseInt(textWidth.getText()); 
dataHeight=Integer.parseInt(textHeight.getText()); 
dataNum=Integer.parseInt(textNum.getText());//将输入数据转换为int型 //对输入数据进行判断,是否有效赋值给boolean型变量judge 
judge=(dataWidth>40|dataWidth<0)|(dataHeight>30|dataHeight<0)|(dataNum>dataWidth*dataHeight|dataNum<0); //对非法、有效两种情况作响应处理 
if (judge){ 
messageBox.showMessageDialog(null,"输入超出范围","错误!",JOptionPane.ERROR_MESSAGE); 
dataWidth=10; 
dataHeight=10; 
dataNum=10; 
} 
setVisible(false); 
} 
catch(NumberFormatException e1){ 
messageBox.showMessageDialog(null,"输入数据格式有错!","错误!",JOptionPane.ERROR_MESSAGE); 
setVisible(false); 
} 
} 
if(e.getSource()==cancelButton){ 
setVisible(false); 
} 
} //inputDialog的三个方法,用于返回有效的输入值 
public int getW(){ 
return dataWidth; 
} 
public int getH(){ 
return dataHeight; 
} 
public int getN(){ 
return dataNum; 
} 
} //主窗体,有ActionListener,MouseListener两个接口,对鼠标按键的事件和界面上的button按下的事件作处理 
class MainFrame extends JFrame implements ActionListener,MouseListener{ 
boolean mouseJudge,loseJudge,winJudge; 
//三个boolean型变量,mouseJudge用于判断鼠标是否在窗体区域内,loseJudge用于判断是否GameOver,winJudge用于判断是否Win ImageIcon iconRestart0,iconRestart1,iconMine0,iconMine1,iconLose,iconWin,iconSign;//雷以及各种标志的图标定义 
ImageIcon icon1,icon2,icon3,icon4,icon5,icon6,icon7,icon8;//数字的图标定义 
JPanel panel,panel1,panel2; 
JMenuBar menuBar; 
JMenu menu1,menu2; 
JMenuItem item1,item2,item3,item4,item5,item6,item7,item8; 
Timestart thread1;//全局线程类
mineSquare[][] button;//按钮数组 
JButton restart;//重新开始按钮 
JLabel timeLabel,leftLabel;//用于显示时间和剩余雷的数目 
JOptionPane aboutBox;//用于显示提示信息 
inputDialog input;//"自定义..."输入对话框 
int[][] data,minePos;//data[][]用于记录数字及雷,minePos[][]用于记录初始化雷的位置 
int[] randomNum,cmpr;//randomNum[]用于生成随即序列来使每次雷的位置不同,cmpr[]用于使随即序列中的数各不相同 
int num,width,height,mineDim,temp,counter,bombNum,leftNum; 
//num表示雷的数目,width表示雷区宽度,height表示雷区高度, 
//mineDim表示雷的尺寸,bombNum用于记录正确的扫雷数目,leftNum用于记录剩余雷的数目 
//temp,counter为临时变量 Random randomGen;//随即数声明 
MainFrame(){ 
super("扫雷游戏"); 
setVisible(true); 
setResizable(false); 
icon1=new ImageIcon("1.gif"); 
icon2=new ImageIcon("2.gif"); 
icon3=new ImageIcon("3.gif"); 
icon4=new ImageIcon("4.gif"); 
icon5=new ImageIcon("5.gif"); 
icon6=new ImageIcon("6.gif"); 
icon7=new ImageIcon("7.gif"); 
icon8=new ImageIcon("8.gif"); 
iconRestart0=new ImageIcon("smile.gif"); 
iconRestart1=new ImageIcon("Ooo.gif"); 
iconMine0=new ImageIcon("mine.gif"); 
iconMine1=new ImageIcon("bomd.gif"); 
iconLose=new ImageIcon("lose.gif"); 
iconWin=new ImageIcon("Ooo.gif"); 
iconSign=new ImageIcon("flag.gif");
 
menuBar=new JMenuBar(); 
menu1=new JMenu("游戏(G)"); 
menu2=new JMenu("关于(A)"); 
menu1.setMnemonic('G'); 
menu2.setMnemonic('A'); 
item1=new JMenuItem("开局(N)",'N'); 
item2=new JMenuItem("初级(R)",'R'); 
item3=new JMenuItem("中级(P)",'P'); 
item4=new JMenuItem("高级(W)",'W'); 
item5=new JMenuItem("自定义(S)...",'S'); 
item6=new JMenuItem("退出(X)",'X'); 
item7=new JMenuItem("排行榜(T)...",'T'); 
item7.setEnabled(false); 
item8=new JMenuItem("关于(A)",'A'); 
item1.addActionListener(this); 
item2.addActionListener(this); 
item3.addActionListener(this); 
item4.addActionListener(this); 
item5.addActionListener(this); 
item6.addActionListener(this); 
item7.addActionListener(this); 
item8.addActionListener(this); 
menu1.add(item1); 
menu1.addSeparator(); 
menu1.add(item2); 
menu1.add(item3); 
menu1.add(item4); 
menu1.add(item5); 
menu1.addSeparator(); 
menu1.add(item7); 
menu1.addSeparator(); 
menu1.add(item6); 
menu2.add(item8); 
menuBar.add(menu1); 
menuBar.add(menu2); 
setJMenuBar(menuBar); 
panel=new JPanel(); 
panel1=new JPanel(); 
panel2=new JPanel(); 
leftLabel=new JLabel(); 
leftLabel.setSize(50,25); 
leftLabel.setHorizontalAlignment(JLabel.CENTER); 
leftLabel.setVerticalAlignment(JLabel.CENTER); 
restart=new JButton(); 
restart.setSize(25,25); 
restart.setIcon(iconRestart0); 
restart.addActionListener(this); 
timeLabel=new JLabel("0"); 
timeLabel.setSize(50,25); 
timeLabel.setHorizontalAlignment(JLabel.CENTER); 
timeLabel.setVerticalAlignment(JLabel.CENTER);//界面布局 
num=10; 
width=10; 
height=10; 
mineDim=17;//默认雷区尺寸及类数目 
reLoad();//用于每次新开游戏的重载,以便num,width,height,mineDim参数的变化 addWindowListener(new WindowAdapter(){//主窗体关闭时的监听器 
public void windowClosing(WindowEvent e) 
{ 
setVisible(false); 
System.exit(0); 
} 
}); 
} 
class Timestart extends Thread
{
 boolean b;
 
 public void run()
 {
  b=true;
  System.out.println(b);
  int i=0;
  while(b)
  { 
    timeLabel.setText(String.valueOf(i));
    i++;
    try{Thread.sleep(1000);}
    catch(InterruptedException e){}
    System.out.println(i);
    if(i==1000)
    {
     b=false;
    }
  }
  
 }
}//每次num,width,height,mineDim参数变化都要重载的方法 
void reLoad(){ 
loseJudge=false; 
winJudge=false;//输赢标志初始化 
bombNum=0;//已找到的雷数目初始化 
leftNum=num;//剩余的雷数目初始化 
leftLabel.setText(String.valueOf(leftNum));
//根据参数的变化调整界面的显示 
panel1.removeAll(); 
panel2.removeAll(); 
this.setLayout(null); 
panel.setLayout(null); 
panel1.setLayout(null); 
panel2.setLayout(new GridLayout(height,width)); 
this.setSize(mineDim*width+7,mineDim*height+60+28); 
panel.setBounds(0,0,mineDim*width,mineDim*height+60); 
panel1.setBounds(0,0,mineDim*width,30); 
panel2.setBounds(0,30,mineDim*width,mineDim*height); 
menuBar.setSize(mineDim*width,30); 
leftLabel.setBounds(mineDim*width/4-26,0,50,30); 
restart.setBounds(mineDim*width/2-16,0,30,30); 
timeLabel.setBounds(mineDim*width/4*3-26,0,50,30); 
button=new mineSquare[height][width]; 
for(int i=0;i<height;i++){ 
for(int j=0;j<width;j++){ 
button[i][j]=new mineSquare(); 
button[i][j].addActionListener(this); 
button[i][j].addMouseListener(this); 
button[i][j].setSize(mineDim,mineDim); 
panel2.add(button[i][j]); 
} 
} 
panel1.add(leftLabel); 
panel1.add(restart); 
panel1.add(timeLabel); 
panel.add(panel1); 
panel.add(panel2); 
this.add(panel); 
this.show(true); //生成随机数序列,并通过循环比较使各个随机数不同 
randomNum=new int[num]; 
cmpr=new int[num]; 
randomGen=new Random(); 
for (int i=0;i<num;i++){ 
randomNum[i]=randomGen.nextInt(width*height); 
cmpr[i]=randomNum[i]; 
counter=i; 
for(int j=0;j<counter;j++){ 
if(randomNum[i]==cmpr[j]){ 
j=counter; 
i--; 
} 
} 
} 
for (int i=0;i<num-1;i++){ 
for(int j=1;j<num-i;j++){ 
if(randomNum[i]>=randomNum[i+j]){ 
temp=randomNum[i+j]; 
randomNum[i+j]=randomNum[i]; 
randomNum[i]=temp; 
} 
} 
} //根据随机序列的内容生成表示雷位置的数组minePos[][] 
minePos=new int[height][width]; 
for (int i=0;i<height;i++){ 
for(int j=0;j<width;j++){ 
minePos[i][j]=0; 
for (int k=0;k<num;k++){ 
if(randomNum[k]==i*width+j){ 
minePos[i][j]=1; 
} 
} 
} 
} //按钮对应位置数组元素的内容初始化 
data=new int[height][width]; 
for(int i=0;i<height;i++){ 
for(int j=0;j<width;j++){ 
data[i][j]=0; 
} 
} //根据minePos[][]设置按钮对应位置所对应的内容,-1表示有雷存在,其余数字大小表示应该显示的数字大小 
//通过逻辑判断设置边缘区域,防止数组下标溢出 
for(int i=0;i<height;i++){ 
for(int j=0;j<width;j++){ 
if(minePos[i][j]==1){ 
if(i==0&&j==0){ 
data[i][j+1]+=1; 
data[i+1][j+1]+=1; 
data[i+1][j]+=1; 
} 
else if (i==0&&j!=0&&j!=(width-1)){ 
data[i][j-1]+=1; 
data[i][j+1]+=1; 
data[i+1][j-1]+=1; 
data[i+1][j]+=1; 
data[i+1][j+1]+=1; 
} 
else if (i==0&&j==(width-1)){ 
data[i][j-1]+=1; 
data[i+1][j-1]+=1; 
data[i+1][j]+=1; 
} 
else if (j==(width-1)&&i!=0&&i!=(height-1)){ 
data[i-1][j-1]+=1; 
data[i-1][j]+=1; 
data[i][j-1]+=1; 
data[i+1][j-1]+=1; 
data[i+1][j]+=1; 
} 
else if(i==(height-1)&&j==(width-1)){ 
data[i-1][j-1]+=1; 
data[i-1][j]+=1; 
data[i][j-1]+=1; 
} 
else if(i==(height-1)&&j!=0&&j!=(width-1)){ 
data[i-1][j-1]+=1; 
data[i-1][j]+=1; 
data[i-1][j+1]+=1; 
data[i][j-1]+=1; 
data[i][j+1]+=1; 
} 
else if(i==(height-1)&&j==0){ 
data[i-1][j]+=1; 
data[i-1][j+1]+=1; 
data[i][j+1]+=1; 
} 
else if(j==0&&i!=0&&i!=(height-1)){ 
data[i-1][j]+=1; 
data[i-1][j+1]+=1; 
data[i][j+1]+=1; 
data[i+1][j]+=1; 
data[i+1][j+1]+=1; 
} 
else{ 
data[i-1][j-1]+=1; 
data[i-1][j]+=1; 
data[i-1][j+1]+=1; 
data[i][j-1]+=1; 
data[i][j+1]+=1; 
data[i+1][j-1]+=1; 
data[i+1][j]+=1; 
data[i+1][j+1]+=1; 
} 
} 
} 
} 
for(int i=0;i<height;i++){ 
for(int j=0;j<width;j++){ 
if(minePos[i][j]==1){ 
data[i][j]=-1; 
} 
} 
} 
} //响应菜单及按钮按下产生的事件 
public void actionPerformed(ActionEvent e){ 
if(e.getSource()==restart|e.getSource()==item1){
 String s=timeLabel.getText();
 int h=Integer.parseInt(s);
// if(h==0){
 thread1=new Timestart();
 thread1.b=true;
 thread1.start();
// }
reLoad(); }//开局 
if(e.getSource()==item2){ 
num=10; 
width=10; 
height=10; 
reLoad(); 
}//初级游戏 
if(e.getSource()==item3){ 
num=40; 
width=16; 
height=16; 
reLoad(); 
}//中级游戏 
if(e.getSource()==item4){ 
num=99; 
width=30; 
height=16; 
reLoad(); 
}//高级游戏 
if(e.getSource()==item5){ 
input=new inputDialog(this); 
num=input.getN(); 
width=input.getW(); 
height=input.getH(); 
reLoad(); 
}//调用inputDialog输入自定义数据 
if(e.getSource()==item6){ 
System.exit(0); 
}//退出 
if(e.getSource()==item7){ 
//排行榜,待完成 
} 
if(e.getSource()==item8){ 
aboutBox.showMessageDialog(null,"            Java 扫雷 \n       第三小组 Work  \n      时间 2008-9-21","关于...",JOptionPane.INFORMATION_MESSAGE); 
thread1.b=false;
}//显示关于信息 //下面判断按钮按下的事件 
for(int i=0;i<height;i++){ 
for(int j=0;j<width;j++){ //只有(触发器是按钮)(未作标记)(左键可以按该按钮)(按钮未锁定)同时有效才触发 
if(e.getSource()==button[i][j]&&button[i][j].sign==false&&button[i][j].left==true&&button[i][j].locked==false){ 
 if(data[i][j]==-1){//如果点到雷,GameOver,作响应显示 
button[i][j].setIcon(iconMine1); 
restart.setIcon(iconLose); 
loseJudge=true;
for(int m=0;m<height;m++){ 
for(int n=0;n<width;n++){ 
if(data[m][n]==-1){ 
if(m==i&&n==j){ 
button[m][n].setIcon(iconMine1); 
} 
else{ 
button[m][n].setIcon(iconMine0); 
} 
} 
else if(data[m][n]==0){ 
button[m][n].setEnabled(false); 
} 
else if(data[m][n]==1){ 
button[m][n].setIcon(icon1); 
} 
else if(data[m][n]==2){ 
button[m][n].setIcon(icon2); 
} 
else if(data[m][n]==3){ 
button[m][n].setIcon(icon3); 
} 
else if(data[m][n]==4){ 
button[m][n].setIcon(icon4); 
} 
else if(data[m][n]==5){ 
button[m][n].setIcon(icon5); 
} 
else if(data[m][n]==6){ 
button[m][n].setIcon(icon6); 
} 
else if(data[m][n]==7){ 
button[m][n].setIcon(icon7); 
} 
else if(data[m][n]==8){ 
button[m][n].setIcon(icon8); 
} 
button[m][n].left=false; 
button[m][n].sign=false; 
button[m][n].locked=true; 
} 
} 
thread1.b=false;
aboutBox.showMessageDialog(null,"           很遗憾,中弹了...","Lose!",JOptionPane.INFORMATION_MESSAGE); } 
else if(data[i][j]==0){//如果是空白,则翻出除已作标记的所有空白,作响应显示 
for(int m=0;m<height;m++){ 
for(int n=0;n<width;n++){ 
if(data[m][n]==0){ 
if(button[m][n].getIcon()==iconSign){ 
button[m][n].setIcon(null); 
button[m][n].sign=true; 
leftNum++; 
leftLabel.setText(String.valueOf(leftNum)); 
} 
button[m][n].setEnabled(false); 
button[m][n].left=false; 
} 
} 
} 
} 
//如果是其他数字,作响应显示 
else if(data[i][j]==1){ 
button[i][j].setIcon(icon1); 
button[i][j].left=false; 
} 
else if(data[i][j]==2){ 
button[i][j].setIcon(icon2); 
button[i][j].left=false; 
} 
else if(data[i][j]==3){ 
button[i][j].setIcon(icon3); 
button[i][j].left=false; 
} 
else if(data[i][j]==4){ 
button[i][j].setIcon(icon4); 
button[i][j].left=false; 
} 
else if(data[i][j]==5){ 
button[i][j].setIcon(icon5); 
button[i][j].left=false; 
} 
else if(data[i][j]==6){ 
button[i][j].setIcon(icon6); 
button[i][j].left=false; 
} 
else if(data[i][j]==7){ 
button[i][j].setIcon(icon7); 
button[i][j].left=false; 
} 
else if(data[i][j]==8){ 
button[i][j].setIcon(icon8); 
button[i][j].left=false; 
} 
} 
} 
} 
} //处理鼠标事件 
public void mouseClicked(MouseEvent e){ 
boolean rightClicked=SwingUtilities.isRightMouseButton(e);//判断右键是否按下 
boolean leftClicked=SwingUtilities.isLeftMouseButton(e);//判断左键是否按下 //右键按下触发的事件 
if(rightClicked==true){ //只有(左键可以按下该事件源按钮)(事件源按钮未作标记)(事件源按钮未锁定)同时有效才触发 
if(((mineSquare)e.getSource()).left==true&&((mineSquare)e.getSource()).sign==false&&((mineSquare)e.getSource()).locked==false){ 
 //剩余标记数有效,作标记 
if(leftNum>0&&leftNum<=num){ 
((mineSquare)e.getSource()).sign=true; 
((mineSquare)e.getSource()).setIcon(iconSign); 
leftNum--; 
((mineSquare)e.getSource()).left=false; 
leftLabel.setText(String.valueOf(leftNum)); 
if(leftNum==0){//判断是否赢得游戏 
for(int m=0;m<height;m++){ 
for(int n=0;n<width;n++){ 
if(data[m][n]==-1&&button[m][n].getIcon()==iconSign){ 
bombNum++; 
} 
} 
} 
if(bombNum==num){ 
for(int m=0;m<height;m++){ 
for(int n=0;n<width;n++){ 
if(data[m][n]==-1){ 
button[m][n].setIcon(iconMine0); 
} 
button[m][n].left=false; 
button[m][n].sign=true; 
button[m][n].locked=true; 
} 
} 
restart.setIcon(iconWin); 
aboutBox.showMessageDialog(null,"              恭喜你,胜利了!","Win!",JOptionPane.INFORMATION_MESSAGE); 
} 
} 
} 
} 
//如果该事件源按钮已被作了标记,则取消该标记 
else if(((mineSquare)e.getSource()).sign==true){ 
if(leftNum>=0&&leftNum<num){ 
((mineSquare)e.getSource()).sign=false; 
((mineSquare)e.getSource()).left=true; 
((mineSquare)e.getSource()).setIcon(null); 
leftNum++; 
leftLabel.setText(String.valueOf(leftNum)); 
} 
} 
} //右键按下触发的事件 
if (leftClicked==true){ 
((mineSquare)e.getSource()).left=false; 
} 
} 
//判断鼠标是否在主窗体范围之内 
//如果在主窗体范围内鼠标按下,则restart按钮的图标发生变化(模仿Windows扫雷) 
public void mouseEntered(MouseEvent e){ 
mouseJudge=true; 
} 
public void mouseExited(MouseEvent e){ 
mouseJudge=false; 
if(loseJudge==false){ 
restart.setIcon(iconRestart0); 
} 
} 
public void mousePressed(MouseEvent e){ 
if (mouseJudge==true&&loseJudge==false){ 
restart.setIcon(iconRestart1); 
} 
} 
public void mouseReleased(MouseEvent e){ 
if (mouseJudge==true&&loseJudge==false){ 
restart.setIcon(iconRestart0); 
} 
} 
}