• 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.终于做成了现在比较完善的程序.


  • 相关阅读:
    'IDataObject': ambiguous symbol的解决方法
    捕获windows系统的sleep或hibernate状态
    CallingConvention理解
    Exception from HRESULT: 0x8001010D (RPC_E_CANTCALLOUT_ININPUTSYNCCALL))
    .Net Managed C++如何获取当前线程id和当前进程id
    div垂直居中于div中
    父级是relative,子级为absolute的情况下,子级宽度自适应
    background-img高度固定,图片自适应
    如何让两个input紧挨着.
    C# 调用百度短链接api
  • 原文地址:https://www.cnblogs.com/frankM/p/4399442.html
Copyright © 2020-2023  润新知