频道栏目
首页 > 程序开发 > 软件开发 > java教程 > Java实例 > 正文
扫雷(java版)
2016-08-09 09:32:49      个评论    来源:苏苏爱自由  
收藏   我要投稿

首先说一下扫雷规则。

1.数字是几就表示此数字位置邻接的八个方向有几个地雷

2.鼠标右键单击一次标记此位置为地雷(插上一个小旗),再单击一次标记为?

3.鼠标左键单击某位置

如果这个位置上的数字为1-8 即显示

如果为数字为0(即空白) 自动延伸八个方向直到遇见数字(1-8)为止

如果为地雷,游戏失败

4.当地图上的所有数字都点击完毕 游戏胜利

首先是MineClient类,初始化地雷,有刷新线程,画图等等

 

package com.xynu.mine;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;

import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JSeparator;

public class MineClient extends JFrame {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	//屏幕宽度
	private int screenWidth;
	//屏幕高度
	private int screenHeight;
	//图片宽度
	private int imgWidth = 20;
	//图片高度
	private int imgHeight = 20;
	//地图的行数
	private int rowNum = 0;
	//地图的列数
	private int colNum = 0;
	//地雷的总数
	private int mineNum=99;
	//计时器
	private int timer=0;
	//游戏时间
	private int time=0;
	//未扫雷的个数
	private int restMine;
	//不是雷的个数
	private int notMine;
	private MyPanel myPanel;
	//当前游戏状态
	private String gameState = "start";
	//第一次点击
	private boolean firstClick = true;
	private JMenuBar menuBar;
	private JMenu menu;
	private JMenuItem lowLevel;
	private JMenuItem midLevel;
	private JMenuItem heightLevel;
	private JMenuItem restart;
	private Toolkit tk=Toolkit.getDefaultToolkit();
	private Image icon=tk.getImage("Image/icon.jpg");
	//地图集合
	private ArrayList bombList = new ArrayList();


	public MineClient(int screenWidth,int screenHeight,int mineNum) {
		this.screenHeight=screenHeight;
		this.screenWidth=screenWidth;
		this.mineNum=mineNum;
		//初始化菜单栏
		initMenu();
		setTitle("扫雷");
		setIconImage(icon);
		setSize(screenWidth	, screenHeight);
		setLocationRelativeTo(null);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setVisible(true);
		initList();
		myPanel = new MyPanel();
		myPanel.setBackground(Color.BLACK);
		add(myPanel);
		//鼠标事件
		myPanel.addMouseListener(new MyMouseListener(this));
		new updateThread().start();
	}
	/*
	 * 初始化菜单栏
	 */
	private void initMenu() {
		menu=new JMenu("参数设置");
		menuBar=new JMenuBar();
		lowLevel=new JMenuItem("初级(10个雷)");
		midLevel=new JMenuItem("中级(44个雷)");
		heightLevel=new JMenuItem("高级(99个雷)");
		restart=new JMenuItem("重新开始");
		lowLevel.addActionListener(new ActionListener() {
			
			public void actionPerformed(ActionEvent e) {
				// TODO Auto-generated method stub
				dispose();
				new MineClient(225,305,10);
			}
		});
		midLevel.addActionListener(new ActionListener() {
			
			public void actionPerformed(ActionEvent e) {
				// TODO Auto-generated method stub
				dispose();
				new MineClient(380,460,44);
			}
		});
		heightLevel.addActionListener(new ActionListener() {
			
			public void actionPerformed(ActionEvent e) {
				// TODO Auto-generated method stub
				dispose();
				new MineClient(660,460,99);
			}
		});
		restart.addActionListener(new ActionListener() {
			
			public void actionPerformed(ActionEvent e) {
				// TODO Auto-generated method stub
				dispose();
				new MineClient(screenWidth,screenHeight,mineNum);
			}
		});
		menu.add(restart);
		menu.add(new JSeparator());
		menu.add(lowLevel);
		menu.add(midLevel);
		menu.add(heightLevel);
		menuBar.add(menu);
		setJMenuBar(menuBar);
	}
	
	public boolean isFirstClick() {
		return firstClick;
	}
	public void setFirstClick(boolean firstClick) {
		this.firstClick = firstClick;
	}
	public int getImgWidth() {
		return imgWidth;
	}
	
