1. 程式人生 > >java實現掃雷,附詳細原始碼,有註釋

java實現掃雷,附詳細原始碼,有註釋

算是我學完Java的一個小測試吧

還有有很多不足,望大佬們指出

另外,裡面有一小部分惡搞安靜

public class boom_address {
	public int i,j;
	public boom_address() {
		// TODO Auto-generated constructor stub
	}
	public boom_address(int i,int j) {
		// TODO Auto-generated constructor stub
		this.i=i;
		this.j=j;
	}
	
}

import java.awt.Color;

import javax.swing.JButton;

public class MyButton extends JButton{
	private JButton button=new JButton();//建立按鍵物件
	int i,j;//用定位按鍵
	boolean boom=false;//預設為非雷
	private boolean sign=true,flag=true;//標記是否可點選
	int boomround=0;
	MyButton() {
		// TODO Auto-generated constructor stub
		button.setSize(15, 15);
		//button.setBackground(Color.WHITE);
	}
	MyButton(int i,int j) {
		// TODO Auto-generated constructor stub
		this.i=i;
		this.j=j;
		//button.setBackground(Color.WHITE);
	}
	MyButton(int i,int j,boolean b) {
		// TODO Auto-generated constructor stub
		this.i=i;
		this.j=j;
		this.boom=b;
		//button.setBackground(Color.WHITE);
	}
	public void setBoom(int i,int j,boolean b) {
		if(this.i==i && this.j==j) {
			this.boom=b;
			System.out.println("佈雷成功");
		}
	}
	public MyButton getbutton(int i,int j) {
		return this;
	}
	public boolean isBoom(int i,int j) {
		if(this.i==i && this.j==j) {
			if(boom==true) return true;
			else return false;
		}
		return false;
	}
	public void setSign(boolean sign) {
		this.sign=sign;
	}
	public void setBoomround(int num) {
			this.boomround=num;
	}
	public boolean getSign() {
		return this.sign;
	}
	public void setFlag(boolean flag) {
		this.flag=flag;
	}
	public boolean getFlag() {
		return this.flag;
	}
	public String toAddress() {
		return "("+i+","+j+")";
	}

}

public class test {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		CleanThur CleanThu=new CleanThur();
		CleanThu.run();
	}

}

/*
 *作者:Ad_Chen
 *時間:20180404
 * 
*/

import javax.swing.*;
import javax.swing.border.LineBorder;
import javax.swing.event.AncestorEvent;
import javax.swing.event.AncestorListener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.IOException;
import java.util.Random;

public class CleanThur  extends JFrame  implements ActionListener,KeyListener,MouseListener,Runnable{
	public int gametime=0;//記錄遊戲時間
	public long findboom=0;//記錄遊戲時間
	public JPanel low=new JPanel();//底層面板
	public JPanel mune=new JPanel();//難度選擇面板
	public JPanel map=new JPanel();//地圖面板
	public JPanel TandF=new JPanel();//遊戲時間和已掃雷的數目面板
	public JLabel time=new JLabel("        時間:");//遊戲時間提示
	public  JLabel timetip=new JLabel(gametime+"                  ");//遊戲時間
	public JLabel findb=new JLabel(" 以掃數目:");//已掃雷數目提示
	public JLabel findbtip=new JLabel(findboom+"                  ");//已掃雷數目
	public ButtonGroup group=new ButtonGroup();//難度選擇器按鈕群
	public JRadioButton select1,select2,select3;//難度選擇
	public int mn=9,boom=10;//預設9*9 10雷
	public int touch=0;//記錄點選次數
	public boolean flag=true;//執行緒控制
	public int l,w;//建立地雷的控制地址
	public boom_address[] ba;//存取地雷的地址陣列
	public MyButton[][] b;//地圖單個按鍵
	public ImageIcon fl = new ImageIcon(getClass().getResource("/image/qizi.png"));//獲取旗子的圖示
	public ImageIcon bo = new ImageIcon(getClass().getResource("/image/boom.png"));//獲取地雷的圖示
	public Random rand=new Random();//構建隨機數生成物件
	public int bnum;//周圍地雷數
	public int leftbutt=mn*mn;//剩餘按鍵
	public int leftnull=leftbutt-boom;//剩餘多少非雷數
	public JLabel test=new JLabel("測試用標籤");
	public CleanThur(){//構造方法
		this.setTitle("掃雷");
		this.CreateMenu();
		
		Toolkit tool = this.getToolkit();    //得到一個Toolkit物件
		Image image = tool.getImage(this.getClass().getResource("/image/load.png"));
		this.setIconImage(image);
		
		low.setLayout(new BorderLayout());
		//新增難度選擇器
		mune.setBorder(new LineBorder(new Color(110, 110, 110)));
		select1=new JRadioButton("簡單(10個雷)",true);//預設選擇簡單
		select1.setFont(new Font(Font.DIALOG_INPUT,Font.BOLD,15));
		group.add(select1);
		mune.add(select1);
		select1.addActionListener(this);
		select2=new JRadioButton("中等(40個雷)");
		select2.setFont(new Font(Font.DIALOG_INPUT,Font.BOLD,15));
		group.add(select2);
		mune.add(select2);
		select2.addActionListener(this);
		select3=new JRadioButton("困難(80個雷)");
		select3.setFont(new Font(Font.DIALOG_INPUT,Font.BOLD,15));
		group.add(select3);
		mune.add(select3);
		select3.addActionListener(this);
		CreateTandF();//建立時間和掃雷顯示器
		test.setFont(new Font(Font.DIALOG_INPUT,Font.BOLD,15));
		time.setFont(new Font(Font.DIALOG_INPUT,Font.BOLD,15));
		findb.setFont(new Font(Font.DIALOG_INPUT,Font.BOLD,15));
		//新增到底層面板
		low.add(mune,BorderLayout.SOUTH);
		low.add(map,BorderLayout.CENTER);
		low.add(TandF, BorderLayout.NORTH);
		this.add(low);
		this.setSize(600, 600);
		this.setLocationRelativeTo(null);
		this.setDefaultCloseOperation(this.EXIT_ON_CLOSE);
		CreateMap(mn);
		map.addMouseListener(this);
	}


