以下每行代码,文字均为原创,转载请注明出处.
程序一共分为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
随机雷的位置.储存在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=0&&ny>=0&&nx
继承自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;
}
}
存储用户以标记的雷数,标记正确的雷数,以及雷区的总雷数
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);
}
}
左击事件的处理. 分两种情况:
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 que=new LinkedList();
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
处理右键事件,如果该位置还没有被标记,点击后将按钮的标签设置为"#" ,如果已经被标记为"#" ,则将标记清除.
如果标记的雷数==标记对的雷数==总雷数,接结束游戏,弹出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.终于做成了现在比较完善的程序.