Java写一个简单的扫雷游戏

一、前言

这个学期学习了Java,课程的最后一项作业就是做一个扫雷游戏和一个计算器,经历一段时间的煎熬终于做出来了,就想来分享一下我的喜悦和成果。

在老师布置作业后,我的计算器代码就根据老师黑板上代码微调后很快就收工了,而这个扫雷也是有了明确的思路,但是却找不到相对应的代码来实现,后来在百度上看了一位前辈的扫雷代码终于解决了我问题。这里是那位前辈的扫雷代码链接

其实回过头来看,我写这个代码确实极其简陋,相比我在百度上找的各种大佬做出来的扫雷,感觉差距极大。但是想想是我自己做出来的还是很高兴的,但是也明白我还只是个小白。

二、过程中遇到的困难

老师一布置作业我就想出来了一个做法,那就是做两层组件,底层是label,可以用来显示数字和雷,如下图所示这样的效果,其中"!"表示随机生成的雷。
图1
再在这上面盖一层相同数量button组件,点击一个button,这个button就消失,显示出下层的label。

当我开始写代码时,我就卡在了这一步。我定义一个panel并设置了20*20的gridlayout(网格布局),当我添加进去400个label时,成功达到了上图的底层效果,但是当我再添加400个button时,就出现问题了,这个button不会重叠到label上面,而是继续向下排列,和label处于了同一层,然后百度了好久都没有解决问题,最后决定看看别人的代码是怎么做的。最后看了某位前辈的作品,原来他是清除了panel原有的layout,用坐标放置组件,这样就可以重叠了,于是后面我就很快的写好了。
(也许这个问题也有其他的解决方法,我感觉用gridlayout也可以做出的,知道怎么做的大佬可以说一下)

三、代码

最重要的代码来了

package testone;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Arrays;

public class Try1 {
	JFrame f;
	JPanel p,p1,p2;
	int n = 20;                   //扫雷正方形界面的的边长(只能手动修改控制难度)
	int boomnumber = 50;          //设置雷的个数(只能手动修改控制难度)后续可以添加按键修改难度
	JButton zuobi,restart;       //作弊和重新开始的按钮
	JButton b[][] = new JButton[n][n];  
	JLabel l[][] = new JLabel[n][n];  //下层显示的label
	int boxy[][];                     //存储雷的横纵坐标的数组 
	int visited[][] = new int[n][n];  //被访问记录,访问过为1
	Try1() {

		f = new JFrame("扫雷");
		f.setBounds(600, 200, 495, 545);
		p = new JPanel();    //扫雷游戏面板
		p.setLayout(null);   //清除原有的layout,后面使用坐标放置组件
		p1 = new JPanel();   //最底层面板
		p2 = new JPanel();   //放置功能按键的面板
		p1.setLayout(new BorderLayout());
		p2.setLayout(new GridLayout(1,3)); //网格布局,一行三列
		p.setBackground(new Color(193, 210, 240));
		makeboom(n, p);   //自己定义的函数,生成雷和数组label的
		makebutton(n, p); //生成扫雷按钮的,会覆盖在底层label上
		zuobi =new JButton("作弊");
		zuobi.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				for (int i[]:boxy) {
					b[i[0]][i[1]].setText(".");
				}
			}
		});
		restart = new JButton("重新开始"); 
		restart.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				f.dispose();  //关闭
				new Try1();
			}
		});
		p1.add(p,BorderLayout.CENTER);
		p1.add(p2,BorderLayout.NORTH);
		p2.add(restart);
		p2.add(zuobi);
		f.add(p1);
		f.setVisible(true);
		f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}

	public void makebutton(int n, JPanel a) {
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < n; j++) {
				a.add(b[i][j] = new JButton());
				b[i][j].setBounds(j * 24, i * 24, 24, 24);
				b[i][j].addActionListener(new ActionListener() {
					@Override
					public void actionPerformed(ActionEvent e) {
						// TODO Auto-generated method stub
						JButton d = (JButton) e.getSource();
						int index = 0;
						int indey = 0;
						for (int i = 0; i < n; i++) { //获取点击的按钮的坐标
							for (int j = 0; j < n; j++) {
								if (d == b[i][j]) {
									index = i;
									indey = j;
								}
							}
						}
						open(index,indey);
					}
				});
			}
		}
	}

	public void makeboom(int n, JPanel a) {
		boxy = boom(n, boomnumber);
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < n; j++) {
				l[i][j] = new JLabel("0", JLabel.CENTER);
				l[i][j].setBounds(j * 24, i * 24, 24, 24);
				l[i][j].setBorder(BorderFactory.createLineBorder(Color.GRAY));
				l[i][j].setOpaque(true);
				l[i][j].setVisible(false);
				a.add(l[i][j]);
			}
		}
		for (int i = 0; i < boomnumber; i++) {
			l[boxy[i][0]][boxy[i][1]].setText("!");
			visited[boxy[i][0]][boxy[i][1]] = 1;
		}
		setshuzi();
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < n; j++) {
				if(l[i][j].getText().equals("0")) {
					l[i][j].setText("");
				}
			}
		}
	}
	

	public  int[][] boom(int n, int m) { // n是网格最大长宽,m是雷的个数
		int[][] boxy = new int[m][2];
		int cishu = 0;
		while (cishu != m) {
			int x = (int)(Math.random() * n);
			int y = (int)(Math.random() * n);
			if(isrepeat(x,y,boxy,cishu) == 0){
				boxy[cishu][0] = x;
				boxy[cishu][1] = y;
				cishu++;
			}
		}
		return boxy;
	}

	public int isrepeat(int x, int y, int a[][], int cishu) {
		int is = 0;
		for (int i = 0; i < cishu; i++) {
			if (a[i][0] == x && a[i][1] == y) {
				is = 1;
				break;
			} else {
				is = 0;
			}
		}
		return is;
	}

	public void setshuzi() {
		for (int[] i:boxy) {
			int x = i[0];
			int y = i[1];
			for(int u = x-1;u<x+2;u++) {
				for(int v = y-1;v<y+2;v++) {
					
					if(u>=0&&u<n&&v>=0&&v<n) {
						String s = l[u][v].getText();
						if(!s.equals("!")) {
							
							int lnumb = Integer.parseInt(s);
							lnumb ++;
							l[u][v].setText(lnumb+"");
						}
					}
				}
			}
		}
	}
	
	public void open(int x,int y) {
		b[x][y].setVisible(false);
	    l[x][y].setVisible(true);
	    visited[x][y]=1;
	    if(iswin()) {
	    	JOptionPane.showMessageDialog(null,"游戏获胜","游戏获胜",JOptionPane.PLAIN_MESSAGE);
	    }else {
	    	if(l[x][y].getText().equals("!")) {
	    		JOptionPane.showMessageDialog(null,"您失败了","游戏结束",JOptionPane.PLAIN_MESSAGE);
	    	}else if(l[x][y].getText().equals("")){
	    		
	    		for(int u = x-1;u<x+2;u++) {
	    			for(int v = y-1;v<y+2;v++) {
	    				if(u>=0&&u<n&&v>=0&&v<n&&visited[u][v]!=1) {
	    					open(u,v);
	    				}
	    			}
	    		}
	    	}else {
	    		
	    	}
	    }
	}
	
	public boolean iswin() {
		int last =-1;
		for(int i[]:visited) {
			if(Arrays.binarySearch(i, 0)< 0) {
				last = 1;
			}else {//只要存在1个没有访问的,就判定没有赢,退出循环
				last = -1;
				break;
			}
		}
		if(last==1) {
			return true;
		}else {
			return false;
		}
	}
	public static void main(String[] args) {
		Try1 t = new Try1();
	}
}

四、成品图

在这里插入图片描述

五、代码存在的bug

1.游戏获胜判断提前:
游戏获胜判断每次点击按钮都要判断的,如果所有的位置都被访问过即可获胜(其中生成雷的位置提在生成雷时编辑为访问过的状态),但是在还未全部点击的情况,就会提醒游戏获胜。
2.游戏失败还能继续游戏:
这个问题可以解决,但是由于本人太懒了没写,只要在踩雷后使所有button不可见即可。
3.未知…(等待读者发现)

六、完善建议

1.雷的颜色可以设置高亮颜色,踩雷后更醒目。
2.添加可控难度的按钮,可以放到菜单栏。
3.设置插旗子的功能。如果可以的话,最好用图片而不是字符。

七、结语

欢迎评论留言交流,有错误或者修改建议请评论留言,可能回复不及时请见谅。

  • 40
    点赞
  • 113
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 32
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 32
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TwilightPureDrm

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值