	public void setImgWidth(int imgWidth) {
		this.imgWidth = imgWidth;
	}

	public int getImgHeight() {
		return imgHeight;
	}

	public void setImgHeight(int imgHeight) {
		this.imgHeight = imgHeight;
	}
	
	public MyPanel getMyPanel() {
		return myPanel;
	}

	public void setMyPanel(MyPanel myPanel) {
		this.myPanel = myPanel;
	}
	public String getGameState() {
		return gameState;
	}

	public void setGameState(String gameState) {
		this.gameState = gameState;
	}
	
	public ArrayList getBombList() {
		return bombList;
	}

	public int getRowNum() {
		return rowNum;
	}

	public void setRowNum(int rowNum) {
		this.rowNum = rowNum;
	}

	public int getColNum() {
		return colNum;
	}

	public void setColNum(int colNum) {
		this.colNum = colNum;
	}
	
	public int getMineNum() {
		return mineNum;
	}

	//创建地图
	private void initList() {
		for (int i = imgWidth; i < this.getWidth() - 2 * imgWidth; i += imgWidth) {
			for (int j = imgWidth; j < this.getHeight() - 6 * imgWidth; j += imgHeight) {
				rowNum = rowNum > i / imgWidth ? rowNum : i / imgWidth;
				colNum = colNum > j / imgWidth ? colNum : j / imgWidth;
				Bomb bomb = new Bomb(i, j, 13, this);
				bombList.add(bomb);
			}
		}
	}
	
	public static void main(String[] args) {
		new MineClient(225,305,10);
		
	}
	
	
	//自定义panel
	public class MyPanel extends JPanel {
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		public void paint(Graphics g) {
			super.paintComponent(g);
			restMine=mineNum;
			notMine=0;
			//画地雷 数字
			for (Bomb bomb : bombList) {
				bomb.draw(g);
				if(bomb.getWhat()==11)
					restMine--;
				if(bomb.getWhat()>=0&&bomb.getWhat()<=8)
					notMine++;
			}
			//游戏失败
			if (gameState.equals("lose")) {
				for (Bomb bomb : bombList) {
					if (bomb.getHide() == 9) {
						bomb.setWhat(bomb.getHide());
					}
				}
				Font font = new Font("微软雅黑", Font.BOLD, 20);
				g.setFont(font);
				g.setColor(new Color(255, 0, 255));
				g.drawString("GAME OVER!!", this.getWidth() / 2 - 80,
						this.getHeight() / 2);
			}
			//画当前游戏进行时间  和未扫的地雷数目
			drawTimeAndMineNum(g);
			
			//取得游戏胜利
			if(!gameState.equals("lose")&¬Mine+mineNum==colNum*rowNum)
			{
				gameState="win";
				Toolkit tk=Toolkit.getDefaultToolkit();
				Image img=tk.getImage("Image/win.jpg");
				g.drawImage(img, 0, 0, this.getWidth(), this.getHeight(), this);
				Font font1 = new Font("华文行楷", Font.BOLD, 40);
				g.setFont(font1);
				g.setColor(new Color(248 ,29 ,56));
				g.drawString("YOU WIN!!!", this.getWidth()/2-100, 30);
			}
		}

