Java语言实现扫雷的设计与源码(Swing的学习总结)

扫雷,是一款耐玩有意思的小游戏。但是通过代码实现对于新手来说并不算简单。本人是一个新手,通过这几天摸索、分析设计,也算基本能做出来了,当然有部分功能尚未实现,如果有人能指出错误,那就更好了。下面来分享一下学习的历程。博文有点长,如果只想要源码的,可以直接拉到最下面。
效果图:
Mine_sweep 1

Mine_sweep 2

Mine_sweep 3

Mine_sweep 4

扫雷核心算法
ps:本人算法跟数据结构涉及不算多,所以有些算法虽然能实现功能,但是对于系统内存占用会比较大。如果有人对于扫雷算法有更好的实现方法,欢迎指出。

1.随机生成雷:
雷的表示:可以用二维数组的下标表示,所以可以用随机数Math.random()方法来生成随机横纵坐标,random()方法是随机生成0~1之间的小数,但是不会生成0和1。所以random()*16就表示随机生成0~16之间的浮点数,不包括0和16。
因为坐标是整数类型,所以生成的随机横纵坐标需要强制转换为int类型 有一点需要注意的是,强制转换类型并不是四舍五入转换,例如:
random()*30随机生成一个数的值为29.99999999999,转换为会变为29。

/**
 * @param mineNum:表示要生成雷的总数
 * @param row:表示随机雷的横坐标的int类型
 * @param col:表示随机雷的纵坐标的int类型
 * @param EMPTY:值为0,表示该组件尚未设置任何东西
 * @param MINE:值为1,表示该组件已经设置为雷
 */
private void addMine() {

        for (int mineNum = 1; mineNum <= MINE_NUMBER;) {
            int row = (int) (Math.random() * 16);
            int col = (int) (Math.random() * 30);
            // 为了避免有相同位置的雷的生成,需要简单判断一下
            if (map[row][col] == EMPTY) {
                map[row][col] = MINE;
                mineLab[row][col].setIcon(img(9));//设置雷的图标
                mineNum++;
            }
        }
    }

2.统计每个按钮周围8个格子的雷的总数:
原理如同下图:(i,j)就是我们要统计的点,周围8个格子的坐标就是下图,通过图片我们可以发现,每一行的都是横坐标累加,纵坐标不变。每一列都是横坐标不变,纵坐标累加。所以就可以用两层for循环实现历遍周围八个格的功能了。有一点需要注意的是,如果(i,j)这个点位于边界,那么就有可能发生越界,比如(i,j)是(0,0),那么i-1=-1,数组就会报错,因为数组下标不能为负数,或者大于长度。所以,每次循环都要判断一下
if (i >= 0 && j >= 0 && i < 16 && j < 30) 是否为真
这里写图片描述

/**
 * 计算每个格周围八个格的雷的总数量的方法,并返回int类型的雷的数量值
 * @param i:传入按钮的横坐标
 * @param j:传入按钮的纵坐标
 */
    private int mN(int i, int j) {
        int count = 0; // 雷的数量
        int row = i; //保存固定的横坐标
        int col = j; //保存固定的纵坐标
        for (int m = -1; m < 2; m++) {
            i = row; //使得每次循环的i的初始坐标不变
            i += m;
            for (int n = -1; n < 2; n++) {
                j = col; //同上
                j += n;
                if (i >= 0 && j >= 0 && i < 16 && j < 30) {
                    if (map[i][j] == MINE) {
                        count++;
                    }
                }
            }

        }
        return count;
    }

3.空雷区自动翻开:

    private void isBlank(int i, int j) {
        if (mN(i, j) == 0) {
            map[i][j] = CHECKED;
            int row = i;
            int col = j;
            for (int m = -1; m < 2; m++) {
                i = row;
                i += m;
                for (int n = -1; n < 2; n++) {
                    j = col;
                    j += n;
                    if (i >= 0 && j >= 0 && i < 16 && j < 30) {
                        if (mN(i, j) == 0) {
                            if (map[i][j] != MINE && map[i][j] != CHECKED) {
                                showLab(i, j);
                                isBlank(i, j);
                            }
                        } else {
                            showLab(i, j);
                        }
                    }
                }
            }
        }
    }

4.统计剩余雷数

    /**
     * 判断剩余雷数
     */
    private void isClean() {
        int mineFound = MINE_NUMBER_H;
        for (int i = 0; i < ROW; i++) {
            for (int j = 0; j < COL; j++) {
                if (mineFalg[i][j] == IS_FLAG) {
                    mineFound--;
                }
            }
        }
        mineText.setText("" + mineFound);
        if (mineFound == 0) {
            flag = true;
            showMine();
        }
    }

完整代码:

package view;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import<
  • 8
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值