通过Java awt 界面上的知识编写的扫雷游戏

代码中有详细的注解

package com.langsin.saolei;

import java.awt.Color;
import java.awt.Font;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.Insets;
import java.awt.Label;
import java.awt.Menu;
import java.awt.MenuBar;
import java.awt.MenuItem;
import java.awt.MenuShortcut;
import java.awt.TextArea;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

public class Saolei extends Frame implements ActionListener {
// 先定义横向的按钮的个数和纵向的按钮的个
private static int WITH = 10;
private static int LENG = 10;
// 定义地雷的个数
private static int Mines_Count = 10;
// 定义旗帜的个数
private static int Red_Count = 10;
// 定义一个random类
private static Random random = new Random();
// 定义一个二维数组
private static Bomb[][] jb = new Bomb[WITH][LENG];
// 判断是否结束
private boolean flag = false;
// 判断是否成功 默认是没有成功
private boolean sucess = false;
// 用集合暂存sucess.txt中的内容
private List<String> list = new ArrayList<String>();
// 用集合暂存游戏时间
private List<String> listtime = new ArrayList<String>();
StringBuffer buffer = new StringBuffer();
// 定义一个面板成员变量
private JPanel jp;
// 记录时间的线程
private Runnable runnable;
// 已用时间
private int usedTime = 0;
// 定义两个标签 时间和旗帜
private Label time, redFlag;
/*
* 检测某点周围是否有雷,周围点的坐标可由该数组计算得到
*/
private int[][] mv = { { 1, 0 }, { -1, 0 }, { 0, 1 }, { 0, -1 }, { 1, 1 },
{ -1, -1 }, { 1, -1 }, { -1, 1 } };

// 通过构造器初始化
public Saolei() throws Exception {
super("扫雷");
// 绝对布局管理器
this.setLayout(null);
// 设置图标
this.setIconImage(ImageIO.read(new File("./image/图标.jpg")));
// 设置大小
this.setBounds(100, 100, 500, 500);
this.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
setMenu();
intMine();
intBottom();
this.setResizable(false);
this.setVisible(true);
}

// 设置初始化菜单
public void setMenu() {
// 菜单条
MenuBar menbar = new MenuBar();
// 菜单项 游戏
Menu game = new Menu("游戏(G)");
// 菜单项游戏的组件 新游戏
MenuItem newgame = new MenuItem("新游戏");
// 游戏从新开始

newgame.addActionListener(new ActionListener() {

@Override
public void actionPerformed(ActionEvent e) {
// 调用重新开始游戏的方法
resetGame();
}
});
game.add(newgame);

// 菜单项游戏的组件 更改外观
MenuItem change = new MenuItem("更改外观");
change.addActionListener(new ActionListener() {

@Override
public void actionPerformed(ActionEvent e) {
for (int i = 0; i < WITH; i++) {
for (int j = 0; j < LENG; j++) {
if (!jb[i][j].isIsclicked() && jb[i][j].isEnabled()) {
jb[i][j].setBackground(Color.BLUE);
} else {
jb[i][j].setBackground(Color.WHITE);
}
}
}
}
});
game.add(change);
// 加一条横线
// game.addSeparator();
game.add(new MenuItem("-"));
// 菜单项游戏的组件 退出
MenuItem exit = new MenuItem("退出",
new MenuShortcut(KeyEvent.VK_A, true));
exit.addActionListener(new ActionListener() {

@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
System.exit(0);
}

});
game.add(exit);
menbar.add(game);

// 菜单项 帮助
Menu Tj = new Menu("统计(T)");
// 菜单项游戏的组件 统计信息
MenuItem record = new MenuItem("查看统计信息");
// 将游戏的成败和时间记录两个txt文本中
record.addActionListener(new ActionListener() {

@Override
public void actionPerformed(ActionEvent e) {
try {
Tongji();
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
});
Tj.add(record);
menbar.add(Tj);
// 添加菜单条
this.setMenuBar(menbar);
}

// 初始化底部
private void intBottom() {
// 创建两个label 一个是时间 一个是计时
Label lab1 = new Label("时间");
lab1.setFont(new Font("宋体", Font.BOLD, 15));
lab1.setForeground(Color.BLUE);
lab1.setBounds(80, 430, 35, 35);
this.add(lab1);
time = new Label("0");
time.setFont(new Font("宋体", Font.PLAIN, 15));
time.setBounds(140, 435, 50, 25);
this.add(time);
// 一个是标记 小红旗的个数
Label lab2 = new Label("旗帜");
lab2.setFont(new Font("宋体", Font.BOLD, 15));
lab2.setForeground(Color.BLUE);
lab2.setBounds(300, 430, 35, 35);
this.add(lab2);
redFlag = new Label(" 10");
redFlag.setFont(new Font("宋体", Font.PLAIN, 15));
redFlag.setBounds(350, 435, 50, 25);
this.add(redFlag);
// 通过接口来实现
runnable = new Runnable() {
public void run() {
while (true) {
// 是否结束
if (flag) {
break;
}
try {
// 睡眠1s
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 已用时间+1
usedTime++;
time.setText(String.valueOf(usedTime));
}
}
};
// 开始线程
new Thread(runnable).start();
}

// 初始化雷区(用按钮来充当地雷 用面板在面板上添加按钮)
private void intMine() {
// 将按钮放在面板上
jp = new JPanel();
// 面板的布局管理器为网格布局管理器
jp.setLayout(new GridLayout(WITH, LENG, 0, 0));
// 设置面板的位置
jp.setBounds(75, 70, 350, 350);
makeMines(true);
this.add(jp);
}

// 随机布置雷区 重置雷区
private void makeMines(boolean newFlag) {
// 在面板上面放按钮 并设置初始按钮属性
for (int i = 0; i < LENG; i++) {
for (int j = 0; j < WITH; j++) {
if (newFlag) {
// 记录下位置
jb[i][j] = new Bomb(i, j);
jp.add(jb[i][j]);
// 设置按钮和标签之间的空白 数字所在按钮的位置
jb[i][j].setMargin(new Insets(0, 0, 0, 0));
jb[i][j].addActionListener(this);
// 鼠标点击事件 鼠标右击
jb[i][j].addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
Object obj = e.getSource();
// e.isMetaDown() 检测鼠标右键单击
if (e.isMetaDown() && obj instanceof Bomb) {
// 强制类型转换
Bomb bomb = (Bomb) obj;
// 旗帜的个数大于等于0
if (bomb.isEnabled() && Red_Count >= 0) {
// 定义一个数字 来判定状态
// 右击点一下 变为1 红旗状态 两下变为2 ?号状态
int num = (bomb.getBombflag() + 1) % 3;
switch (num) {
case 0:
// 初始状态
bomb.setIcon(null);
break;
case 1:
Red_Count--;
// 缓冲图片对象
BufferedImage bf1 = new BufferedImage(
35, 35,
BufferedImage.TYPE_INT_RGB);
// 通过缓存图片对象,来得到画笔工具对象Graphics,对缓存图片进行修改
Graphics grap = bf1.getGraphics();
// 先读到这幅图片
Image image;
try {
image = ImageIO.read(new File(
"./image/红旗.jpg"));
// 然后通过画笔对象来改变它,将这幅图片进行缩放
grap.drawImage(image, 0, 0, 35, 35,
null);
bomb.setIcon(new ImageIcon(bf1));
} catch (IOException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}

break;
case 2:
Red_Count++;
// 缓冲图片对象
BufferedImage bf2 = new BufferedImage(
35, 35,
BufferedImage.TYPE_INT_RGB);
// 通过缓存图片对象,来得到画笔工具对象Graphics,对缓存图片进行修改
Graphics grap2 = bf2.getGraphics();
// 先读到这幅图片
Image image2;
try {
// 然后通过画笔对象来改变它,将这幅图片进行缩放
image2 = ImageIO.read(new File(
"./image/问号.jpg"));
grap2.drawImage(image2, 0, 0, 35,
35, null);
bomb.setIcon(new ImageIcon(bf2));
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}

break;
default:
break;
}
redFlag.setText(String.valueOf(Red_Count));
// 改变状态
bomb.setBombflag(num);
try {
checkSuccess();
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
}
});
} else {
jb[i][j].setIcon(null);
jb[i][j].setEnabled(true);
// 默认为都没有点击
jb[i][j].setIsclicked(false);
jb[i][j].setText("");
// 默认是无雷
jb[i][j].setBomb(false);
// 默认初始状态值为0
jb[i][j].setBombflag(0);
}
}
}
// 布雷的个数
int i = 0;
// 定义坐标
int x, y;
while (i < 10) {
x = random.nextInt(WITH);
y = random.nextInt(LENG);
// 判断这个地方是否有雷 默认没有
if (!jb[x][y].isBomb()) {
// 设置为有雷
jb[x][y].setBomb(true);
// 查看是否有重复的
// 查看坐标位置 其中y对应的是列 x对应的是行 从0-9
System.out.println(x + " " + y);
i++;
}
}
}

// 通过点击事件来判断游戏的进展
// 点击事件
@Override
public void actionPerformed(ActionEvent e) {
Object obj = e.getSource();
if (obj instanceof Bomb) {
Bomb bs = (Bomb) obj;
// 如果得到的状态是1 即红旗 结束点击事件
if (bs.getBombflag() == 1) {
return;
}
// 如果得到的状态是2 即“?”
else if (bs.getBombflag() == 2) {
// 点击一下将问号去除
bs.setIsclicked(true);
bs.setIcon(null);
}
// 如果点到的是雷
if (bs.isBomb()) {
// 缓冲图片对象
BufferedImage bf1 = new BufferedImage(35, 35,
BufferedImage.TYPE_INT_RGB);
// 通过缓存图片对象,来得到画笔工具对象Graphics,对缓存图片进行修改
Graphics grap = bf1.getGraphics();
// 先读到这幅图片
Image image;
try {
image = ImageIO.read(new File("./image/地雷.png"));
// 然后通过画笔对象来改变它,将这幅图片进行缩放
grap.drawImage(image, 0, 0, 35, 35, null);
// 将图片设置为雷
bs.setIcon(new ImageIcon(bf1));
} catch (IOException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
// 游戏结束
flag = true;
// 显示所有的雷
try {
showMine();
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
// 弹出一个窗口对话框显示游戏结束 结束点击事件
JOptionPane.showMessageDialog(this, "扫雷失败!");
return;
}
// 没有点到雷时
// 通过算法判断是否有雷 来判断周围雷的情况
judge(bs.getNum_x(), bs.getNum_y());
}
}

// 重新开始游戏
private void resetGame() {
flag = true;
Red_Count = 10;
time.setText("0");
usedTime = 0;
redFlag.setText("10");
makeMines(false);
// 将游戏外观设为初始
for (int i = 0; i < WITH; i++) {
for (int j = 0; j < LENG; j++) {
jb[i][j].setBackground(null);
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}

new Thread(runnable).start();
flag = false;
}

// 如果点到雷,游戏结束显示所有雷
// 显示所有雷的方法
private void showMine() throws Exception {
for (int i = 0; i < WITH; i++) {
for (int j = 0; j < LENG; j++) {
if (jb[i][j].isBomb()) {
// 缓冲图片对象
BufferedImage bf1 = new BufferedImage(35, 35,
BufferedImage.TYPE_INT_RGB);
// 通过缓存图片对象,来得到画笔工具对象Graphics,对缓存图片进行修改
Graphics grap = bf1.getGraphics();
// 先读到这幅图片
Image image = ImageIO.read(new File("./image/地雷.png"));
// 然后通过画笔对象来改变它,将这幅图片进行缩放
grap.drawImage(image, 0, 0, 35, 35, null);
jb[i][j].setIcon(new ImageIcon(bf1));

}
}
}
}

// 判断是否成功
private void checkSuccess() throws Exception {
int count = 0;
for (int i = 0; i < LENG; i++) {
for (int j = 0; j < WITH; j++) {
// 如果是雷 并且这个地方有红旗
if (jb[i][j].isBomb() && jb[i][j].getBombflag() == 1) {
// 进行累加
count++;
}
}
}
if (count == Mines_Count) {
flag = true;
JOptionPane.showMessageDialog(this, "恭喜你,胜利了!");
sucess = true;
String tm = time.getText();
listtime.add(tm);
writesucess(sucess);
}
}

// 判断周围是否有雷
private void judge(int x, int y) {
// 设置(x,y)这个位置已经点击 得到这个位置
jb[x][y].setIsclicked(true);
// 点击了以后将背景设置为白色
jb[x][y].setBackground(Color.WHITE);
// 点过的设置为不可点击 点击过设置为不可用
jb[x][y].setEnabled(false);
// 设定点击的这个点的相对初始位置是(0,0) 设定初始周围雷的个数是0
int sx = 0;
int sy = 0;
int mineNumber = 0;
for (int i = 0; i < mv.length; i++) {
sx = x + mv[i][0];
sy = y + mv[i][1];
// 保证所有的坐标点都在面板上 判断那些没有被点击过的按钮
if (sx >= 0 && sx < WITH && sy >= 0 && sy < LENG) {
if (jb[sx][sy].isBomb()) {
// 如果是雷的话
// 显示的数字累加 得到(x,y)这个位置周围雷的个数
mineNumber++;
}
}
}
// 通过递归来实现
if (mineNumber == 0) {
for (int i = 0; i < mv.length; i++) {
sx = x + mv[i][0];
sy = y + mv[i][1];
// 保证所有的坐标都对应一个按钮
if (sx >= 0 && sx < LENG && sy >= 0 && sy < LENG
&& !jb[sx][sy].isIsclicked()) {
judge(sx, sy);
}
}

} else {
jb[x][y].setFont(new Font("宋体", Font.BOLD, 12));
jb[x][y].setText(String.valueOf(mineNumber));
}
}

// 只有成功了才写
// 写一个方法将成功记录写到sucess.txt 文件中
private void writesucess(boolean sucess) throws Exception {
int snum = 0;
// 如果list中没有元素
readsucess();
if (list.isEmpty()) {
PrintWriter pw = new PrintWriter(new File("./sucess.txt"));
pw.println("游戏结果\t游戏时间");

buffer.append("游戏成功" + "\t" + listtime.get(snum));
pw.println(buffer.toString());
pw.close();
snum++;
} else {
PrintWriter pw = new PrintWriter(new File("./sucess.txt"));
for (int i = 0; i < list.size(); i++) {
pw.println(list.get(i));
}
buffer.append("游戏成功" + "\t" + listtime.get(snum));
pw.println(buffer.toString());
pw.close();
snum++;
}

}

private void readsucess() throws Exception {
BufferedReader br = new BufferedReader(new FileReader("./sucess.txt"));
String line = null;
while ((line = br.readLine()) != null) {
list.add(line);
}
br.close();
}

// 建立一个新的窗口
private void Tongji() throws Exception {
final Frame frame = new Frame("统计信息");
frame.setBounds(100, 100, 300, 300);
TextArea ta = new TextArea();
ta.setFont(new Font("宋体", Font.BOLD, 15));
ta.setForeground(Color.BLUE);
BufferedReader bf = new BufferedReader(new FileReader(new File(
"./sucess.txt")));
String line = null;
StringBuffer buf = new StringBuffer();
while ((line = bf.readLine()) != null) {
buf.append(line + "\n");
}
ta.setText(buf.toString());
bf.close();
frame.add(ta);
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
frame.dispose();
}
});
frame.setResizable(false);
frame.setVisible(true);

}

// 程序执行
public static void main(String[] args) throws Exception {
new Saolei();
}
}

Java awt项目开发的更多相关文章

  1. 使用MyEclipse搭建java Web项目开发

    转自:http://blog.csdn.net/jiuqiyuliang/article/details/36875217 首先,在开始搭建MyEclipse的开发环境之前,还有三步工具的安装需要完成 ...

  2. JAVA WEB项目开发案例精粹

    http://www.blogjava.net/zongbao/archive/2012/07/24/383884.htmlJAVA WEB项目开发案例精粹.pdf main Alt + / => ...

  3. SpringMVC内容略多 有用 熟悉基于JSP和Servlet的Java Web开发,对Servlet和JSP的工作原理和生命周期有深入了解,熟练的使用JSTL和EL编写无脚本动态页面,有使用监听器、过滤器等Web组件以及MVC架构模式进行Java Web项目开发的经验。

    熟悉基于JSP和Servlet的Java Web开发,对Servlet和JSP的工作原理和生命周期有深入了解,熟练的使用JSTL和EL编写无脚本动态页面,有使用监听器.过滤器等Web组件以及MVC架构 ...

  4. 【java项目实战】一步步教你使用MyEclipse搭建java Web项目开发环境(一)

    首先.在開始搭建MyEclipse的开发环境之前.还有三步工具的安装须要完毕,仅仅要在安装配置成功之后才干够进入以下的java Web项目开发环境的搭建. 1.安装工具 第一步,下载并安装JDK,到官 ...

  5. Java AWT组件开发和Swing界面编程

    一.AWT组件开发 1.AWT AWT是抽象窗口工具箱的缩写,它为编写图形用户界面提供了用户接口,通过这个接口就可以继承很多方法,省去了很多工作.AWT还能使应用程序更好地同用户进行交互. AWT中的 ...

  6. 《转载》IntelliJ 2016.2 IDEA 中进行 Java Web 项目开发配置

    本文转载自 https://segmentfault.com/a/1190000007088964 1. 新建一个 Web Application 项目 打开 IntelliJ,选择新建项目: 左边栏 ...

  7. Java Web项目开发中常见路径获取方法

    项目绝对路径 String serverPath = request.getSession().getServletContext().getRealPath("/"); E:\J ...

  8. Web —— java web 项目开发 笔记

    1.tomcat 配置虚拟路径:Tomcat下配置虚拟路径管理web项目 发布路径配置( 即虚拟目录配置 )  配置虚拟路径的4种方法 2.

  9. Java IO在实际项目开发中应用

    IO是java绕不过去的槛,在开发中io无处不在, 正如同 世界上本没有路,java io写多了,也就知道了大体是什么意思,在读完thinking in java 感觉就更清晰了,结合具体的业务场景, ...

随机推荐

  1. 17秋 软件工程 第六次作业 Beta冲刺 Scrum3

    17秋 软件工程 第六次作业 Beta冲刺 Scrum3 各个成员冲刺期间完成的任务 世强:完成手势签到模块,重构活动详情页面: 陈翔:完善超级管理员后端login模块,完成logout模块: 树民: ...

  2. 命令行方式安装Pycharm

    sudo apt install snapd snapd-xdg-open snap refresh sudo snap install pycharm-professional --classic

  3. HTML和CSS实现左侧固定宽度右侧内容可滚动

    在做移动端页面的时候,经常会碰到一个div中分左右两个div,左侧div固定宽度或百分比,右侧div中内容左右溢出,需要左右滑动才可以浏览到全部内容,为此写了一个demo. 处理这个问题的核心关键点是 ...

  4. NET Framework 各版本官方下载

    https://msdn.microsoft.com/en-us/library/5a4x27ek(v=vs.110).aspx https://www.microsoft.com/zh-CN/dow ...

  5. 使用ElasticSearch实现搜索时即时提示与全文搜索功能

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  6. 用OpenSCAD設計特製的遊戲骰子

    一開始先製作一個簡單的立方體.定義一個變量「cube_size」,然後使用下圖的立方體程式.center=true的設定可讓立方體位於起始模型的正中央. 為你在OpenSCAD創造的物體加上不同顏色是 ...

  7. leetcode 235. Lowest Common Ancestor of a Binary Search Tree 236. Lowest Common Ancestor of a Binary Tree

    https://www.cnblogs.com/grandyang/p/4641968.html http://www.cnblogs.com/grandyang/p/4640572.html 利用二 ...

  8. Android Studio中依赖第三库导致support版本冲突解决方案

    1.今天在Android Studio的app/gradle文件中依赖文件选择器的第三方库:“com.leon:lfilepickerlibrary:1.8.0” 时,github地址:https:/ ...

  9. <转>大型分布式网站术语浅析

    夜半睡起看书,看到一篇关于分布式网站性能优化术语的文章,个人觉得不错,分享出来... 原文地址:大型分布式网站术语分析 一.I/O优化 1.增加缓存,减少磁盘的访问次数. 2.优化磁盘的管理系统,设计 ...

  10. java从命令行接受多个数字求和输出

    一·设计思路 1.定义一个整型变量sum,用于接收和 2.利用循环将命令行数字求和 3.输出参数个数以及参数之和 二·流程图 三·程序源代码 public class JavaAppArguments ...