You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

275 lines
10 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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;
}