Java game development - Minesweeper

introduction:

        The code implementation of minesweeper is very simple. It is a little troublesome to click the left and right mouse buttons at the same time, but it is not a big problem!

Idea:

        1. Create the main window, load menu and game panel.

        2. Initialize various parameters in the game panel and set various functional components according to the difficulty of the game.

        3. Use the mousePressed() mouse press function to handle simultaneous left and right click events to open the surrounding squares that can be opened.

        ​​ 4. Use the mouseReleased() mouse release function to handle the click events of the left and right keys to open a certain square. If it is a blank square, recursively use a recursive method to open all the blank squares around it.

        5. Determine whether the mines have been stepped on or all the mines have been found, and whether the game is over.

 Code: 

 

        After compilation, the image position is flush with the package position, because when I load the image, I start from the class path, and the absolute path is not allowed.

This game uses JDK1.8 and encodes UTF-8;

        There are 4 classes in total, Gobang.java is the game entry class. GameFrame.java is the main window class. GamePanel.java is the game panel class. GameLogic.java is the game logic class. Let’s post all the code in one go first.

1. Gobang.java game entry class

package com.game.mine;

/**
 * 功能:扫雷<br>
 * 作者:我是小木鱼(Lag)<br>
 */
public class Mine {

    public static void main(String[] args)
    {
        new GameFrame();
    }
}

 2. GameFrame.java main window class.

package com.game.mine;

import java.awt.Color;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;

/**
 * 功能:游戏窗口<br>
 * 作者:我是小木鱼(Lag)<br>
 */
public class GameFrame extends JFrame implements ActionListener
{
	private static final long serialVersionUID = 2596945399892762751L;

	/** 游戏面板 */
	private GamePanel gamePanel;
	
	/** 菜单控件 */
	JMenuItem jmi_easy,jmi_normal,jmi_hard;
        
	/**
	 * 功能:构造函数<br>
	 */
	public GameFrame()
	{
		try
		{
			//窗口
			this.setTitle("扫雷");
			this.setLayout(null);
			this.setBackground(Color.WHITE);
			this.setResizable(false);
			this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
			//菜单
			JMenuBar jmb_mine = new JMenuBar();
			JMenu jm_game = new JMenu("游戏");
			jm_game.setFont(new Font("微软雅黑",Font.PLAIN,12));
			JMenuItem jmi_new = jm_game.add("  开局");
			jmi_new.setFont(new Font("微软雅黑",Font.PLAIN,12));
			jmi_new.addActionListener(this);
			jmi_new.setActionCommand("new");
			jm_game.addSeparator();
			this.jmi_easy = jm_game.add("√ 初级");
			this.jmi_easy.setFont(new Font("微软雅黑",Font.PLAIN,12));
			this.jmi_easy.addActionListener(this);
			this.jmi_easy.setActionCommand("easy");
			this.jmi_normal = jm_game.add("  中级");
			this.jmi_normal.setFont(new Font("微软雅黑",Font.PLAIN,12));
			this.jmi_normal.addActionListener(this);
			this.jmi_normal.setActionCommand("normal");
			this.jmi_hard = jm_game.add("  高级");
			this.jmi_hard.setFont(new Font("微软雅黑",Font.PLAIN,12));
			this.jmi_hard.addActionListener(this);
			this.jmi_hard.setActionCommand("hard");
			jm_game.addSeparator();
			JMenuItem jmi_exit = jm_game.add("  退出");
			jmi_exit.setFont(new Font("微软雅黑",Font.PLAIN,12));
			jmi_exit.addActionListener(this);
			jmi_exit.setActionCommand("exit");
			jmb_mine.add(jm_game);
			JMenu jm_help = new JMenu("帮助");
			jm_help.setFont(new Font("微软雅黑",Font.PLAIN,12));
			JMenuItem jmi_about = jm_help.add("关于");
			jmi_about.setFont(new Font("微软雅黑",Font.PLAIN,12));
			jmi_about.addActionListener(this);
			jmi_about.setActionCommand("about");
			jmb_mine.add(jm_help);
			this.setJMenuBar(jmb_mine);
			//面板
			this.gamePanel = new GamePanel();
			this.add(this.gamePanel);
			//显示
			this.gamePanel.setLevel(this.gamePanel.EASY);
			this.setSize(this.gamePanel.getWidth() + 15,this.gamePanel.getHeight() + 60);
			this.setLocationRelativeTo(null);   //居中
			this.setBounds(this.getX() - 63,this.getY() - 63,this.getWidth(),this.getHeight());     //因为初级、中级、高级窗口大小不一样,但都以左上角位置为固定点,向右向下拉伸,所以考虑左上角位置再向左上方多挪点。
			this.setVisible(true);
		}
		catch(Exception e)
		{
			JOptionPane.showMessageDialog(this,"程序出现异常错误,即将退出!\r\n\r\n"+e.toString(),"提示",JOptionPane.ERROR_MESSAGE);
			System.exit(0);
		}
	}
	