		private void drawTimeAndMineNum(Graphics g) {
			Font font = new Font("微软雅黑", Font.BOLD, 15);
			g.setFont(font);
			g.setColor(Color.orange);
			g.drawString("已用时:"+time+" 秒", 0, this.getHeight()-20);
			g.drawString("未扫雷:"+restMine+" 个", this.getWidth()-100, this.getHeight()-20);
			
		}
	}
	//屏幕每隔100ms刷新一次
	public class updateThread extends Thread {
		public void run() {

			while (true) {
				repaint();
				if(!firstClick){
					timer+=100;
					if(timer==1000){
						timer=0;
						time++;
					}
				}
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}
}

然后是Bomb封装类。

 

解释两个变量。、

what表示当前地雷(不一定是地雷)所画的内容

hide表示当前地雷(不一定是地雷)真实的内容

解释两个方法

 

public Rectangle getRec() {
		return new Rectangle(x, y, w, h);
}
返回当前地雷的矩形,具体作用我会在MyMouseListener类里面说

 

 

draw(Graphics g)

draw方法 主要实在panel里面画图

 

 

 

package com.xynu.mine;

import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Toolkit;

public class Bomb {
	private int x;
	private int y;
	private int what;
	private int hide = 0;
	private int w = 19;
	private int h = 19;
	private MineClient mc;
	private Toolkit tk = Toolkit.getDefaultToolkit();
	private Image bomb = tk.getImage("Image/bomb.jpg");
	private Image bomb0 = tk.getImage("Image/bomb0.jpg");
	private Image zeroBomb = tk.getImage("Image/0.jpg");
	private Image oneBomb = tk.getImage("Image/1.jpg");
	private Image twoBomb = tk.getImage("Image/2.jpg");
	private Image threeBomb = tk.getImage("Image/3.jpg");
	private Image fourBomb = tk.getImage("Image/4.jpg");
	private Image fiveBomb = tk.getImage("Image/5.jpg");
	private Image sixBomb = tk.getImage("Image/6.jpg");
	private Image severnBomb = tk.getImage("Image/7.jpg");
	private Image eightBomb = tk.getImage("Image/8.jpg");
	private Image flag = tk.getImage("Image/flag.jpg");
	private Image flag2 = tk.getImage("Image/flag2.jpg");
	private Image bg = tk.getImage("Image/s.jpg");

	public Bomb() {
		super();
		// TODO Auto-generated constructor stub
	}

	public Bomb(int x, int y, int what, MineClient mc) {
		super();
		this.x = x;
		this.y = y;
		this.what = what;
		this.mc = mc;
	}

	public int getX() {
		return x;
	}

	public void setX(int x) {
		this.x = x;
	}

	public int getY() {
		return y;
	}

	public void setY(int y) {
		this.y = y;
	}

	public int getWhat() {
		return what;
	}

	public void setWhat(int what) {
		this.what = what;
	}

	public int getHide() {
		return hide;
	}

	public void setHide(int hide) {
		this.hide = hide;
	}
	//画地雷 数字
	public void draw(Graphics g) {
		switch (what) {
		case 0:
			g.drawImage(zeroBomb, x, y, w, h, mc);
			break;
		case 1:
			g.drawImage(oneBomb, x, y, w, h, mc);
			break;
		case 2:
			g.drawImage(twoBomb, x, y, w, h, mc);
			break;
		case 3:
			g.drawImage(threeBomb, x, y, w, h, mc);
			break;
		case 4:
			g.drawImage(fourBomb, x, y, w, h, mc);
			break;
		case 5:
			g.drawImage(fiveBomb, x, y, w, h, mc);
			break;
		case 6:
			g.drawImage(sixBomb, x, y, w, h, mc);
			break;
		case 7:
			g.drawImage(severnBomb, x, y, w, h, mc);
			break;
		case 8:
			g.drawImage(eightBomb, x, y, w, h, mc);
			break;
		case 9:
			g.drawImage(bomb, x, y, w, h, mc);
			break;
		case 10:
			g.drawImage(bomb0, x, y, w, h, mc);
			break;
		case 11:
			g.drawImage(flag, x, y, w, h, mc);
			break;
		case 12:
			g.drawImage(flag2, x, y, w, h, mc);
			break;
		case 13:
			g.drawImage(bg, x, y, w, h, mc);
			break;
		}
	}
	
	public Rectangle getRec() {
		return new Rectangle(x, y, w, h);
	}
}
MyMouseListener类(自定义的鼠标事件)

 

最难的都在这里面了

1.开始玩游戏的时候要保证第一下点击的不是地雷

2.点击到数字0(空白)时自动延伸

解决:

在解决问题之前 我们要首先知道鼠标点击的是哪个地雷

 

