diff --git a/src/MineClearance.java b/src/MineClearance.java new file mode 100644 index 0000000..b43b306 --- /dev/null +++ b/src/MineClearance.java @@ -0,0 +1,275 @@ +package Gamewinmine3; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.*; + +public class MineClearance { + static private int midtime = 3600,mineNum = 0;/* 倒计时时间以及可用旗子数 */ + private static ImageIcon face = new ImageIcon("E:\\java_soft\\ceshi\\src\\Gamewinmine3\\face.jpg");/* 小黄脸图标 */ + static private JLabel label1,label2;/* 提示文字 */ + static private GamePanel gp;/* 雷区 */ + + MineClearance(){ + /* 绘制窗口 */ + JFrame f = new JFrame("扫雷"); + f.setBounds(600,200,500,600); + f.setDefaultCloseOperation(3); + f.setLayout(null); + label1 = new JLabel("剩余时间:" +(midtime / 60 / 60 % 60) + ":"+ (midtime / 60 % 60)+ ":" +(midtime % 60)); + label1.setBounds(10,20,120,20); + f.add(label1); + /* 显示旗子数 */ + label2 = new JLabel("剩余:"+mineNum); + label2.setBounds(400,20,120,20); + f.add(label2); + /* 重置按钮 */ + JButton bt = new JButton(face); + bt.setBounds(230, 15,30,30); + bt.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + f.dispose(); + midtime = 3600; + new MineClearance(); + } + }); + f.add(bt); + /* 绘制雷区 */ + gp = new GamePanel(20,20); + gp.setBounds(40,100,400,400); + f.add(gp); + /* 显示界面 */ + f.setVisible(true); + } + /* 倒计时线程 */ + static class CountDown extends Thread{ + public void run(){ + while (midtime > 0){ + try{ + -- midtime; + label1.setText("剩余时间:" +(midtime / 60 / 60 % 60) + ":"+ (midtime / 60 % 60)+ ":" +(midtime % 60)); + this.sleep(1000); + }catch (Exception e){ + System.out.println("错误:" + e.toString()); + } + } + if(midtime == 0) { + gp.showBomb(); + JOptionPane.showMessageDialog(null,"时间已到","游戏结束",JOptionPane.PLAIN_MESSAGE); + } + } + + } + public static void main(String[] args){ + new MineClearance(); + /* 倒计时 */ + CountDown cd = new CountDown(); + cd.start(); + } + /* 修改旗子数 */ + public static void setMineNum(int i){ + mineNum = i; + label2.setText("剩余:"+mineNum); + } +} + +class GamePanel extends JPanel { + private int rows, cols, bombCount,flagNum; + private final int BLOCKWIDTH = 20; + private final int BLOCKHEIGHT = 20; + private JLabel[][] label; + private boolean[][] state; + private Btn[][] btns; + private byte[][] click; + private static ImageIcon flag = new ImageIcon("E:\\java_soft\\ceshi\\src\\Gamewinmine3\\flag.jpg"); + private static ImageIcon bomb = new ImageIcon("E:\\java_soft\\ceshi\\src\\Gamewinmine3\\bomb.jpg"); + private static ImageIcon lucency = new ImageIcon("E:\\java_soft\\ceshi\\src\\Gamewinmine3\\lucency.png"); + /* 构造雷区 */ + public GamePanel(int row, int col) { + rows = row;/* 行数 */ + cols = col;/* 列数 */ + bombCount = rows * cols / 10; /* 地雷数 */ + flagNum = bombCount;/* 标记数(用于插旗) */ + label = new JLabel[rows][cols]; + state = new boolean[rows][cols];/* 用于存储是否有地雷 */ + btns = new Btn[rows][cols]; + click = new byte[rows][cols];/* 用于存储按钮点击状态(0-未点击,1-已点击,2-未点击但周围有雷,3-插旗) */ + MineClearance.setMineNum(flagNum); + setLayout(null); + initLable(); + randomBomb(); + writeNumber(); + randomBtn(); + } + + public void initLable() { + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + JLabel l = new JLabel("", JLabel.CENTER); + // 设置每个小方格的边界 + l.setBounds(j * BLOCKWIDTH, i * BLOCKHEIGHT, BLOCKWIDTH, BLOCKHEIGHT); + // 绘制方格边框 + l.setBorder(BorderFactory.createLineBorder(Color.GRAY)); + // 设置方格为透明,便于我们填充颜色 + l.setOpaque(true); + // 背景填充为黄色 + l.setBackground(Color.lightGray); + // 将方格加入到容器中(即面板JPanel) + this.add(l); + // 将方格存到类变量中,方便公用 + label[i][j] = l; + label[i][j].setVisible(false); + } + } + } + + /* 绘制地雷 */ + private void randomBomb() { + for (int i = 0; i < bombCount; ++i) { + int rRow = (int) (Math.random() * rows); + int rCol = (int) (Math.random() * cols); + if (state[rRow][rCol] == true) --i; + label[rRow][rCol].setIcon(bomb); + state[rRow][rCol] = true;/* 有地雷的格子state为真 */ + } + } + + /* 绘制数字 */ + private void writeNumber() { + for (int i = 0; i < rows; ++i) { + for (int j = 0; j < cols; ++j) { + if (state[i][j]) { + continue; + } + int bombCount = 0; + /* 寻找以自己为中心的九个格子中的地雷数 */ + for (int r = -1; (r + i < rows) && (r < 2); ++r) { + if (r + i < 0) continue; + for (int c = -1; (c + j < cols) && (c < 2); ++c) { + if (c + j < 0) continue; + if (state[r + i][c + j]) ++bombCount; + } + } + if (bombCount > 0) { + click[i][j] = 2; + label[i][j].setText(String.valueOf(bombCount)); + } + } + } + } + /* 绘制按钮 */ + private void randomBtn() { + for (int i = 0; i < rows; ++i) { + for (int j = 0; j < cols; ++j) { + Btn btn = new Btn(); + btn.i = i; + btn.j = j; + btn.setBounds(j * BLOCKWIDTH, i * BLOCKHEIGHT, BLOCKWIDTH, BLOCKHEIGHT); + this.add(btn); + btns[i][j] = btn; + btn.addMouseListener(new MouseAdapter() { + public void mouseClicked(MouseEvent e) { + /* 左键点击,屏蔽插旗格子的点击事件 */ + if(e.getButton() == MouseEvent.BUTTON1) { + if(click[btn.i][btn.j] != 3) open(btn); + } + /* 右键点击 */ + if(e.getButton() == MouseEvent.BUTTON3) placeFlag(btn); + } + + } + ); + + } + } + + } + + /* 打开这个雷区 */ + private void open(Btn b){ + /* 踩雷 */ + if(state[b.i][b.j]){ + for (int r = 0;r < rows;++r){ + for(int c = 0;c < cols; ++c){ + btns[r][c].setVisible(false);/* 隐藏label */ + label[r][c].setVisible(true);/* 显示按钮(这里只有隐藏了按钮才能显示按钮下面的label) */ + } + } + JOptionPane.showMessageDialog(null,"您失败了","游戏结束",JOptionPane.PLAIN_MESSAGE); + }else /* 没有踩雷 */{ + subopen(b); + } + } + /* 递归打开周边雷区 */ + private void subopen(Btn b){ + /* 有雷,不能打开 */ + if(state[b.i][b.j]) return; + /* 打开过的和插旗的,不用打开 */ + if(click[b.i][b.j] == 1 || click[b.i][b.j] == 3) return; + /* 周围有雷的,只打开它 */ + if(click[b.i][b.j] == 2) { + b.setVisible(false); + label[b.i][b.j].setVisible(true); + click[b.i][b.j] = 1; + return; + } + /* 打开当前这个按钮 */ + b.setVisible(false); + label[b.i][b.j].setVisible(true); + click[b.i][b.j] = 1; + /* 递归检测周边八个按钮 */ + for (int r = -1; (r + b.i < rows) && (r < 2); ++r) { + if (r + b.i < 0) continue; + for (int c = -1; (c + b.j < cols) && (c < 2); ++c) { + if (c + b.j < 0) continue; + if (r==0 && c==0) continue; + Btn newbtn = btns[r + b.i][c + b.j]; + subopen(newbtn); + } + } + } + /* 插旗 */ + private void placeFlag(Btn b){ + /* 只能插和地雷数相同数目的旗子 */ + if(flagNum>0){ + /* 插过旗的,再点一次取消 */ + if(click[b.i][b.j] == 3){ + if(label[b.i][b.j].getText() == "[0-9]") click[b.i][b.j] = 2; + else click[b.i][b.j] = 0; + b.setIcon(lucency); + ++ flagNum; + MineClearance.setMineNum(flagNum); + }else /* 未插旗的,插旗 */{ + b.setIcon(flag); + click[b.i][b.j] = 3; + -- flagNum; + MineClearance.setMineNum(flagNum); + } + /* 把所有旗子插完了,检测是否成功 */ + if(flagNum == 0){ + boolean flagstate = true; + for(int i = 0;i < rows; ++i){ + for(int j = 0;j < cols; ++j){ + if (click[i][j] != 3 && state[i][j]) flagstate = false; + } + } + if(flagstate) JOptionPane.showMessageDialog(null,"您成功了","游戏结束",JOptionPane.PLAIN_MESSAGE); + } + }else /* 旗子用完了,不能插 */{ + JOptionPane.showMessageDialog(null,"标记已用尽","错误操作",JOptionPane.PLAIN_MESSAGE); + } + } + /* 显示雷区 */ + public void showBomb(){ + for (int r = 0;r < rows;++r){ + for(int c = 0;c < cols; ++c){ + btns[r][c].setVisible(false);/* 隐藏label */ + label[r][c].setVisible(true);/* 显示按钮(这里只有隐藏了按钮才能显示按钮下面的label) */ + } + } + } +} + +class Btn extends JButton{ + public int i,j; +} \ No newline at end of file