	/**
	 * 功能:事件监听<br>
	 */
	@Override
	public void actionPerformed(ActionEvent e)
	{
		String command = e.getActionCommand();
		if("new".equals(command))
		{
			this.gamePanel.newGame();
		}
		else if("easy".equals(command))
		{
			this.jmi_easy.setText("√ 初级");
			this.jmi_normal.setText("  中级");
			this.jmi_hard.setText("  高级");
			this.gamePanel.setLevel(this.gamePanel.EASY);
			this.setSize(this.gamePanel.getWidth() + 15,this.gamePanel.getHeight() + 60);
		}
		else if("normal".equals(command))
		{
			this.jmi_easy.setText("  初级");
			this.jmi_normal.setText("√ 中级");
			this.jmi_hard.setText("  高级");
			this.gamePanel.setLevel(this.gamePanel.NORMAL);
			this.setSize(this.gamePanel.getWidth() + 15,this.gamePanel.getHeight() + 60);
		}
		else if("hard".equals(command))
		{
			this.jmi_easy.setText("  初级");
			this.jmi_normal.setText("  中级");
			this.jmi_hard.setText("√ 高级");
			this.gamePanel.setLevel(this.gamePanel.HARD);
			this.setSize(this.gamePanel.getWidth() + 15,this.gamePanel.getHeight() + 60);
		}
		else if("exit".equals(command))
		{
			System.exit(0);
		}
		else if("about".equals(command))
		{
			JOptionPane.showMessageDialog(this,"我是小木鱼(Lag)","提示",JOptionPane.INFORMATION_MESSAGE);
		}
	}

}

3. GamePanel.java game panel class.

package com.game.mine;

import java.util.Map;
import java.util.HashMap;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.BorderFactory;
import javax.swing.JLabel;

/**
 * 功能:游戏面板<br>
 * 作者:我是小木鱼(Lag)<br>
 */
public class GamePanel extends JPanel implements MouseListener,ActionListener
{
	private static final long serialVersionUID = -3395178511152885550L;

	/** 游戏逻辑 */
	private GameLogic gameLogic;

	/** 初级难度(9×9,10个地雷) */
	final int EASY = 1;
	
	/** 中级难度(16×16,40个地雷) */
	final int NORMAL = 2;

	/** 高级难度(30×16,99个地雷) */
	final int HARD = 3;

	/** 上次游戏难度 */
	private int oldLevel = -1;
	
	/** 本次游戏难度 */
	private int newLevel = 0;
	
	/** 网格行数 */
	int gridRows;

	/** 网格列数 */
	int gridColumns;

	/** 网格尺寸 */
	final int gridSize = 17;

	/** 网格宽度 */
	private int gridsWidth;

	/** 网格高度 */
	private int gridsHeight;

	/** 地雷数 */
	int mineNum;

	/** 提示区面板 */
	private JPanel panelTip = new JPanel();
	
	/** 地雷区面板 */
	private JPanel panelMine = new JPanel();
	
	/** 笑脸按钮 */
	private JButton buttonFace = new JButton();
        
	/** 地雷数提示标签 */
	JLabel labelMineTip[] = new JLabel[3];
        
	/** 时间提示标签 */
	JLabel labelTimeTip[] = new JLabel[3];

	/** 地雷按钮数组 */
	JButton[][] buttonMine = new JButton[16][30];
        
	/**
	 * 地雷信息数组<br>
	 * number->地雷数:-1-地雷,0到8-周围地雷数<br>
	 * flag->地雷状态:0-未打开,1-已打开,2-插小旗,3-插问号<br>
	 */
	@SuppressWarnings("unchecked")	//数组不支持泛型
	Map<String,Integer>[][] mapMine = new Map[16][30];

	/** 笑脸图片 */
	private ImageIcon[] imageIconFace = new ImageIcon[2];
        