		int x = e.getX();
		int y = e.getY();
		Rectangle rec = new Rectangle(x, y, 1, 1);
		for (Bomb bomb : bombList) {
			if(rec.intersects(bomb.getRec())){
				//表示鼠标矩形和地雷矩形相交
			}
		}

解释一下,我们可以通过getx() ,gety()方法获得当前鼠标的坐标 然后把鼠标的宽和高认为1 new一个矩形对象

 

然后通过API提供的intersects方法判断两个矩形是否相交,也就是鼠标点击的地雷位置

1.为了保证第一次点击时点击不到地雷,我们在mousePressed(MouseEvent e)方法中初始化地图,把当前鼠标

点击的位置设置为地雷,当随机初始完地雷后再把当前位置恢复默认

2.这个应该是最难的了吧。当然 如果你学过算法中的搜索 那么久太简单了

DFS和BFS都行。从当前位置出发,向它的八个方向进行深搜 直到遇到数字结束当前递归

感觉这两个比较难 其它的有疑问可以留言 一起解决~~

package com.xynu.mine;

import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Random;

public class MyMouseListener extends MouseAdapter {
	private MineClient mc;
	private int colNum;
	private int rowNum;
	private boolean isFirstClick;
	private ArrayList bombList = new ArrayList();
	boolean[] vis ;
	public MyMouseListener() {
		super();
		// TODO Auto-generated constructor stub
	}

	public MyMouseListener(MineClient mc) {
		super();
		this.mc = mc;
		colNum = mc.getColNum();
		rowNum = mc.getRowNum();
		vis = new boolean[colNum * rowNum];
		bombList = mc.getBombList();
		this.isFirstClick=mc.isFirstClick();
	}
	/*
	 * 鼠标松下事件
	 * 如果松下的是鼠标左键  那么显示当前位置的地雷
	 * 如果松下的鼠标右键  那么标记当前位置
	 * @see java.awt.event.MouseAdapter#mouseReleased(java.awt.event.MouseEvent)
	 */
	public void mouseReleased(MouseEvent e) {
		if (mc.getGameState().equals("lose")) {
			return;
		}
		int x = e.getX();
		int y = e.getY();
		Rectangle rec = new Rectangle(x, y, 1, 1);
		if (e.getButton() == MouseEvent.BUTTON1) {
			for (Bomb bomb : bombList) {
				if (rec.intersects(bomb.getRec())) {
					if (bomb.getHide() == 9) {
						mc.setGameState("lose");
					} else {
						if (bomb.getHide() == 0) {
							increasePoint(bombList.indexOf(bomb));
						}
						bomb.setWhat(bomb.getHide());
					}

				}
			}
		}
		if (e.getButton() == MouseEvent.BUTTON3) {
			for (Bomb bomb : bombList) {
				if (rec.intersects(bomb.getRec())) {
					if(bomb.getWhat()!=bomb.getHide()){
						if(bomb.getWhat()==13){
							bomb.setWhat(11);
						}
						else if(bomb.getWhat()==11){
							bomb.setWhat(12);
						}
						else if(bomb.getWhat()==12){
							bomb.setWhat(13);
						}
					}
				}
			}
		}

	}

