以下每行代碼,文字均爲原創,轉載請註明出處.
程序一共分爲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.終於做成了現在比較完善的程序.