Java 课程设计 —— 扫雷

news2024/10/6 6:47:14

一、团队课程设计博客链接:

https://www.cnblogs.com/luomeili/p/10280310.html

二、个人负责模块或任务说明:

模块:文件操作  Minefield 类实现

三、自己的代码提交记录截图

四、自己负责模块或任务详细说明

1.Minefield 类实现

Minefield 是我们主要的算法实现模块。在正式开始扫雷游戏时,看见的是如下界面:一格一格的蓝色格子表示可点击区域。

点击后,分三个情况:1)标记该区域为雷(右击)2)该区域是点击到雷,游戏结束 3)该区域无雷,显示区域九宫格范围内的雷的个数。(此处有 9 种情况)4) 游戏提前结束,显示所有未被点击的雷。下图囊括四种情况:

选项区域:

这里涉及到的保存进度,下条中讲解。

对于以上游戏功能,我们是这样实现的。

先根据所选等级,初始化一个 map 数组,数组的行数和列数取决于等级。然后用 Math.random () 数结合循环语句和判断语句生成,将类的区域置 9。其余位置元素值属于 0~8,分别表示以当前位置为中心的九宫格中雷的数目。至此,map 数组生成完毕。由于游戏界面中,真正显示出来的状态有 13 种(0~8 九个数字九种,标记该位置为雷、该位置是被点击的雷、游戏成功后未被点击的雷、当前可点击区域各一种),用 map 数组来控制游戏界面的显示会有冲突,所以此处引入 hiddenmap 数组,元素数值范围为 0~12,分别表示上述 13 种情况。对于游戏界面,其实是一个 JButton 数组,由于界面的美观性,用 hiddenmap 数组值为每个按钮分配图片,根据 hiddenmap 数组值分配对应的功能图片。

 生成雷:

生成 map 数组其他位置的数字:

for (int i = 0; i < getWidth(); i++)
            for (int j = 0; j < getLength(); j++) {
                if (map[i][j] != 9) // 只对不为雷的区域进行雷数判断
                {
                    int number = 0;
                    if (i == 0) {
                        if (j == 0) {
                            if (map[i][j + 1] == 9)
                                number++;
                            if (map[i + 1][j] == 9)
                                number++;
                            if (map[i + 1][j + 1] == 9)
                                number++;
                        } else if (j == getLength() - 1) {
                            if (map[i][j - 1] == 9)
                                number++;
                            if (map[i + 1][j] == 9)
                                number++;
                            if (map[i + 1][j - 1] == 9)
                                number++;
                        } else {
                            if (map[i][j - 1] == 9)
                                number++;
                            if (map[i][j + 1] == 9)
                                number++;
                            if (map[i + 1][j - 1] == 9)
                                number++;
                            if (map[i + 1][j] == 9)
                                number++;
                            if (map[i + 1][j + 1] == 9)
                                number++;
                        }

                    }
                    if (i == getWidth() - 1) {
                        if (j == 0) {
                            if (map[i][j + 1] == 9)
                                number++;
                            if (map[i - 1][j] == 9)
                                number++;
                            if (map[i - 1][j + 1] == 9)
                                number++;
                        } else if (j == getLength() - 1) {
                            if (map[i][j - 1] == 9)
                                number++;
                            if (map[i - 1][j] == 9)
                                number++;
                            if (map[i - 1][j - 1] == 9)
                                number++;
                        } else {
                            if (map[i][j - 1] == 9)
                                number++;
                            if (map[i][j + 1] == 9)
                                number++;
                            if (map[i - 1][j - 1] == 9)
                                number++;
                            if (map[i - 1][j] == 9)
                                number++;
                            if (map[i - 1][j + 1] == 9)
                                number++;
                        }
                    }
                    if (i != 0 && i != (getWidth() - 1)) {
                        if (j == 0) {
                            if (map[i - 1][j + 1] == 9)
                                number++;
                            if (map[i][j + 1] == 9)
                                number++;
                            if (map[i + 1][j + 1] == 9)
                                number++;
                            if (map[i - 1][j] == 9)
                                number++;
                            if (map[i + 1][j] == 9)
                                number++;
                        }

                        if (j == getLength() - 1) {
                            if (map[i - 1][j - 1] == 9)
                                number++;
                            if (map[i][j - 1] == 9)
                                number++;
                            if (map[i + 1][j - 1] == 9)
                                number++;
                            if (map[i - 1][j] == 9)
                                number++;
                            if (map[i + 1][j] == 9)
                                number++;
                        }

                    }

                    if ((i != 0) && (j != 0) && (i != getWidth() - 1) && (j != getLength() - 1)) { // 不在边缘的情况
                        // 单位九宫格内的雷数
                        for (int n = i - 1; n <= i + 1; n++)
                            for (int m = j - 1; m <= j + 1; m++)
                                if (map[n][m] == 9)
                                    number++;

                    }
                    map[i][j] = number;
                }

            }
    }

所有过程中我们的操作都是对我们的 hiddenmap 做修改,我们的 map 是我们的真实雷区不做改动,接下来讲讲核心的具体实现。
所以我们的 hiddenmap 刚开始都是初始化为 10,当进行第一次点击的时候,如果 hiddenmap 下面对应的 map 对应的数字是 0,则需要展开所有为 0 的区域,所以我们这里对 hiddenmap 进行了递归搜索为 0 的区域并为 hiddenmap 标注上去,以显示空白区域,我们的做法是对当前为 0 的方块检查它的上下左右不为 9 的方块,给它标注出来,然后对上下左右递归,直到遍历整个区域,因为我们直对当前为 0 的方块进行递归,所以不会使我们的递归遍历整个图,只会遍历当前区域。这个是 findzero 方法的具体思想。

public void findZero(int i, int j) {
        if (hiddenmap[i][j] != 0) {
            if (map[i][j] == 0) {
                hiddenmap[i][j] = 0;

                if (i == 0) {
                    if (j == 0) {
                        if (map[i][j + 1] != 0 && map[i][j + 1] != 9)
                            hiddenmap[i][j + 1] = map[i][j + 1];
                        if (map[i + 1][j] != 0 && map[i + 1][j] != 9)
                            hiddenmap[i + 1][j] = map[i + 1][j];
                    } 
                    else if (j == length - 1) {
                        if (map[i][j - 1] != 0 && map[i][j - 1] != 9)
                            hiddenmap[i][j - 1] = map[i][j - 1];
                        if (map[i + 1][j] != 0 && map[i + 1][j] != 9)
                            hiddenmap[i + 1][j] = map[i + 1][j];
                    } 
                    else {
                        if (map[i][j - 1] != 0 && map[i][j - 1] != 9)
                            hiddenmap[i][j - 1] = map[i][j - 1];
                        if (map[i + 1][j] != 0 && map[i + 1][j] != 9)
                            hiddenmap[i + 1][j] = map[i + 1][j];
                        if (map[i][j + 1] != 0 && map[i][j + 1] != 9)
                            hiddenmap[i][j + 1] = map[i][j + 1];
                    }
                }

                if (i == width - 1) {
                    if (j == 0) {
                        if (map[i][j + 1] != 0 && map[i][j + 1] != 9)
                            hiddenmap[i][j + 1] = map[i][j + 1];
                        if (map[i - 1][j] != 0 && map[i - 1][j] != 9)
                            hiddenmap[i - 1][j] = map[i - 1][j];
                    } else if (j == length - 1) {
                        if (map[i - 1][j] != 0 && map[i - 1][j] != 9)
                            hiddenmap[i - 1][j] = map[i - 1][j];
                        if (map[i][j - 1] != 0 && map[i][j - 1] != 9)
                            hiddenmap[i][j - 1] = map[i][j - 1];
                    } else {
                        if (map[i][j + 1] != 0 && map[i][j + 1] != 9)
                            hiddenmap[i][j + 1] = map[i][j + 1];
                        if (map[i - 1][j] != 0 && map[i - 1][j] != 9)
                            hiddenmap[i - 1][j] = map[i - 1][j];
                        if (map[i][j - 1] != 0 && map[i][j - 1] != 9)
                            hiddenmap[i][j - 1] = map[i][j - 1];
                    }
                }

                if (j == 0) {
                    if (i != 0 && i != width - 1) {
                        if (map[i - 1][j] != 0 && map[i - 1][j] != 9)
                            hiddenmap[i - 1][j] = map[i - 1][j];
                        if (map[i + 1][j] != 0 && map[i + 1][j] != 9)
                            hiddenmap[i + 1][j] = map[i + 1][j];
                        if (map[i][j + 1] != 0 && map[i][j + 1] != 9)
                            hiddenmap[i][j + 1] = map[i][j + 1];
                    }
                }
                if (j == length - 1) {
                    if (i != 0 && i != width - 1) {
                        if (map[i - 1][j] != 0 && map[i - 1][j] != 9)
                            hiddenmap[i - 1][j] = map[i - 1][j];
                        if (map[i + 1][j] != 0 && map[i + 1][j] != 9)
                            hiddenmap[i + 1][j] = map[i + 1][j];
                        if (map[i][j - 1] != 0 && map[i][j - 1] != 9)
                            hiddenmap[i][j - 1] = map[i][j - 1];
                    }
                }
                if (i != 0 && i != width - 1 && j != 0 && j != length - 1) {
                    if (map[i][j + 1] != 0 && map[i][j + 1] != 9)
                        hiddenmap[i][j + 1] = map[i][j + 1];
                    if (map[i + 1][j] != 0 && map[i + 1][j] != 9)
                        hiddenmap[i + 1][j] = map[i + 1][j];
                    if (map[i][j - 1] != 0 && map[i][j - 1] != 9)
                        hiddenmap[i][j - 1] = map[i][j - 1];
                    if (map[i - 1][j] != 0 && map[i - 1][j] != 9)
                        hiddenmap[i - 1][j] = map[i - 1][j];
                }

                if (j >= 1)
                    findZero(i, j - 1);
                if (i >= 1)
                    findZero(i - 1, j);
                if (j <= getLength() - 2)
                    findZero(i, j + 1);
                if (i <= getWidth() - 2)
                    findZero(i + 1, j);
            }
        }
    }

setButton 函数为 JButton [][] 数组每个位置放置图片:

public void setButton(JButton button, int i, int j) {
        if (minefield.getHiddenMap()[i][j] == 0)
            button.setIcon(new ImageIcon("whilt.png"));
        if (minefield.getHiddenMap()[i][j] == 1)
            button.setIcon(new ImageIcon("whilt-1.png"));
        if (minefield.getHiddenMap()[i][j] == 2)
            button.setIcon(new ImageIcon("whilt-2.png"));
        if (minefield.getHiddenMap()[i][j] == 3)
            button.setIcon(new ImageIcon("whilt-3.png"));
        if (minefield.getHiddenMap()[i][j] == 4)
            button.setIcon(new ImageIcon("whilt-4.png"));
        if (minefield.getHiddenMap()[i][j] == 5)
            button.setIcon(new ImageIcon("whilt-5.png"));
        if (minefield.getHiddenMap()[i][j] == 6)
            button.setIcon(new ImageIcon("whilt-6.png"));
        if (minefield.getHiddenMap()[i][j] == 7)
            button.setIcon(new ImageIcon("whilt-7.png"));
        if (minefield.getHiddenMap()[i][j] == 8)
            button.setIcon(new ImageIcon("whilt-8.png"));
        if (minefield.getHiddenMap()[i][j] == 9)
            button.setIcon(new ImageIcon("boom.png"));
        if (minefield.getHiddenMap()[i][j] == 10)
            button.setIcon(new ImageIcon("blue.png"));
        if (minefield.getHiddenMap()[i][j] == 11)
            button.setIcon(new ImageIcon("red.png"));
        if (minefield.getHiddenMap()[i][j] == 12)
            button.setIcon(new ImageIcon("redboom.png"));
    }

2.. 文件操作

我们引入了文件保存的机制,为了不用保存过多的参数,而且不希望一个一个量地保存,我们把所有的操作需要用到的数据都保存到了 minefield 类里面,包含我们整个扫雷模块的数据,因为学习过文件处理,我们以 object 的形式可以把所有类都保存起来,再以同样的方式读取,并强制转换类型为 minefield 子类,就可以恢复我们之前保存的数据,所以我们就引入了文件保存机制,能使用户保存他的上一局未完成的游戏,我们会以用户名的形式创建一个同名的 file 来保存,文件保存在当前目录下。当然,如果没有上一局记录的话,就找不到我们的记录文件,我们会默认打开一个初始化的界面。

读取上局文件:

if (file.isNewOne() == false) {
                try {
                    readFile = new ObjectInputStream(new FileInputStream(file.getFileName()));
                    this.minefield = (Minefield) readFile.readObject();
                    readFile.close();
                    if (minefield.isBoom() == true) {
                        boom.play();
                        upset.play();
                    } else {
                        playGame.play();
                    }
                } catch (FileNotFoundException e) {   //不存在上局时,自动生成一局
                    this.minefield = new Minefield(file.getWidth(), file.getLength(), file.getLambnumber());
                    playGame.play();
//                        JOptionPane.showMessageDialog(null, "您还未开始游戏,不存在上局哦,即将为您自动生成上局!");
//                        e.printStackTrace();
                } catch (IOException e) {
//                        e.printStackTrace();
                }
                
            }

 保存进度:

item3.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent arg0) {
                try {
                    ObjectOutputStream dateSave = new ObjectOutputStream(new FileOutputStream(getFileName()));
                    dateSave.writeObject(minefield);
                    dateSave.close();
                } catch (FileNotFoundException e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                } catch (IOException e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                }
            }
        });

五、课程设计感想

通过这次课程设计,我大大提高了自己的自主学习能力,俗话说 “师傅领进门,修行在个人”,要完成如此复杂的课程设计,仅靠老师上课教授的知识是远远不够的,需要我们自己去多加学习。在学习中,还应学会提问的方法,遇文图时不要慌张,要仔细往根源去找问题,不要一有问题就寻求老师同学帮忙,要有自主解决问题的能力。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/526430.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java中的CountDownLatch和CyclicBarrier有什么作用?

在Java并发编程中&#xff0c;CountDownLatch和CyclicBarrier是两个非常有用的工具&#xff0c;它们可以帮助我们更加方便地进行线程通信和协作。在本文中&#xff0c;我将从面试的角度&#xff0c;详细讲解Java中的CountDownLatch和CyclicBarrier的概念、作用和实现方式&#…

基于卷积的图像分类识别(六):DenseNet FractalNet

系列文章目录 本专栏介绍基于深度学习进行图像识别的经典和前沿模型&#xff0c;将持续更新&#xff0c;包括不仅限于&#xff1a;AlexNet&#xff0c; ZFNet&#xff0c;VGG&#xff0c;GoogLeNet&#xff0c;ResNet&#xff0c;DenseNet&#xff0c;SENet&#xff0c;MobileN…

如何搭建自己的git服务器

GitHub&#xff0c;Gitee 想来大家都用过&#xff0c;我们的代码就是托管在这些平台上的。因此&#xff0c;你可能好奇为什么我们不自己搭建一个 git 呢服务器&#xff1f;下面&#xff0c;就开始教大家如何一步步搭建自己的 git 服务器&#xff08;试验成功的那一刻还是很让人…

Java 中 ArrayList 和 LinkedList 有什么区别

在Java中&#xff0c;ArrayList和LinkedList是两种常见的集合类。它们都实现了List接口&#xff0c;提供了类似数组的功能&#xff0c;可以存储任意类型的对象。虽然它们都可以实现相同的功能&#xff0c;但是它们的底层实现方式有所不同&#xff0c;因此在性能和用途上也存在一…

dom4j解析XML文件

主要为了讲解Mybatis中如何用dom4j解析XML,这里当作dom4j解析.XML文件的练习 引入mybatis配置文件和一个.xml文件 都是.xml <?xml version"1.0" encoding"UTF-8" ?> <!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN…

【C++】| 04——STL | 容器_vector

系列文章目录 【C】| 01——泛型编程 | 模板 【C】| 02——STL | 初识 【C】| 03——STL | 迭代器 【C】| 04——STL | 容器_vector 文章目录 1. vector容器2. vector库2.1 迭代器相关函数2.1 ww 1. vector容器 vector 与 动态数组 相似&#xff0c;可以自动调节自身大小。元素…

基于SpringBoot的美容院管理系统

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SpringBoot 前端&#xff1a;Vue 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#xff1a;是 目录 一、项目简介 二、系…

Windows10中英文切换按钮消失?一招解决

目录 问题场景&#xff1a; 问题描述 原因分析&#xff1a; 解决方案&#xff1a; 1. 打开设置&#xff0c;选择时间和语言 2. 进入日期时间设置 3. 进入高级键盘设置 4. 勾选这个勾选框&#xff0c;问题解决 问题场景&#xff1a; 博主玩道德与法治V在线模式时&#…

BGP防环,路由反射器,BGP联盟

数据的出口是路由的入口 ospf内部&#xff1a;10 ospf外部&#xff1a;150 静态路由&#xff1a;60 RIP&#xff1a;100 BGP&#xff1a;255 当下一跳是0.0.0.0 表示的是自己 display bgp peer //查看bgp邻居表 display bgp routing-table //查看bgp数据库 display i…

WPF MaterialDesign 初学项目实战(3)动态侧边栏