	//自动扩大区域直到遇见数字
	private void increasePoint(int index) {
		if (vis[index])
			return;
		vis[index] = true;
		boolean edgeU = false, edgeD = false;
		if ((index + 1) % (colNum) != 0)
			edgeU = true;
		if (index % (colNum) != 0)
			edgeD = true;
		if (judgeLimit(index - 1) && edgeD) {
			Bomb bomb = bombList.get(index - 1);
			setVis(bomb, index - 1);
		}

		if (judgeLimit(index + 1) && edgeU) {
			Bomb bomb = bombList.get(index + 1);
			setVis(bomb, index + 1);
		}

		if (judgeLimit(index - colNum)) {
			Bomb bomb = bombList.get(index - colNum);
			setVis(bomb, index - colNum);
		}

		if (judgeLimit(index + colNum)) {
			Bomb bomb = bombList.get(index + colNum);
			setVis(bomb, index + colNum);
		}

		if (judgeLimit(index - colNum + 1) && edgeU) {
			Bomb bomb = bombList.get(index - colNum + 1);
			setVis(bomb, index - colNum + 1);
		}

		if (judgeLimit(index - colNum - 1) && edgeD) {
			Bomb bomb = bombList.get(index - colNum - 1);
			setVis(bomb, index - colNum - 1);
		}

		if (judgeLimit(index + colNum + 1) && edgeU) {
			Bomb bomb = bombList.get(index + colNum + 1);
			setVis(bomb, index + colNum + 1);
		}

		if (judgeLimit(index + colNum - 1) && edgeD) {
			Bomb bomb = bombList.get(index + colNum - 1);
			setVis(bomb, index + colNum - 1);
		}

	}
	//判断边界
	private boolean judgeLimit(int i) {
		if (i >= 0 && i < bombList.size())
			return true;
		return false;
	}
	//显示某位置
	public void setVis(Bomb bomb, int index) {
		if (bomb.getWhat() == bomb.getHide() && bomb.getWhat() != 0)
			return;
		if (bomb.getHide() >= 0 && bomb.getHide() <= 8 && bomb.getHide() != 9) {
			bomb.setWhat(bomb.getHide());
			if (bomb.getWhat() == 0)
				increasePoint(index);
		} else {
			increasePoint(index);
		}
	}
	/*
	 * 按下鼠标左键的同时开始初始化地图
	 * @see java.awt.event.MouseAdapter#mousePressed(java.awt.event.MouseEvent)
	 */
	@Override
	public void mousePressed(MouseEvent e) {
		if (mc.getGameState().equals("lose")) {
			return;
		}
		if (e.getButton() == MouseEvent.BUTTON1) {
			if (isFirstClick) {
				isFirstClick = false;
				mc.setFirstClick(false);
				initBomb(e);
				checkBomb();
			}
		}
	}

	private void checkBomb() {

		for (Bomb bomb : bombList) {
			int x = bombList.indexOf(bomb);
			//edgeU edgeD边界状态值
			boolean edgeU = false, edgeD = false;
			if ((x + 1) % (colNum) != 0)
				edgeU = true;
			if (x % (colNum) != 0)
				edgeD = true;
			if (bomb.getHide() != 9) {
				if (judge(x - 1) && edgeD)
					bomb.setHide(bomb.getHide() + 1);
				if (judge(x + 1) && edgeU)
					bomb.setHide(bomb.getHide() + 1);
				if (judge(x - colNum))
					bomb.setHide(bomb.getHide() + 1);
				if (judge(x + colNum))
					bomb.setHide(bomb.getHide() + 1);
				if (judge(x - colNum + 1) && edgeU)
					bomb.setHide(bomb.getHide() + 1);
				if (judge(x - colNum - 1) && edgeD)
					bomb.setHide(bomb.getHide() + 1);
				if (judge(x + colNum + 1) && edgeU)
					bomb.setHide(bomb.getHide() + 1);
				if (judge(x + colNum - 1) && edgeD)
					bomb.setHide(bomb.getHide() + 1);
			}
		}
	}
	//判断某位置是否是地雷
	private boolean judge(int x) {
		if (x >= 0 && x < bombList.size()) {
			if (bombList.get(x).getHide() == 9)
				return true;
		}
		return false;
	}
	/*
	 * 初始化地雷
	 */
	private void initBomb(MouseEvent e) {
		int x = e.getX();
		int y = e.getY();
		Rectangle rec = new Rectangle(x, y, 1, 1);
		Bomb bombTemp=new Bomb();	
		int what=0;
		//为了避免第一下点击的不是地雷 首先让它设置为地雷,初始化地雷完成后 在恢复原样
		for (Bomb bomb : bombList) {
			if(rec.intersects(bomb.getRec())){
				what=bomb.getHide();
				bombTemp=bomb;
				bomb.setHide(9);
				break;
			}
		}
		//使用随机数  初始化地图 
		Random r = new Random();
		for (int i = 0; i < mc.getMineNum(); i++) {
			while (true) {
				int index = r.nextInt(bombList.size());
				if (bombList.get(index).getHide() != 9) {
					bombList.get(index).setHide(9);
					break;
				}
			}
		}
		bombTemp.setHide(what);
	}
}
还是自己的扫雷玩着有意思 哈哈

 

如果有问题 可以留言哦~一起解决

\\

所有代码+图片

下载地址:

点击打开链接


 

点击复制链接 与好友分享!回本站首页
相关TAG标签
上一篇:java-截取字符串的substring和substr
下一篇:【自学笔记】简单java电话本管理系统v1.0源码
相关文章
图文推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站