	/** 数字提示图片 */
	ImageIcon[] imageIconNumberTip = new ImageIcon[10];
        
	/** 数字图片 */
	ImageIcon[] imageIconNumber = new ImageIcon[9];
        
	/** 空白图片 */
	ImageIcon imageIconBlank = new ImageIcon();
        
	/** 方格图片 */
	ImageIcon imageIconCell = new ImageIcon();

	/** 红旗图片 */
	ImageIcon imageIconFlag = new ImageIcon();
	
	/** 问号图片 */
	ImageIcon imageIconQuestion = new ImageIcon();
	
	/** 地雷图片 */
	ImageIcon imageIconMine = new ImageIcon();
        
	/** 爆炸图片 */
	ImageIcon imageIconBomb = new ImageIcon();
	
	/** 找雷错误图片 */
	ImageIcon imageIconWrongMine = new ImageIcon();
        
	/** 时间提示数字 */
	int timeTip = 0;
	
	/** 扫雷提示数字 */
	int mineTip = 0;

	/** 计时器 */
	Timer timer = new Timer(1000,this);
	
	/** 游戏是否开始(true-开始,false-未开始) */
	boolean isStart = false;

	/** 游戏是否结束(true-结束,false-未结束) */
	boolean isGameOver = true;
	
	/**
	 * 功能:构造函数<br>
	 */
	public GamePanel()
	{
		//主面板初始化
		this.setBackground(Color.LIGHT_GRAY);
		this.setBorder(BorderFactory.createRaisedBevelBorder());    //边框凸起
		this.setLayout(null);   //自由布局

		//提示区面板初始化
		this.panelTip.setBackground(Color.LIGHT_GRAY);
		this.panelTip.setBorder(BorderFactory.createLoweredBevelBorder());  //边框下凹
		this.panelTip.setLayout(null);
		this.add(this.panelTip);
		
		//地雷区面板初始化
		this.panelMine.setBackground(Color.LIGHT_GRAY);
		this.panelMine.setBorder(BorderFactory.createLoweredBevelBorder());     //边框下凹
		this.add(this.panelMine);
                
		//地雷数提示标签初始化
		for(int i=0;i<this.labelMineTip.length;i++)
		{
			this.labelMineTip[i] = new JLabel();
		}

		//笑脸按钮初始化
		this.buttonFace.addActionListener(this);     //事件监听只能添加一次,若多次添加会造成监听事件重复执行。
                
		//时间提示标签初始化
		for(int i=0;i<this.labelTimeTip.length;i++)
		{
			this.labelTimeTip[i] = new JLabel();
		}
                
		//地雷按钮初始化
		for(int row=0;row<this.buttonMine.length;row++)
		{
		    for(int column=0;column<this.buttonMine[0].length;column++)
		    {
		        this.buttonMine[row][column] = new JButton();
		        this.buttonMine[row][column].addMouseListener(this);
		        this.buttonMine[row][column].setName(row+"_"+column);         //用名字来区分行列坐标
		    }
		}
                
		//地雷信息初始化
		for(int row=0;row<this.mapMine.length;row++)
		{
		    for(int column=0;column<this.mapMine[0].length;column++)
		    {
		    	this.mapMine[row][column] = new HashMap<String,Integer>();
		    	this.mapMine[row][column].put("number",0);	//0个雷
		    	this.mapMine[row][column].put("flag",0);	//未打开
		    }
		}

		//加载图片
		this.loadImage();

		//游戏逻辑
		this.gameLogic = new GameLogic(this);

		//设置游戏难度并调整各组件大小
		this.setLevel(this.EASY);
		
	}
	
	/**
	 * 功能:加载图片<br>
	 * 备注:考虑Jar包问题,所以图片路径用URL格式<br>
	 */
	private void loadImage()
	{
		try
		{
			//笑脸图片
			this.imageIconFace[0] = new ImageIcon(this.getClass().getResource("/resource/mine/smile.gif"));
			this.imageIconFace[1] = new ImageIcon(this.getClass().getResource("/resource/mine/ooo.gif"));
			//数字提示图片
			for(int i=0;i<this.imageIconNumberTip.length;i++)
			{
			    this.imageIconNumberTip[i] = new ImageIcon(this.getClass().getResource("/resource/mine/c"+i+".gif"));
			}
			//数字图片
			for(int i=0;i<this.imageIconNumber.length;i++)
			{
			    this.imageIconNumber[i] = new ImageIcon(this.getClass().getResource("/resource/mine/"+i+".gif"));
			}
			//空白图片
			this.imageIconBlank = new ImageIcon(this.getClass().getResource("/resource/mine/blank.gif"));
			//方格图片
			this.imageIconCell = new ImageIcon(this.getClass().getResource("/resource/mine/cell.gif"));
			//红旗图片
			this.imageIconFlag = new ImageIcon(this.getClass().getResource("/resource/mine/flag.gif"));
			//问号图片
			this.imageIconQuestion = new ImageIcon(this.getClass().getResource("/resource/mine/question.gif"));
			//地雷图片
			this.imageIconMine = new ImageIcon(this.getClass().getResource("/resource/mine/mine.gif"));
			//爆炸图片
			this.imageIconBomb = new ImageIcon(this.getClass().getResource("/resource/mine/bomb.gif"));
			//找雷错误图片
			this.imageIconWrongMine = new ImageIcon(this.getClass().getResource("/resource/mine/wrongmine.gif"));
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}

	/**
	 * 功能:初始化游戏<br>
	 */
	private void initGame()
	{
		//重新设置参数
		this.mineTip = this.mineNum;
		this.gameLogic.setNumberTip(this.mineNum,0);
		this.timeTip = 0;
		this.gameLogic.setNumberTip(0,1);
		this.isGameOver = false;
		this.isStart = false;
		this.timer.stop();
		//重置所有的信息
		this.gameLogic.resetAll();
		//随机生雷并记录周围地雷数
		this.gameLogic.randomMine();
	}
	
	/**
	 * 功能:设置游戏难度级别<br>
	 */
	public void setLevel(int _level)
	{
		//判断难度是否有变化
		if(this.oldLevel == _level){return;}
		//记录难度
		this.oldLevel = _level;
		this.newLevel = _level;
		//开始调试
		if(this.newLevel == this.EASY)
		{
			this.gridRows = 9;
			this.gridColumns = 9;
			this.mineNum = 10;
		}
		else if(this.newLevel == this.NORMAL)
		{
			this.gridRows = 16;
			this.gridColumns = 16;
			this.mineNum = 40;
		}
		else if(this.newLevel == this.HARD)
		{
			this.gridRows = 16;
			this.gridColumns = 30;
			this.mineNum = 99;
		}
		this.gridsWidth = this.gridSize * (this.gridColumns);
		this.gridsHeight = this.gridSize * (this.gridRows);
		//重新设置主面板尺寸
		this.setBounds(0,0,this.gridsWidth + 22,this.gridsHeight + 64);
		//重新设置提示区面板尺寸并清除上面的组件
		this.panelTip.setBounds(8,8,this.getWidth() - 17,36);
		this.panelTip.removeAll();
		//重新设置地雷区面板尺寸并清除上面的组件
		this.panelMine.setBounds(8,50,this.gridsWidth + 5,this.gridsHeight + 5);
		this.panelMine.removeAll();
		//重新设置笑脸按钮
		this.buttonFace.setBounds((this.panelTip.getX() + this.panelTip.getWidth() - 34)/2,5,26,27);
		this.buttonFace.setIcon(this.imageIconFace[0]);
		this.buttonFace.setPressedIcon(this.imageIconFace[1]);
		this.buttonFace.setBorder(null);   //边框太难看,不要
		this.panelTip.add(this.buttonFace);
		//重新设置地雷数提示标签并显示总地雷数
		this.labelMineTip[0].setBounds(8,7,13,23);
		this.labelMineTip[1].setBounds(21,7,13,23);
		this.labelMineTip[2].setBounds(34,7,13,23);
		this.gameLogic.setNumberTip(this.mineNum,0);
		this.panelTip.add(this.labelMineTip[0]);
		this.panelTip.add(this.labelMineTip[1]);
		this.panelTip.add(this.labelMineTip[2]);
		//重新设置时间提示标签并显示时间数
		this.labelTimeTip[0].setBounds(this.panelTip.getX() + this.panelTip.getWidth() - 54,7,13,23);
		this.labelTimeTip[1].setBounds(this.panelTip.getX() + this.panelTip.getWidth() - 41,7,13,23);
		this.labelTimeTip[2].setBounds(this.panelTip.getX() + this.panelTip.getWidth() - 28,7,13,23);
		this.gameLogic.setNumberTip(0,1);
		this.panelTip.add(this.labelTimeTip[0]);
		this.panelTip.add(this.labelTimeTip[1]);
		this.panelTip.add(this.labelTimeTip[2]);
		//重新设置地雷区按钮
		this.panelMine.setLayout(null);		//千万不要用GridLayout布局,那就是一个坑啊
		for(int row=0;row<this.gridRows;row++)
		{
		    for(int column=0;column<this.gridColumns;column++)
		    {
		    	this.buttonMine[row][column].setIcon(this.imageIconCell);
		    	this.buttonMine[row][column].setPressedIcon(this.imageIconBlank);
		    	this.buttonMine[row][column].setBorder(null);		//先不要边框,极其难看。但后面开始挖雷时又必须设置边框,要不更极其难看。
		    	this.buttonMine[row][column].setBounds(column * this.gridSize + 2,row * this.gridSize + 2,this.gridSize,this.gridSize);
		    	this.panelMine.add(this.buttonMine[row][column]);
		    }
		}
		//初始化游戏
		this.initGame();
	}
	
	/**
	 * 功能:开始新游戏<br>
	 */
	public void newGame()
	{
		this.initGame();
	}
	
	/**
	 * 功能:事件监听<br>
	 */
	@Override
	public void actionPerformed(ActionEvent e) 
	{
		if(e.getSource() == this.timer)		//定时器
		{
			this.timeTip++;
			this.gameLogic.setNumberTip(this.timeTip,1);
		}
		else if(e.getSource() == this.buttonFace)
		{
			this.newGame();
		}
	}
	
	/**
	 * 功能:鼠标按下事件监听<br>
	 */
	@Override
	public void mousePressed(MouseEvent e)
	{
		//游戏结束,退出
		if(this.isGameOver) {return;}
		
		//游戏未开始,开始游戏,不退出
	    if(this.isStart == false)
		{
			this.isStart = true;
			this.timer.start();
		}
		
        //判断是否鼠标左右键同时点击。该判断仅在鼠标按下事件中判断,我认为无论如何操作都可能会触发鼠标左键点击事件和鼠标右键点击事件。
	    if(e.getModifiersEx() == MouseEvent.BUTTON1_DOWN_MASK + MouseEvent.BUTTON3_DOWN_MASK)
	    {
	        Object obj = e.getSource();
	        if(obj instanceof JButton)
            {
            	JButton jbMine = (JButton)obj;
            	String location[] = jbMine.getName().split("_");
            	int row = Integer.parseInt(location[0]);
            	int column = Integer.parseInt(location[1]);
            	this.gameLogic.openCellAround(row, column);	//鼠标左右键同时点击会打开周围的格子
            }
	    }

	}

	/**
	 * 功能:鼠标释放事件监听<br>
	 */
	@Override
	public void mouseReleased(MouseEvent e) 
	{
		//游戏结束,退出
		if(this.isGameOver) {return;}
		
		//游戏未开始,开始游戏,不退出
	    if(this.isStart == false)
		{
			this.isStart = true;
			this.timer.start();
		}
		
        Object obj = e.getSource();
        
        //鼠标左键点击
        if(e.getButton() == MouseEvent.BUTTON1)
        {
            if(obj instanceof JButton)
            {
            	JButton jbMine = (JButton)obj;
            	String location[] = jbMine.getName().split("_");
            	int row = Integer.parseInt(location[0]);
            	int column = Integer.parseInt(location[1]);
            	this.gameLogic.openCell(row,column);	//打开该格子
            }
        }
        else if(e.getButton() == MouseEvent.BUTTON3)    //鼠标右键点击
        {
            if(obj instanceof JButton)
            {
	        	JButton jbMine = (JButton)obj;
	        	String location[] = jbMine.getName().split("_");
	        	int row = Integer.parseInt(location[0]);
	        	int column = Integer.parseInt(location[1]);
	        	if(this.mapMine[row][column].get("flag") == 0)		//处于未打开状态插红旗
	        	{
	        		this.mapMine[row][column].put("flag",2);
	        		this.buttonMine[row][column].setIcon(this.imageIconFlag);
	        		this.buttonMine[row][column].setPressedIcon(this.imageIconFlag);
	        		//更改地雷提示数字
	        		this.mineTip--;
	        		this.gameLogic.setNumberTip(this.mineTip,0);
	        	}
	        	else if(this.mapMine[row][column].get("flag") == 2)	//处于插红旗状态变问号
	        	{
	        		this.mapMine[row][column].put("flag",3);
	        		this.buttonMine[row][column].setIcon(this.imageIconQuestion);
	        		this.buttonMine[row][column].setPressedIcon(this.imageIconQuestion);
	        		//更改地雷提示数字
	        		this.mineTip++;
	        		this.gameLogic.setNumberTip(this.mineTip,0);
	        	}
	        	else if(this.mapMine[row][column].get("flag") == 3)	//处于问号状态变未打开
	        	{
	        		this.mapMine[row][column].put("flag",0);
	        		this.buttonMine[row][column].setIcon(this.imageIconCell);
	        		this.buttonMine[row][column].setPressedIcon(this.imageIconBlank);
	        	}
            }
        }
		
	}

	@Override
	public void mouseClicked(MouseEvent e){}
	
	@Override
	public void mouseEntered(MouseEvent e) {}

	@Override
	public void mouseExited(MouseEvent e) {}

}

 4. GameLogic.java game logic class.

package com.game.mine;

import java.awt.Color;
import javax.swing.JOptionPane;
import javax.swing.BorderFactory;

public class GameLogic
{
	/** 游戏面板 */
	private GamePanel gamePanel;
    
	/**
	 * 功能:构造函数<br>
	 */
	public GameLogic(GamePanel _gamePanel)
	{
		this.gamePanel = _gamePanel;
	}
        
	/**
	 * 功能:设置地雷数与时间提示<br>
	 * 参数:_number -> 要显示的数字<br>
	 * 参数:_flag -> 标识(0-地雷数,1-时间)<br>
	 */
	public void setNumberTip(int _number,int _flag)
	{
		if(_number <0){_number = 0;}
		
		//将数字转换为3位长字符串,前面不足补零
		String tip = "000" + Integer.toString(_number);
		tip = tip.substring(tip.length() - 3,tip.length());
		if(_flag == 0)      //显示剩余地雷数
		{
			if(_number > this.gamePanel.mineNum){_number = this.gamePanel.mineNum;}
		    for(int i=0;i<3;i++)
		    {
		        this.gamePanel.labelMineTip[i].setIcon(this.gamePanel.imageIconNumberTip[Integer.parseInt(tip.substring(i,i+1))]);
		    }
		}
		else if(_flag == 1)     //显示游戏时间
		{
			if(_number > 999){_number = 999;}
		    for(int i=0;i<3;i++)
		    {
		        this.gamePanel.labelTimeTip[i].setIcon(this.gamePanel.imageIconNumberTip[Integer.parseInt(tip.substring(i,i+1))]);
		    }
		}

	}