其他文章 WPF MaterialDesign 初学项目实战&#xff08;0&#xff09;:github 项目Demo运行 WPF MaterialDesign 初学项目实战&#xff08;1&#xff09;首页搭建 WPF MaterialDesign 初学项目实战&#xff08;2&#xff09;首页导航栏样式 创建侧边栏实体类 新建MenuBar文件…

Python动物图像分割API简单调用实例演示,阿里达摩院视觉智能开放平台使用步骤

阿里云视觉智能开放平台 - 动物分割 效果图演示平台入口创建获取密钥本地图片转 URL 与密钥测试代码调用演示语义分割知识拓展阿里云达摩院智能视觉开放平台 效果图演示 调用本地图片处理后可以直接保存到本地&#xff0c;右边就是分割好的效果图&#xff0c;可以看到分割的效…

基于卷积的图像分类识别(五):ResNet ResNeXt

系列文章目录 本专栏介绍基于深度学习进行图像识别的经典和前沿模型&#xff0c;将持续更新&#xff0c;包括不仅限于&#xff1a;AlexNet&#xff0c; ZFNet&#xff0c;VGG&#xff0c;GoogLeNet&#xff0c;ResNet&#xff0c;DenseNet&#xff0c;SENet&#xff0c;MobileN…

C语言实现扫雷

总有一天你要一个人在暗夜中&#xff0c;向那座桥走过去 目录 一、文件及其对应代码 1.test.c 2.game.c 3.game.h 二、数组创建解析 1.创建两个数组的原因 2.预设数组较大的原因 三、计算周围雷的个数 四、向外扩展并延伸判断 扫雷游戏&#xff0c;相信大家都玩过&am…

【c++】图解类和对象(上)

类和对象&#xff08;上&#xff09; 文章目录 类和对象&#xff08;上&#xff09;一、面向过程和面向对象初步认识二、类的引入三、类的定义四、类的访问限定符及封装1.访问限定符2.封装 五、类的作用域六、类的实例化七、类对象模型八、this指针总结 一、面向过程和面向对象…

Mysql中select语句的执行流程?

Mysql中select语句的执行流程&#xff1f; 答&#xff1a; SELECT 语句的执行过程为&#xff1a;连接、查询缓存、a词法分析&#xff0c;语法分析&#xff0c;语义分析&#xff0c;构造执行树&#xff0c;生成执行计划、执行器执行计划&#xff0c;下面开始梳理一次完整的查询…

【MySQL】视图,事务、隔离级别

视图--虚表&#xff0c;不在数据库中存放数据&#xff0c;数据源于基本表。 为什么要使用视图 简化复杂的sql操作&#xff0c;在编写查询后&#xff0c;可以方便的重用它而不必知道它的查询细节。重复使用该sql语句。使用表的组成部分而不是整个表。保护数据&#xff0c;可以给…

vscode编译的时候:未定义标识符 thread

vscode编译的时候&#xff1a;未定义标识符 thread thread’ was not declared in this scope" 未定义标识符 thread 原因 MinGW GCC当前仍缺少标准C 11线程类的实现。 对于跨平台线程实现&#xff0c;GCC标准库依赖于gthreads / pthreads库。如果该库不可用&#xf…

手搓GPT系列之 - 通过理解LSTM的反向传播过程,理解LSTM解决梯度消失的原理 - 逐条解释LSTM创始论文全部推导公式,配超多图帮助理解(上篇)

1. 前言 说起RNN和LSTM&#xff0c;就绕不过Sepp Hochreiter 1997年的开山大作 Long Short-term Memory。奈何这篇文章写的实在是太劝退&#xff0c;整篇论文就2张图&#xff0c;网上很多介绍LSTM的文章都对这个模型反向传播的部分避重就轻&#xff0c;更少见&#xff08;反正…

2023/5/14学习总结

这道题我们可以看到数据范围很小 &#xff0c;所以可以使用暴力枚举&#xff0c;将所有可以组成长方形的长宽全遍历一遍&#xff0c;同时要满足这个长方形里没有障碍物的条件&#xff0c;取得周长最大值 #include<bits/stdc.h> using namespace std; typedef long long …

JavaSE基础(六)—— 面向对象、封装、对象内存图、成员变量和局部变量区别

目录 一、面向对象对象介绍 1. 面向对象的重点学习什么 二、设计对象并使用 1. 设计类&#xff0c;创建对象并使用 1.1 如何得到对象 1.2 如何使用对象 2. 定义类的几个补充注意事项 2.1 对象的成员变量的默认值规则 三、对象内存图 1. 多个对象内存图 2. 两个变量指…