您的位置:首页 > 编程语言 > Java开发

java学期实习扫雷程序

2008-10-07 12:17 330 查看
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]
==-1){
if(m==i&&n==j){
button[m]
.setIcon(iconMine1);
}
else{
button[m]
.setIcon(iconMine0);
}
}
else if(data[m]
==0){
button[m]
.setEnabled(false);
}
else if(data[m]
==1){
button[m]
.setIcon(icon1);
}
else if(data[m]
==2){
button[m]
.setIcon(icon2);
}
else if(data[m]
==3){
button[m]
.setIcon(icon3);
}
else if(data[m]
==4){
button[m]
.setIcon(icon4);
}
else if(data[m]
==5){
button[m]
.setIcon(icon5);
}
else if(data[m]
==6){
button[m]
.setIcon(icon6);
}
else if(data[m]
==7){
button[m]
.setIcon(icon7);
}
else if(data[m]
==8){
button[m]
.setIcon(icon8);
}
button[m]
.left=false;
button[m]
.sign=false;
button[m]
.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]
==0){
if(button[m]
.getIcon()==iconSign){
button[m]
.setIcon(null);
button[m]
.sign=true;
leftNum++;
leftLabel.setText(String.valueOf(leftNum));
}
button[m]
.setEnabled(false);
button[m]
.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]
==-1&&button[m]
.getIcon()==iconSign){
bombNum++;
}
}
}
if(bombNum==num){
for(int m=0;m<height;m++){
for(int n=0;n<width;n++){
if(data[m]
==-1){
button[m]
.setIcon(iconMine0);
}
button[m]
.left=false;
button[m]
.sign=true;
button[m]
.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);
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: