JAVA实现简单扫雷(续)

  1. 前言
    我这次写的这个扫雷程序是java面向对象编程的结课作业,说实话一开始我没想到我会遇到这么多问题,也没想到这么一个小程序会让我有这么多的收获,从简陋的Demo1,到稍微完善的Demo2,再到现在有点样子的Demo3,感受颇多,在这里我想稍微花一点时间总结一下我的思路,和我在实际编写代码时遇到的问题。

  2. 整体思路
    (有空再写)

  3. 遇到的困难
    (1)>遇到困难的地方主要是广搜那段算法,具体思路很简单,就是不停的搜索上下左右四个方向的方格,遇到(next)0的或是(now)0的并且(next)为除0以外数字的就把他压入队列中具体判断条件如下
    if(gameMap4[next.x][next.y].equals("0")||(gameMap4[next.x][next.y].matches("[0-9]{1}")&&gameMap4[now.x])
    前面都没问题,最坑爹(主要还是自己基础不牢)的地方就是Linklist的add()方法会覆盖了前面的所有元素,原因主要是如果我这样写代码
    next.x = now.x+dir[i][0];next.y = now.y+dir[i][1];
    那么至始至终我只有一个next对象,我每次add进队列的对象都是同一个next(都是相同地址),所以for循环里我next的属性值改变,之前所有的值都会被覆盖(同一个对象,同一个地址)所以正确代码应该这么写
    next = new Grid(now.x+dir[i][0],now.y+dir[i][1]);
    (每次for循环都创建y一个新的对象,新的地址,值就不会覆盖)
    eg.如果觉得我解释的不够清楚可以参考https://bbs.youkuaiyun.com/topics/390774337

    (2)>广搜算法单独列出来:

    public void bfsMap(int x,int y) {
    
    final int[][]dir = {{1,0},{0,1},{-1,0},{0,-1}};
    
    class Grid{
    	int x;
    	int y;
    	
    	public Grid(int x,int y) {
    		this.x = x;
    		this.y = y;
    	}
    }
    
    Queue<Grid> q = new LinkedList<Grid>();
    
    Grid now = new Grid(x,y);
    Grid next;
    vis[now.x][now.y] = 1;//点击过的点置1
    q.add(now);
    while(!q.isEmpty()) {
    	now = q.poll();//现在位置
    	System.out.println("nowx:   "+now.x+"    nowy   "+now.y);//调试用
    	for(int i=0;i<4;i++) {
    		//next.x = now.x+dir[i][0];
    		//next.y = now.y+dir[i][1];
    		next = new Grid(now.x+dir[i][0],now.y+dir[i][1]);//重点一定要注意!!!!!
    		
    		if(next.x>=0&&next.x<cols&&next.y>=0&&next.y<rows&&vis[next.x][next.y]!=1) {
    			if(gameMap4[next.x][next.y].equals("0")||(gameMap4[next.x][next.y].matches("[0-9]{1}")&&gameMap4[now.x][now.y].equals("0"))) {//一定要注意了这里一定要用equals比较,用==比较的是地址(对象)
    				//bfs队列
    				buttons[next.x][next.y].setBackground(Color.green);
    				buttons[next.x][next.y].setText(gameMap4[next.x][next.y]);
    				buttons[next.x][next.y].setEnabled(false);
    				vis[next.x][next.y] = 1;
    				
    				System.out.println("map  "+gameMap4[next.x][next.y]+"  x:  "+next.x+"  y:  "+next.y);//调试用
    				q.add(next);
    				//调试用
    				}
    				
    			}
    		}
    	}
    }
    

    }

    ```
    
package boom;

import java.awt.*;
import java.awt.event.*;
import java.util.Random;
import javax.swing.*;
import java.util.LinkedList;
import java.util.Queue;


class Map4 extends JPanel implements ActionListener,MouseListener{//创建地图(加按钮)
	private static final long serialVersionUID = 1L;
	
	private int rows;
	private int cols;
	private int boom;
	private String[][] gameMap4;
	int[][] vis;//用来判断那些点已经访问过 
	JFrame frame;
	Font font;
	JButton [][] buttons;
	JTextArea text;
	
	public Map4(int rows,int cols,int boom) {
		this.rows = rows;
		this.cols = cols;
		this.boom = boom;
		
		font = new Font("宋体",Font.BOLD,22);
		UIManager.put("Button.font", font);
		init();
		//System.out.println(buttons.length);

	}
	
	private void init() {
		buttons = new JButton[rows][cols];
		gameMap4 = new String[rows][cols];
		vis = new int[rows][cols];
		text = new JTextArea();
		frame = new JFrame();
		addButtons();
		addBoom();
		mkMap();
	}
	public void addButtons(){
		this.setLayout(new GridLayout(rows,cols));

		for(int i=0;i<rows;i++){
			for(int j=0;j<cols;j++){

				JButton button = new JButton();
				button.setBackground(Color.gray);
				button.setOpaque(true);//设置button不透明
				button.addMouseListener(this);
				button.addActionListener(this);
				buttons[i][j]=button;//将button对象赋给buttons数组,形成映射关系,以此来判断点击的是哪个按钮
				this.add(button);
			}
		}
	}
	public void addBoom() {
		Random rand=new Random();
		int randRow,randCol;
		for(int i=0;i<boom;i++){
			randRow=rand.nextInt(rows);
			randCol=rand.nextInt(cols);
			if(gameMap4[randRow][randCol]== "X"){//如果布雷的地方已经有雷了那么i--
				i--;
			}
			else{
				gameMap4[randRow][randCol]="X";
				//buttons[randRow][randCol].setText("*");
			
			}
		}
	}
	
	@Override
	public void mousePressed(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void mouseReleased(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void mouseEntered(MouseEvent e) {
		// TODO Auto-generated method stub
	}

	@Override
	public void mouseExited(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}
	
	@Override
	//有问题
	public void mouseClicked(MouseEvent e) {
		// TODO Auto-generated method stub
		for(int i=0;i<rows;i++) {
			for(int j=0;j<cols;j++) {
				if(e.getSource().equals(buttons[i][j])) {//重要!!!判断是哪个按钮点击
					
					if(e.getButton()!=MouseEvent.BUTTON1){
						buttons[i][j].setText("?");
						buttons[i][j].setBackground(Color.WHITE);
					}
				}
			}
		}
	}
	
	
	public void actionPerformed(ActionEvent e) {
		//buttons[randRow][randCol].setText("X");
		for(int i=0;i<rows;i++) {
			for(int j=0;j<cols;j++) {
				if(e.getSource().equals(buttons[i][j])) {//重要!!!判断是哪个按钮点击
					//System.out.println(i+"  "+j);
					if(gameMap4[i][j]=="X") {
						buttons[i][j].setText("X");
						buttons[i][j].setBackground(Color.red);

						lose();
					}
					else {
						buttons[i][j].setBackground(Color.green);
						//gameMap4[i][j]="*";
						//calcMap4(i,j);
						buttons[i][j].setText(gameMap4[i][j]);
						buttons[i][j].setEnabled(false);
						bfsMap(i,j);
						win();
					}
				}
			}
		}
	}
	
	public void lose() {
		for(int i=0;i<rows;i++) {
			for(int j=0;j<cols;j++) {
				buttons[i][j].setEnabled(false);
				
			}
		}
		text.setText("You are Dead");
		
	}
	
	public void win() {
		int count = 0;
		JDialog log = new JDialog(frame,"Congratulations!"); 
		JTextArea area = new JTextArea("恭喜通关!");
		for(int i=0;i<rows;i++) {
			for(int j=0;j<cols;j++) {
				if(vis[i][j]==1) {
					count++;
				}
			}
		}
		if(count==rows*cols-boom)
		{
			System.out.println("count"+count);
			text.setText("You are win");
			area.setBackground(Color.RED);
			log.add(area,"Center");
			log.setBounds(320,320,100,100);
			log.setVisible(true);
		}
	}
	
	public void bfsMap(int x,int y) {
		
		final int[][]dir = {{1,0},{0,1},{-1,0},{0,-1}};
		
		class Grid{
			int x;
			int y;
			
			public Grid(int x,int y) {
				this.x = x;
				this.y = y;
			}
		}
		
		Queue<Grid> q = new LinkedList<Grid>();
		
		Grid now = new Grid(x,y);
		Grid next;
		vis[now.x][now.y] = 1;//点击过的点置1
		q.add(now);
		while(!q.isEmpty()) {
			/*
			Iterator<Grid> iter = q.iterator();//调试用遍历
			while(iter.hasNext()) {
				Grid show = iter.next();
				System.out.print("queue :"+"x  "+show.x+"   "+"y   "+show.y);
			}System.out.println();
			*/
			now = q.poll();//现在位置
			System.out.println("nowx:   "+now.x+"    nowy   "+now.y);//调试用
			for(int i=0;i<4;i++) {
				//next.x = now.x+dir[i][0];
				//next.y = now.y+dir[i][1];//下一跳位置
				next = new Grid(now.x+dir[i][0],now.y+dir[i][1]);//重点一定要注意!!!!!
				
				if(next.x>=0&&next.x<cols&&next.y>=0&&next.y<rows&&vis[next.x][next.y]!=1) {
					//System.out.println("map  "+gameMap4[next.x][next.y]+"  x:  "+next.x+"y:  "+next.y);//调试用
					//System.out.println("bool  "+gameMap4[next.x][next.y].equals("0"));//调试用
					if(gameMap4[next.x][next.y].equals("0")||(gameMap4[next.x][next.y].matches("[0-9]{1}")&&gameMap4[now.x][now.y].equals("0"))) {//一定要注意了这里一定要用equals比较,用==比较的是地址(对象)
						//bfs队列
						//System.out.println("flag");//调试用
						
						buttons[next.x][next.y].setBackground(Color.green);
						buttons[next.x][next.y].setText(gameMap4[next.x][next.y]);
						buttons[next.x][next.y].setEnabled(false);
						vis[next.x][next.y] = 1;
						
						System.out.println("map  "+gameMap4[next.x][next.y]+"  x:  "+next.x+"  y:  "+next.y);//调试用
						q.add(next);
						//调试用
						for(int r=0;r<rows;r++) {
							for(int c=0;c<cols;c++) {
								System.out.print(vis[r][c]);
							}System.out.println();
						}
						
					}
				}
			}
		}
		
	}
	
	public void mkMap() {
		for(int i=0;i<rows;i++) {
			for(int j=0;j<cols;j++) {
				if(gameMap4[i][j]!="X") {
					calcMap4(i,j);

				}
			}
			
		}
		//显示gameMap4方便调试
		for(int i=0;i<rows;i++) {
			for(int j=0;j<cols;j++) {
					System.out.print(gameMap4[i][j]);
				}System.out.println();
			}

	}
	
	public void calcMap4(int x,int y) {
		int count = 0;
		class Grid{
			int x;
			int y;
			
			public Grid(int x,int y) {
				this.x = x;
				this.y = y;
			}
		}
		
		Grid now = new Grid(x,y);
		Grid next;
		final int[][]dir = {{1,0},{0,1},{-1,0},{0,-1},{1,1},{1,-1},{-1,1},{-1,-1}};
		
		for(int i=0;i<8;i++) {
			next = new Grid(now.x+dir[i][0],now.y+dir[i][1]);
			
			if(next.x>=0&&next.x<cols&&next.y>=0&&next.y<rows) {
				if(gameMap4[next.x][next.y]=="X") {
					count++;
				}
			}
		}
		//System.out.println(count);
		gameMap4[x][y] = String.valueOf(count);
		//buttons[x][y].setText(String.valueOf(count));
	}

}

class Diff3 extends JComboBox<String> implements ItemListener{
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	String[] level = {"Easy","Normal","Difficult"};
	private int rows;
	private int cols;
	private int boom;
	GameFrame4 mf;
	Boolean flag = true;
	
	public Diff3(GameFrame4 f){
		
		mf = f;
		addItem("Choose the level");
		for(String i:level) {
			addItem(i);
		}
		
		this.addItemListener(this);
	}

	@Override
	public void itemStateChanged(ItemEvent e) {
		// TODO Auto-generated method stub
		String selectedLevel = this.getSelectedItem().toString();
		//selectedLevel = selectedLevel.substring(0, selectedLevel.indexOf("\n"));//不知道为啥会出现两个level所以在这里去掉一个
		setLevel(selectedLevel);
		System.out.println(rows+"  "+cols);
		//System.out.println(selectedLevel.substring(0,5));
		
	}
	
	
	public void setLevel(String level) {
		//System.out.println(level);
		if(level=="Easy") {
			this.rows = 10;
			this.cols = 10;
			this.boom = 20;
		}
		else if(level=="Normal") {
			this.rows = 15;
			this.cols = 15;
			this.boom = 30;			
		}
		else if(level=="Difficult") {
			this.rows = 20;
			this.cols = 20;
			this.boom = 100;			
		}
		if(flag) {
			GameFrame4 frame = new GameFrame4(cols,rows,boom);
			flag = false;
		}
		System.out.print("flag");//为什么会运行两次???????
		mf.dispose();
	}
}

class MyMenuBar extends JMenuBar implements ActionListener//获取帮助(游戏规则,关于扫雷(开发者信息,退出等菜单(退出)
{
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	JMenu help;
	JMenu about;
	JMenu exit;
	
	JMenuItem rules;
	JMenuItem ex;
	JMenuItem aboutus;
	public MyMenuBar() {
		
		help = new JMenu("获取帮助");
		about = new JMenu("关于扫雷");
		exit = new JMenu("退出");
		
		ex = new JMenuItem("exit");
		aboutus = new JMenuItem("About us");
		rules = new JMenuItem("rules");
		
		ex.addActionListener(this);
		rules.addActionListener(this);
		aboutus.addActionListener(this);
		
		exit.add(ex);
		help.add(rules);
		about.add(aboutus);
		
		add(help);
		add(about);
		add(exit);
		
		
	}
	@Override
	public void actionPerformed(ActionEvent e) {
		// TODO Auto-generated method stub
		if(e.getSource()==ex) {
			System.exit(0);
		}
		else if(e.getSource()==rules) {
			String ru = new String("当你随机点开一个方格的时候(如果上来就是炸弹\n,就只能重新开局咯)"
					+ "会看到一个数字,那么扫雷\n的规律就是围绕着一个数字的九宫格里的炸弹数就\n是这个数字,"
					+ "每个数字都会有自己的九宫格,这样\n结合起来分析就可以知道一个小白块是炸弹还是安\n全区域了");
			JDialog r = new JDialog();
			JTextArea label = new JTextArea(ru);
			label.setLayout(new FlowLayout());
			r.add(label);
			r.setTitle("游戏规则");
			r.setBounds(320,320,320,320);
			r.setVisible(true);

		}
		else {
			String ru = new String("作者:KolaFish\n制作日期:2018.12.29\n本扫雷游戏仅用作学习交流用途");
			JDialog r = new JDialog();
			JTextArea label = new JTextArea(ru);
			label.setLayout(new FlowLayout());
			r.add(label);
			r.setTitle("关于我们");
			r.setBounds(320,320,320,320);
			r.setVisible(true);
		}
	}
	
}


class GameFrame4 extends JFrame implements ActionListener{//框架,有面板(地图),文本框,重置按钮,combobox

	private static final long serialVersionUID = 1L;
	private int[][] clear;
	private int rows,cols;
	Map4 m;
	JButton reset;
	JTextArea frametext;
	JPanel pane;
	Diff3 level;
	MyMenuBar bar;
	
	public GameFrame4(int rows,int cols,int boom) {
		this.rows = rows;
		this.cols = cols;
		
		
		pane = new JPanel();
		level = new Diff3(this);
		bar = new MyMenuBar();
		
		//System.out.println(rows+"  "+cols+"  "+boom);
		m = new Map4(rows,cols,boom);
		m.frame = this;
		frametext = m.text;
		init();
	}
	
	private void init() {
		//JFrame.setDefaultLookAndFeelDecorated(true);
		pane.setLayout(new FlowLayout());
		pane.add(bar);
		pane.add(level);
		
		add(m);
		addResetButton();
		add(frametext,"South");
		add(pane,"North");
		setBounds(100,50,1000,1000);
		setVisible(true);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}
	
	public void addResetButton(){
		reset = new JButton("Reset");
		reset.setBackground(Color.yellow);
		reset.setOpaque(true);
		reset.addActionListener(this);
		pane.add(reset);
	}
	
	public void actionPerformed(ActionEvent e) {
		for(int i=0;i<rows;i++) {
			for(int j=0;j<cols;j++) {
				clear = new int[rows][cols];
				m.buttons[i][j].setEnabled(true);
				m.buttons[i][j].setBackground(Color.gray);
				m.buttons[i][j].setText(" ");
				m.vis = clear;//清除vis
				frametext.setText("");
			}
		}
	}
}


public class BoomDemo4{
	public static void main(String[] args) {
		
		GameFrame4 frame = new GameFrame4(10,10,10);
		
	}
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值