JAVA基礎課程設計 簡易掃雷

以下每行代碼,文字均爲原創,轉載請註明出處.

程序一共分爲7個文件,每個文件爲一個類

文件名 功能描述
Test.java 測試類,包含main()函數
Mine.java 設計主界面,
Calmine.java 隨機雷的位置.計算雷區點擊後應該顯示的數字
My_button.java 繼承自button類,添加按鈕的座標x,y.
Num_Mine.java 雷數,包括用戶以標記的雷數,標記正確的雷數,以及總雷數
ClickLone.java 鼠標左擊處理
ClickRone.java 鼠標右擊處理


Test.java

測試類,Mine()接受的三個參數分別爲雷區的長,寬,總雷數

package mine_sweep;
public class Test {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		new Mine(16,16,20);
	}

}

Mine.java

繼承自JFame類,採用BorderLayout()佈局,.NORTH區域放置顯示面板JPanel,提示用戶以標記的雷數,.SOUTH區域放置雷區,採用GridLayout佈局

用一個雙重循環向雷區minepanel添加按鈕,同時在buttons[]中儲存該按鈕的引用.

同時添加按鈕監聽器..在用戶點擊了右鍵後,負責更新標記的類數


package mine_sweep;
import java.awt.*;
import java.awt.event.*;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;


@SuppressWarnings("serial")
public class Mine extends JFrame {

	Integer rn;				//用戶已標記的雷數
	Integer sn;				//標記對的雷數
	public Mine(int rows,int cols,int n)		//雷區的行數,列數,雷數
	{
		My_button buttons[]=new My_button[rows*cols];	//記錄每個按鈕的引用
		Integer mine[]= new Integer[rows*cols];			//每個位置的數字
		Boolean ismine[]=new Boolean[rows*cols];		//是否有雷的標誌
		new Calmine(mine,ismine,rows,cols,n);
		this.setSize(500, 450);
		this.setTitle("mine_sweep");
		this.setLayout(new BorderLayout());		

		rn=new Integer(0);				//用戶標記的雷數
		sn=new Integer(0);				//標記對的雷數
		JPanel showpanel=new JPanel();			//設置控制面板
		showpanel.setLayout(new FlowLayout(FlowLayout.LEFT));
		JTextArea showArea=new JTextArea("sum of mine: "+n);
		JTextArea showrmArea=new JTextArea("num of marked  mine: "+rn.intValue());
		showArea.setEditable(false);
		showrmArea.setEditable(false);
		showpanel.add(showrmArea );
		showpanel.add(showArea);
		this.add(showpanel,BorderLayout.NORTH);  	
		
		JPanel minepanel=new JPanel();			//設置雷區
		minepanel.setLayout(new GridLayout(rows,cols));
		minepanel.setSize(500, 450);
		Mine t=this;
		for(int i=0;i<rows;i++)
		{
			for(int j=0;j<cols;j++)
			{
				My_button btn=new My_button(i,j);
				buttons[i*cols+j]=btn;
				minepanel.add(buttons[i*cols+j] );
				btn.setBackground(Color.blue);
				btn.addMouseListener(new MouseAdapter()
				{
					public void mouseClicked(MouseEvent e)
					{
						if(e.getButton()==MouseEvent.BUTTON1)
						{
							int ans=rn.intValue();
							if(btn.getLabel()!="#")
								 ans = new ClickLone(buttons,btn.x,btn.y,rows,cols,mine,ismine,t,rn).rep();		
							showrmArea.setText("num of marked  mine: "+ans);	//更新已標記雷數;
							rn=new Integer(ans);
						}
						if(e.getButton()==MouseEvent.BUTTON3)
						{
							Num_Mine num_mine=new Num_Mine(rn,sn,n);
							num_mine=new ClickRone(buttons,btn.x,btn.y,rows,cols,num_mine,t,ismine).repnum();
							rn=new Integer(num_mine.mark_mine);
							showrmArea.setText("num of marked  mine: "+rn);	//更新已標記雷數
							sn=new Integer(num_mine.mark_correct_mine);	//更新標記正確雷數
							
						}
					}
					
				}); //添加鼠標點擊事件
			}
			
			
		}
		this.addWindowListener(new WindowAdapter(){		//添加窗口關閉監聽器
			public void windowClosing(WindowEvent e)
			{
				t.dispose();
			}
		});
		this.add(minepanel,BorderLayout.SOUTH);
		minepanel.setVisible(true);
		this.setVisible(true);
	}

}

Calmine.java

隨機雷的位置.儲存在ismine[]中. 並通過dx[].dy[]遍歷一個按鈕周圍的8個位置.計算出每個按鈕點擊後應該顯示的值,計算出的結果存儲在mine[]中

注意:隨機數可能產生重複的,導致雷數不夠.所以,要加一個while循環放置產生重複的位置

package mine_sweep;

import java.util.Random;