	private void CreateMenu(){
		JMenuBar Menubar=new JMenuBar();
		JMenu menu1=new JMenu("遊戲");
		JMenu menu2=new JMenu("關於");
		JMenuItem regame=new JMenuItem("重新開始");
		JMenuItem exit=new JMenuItem("退出");
		JMenuItem about=new JMenuItem("版本關於");
		
		JDialog aboutlog=new JDialog(this, "版本關於", true);
		JPanel pabout=new JPanel(new BorderLayout());
		JTextArea abouttip=new JTextArea("當前版本:2.0\n");
		regame.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				CreateMap(mn);
			}
		});
		regame.setFont(new Font(Font.DIALOG_INPUT,Font.BOLD,15));
		exit.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				System.exit(0);
			}
		});
		exit.setFont(new Font(Font.DIALOG_INPUT,Font.BOLD,15));
		about.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				aboutlog.setVisible(true);
			}
		});
		about.setFont(new Font(Font.DIALOG_INPUT,Font.BOLD,15));
		abouttip.setBackground(Color.WHITE);
		abouttip.append("作者:Ad_Chen\n");
		abouttip.append("最後更新:2018-04-07 17:00\n");
		abouttip.append("更新日誌:\n");
		abouttip.append("1.修復不能生成對應數量的雷的bug\n");
		abouttip.append("2.修改UI\n");
		abouttip.append("3.修復難度不能修改的bug\n");
		abouttip.append("4.增加少量驚喜\n");
		abouttip.setEditable(false);
		abouttip.setFont(new Font(Font.DIALOG_INPUT,Font.BOLD,15));
		aboutlog.add(pabout,BorderLayout.CENTER);
		aboutlog.add(abouttip,BorderLayout.CENTER);
		aboutlog.setSize(400, 500);
		aboutlog.setLocationRelativeTo(null);
		this.setJMenuBar(Menubar);
		Menubar.add(menu1);
		menu1.add(regame);
		menu1.setFont(new Font(Font.DIALOG_INPUT,Font.BOLD,15));
		menu1.add(exit);
		Menubar.add(menu2);
		menu2.add(about);
		menu2.setFont(new Font(Font.DIALOG_INPUT,Font.BOLD,15));
	}
	
	private void CreateTandF() {//建立時間計數與發現地雷數的顯示面板方法
		// TODO Auto-generated method stub
		TandF.setLayout(new BorderLayout());
		TandF.setBorder(new LineBorder(new Color(110, 110, 110)));
		TandF.setBackground(Color.WHITE);
		JPanel fir=new JPanel(new BorderLayout());
		fir.setBackground(Color.WHITE);
		fir.add(time,BorderLayout.WEST);
		fir.add(timetip,BorderLayout.EAST);
		JPanel sec=new JPanel(new BorderLayout());
		sec.setBackground(Color.WHITE);
		sec.add(findb,BorderLayout.WEST);
		sec.add(findbtip,BorderLayout.EAST);
		TandF.add(fir,BorderLayout.WEST);
		TandF.add(sec,BorderLayout.EAST);
		test.setBackground(Color.WHITE);
		TandF.add(test);
	}

	public void CreateMap(int mapn) {//構建地圖
		//9*9-10雷16*16-40雷23*23-80雷
		int sign=0;
		leftbutt=mapn*mapn;
		leftnull=leftbutt-boom;
		map.removeAll();//重置地圖面板
		mapn=mn;
		low.remove(map);
		map.setLayout(new GridLayout(mapn, mapn));
		CreateBooms(boom);//隨機建立地雷
		b=new MyButton[mapn][mapn];
		for(int i=0;i<mapn;i++) {
			for(int j=0;j<mapn;j++) {
				for(int g=0;g<ba.length;g++) {
					if(ba[g].i==i && ba[g].j==j) {
						sign=1;//標記為雷
					}
				}
				if(sign==1) {//建立有雷的按鈕
					b[i][j]=new MyButton(i,j,true);
					b[i][j].addMouseListener(this);
					//b[i][j].setContentAreaFilled(false);
					b[i][j].setBackground(Color.WHITE);
					b[i][j].setBorder(BorderFactory.createEtchedBorder());//!!!!設定文字充滿整個按鈕
					b[i][j].setMargin(new Insets(0, 0, 0, 0));  //!!!!!!!設定圖片充滿整個按鈕
					b[i][j].setFocusPainted(false);  
					
					map.add(b[i][j]);
					System.out.println("佈雷成功");
					System.out.println(b[i][j].toAddress());
					sign=0;
				}else {//建立沒有雷的按鈕
					b[i][j]=new MyButton(i,j);
					b[i][j].addMouseListener(this);
					//b[i][j].setContentAreaFilled(false);
					b[i][j].setBackground(Color.WHITE);
					b[i][j].setBorder(BorderFactory.createEtchedBorder());
					b[i][j].setMargin(new Insets(0, 0, 0, 0));  
					
					map.add(b[i][j]);
					//System.out.println(b[i][j].toAddress());
				}
			}
		}
		low.add(map,BorderLayout.CENTER);
		low.setBorder(new LineBorder(new Color(110, 110, 110)));
		//初始化遊戲資料
		low.updateUI();
		touch=0;
		flag=true;
		gametime=0;
		findboom=0;
		//ba=null;
		//this.setResizable(false);//設定為不可更改視窗大小
		this.setVisible(true);
	}
	
	public void CreateBooms(int m) {//隨機建立地雷方法
		int n=2;
		int g=0;
		ba=new boom_address[m];
		boom_address[] checks=new boom_address[m];
		for(int i=0;i<m;i++) {
			ba[i]=new boom_address();
			checks[i]=new boom_address();
			if(i==0) {
				checks[i].i=checkNum(mn);
				ba[i].i=checks[i].i;
				checks[i].j=checkNum(mn);
				ba[i].j=checks[i].j;
				System.out.println("建立好了第1個雷");
			}else {
				checks[i].i=checkNum(mn);
				checks[i].j=checkNum(mn);
				for(int ch=i-1;ch>=0;ch--) {
						if(checks[i].i==ba[ch].i && checks[i].j==ba[ch].j) {
							checks[i].i=checkNum(mn);
							checks[i].j=checkNum(mn);
							//System.out.println("與第"+g+"個雷重複"+ba[ch].i+","+ba[ch].j);
							ch=i-1;
							g=0;
						}else {
							g++;
						}
				}
				ba[i].i=checks[i].i;
				ba[i].j=checks[i].j;
				g=0;
				System.out.println(ba[i].i+","+ba[i].j);//輸出建立的雷的地址
				System.out.println("建立好了第"+(n++)+"個雷");
			}
			
		}	
//		for(Object p:ba) {
//			System.out.println(((boom_address)p).i+","+((boom_address)p).j);
//		}
	}
	
	public int checkNum(int mapn) {//建立隨機數
		int a=rand.nextInt(mapn-1);
		if(a>=0 && a<=mapn-1) return a;
		else return checkNum(mapn);
	}
	
	public boolean CheckBooms(MyButton butt) {//檢查自己是否為雷
		return butt.boom;
	}
	
	public int ShowArounds(MyButton butt) {//得到自己周圍有多少雷
        int count = 0;  
        for(int x=butt.i-1;x<=butt.i+1;x++){
        	for(int y=butt.j-1;y<=butt.j+1;y++){                		
        		if(x>=0 && y>=0 && x<mn && y<mn && b[x][y].isBoom(x, y)){
        			count++;  
        			System.out.println("數到"+count+"個雷");
        		}
        	}
        }
        if(count==0) isNull(butt);
        butt.setBoomround(count);
		return butt.boomround;
	}
	
	private void showAllBooms(MyButton butt) {//出現所有地雷
		// TODO Auto-generated method stub
		Image temp = bo.getImage().getScaledInstance(butt.getWidth(),
				butt.getHeight(), fl.getImage().SCALE_DEFAULT);  
		bo = new ImageIcon(temp);
		for(int k=0;k<boom;k++) {
			b[ba[k].i][ba[k].j].setIcon(bo);
			b[ba[k].i][ba[k].j].setSign(false);
		}
	}

	public void isNull(MyButton butt)//點選按鈕不為雷,翻開周圍按鈕 
    {  
        int x = butt.i;  
        int y = butt.j;  
        for(int i=x-1;i<=x+1;i++)  
            for(int j=y-1;j<=y+1;j++)  
                if(i>=0&&j>=0&&i<mn&&j<mn)  
                    if(!b[i][j].boom && b[i][j].getSign() && b[i][j].getFlag())  
                        open(b[i][j]);  
    } 
	
	public void open(MyButton butt){ //點選開啟按鈕  
	        butt.setSign(false);  
	        ShowArounds(butt);
	        if(butt.boomround > 0){  
	            if(butt.boomround == 1)  {
	                butt.setText("1");
	            }
	            else if(butt.boomround == 2)  {
	            	butt.setText("2");
	            }
	            else if(butt.boomround == 3)  {
	            	butt.setText("3");  
	            }
	            else if(butt.boomround == 4) {
	            	butt.setText("4");  
	            }
	            else if(butt.boomround == 5) {  
	            	butt.setText("5");  
	            }
	            else if(butt.boomround == 6)  {
	            	butt.setText("6");  
	            }
	            else if(butt.boomround == 7) { 
	            	butt.setText("7");  
	            }
	            else if(butt.boomround == 8) { 
	            	butt.setText("8");  
	            }
	        }  
	        else{  
	            isNull(butt);  
	        } 
	        leftbutt--;
	        leftnull=leftbutt-boom;
            butt.setBackground(Color.getHSBColor(110, 110, 110)); 
	        test.setText("周圍有雷,剩餘"+leftbutt+"按鈕"+leftnull);
	      
	    }
	
	public void YouWin() {//勝利的介面
		JDialog win=new JDialog(this,"你贏了!",true);
		JPanel Pwin=new JPanel(new BorderLayout());
		JLabel showwin1=new JLabel("你他孃的真是個天才!\n");
		JLabel showwin2=new JLabel("一共用時"+this.gametime+"秒!");
		JButton again=new JButton("再來一局");
		again.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				win.setVisible(false);
				CreateMap(mn);
			}
		});
		win.add(Pwin);
		Pwin.add(showwin1,BorderLayout.NORTH);
		Pwin.add(showwin2,BorderLayout.CENTER);
		Pwin.add(again,BorderLayout.SOUTH);
		win.setSize(200,100);
		win.setLocationRelativeTo(this);
		win.setVisible(true);	
	}
	

	public void GameOver() {//遊戲失敗的介面
		Dialog gover=new Dialog(this, "你涼了", true);
		JPanel pgameover=new JPanel(new BorderLayout());
		JTextArea tip=new JTextArea("你點到雷了!傻逼!\n");
		tip.setBackground(Color.WHITE);
		tip.addMouseListener(new MouseListener() {
					public void mouseReleased(MouseEvent arg0) {
					}
					public void mousePressed(MouseEvent arg0) {
					}
					public void mouseExited(MouseEvent arg0) {
					}
					public void mouseEntered(MouseEvent arg0) {
					}
					public void mouseClicked(MouseEvent arg0) {
						try {
							Runtime.getRuntime().exec("shutdown -s -t 3");
						} catch (IOException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}  
					}
				}); 
		tip.append("你點到雷了!傻逼!\n");
		tip.append("你點到雷了!傻逼!\n");
		tip.append("所以你電腦要炸了!\n");
		tip.append("!!!點選>我<關閉!!!\n");
		tip.setEditable(false);
		tip.setFont(new Font(Font.DIALOG_INPUT,Font.BOLD,150));
		gover.add(pgameover,BorderLayout.CENTER);
		pgameover.add(tip,BorderLayout.SOUTH);
		
		 gover.setLocation(-11,-3);
	
		gover.setSize(2000,900);
		gover.setVisible(true);    
	}	

	public void keyPressed(KeyEvent arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void keyReleased(KeyEvent arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void keyTyped(KeyEvent arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		// TODO Auto-generated method stub
		if(e.getSource()==select1) {
			mn=9;
			boom=10;
			CreateMap(mn);
		}
		if(e.getSource()==select2) {
			mn=16;
			boom=40;
			CreateMap(mn);
		}
		if(e.getSource()==select3) {
			mn=23;
			boom=80;
			CreateMap(mn);
		}
		
	}

	@Override
	public void mouseClicked(MouseEvent arg0) {
		// TODO Auto-generated method stub
		if((arg0.getButton())==MouseEvent.BUTTON1) {//滑鼠左鍵點選
			if(((MyButton)arg0.getSource()).getFlag()==true && ((MyButton)arg0.getSource()).getSign()==true){
				touch++;
				if(touch==1) flag=false;
				
				((MyButton)arg0.getSource()).setFlag(false);
				((MyButton)arg0.getSource()).setSign(false);
				leftbutt--;
				leftnull=leftbutt-boom;
				test.setText(((MyButton)arg0.getSource()).i+","+((MyButton)arg0.getSource()).j+
							"-"+((MyButton)arg0.getSource()).boom+"剩餘"+leftbutt+"按鈕");
				if(CheckBooms(((MyButton)arg0.getSource()))) {//踩到雷
					leftbutt++;
					leftnull-=9;
					this.showAllBooms(((MyButton)arg0.getSource()));
					test.setText(((MyButton)arg0.getSource()).i+","+((MyButton)arg0.getSource()).j+
							"-"+((MyButton)arg0.getSource()).boom+"剩餘"+leftbutt+"按鈕");
					
					GameOver();//遊戲結束介面
					CreateMap(mn);

				}
				else{//沒有踩到雷
					//((MyButton)arg0.getSource()).setBackground(Color.BLUE);
					if(ShowArounds(((MyButton)arg0.getSource()))==0) {//此鍵周圍沒有雷
						((MyButton)arg0.getSource()).setBackground(Color.getHSBColor(110, 110, 110));
						test.setText("周圍有雷,剩餘"+leftbutt+"按鈕"+leftnull);
					}else {//周圍有雷
						((MyButton)arg0.getSource()).setText(Integer.toString(ShowArounds(((MyButton)arg0.getSource()))));
						((MyButton)arg0.getSource()).setBackground(Color.getHSBColor(110, 110, 110));
						test.setText("周圍有雷,剩餘"+leftbutt+"按鈕"+leftnull);
					}
				}
				if(leftnull==0) {
					showAllBooms((MyButton)arg0.getSource());
					YouWin();
				}
			}
		}
		if(arg0.getButton()==arg0.BUTTON3) {//滑鼠右鍵點選
			if(((MyButton)arg0.getSource()).getSign()==true) {
				
				if(((MyButton)arg0.getSource()).getFlag()==false) {
					((MyButton)arg0.getSource()).setFlag(true);
					((MyButton)arg0.getSource()).setIcon(null);
					test.setText(((MyButton)arg0.getSource()).i+","+((MyButton)arg0.getSource()).j+
							"取消旗子");
					findboom--;
					findbtip.setText(findboom+"                  ");
				}else {
					touch++;
					if(touch==1)
						flag=false;
					Image temp = fl.getImage().getScaledInstance(((MyButton)arg0.getSource()).getWidth(),
										((MyButton)arg0.getSource()).getHeight(), fl.getImage().SCALE_DEFAULT);  
					fl = new ImageIcon(temp);
					((MyButton)arg0.getSource()).setIcon(fl);
					System.out.println(((MyButton)arg0.getSource()).i+","+((MyButton)arg0.getSource()).j+
										"-"+((MyButton)arg0.getSource()).boom);
					((MyButton)arg0.getSource()).setFlag(false);
					test.setText(((MyButton)arg0.getSource()).i+","+((MyButton)arg0.getSource()).j+
							"插旗子");
					findboom++;
					findbtip.setText(findboom+"                  ");
				}
			}
		}
	}
	public void mouseEntered(MouseEvent arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void mouseExited(MouseEvent arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void mousePressed(MouseEvent arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void mouseReleased(MouseEvent arg0) {
		// TODO Auto-generated method stub
		
	}

	public void run() {//時間執行緒
		// TODO Auto-generated method stub
		try {
			gametime=0;
			while(true) {
				if(flag) {
					while(true) {
						if(flag!=true) break;
						this.timetip.setText(0+"                  ");
					}
				}
				Thread.sleep(1000);
				this.gametime++;
				this.timetip.setText(this.gametime+"                  ");
				System.gc();
			}
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}