	/**
	 * 功能:模拟雷区组件不可用效果<br>
	 * 备注:只是模拟实际不好用,鼠标点击事件仍然执行。但起码表面看起来像是只读一样。<br>
	 */
	public void setMineAreaDisable()
	{
		for(int row=0;row<this.gamePanel.gridRows;row++)
		{
		    for(int column=0;column<this.gamePanel.gridColumns;column++)
		    {
		    	if(this.gamePanel.mapMine[row][column].get("flag") == 0)
		    	{
			    	this.gamePanel.buttonMine[row][column].setIcon(this.gamePanel.imageIconCell);
			    	this.gamePanel.buttonMine[row][column].setPressedIcon(this.gamePanel.imageIconCell);
		    	}
		    }
		}
	}
	
	/**
	 * 功能:重置所有的信息<br>
	 */
	public void resetAll()
	{
		//重置地雷按钮
		for(int row=0;row<this.gamePanel.gridRows;row++)
		{
		    for(int column=0;column<this.gamePanel.gridColumns;column++)
		    {
		    	this.gamePanel.buttonMine[row][column].setIcon(this.gamePanel.imageIconCell);
		    	this.gamePanel.buttonMine[row][column].setPressedIcon(this.gamePanel.imageIconBlank);
		    	this.gamePanel.buttonMine[row][column].setBorder(null);
		    }
		}
		//重置地雷信息
		for(int row=0;row<this.gamePanel.gridRows;row++)
		{
		    for(int column=0;column<this.gamePanel.gridColumns;column++)
		    {
		    	this.gamePanel.mapMine[row][column].put("number",0);	//0个雷
		    	this.gamePanel.mapMine[row][column].put("flag",0);		//未打开
		    }
		}
	}
	
	/**
	 * 功能:随机生雷并记录周围地雷数<br>
	 */
	public void randomMine()
	{
		//随机生成地雷
		for(int i=0;i<this.gamePanel.mineNum;)
		{
			int row = (int)(Math.random() * this.gamePanel.gridRows);
			int column = (int)(Math.random() * this.gamePanel.gridColumns);
			//判断该位置是否已经有雷
			if(this.gamePanel.mapMine[row][column].get("number") != -1)
			{
				this.gamePanel.mapMine[row][column].put("number",-1);
				i++;
			}
		}
		//记录周围的雷数
		for(int row=0;row<this.gamePanel.gridRows;row++)
		{
		    for(int column=0;column<this.gamePanel.gridColumns;column++)
			{
				if(this.gamePanel.mapMine[row][column].get("number") != -1)
				{
					this.gamePanel.mapMine[row][column].put("number",this.countMineAround(row,column));
				}
			}
		}
	}	
	
	/**
	 * 功能:计算周围的雷数<br>
	 * 备注:九宫格(上、下、左、右、左上、左下、右上、右下)<br>
	 */
	private int countMineAround(int _row,int _column)
	{
		int count = 0;
		for(int row=_row-1;row<=_row+1;row++)
		{
			if(row < 0 || row >= this.gamePanel.gridRows){continue;}	//行出边界了
			for(int column=_column-1;column<=_column+1;column++)
			{
				if(column < 0 || column >= this.gamePanel.gridColumns){continue;}	//列出边界了
				if(row == _row && column == _column){continue;}	//自身不计算在内
				if(this.gamePanel.mapMine[row][column].get("number") == -1){count++;}
			}
		}
		
		return count;
	}
	
	/**
	 * 功能:显示所有的雷<br>
	 */
	public void showMine()
	{
		for(int row=0;row<this.gamePanel.gridRows;row++)
		{
		    for(int column=0;column<this.gamePanel.gridColumns;column++)
		    {
		    	if(this.gamePanel.mapMine[row][column].get("number") == -1)
		    	{
		    		this.gamePanel.buttonMine[row][column].setIcon(this.gamePanel.imageIconMine);
		    		this.gamePanel.buttonMine[row][column].setPressedIcon(this.gamePanel.imageIconMine);
		    		this.gamePanel.mapMine[row][column].put("flag",1);
		    	}
		    }
		}
	}
	
	/**
	 * 功能:打开单元格<br>
	 * 备注:调用递归法<br>
	 */
	public void openCell(int _row,int _column)
	{
    	//System.out.println(_row+","+_column);

		//如果状态是已经打开或标注小红旗了就不往下判断了
		if(this.gamePanel.mapMine[_row][_column].get("flag") == 1 || this.gamePanel.mapMine[_row][_column].get("flag") == 2){return;}
		
		//设置该格子的边框为线条形(这个很重要,要不效果会很难看)
    	this.gamePanel.buttonMine[_row][_column].setBorder(BorderFactory.createLineBorder(Color.GRAY,1));

		if(this.gamePanel.mapMine[_row][_column].get("number") == -1)			//踩到地雷了
		{
			this.gamePanel.mapMine[_row][_column].put("flag",1);
			this.showMine();	//显示所有雷
    		this.gamePanel.buttonMine[_row][_column].setIcon(this.gamePanel.imageIconBomb);	//本格子的雷特殊标记
    		this.gamePanel.buttonMine[_row][_column].setPressedIcon(this.gamePanel.imageIconBomb);
    		this.setMineAreaDisable();	//雷区禁止点击,骗人的
			this.gamePanel.isGameOver = true;
    		this.gamePanel.isStart = false;
			this.gamePanel.timer.stop();
			return;
		}
		else if(this.gamePanel.mapMine[_row][_column].get("number") == 0)		//踩到空白处
		{
			this.gamePanel.mapMine[_row][_column].put("flag",1);
			this.gamePanel.buttonMine[_row][_column].setIcon(this.gamePanel.imageIconNumber[0]);
			this.gamePanel.buttonMine[_row][_column].setPressedIcon(this.gamePanel.imageIconNumber[0]);
			//开始判断周围四面八方的地雷数
			for(int row=_row-1;row<=_row+1;row++)
			{
				if(row < 0 || row >= this.gamePanel.gridRows){continue;}
				for(int column=_column-1;column<=_column+1;column++)
				{
					if(column < 0 || column >= this.gamePanel.gridColumns){continue;}
					if(row == _row && column == _column){continue;}
					if(this.gamePanel.mapMine[row][column].get("number") != -1){openCell(row,column);}	//如果是空白需采用递归法继续向该格子的四面八方判断地雷数,直到无空白格
				}
			}
		}
		else	//踩到数字处
		{
			this.gamePanel.mapMine[_row][_column].put("flag",1);
    		this.gamePanel.buttonMine[_row][_column].setIcon(this.gamePanel.imageIconNumber[this.gamePanel.mapMine[_row][_column].get("number")]);
    		this.gamePanel.buttonMine[_row][_column].setPressedIcon(this.gamePanel.imageIconNumber[this.gamePanel.mapMine[_row][_column].get("number")]);
		}
		
		//判断游戏是否结束
		if(this.GameOver())
		{
    		this.setMineAreaDisable();
			this.gamePanel.isGameOver = true;
    		this.gamePanel.isStart = false;
			this.gamePanel.timer.stop();
		}
		
	}

	/**
	 * 功能:打开周围的单元格<br>
	 * 备注:用于鼠标左右键同时点击事件<br>
	 */
	public void openCellAround(int _row,int _column)
	{
		//仅状态是已经打开且周围地雷数大于零时才生效
		if(this.gamePanel.mapMine[_row][_column].get("flag") == 1 || this.gamePanel.mapMine[_row][_column].get("number") > 0)
		{
			//如果它周围的雷都已经标记出来(插红旗),且没错误,那么它周围未打开的非雷格子都默认打开
			//先判断它周围有几个插了红旗的地雷,是否正确
			int count = 0;
			for(int row=_row-1;row<=_row+1;row++)
			{
				if(row < 0 || row >= this.gamePanel.gridRows){continue;}
				for(int column=_column-1;column<=_column+1;column++)
				{
					if(column < 0 || column >= this.gamePanel.gridColumns){continue;}
					if(row == _row && column == _column){continue;}
					if(this.gamePanel.mapMine[row][column].get("flag") == 2)	//插上小红旗了
					{
						if(this.gamePanel.mapMine[row][column].get("number") == -1)
						{
							count++;
						}
						else
						{
							//完蛋了,标记错误,结束游戏
							this.gamePanel.buttonMine[row][column].setIcon(this.gamePanel.imageIconWrongMine);
							this.gamePanel.buttonMine[row][column].setPressedIcon(this.gamePanel.imageIconWrongMine);
							this.gamePanel.mapMine[row][column].put("flag",1);
							this.showMine();
				    		this.setMineAreaDisable();
							this.gamePanel.isGameOver = true;
				    		this.gamePanel.isStart = false;
							this.gamePanel.timer.stop();
							return;
						}
					}
				}
			}
			if(count == this.gamePanel.mapMine[_row][_column].get("number"))	//当前格子附近的雷都已经挖出来了,那么默认它周围非雷的格子都打开。
			{
				for(int row=_row-1;row<=_row+1;row++)
				{
					if(row < 0 || row >= this.gamePanel.gridRows){continue;}
					for(int column=_column-1;column<=_column+1;column++)
					{
						if(column < 0 || column >= this.gamePanel.gridColumns){continue;}
						if(row == _row && column == _column){continue;}
						if(this.gamePanel.mapMine[row][column].get("flag") == 0 || this.gamePanel.mapMine[row][column].get("flag") == 3)
						{
							this.openCell(row,column);
						}
					}
				}
			}
		}

	}
	
	/**
	 * 功能:判断游戏是否结束<br>
	 */
	public boolean GameOver()
	{
		//判断未被打开的方格数与雷数是否相等
		int count = 0;
		for(int row=0;row<this.gamePanel.gridRows;row++)
		{
		    for(int column=0;column<this.gamePanel.gridColumns;column++)
		    {
	    		if(this.gamePanel.mapMine[row][column].get("flag") != 1){count++;}
		    }
		}
		if(count == this.gamePanel.mineNum)
		{
			this.gamePanel.isGameOver = true;
			JOptionPane.showMessageDialog(null,"恭喜您取得了胜利!");
			return true;
		}
		
		return false;
	}
}

Detailed explanation:

        slightly.

download: 

        Baidu network disk link: https://pan.baidu.com/s/1s_Q1UCvM4XZFd7wUvjCcTA Extraction code: yluk

Remarks:

        none.

Guess you like

Origin blog.csdn.net/lag_csdn/article/details/122062674