public class Calmine {
	Integer mine[];
	Boolean ismine[];
	int rows,cols;
	int dx[]={-1,1,0};
	int dy[]={-1,1,0};
	int num;
	Random rd;
	Calmine(Integer m[],Boolean ism[],int r,int l,int n)
	{
		rows=r;
		cols=l;
		num=n;
		mine=m;
		ismine=ism;
		rd=new Random();
		for(int i=0;i<rows*cols;i++)			//初始化
		{
			ismine[i]=new Boolean(false);
			mine[i]=new Integer(0);
		}
		for(int i=0;i<num;i++)		//隨機產生n雷
		{
			int rom=rd.nextInt(rows*cols);
			while(ismine[rom]==true)			//防止生成重複的隨機數
				rom=rd.nextInt(rows*cols);
			ismine[rom]=new Boolean(true);
		}
		for(int i=0;i<rows;i++)			//計算每個按鈕按下後應該顯示的數字
			for(int j=0;j<cols;j++)
			{
				int t=0;
				for(int x=0;x<3;x++)		//周圍8個位置
					for(int y=0;y<3;y++)
					{
						int nx=dx[x]+i,ny=dy[y]+j;
						if(nx>=0&&ny>=0&&nx<rows&&ny<cols&&(!ismine[i*cols+j].booleanValue()))
						{
							t+=ismine[nx*cols+ny].booleanValue()?1:0;
						}
					}
				mine[i*cols+j]=new Integer(t);
			}
	}

}

My_button.java

繼承自Button類,添加x,y.標記該按鈕是處以雷區的的第幾行第幾列

package mine_sweep;

import java.awt.Button;

 @SuppressWarnings("serial")
public class My_button extends Button {
	 int x;
	 int y;
	 My_button()
	 {
		 super();
	 }
	 My_button(int a,int b)
	 {
		 super();
		 x=a;
		 y=b;
	 }
}

Num_Mine.java

存儲用戶以標記的雷數,標記正確的雷數,以及雷區的總雷數

package mine_sweep;

public class Num_Mine {
	Integer mark_mine;
	Integer mark_correct_mine;
	Integer sum_mine;
	Num_Mine(Integer rn,Integer sn,Integer n)
	{
		mark_mine=new Integer(rn);
		mark_correct_mine=new Integer(sn);
		sum_mine=new Integer(n);

	}

}

ClickLone.java

左擊事件的處理. 分兩種情況:

     1,點擊的位置是雷,這時,彈出一個模態對話框顯示GAME OVER,結束遊戲

     2.點擊的地方不是雷,這時,需要把該按鈕設置爲setEnabled(false).並通過mine[]數組中預先計算出應該顯示的數字設置按鈕標籤,如果爲零,這設置爲空格..然後,如果點擊的位置對應的mine[]的值爲0,則調用BFS,不斷向周圍擴散,直到遇見數字或雷爲止(廣度優先搜索,隊列)

package mine_sweep;

import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.LinkedList;
import java.util.Queue;

import javax.swing.JButton;
import javax.swing.JDialog;

public class ClickLone {
	My_button buttons[]; 		//按鈕的引用
	int i,j;
	int rows,cols;
	Integer  mine[];
	Boolean ismine[];
	boolean used[];
	Integer rn;				//已經標記的雷數
	Mine sjm;
	int dx[]={1,-1,0};
	int dy[]={1,-1,0};
	ClickLone(My_button[] tem,int a,int b,int r,int l,Integer mines[],Boolean ismines[],Mine Jm,Integer n)
	{
		buttons=tem;
		rn=n;
		mine=mines;
		ismine=ismines;
		rows=r;
		cols=l;
		i=a;
		j=b;
		sjm=Jm;
		used=new boolean[rows*cols];
		for(int i=0;i<rows*cols;i++)
			used[i]=false;
		if(ismine[i*cols+j].booleanValue())			//如果選中地雷
		{
			buttons[i*cols+j].setEnabled(false);
			buttons[i*cols+j].setLabel("*");
			buttons[i*cols+j].setBackground(Color.red);
			JButton btc=new JButton("GAME OVER!");
			JDialog dialog=new JDialog(sjm,"game_over");
			dialog.setLayout(new FlowLayout());
			dialog.addWindowListener(new WindowAdapter()		//對話框監聽器
			{

				@Override
				public void windowClosing(
						WindowEvent e) {
					// TODO Auto-generated method stub
					super.windowClosing(e);
					dialog.dispose();
					sjm.dispose();
				}
				
				
			});
			btc.addActionListener(new ActionListener(){

				@Override
				
				public void actionPerformed(
						ActionEvent e) {
					// TODO Auto-generated method stub
					dialog.dispose();
					sjm.dispose();
				}
				
			});
			dialog.add(btc);
			dialog.setModal(true);				//彈出game_over窗口
			dialog.setSize(220,150 );
			dialog.setLocation(350, 250);
			dialog.setVisible(true);
			
			return;
		}
		Bfs(i,j);
//		buttons[i*cols+j].setLabel(mine[i*cols+j].toString());
	//	if(ismine[i*cols+j].booleanValue())
	//	{
	//		buttons[i*cols+j].setLabel("*");
			
	//	}
		
	}
	int rep()
	{
		return rn.intValue();
	}
	void Bfs(int i,int j)			//廣度優先搜索
	{
		Queue<Integer> que=new LinkedList<Integer>();
		que.offer(new Integer(i*cols+j));
		while(!que.isEmpty())
		{
			int t=que.poll().intValue();
			if(new String("#").equals(buttons[t].getLabel()))		//如果該位置標記爲雷,說明用戶標記錯誤
				rn=new Integer(rn.intValue()-1);			//用戶標記的雷數-1
			if(new String("0").equals(mine[t].toString()) )
				buttons[t].setLabel(" ");
			else
			{
				buttons[t].setLabel(mine[t].toString());
			}

			buttons[t].setEnabled(false);
			buttons[t].setBackground(Color.gray);
			if(mine[t].intValue()!=0)
				continue;
			i=t/cols;
			j=t%cols;
			for(int x=0;x<3;x++)
				for(int y=0;y<3;y++)
				{
					int nx=i+dx[x],ny=j+dy[y];
					if(nx>=0&&ny>=0&&nx<rows&&ny<cols&&			//沒有越界
						mine[i*cols+j].intValue()==0					// 是空白區域且沒有雷
						&&(!ismine[nx*cols+ny].booleanValue())
						&&(!(nx==i&&ny==j))
						&&(!used[nx*cols+ny])
					)	
					{
						used[nx*cols+ny]=true;
						que.offer(new Integer(nx*cols+ny));
						
					}
				}

		}
		
	}
}

