/**
* @(#)Block.java
*该类用于创建Block对象,将其放到游戏区的每个格子里面,里面存放着该“格子”的一些属性:
* *************************
* ——1. String name -->是雷时,存入“雷”
* 属性 ——|-2. boolean boo -->是雷时,为true,否则为false。我称为“雷性”
* ——3. int number -->用于存储周边,九回宫格内周边八个方格内的雷数
* *************************
* ——1. void setName(String name) -->设置name
* |-2. void setNumber(int i) -->设置周边雷数
* 方法 ——|-3. int getNumber() -->得到周边雷数
* |-4. String getName() -->得到name
* |-5. boolean isMine() -->判断雷性
* ——6. void setIsMine(boolean boo) -->设置雷性
* ***********************
*
* @author 宋俊林
* @version 1.00 /4/25
*/
public class Block {
String name; //是雷时,存入“雷”
int number; //用于存储周边,九回宫格内周边八个方格内的雷数
boolean boo = false; //是雷时,为true,否则为false。我称为“雷性”
//设置name
public void setName(String name){
this.name = name;
}
//得到name
public String getName(){
return name;
}
//设置周边雷数
public void setNumber(int i){
this.number = i;
}
//得到周边雷数
public int getNumber(){
return number;
}
//设置雷性
public void setIsMine(boolean boo){
this.boo = boo;
}
//判断雷性
public boolean isMine(){
return boo;
}
}
/**
* @(#)MineFrame.java
*
* 该类是主窗体类,该类将以Block类的实例和BlockView类的实例作为成员,并负责二者之间的交互
*
* @author 宋俊林
* @version 1.00 /4/25
*/
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class MineFrame extends JFrame implements ActionListener{
JButton reStart;
Block block[][];
BlockView blockView[][];
LayMines lay;
int row=10,colum=12,mineCount=22;
int colorSwitch = 0;
JPanel pCenter,pNorth;
public MineFrame() {
reStart = new JButton("重新开始"); //做一个restart按钮
pCenter = new JPanel(); //中心主游戏区面板
pNorth = new JPanel(); //上部控制面板
pNorth.setBackground(Color.gray);
block = new Block[row][colum];
for(int i=0;i
for(int j=0;j
block[i][j]=new Block();
}
}
lay = new LayMines();
lay.layMinesForBlock(block,mineCount);
blockView = new BlockView[row][colum];
pCenter.setLayout(new GridLayout(row,colum));
for(int i=0;i
for(int j=0;j
blockView[i][j] = new BlockView(); //实例化一个blockView数组
blockView[i][j].setName(block[i][j].getName());
pCenter.add(blockView[i][j]);
blockView[i][j].getBlockCover().addActionListener(this); //给每一小格添加监听器
}
}
reStart.addActionListener(this); //给reStart添加监听器
pNorth.add(reStart); //将组件添加到窗口中
add(pNorth,BorderLayout.NORTH);
add(pCenter,BorderLayout.CENTER);
setSize(200,232);
setVisible(true);
//pack();
addWindowListener(new WindowAdapter(){ //添加窗口关闭事件的监听
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
validate();
}
public void actionPerformed(ActionEvent e){
JButton source = (JButton)e.getSource();
if(source!=reStart){
int m = -1,n=-1;
for(int i=0;i
for(int j=0;j
//判断事件对象,如果是格子[i][j],则翻开,并将该对象存储到[m][n]
if(source==blockView[i][j].getBlockCover()){
m = i;
n = j;
break;
}
}
}
if(block[m][n].isMine()){
for(int i=0;i
for(int j=0;j
//如果[m][n]是雷,则游戏停止,移除所有格子的事件监听,按钮动作失效
//同时翻开所有是雷的按钮
blockView[i][j].getBlockCover().removeActionListener(this);
if(block[i][j].isMine())
blockView[i][j].seeBlockName();
}
}
}else{
if(block[m][n].getNumber()>0)
blockView[m][n].seeBlockName();
else{
//如果所采处雷数为0,则翻开周边
if(block[m][n].getNumber()==0){
for(int k=Math.max(m-1,0);k<=Math.min(m+1,row-1);k++){
for(int t=Math.max(n-1,0);t<=Math.min(n+1,colum-1);t++){
blockView[k][t].seeBlockName();
}
}
}
}
}
}
if(source==reStart){
for(int i=0;i
for(int j=0;j
block[i][j].setIsMine(false);
}
}
lay.layMinesForBlock(block,mineCount);
for(int i=0;i
for(int j=0;j
blockView[i][j].setName(block[i][j].getName());
blockView[i][j].seeBlockCover();
blockView[i][j].getBlockCover().addActionListener(this);
}
}
}
}
public static void main(String args[]){
new MineFrame();
}
}
/**
* @(#)BlockView.java
*
* 该类是为Block类创建视图,注意,要实现扫雷效果,则需要将试图分为两层,表层是按钮,底层是标签,
* 所以要用到CardLayout布局。另外,想在一个个格子里面放多各元件,得考虑用Panel容器,所以该视图类
* 继承自Panel
*
* @author 宋俊林
* @version 1.00 /4/25
*/
import java.awt.*;
import javax.swing.*;
public class BlockView extends JPanel {
JLabel blockName;
JButton blockCover;
CardLayout card;
BlockView(){ //在构造器中初始化各属性
card = new CardLayout();
setLayout(card);
blockName = new JLabel();
blockCover = new JButton();
add("cover",blockCover); //将blockCover添加到层面板
add("name",blockName); //将blockname添加到层面板
}
public void setName(String name){ //设置blockName的text
blockName.setText(name);
}
public String getName(){ //得到blockName的text
return blockName.getText();
}
public void seeBlockName(){ //显示blockName
card.show(this,"name");
validate();
}
public void seeBlockCover(){ //显示blockCover
card.show(this,"cover");
validate();
}
public JButton getBlockCover(){ //得到blockCover
return blockCover;
}
}
/**
* @(#)LayMines.java
*
* * 我感觉这个类时扫雷的算法核心,只要搞定这个类,其他都不是问题,该类只有一个主方法
* *---> void layMinesForBlock(Block block[][],int mineCount)
* * 其中:
* * 1.参数block[][]数组存放着整个游戏区的方格的block对象,一个方格对应一个
* * 同时,用二维数组也为实现扫描周边的九回宫格统计雷数提供支持
* * 2.参数mineCount来存放你想生成的类的个数
* * 3.这里还用到了集合LinkedList,来存储block[][]中的所有block对象,
*
*
* @author 宋俊林
* @version 1.00 /4/25
*/
import java.util.LinkedList;
public class LayMines {
public void layMinesForBlock(Block block[][],int mineCount){
int row = block.length;
int column = block[0].length;
LinkedList list = new LinkedList(); //创建list(用到范型)
for(int i=0;i
for(int j=0;j
list.add(block[i][j]); //利用循环,将block都加到列表list里
}
}
while(mineCount>0){
int size = list.size();
int randomIndex=(int)(Math.random()*size); //生产随机数,将这些随机数对应的block对象的属性设为是雷的属性
Block b = list.get(randomIndex); //根据随机数,取对应的block对象
b.setName("雷"); //将name设为‘雷’
b.setIsMine(true); //将雷性设为true
list.remove(randomIndex); //将list中是雷的节点删除,以免设置雷重复
mineCount--;
}
for(int i=0;i
for(int j=0;j
if(!block[i][j].isMine()){ //如果block[i][j]不是雷是执行下面的统计操作,扫描周边
int mineNumber = 0;
/**
* 我感觉下面是核心的核心,扫描周围的八个(但是在游戏区的边界上,可能不足八个格子),所以这里扫描是就得处理边界问题
*这里为防止越界,用的是比较大小取值的方法,很精妙“Math.max(j-1,0)”;下面是扫描图:
* [———————————————————————————]
* [(i-1,j-1)|(i-1,j)|(i-1,j+1)]
* [———————————————————————————]
* [ (i,j-1) | (i,j) | (i,j+1)]
* [———————————————————————————]
* [(i+1,j-1)|(i+i,j)|(i+1,j+1)]
* [———————————————————————————]
*/
for(int k=Math.max(i-1,0);k<=Math.min(i+1,row-1);k++){
for(int t=Math.max(j-1,0);t<=Math.min(j+1,column-1);t++){
if(block[k][t].isMine()){
mineNumber++;
}
}
}
block[i][j].setName(""+mineNumber); //将name存为number后边会进行显示
block[i][j].setNumber(mineNumber); //将周边的雷数存入number中
}
}
}
}
}