ClickRone.java

處理右鍵事件,如果該位置還沒有被標記,點擊後將按鈕的標籤設置爲"#" ,如果已經被標記爲"#" ,則將標記清除.

如果標記的雷數==標記對的雷數==總雷數,接結束遊戲,彈出YOU WIN 對話框

package mine_sweep;

import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.JButton;
import javax.swing.JDialog;

public class ClickRone {
	My_button buttons[];
	int x,y;
	int rows,cols;
	Mine sjm;
	Boolean ismine[];
	Num_Mine num_mine;
	ClickRone(My_button button[],int a,int b,int r,int l,Num_Mine num,Mine jm,Boolean ism[])
	{
		ismine=ism;
		buttons=button;
		num_mine=num;
		sjm=jm;
		x=a;
		y=b;
		rows=r;
		cols=l;
		if(buttons[x*cols+y].getLabel()=="#")			//該位置以被標記爲雷,取消標記
		{
			num_mine.mark_mine=new Integer(num_mine.mark_mine.intValue()-1);
			buttons[x*cols+y].setBackground(Color.blue);
			buttons[x*cols+y].setLabel(" ");
			if(ismine[x*cols+y].booleanValue())			//如果該位置是雷
				num_mine.mark_correct_mine=new Integer(num_mine.mark_correct_mine.intValue()-1);
		}
		else						//加上雷的標記	
		{
			num_mine.mark_mine=new Integer(num_mine.mark_mine.intValue()+1);
			buttons[x*cols+y].setBackground(Color.yellow);
			buttons[x*cols+y].setLabel("#");
			if(ismine[x*cols+y].booleanValue())		//如果標記正確
				num_mine.mark_correct_mine=new Integer(num_mine.mark_correct_mine.intValue()+1);
		}
		if(num_mine.mark_correct_mine.intValue()==num_mine.mark_mine.intValue()
				&&num_mine.mark_mine.intValue()==num_mine.sum_mine.intValue())
		{
			JButton btc=new JButton("YOU WIN");
			JDialog dialog=new JDialog(sjm,"you_win");
			dialog.setLayout(new FlowLayout());
			dialog.addWindowListener(new WindowAdapter()		//對話框監聽器
			{

				@Override
				public void windowClosing(
						WindowEvent e) {
					// TODO Auto-generated method stub
					super.windowClosing(e);
					dialog.dispose();
					sjm.dispose();
				}
				
				
			});
			btc.addActionListener(new ActionListener(){			

				@Override
				public void actionPerformed(
						ActionEvent e) {
					// TODO Auto-generated method stub
					dialog.dispose();
					sjm.dispose();
				}
				
			});
			dialog.add(btc);
			dialog.setModal(true);				//彈出you_win窗口
			dialog.setSize(220,150 );
			dialog.setLocation(350, 250);
			dialog.setVisible(true);
		}
	}
	Num_Mine repnum()
	{
		return num_mine;
	}

}

下面是運行截圖:

從拿到題目,到基本完成,一共用了整整一天的時間(早上八點~第二天凌晨1點).

後來用了3天改了十數個bug.終於做成了現在比較完善的程序.


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章