Weekend boring, with Java to write a minesweeper program, say, this should be in school, write will be more fun, after all, their own implementation of a small game, or more fun. To be honest, the core of minesweeper is the click to trigger the data update step.

Swing is out of date, but fun will not be out of date, do not like to spray

Source code address: github.com/Damaer/Game…

Here’s what’s inside:

  • Data structure design
  • Keep views and data as separate as possible
  • Use when you clickBFSscanning
  • Judge success and failure

Data structure design

In this program, for convenience, using the global Data class Data class to maintain the Data of the whole game, directly set as static variables, that is, only one game window can run ata time, otherwise there will be Data security problems. (Just for convenience)

There is the following data (part of the code) :

public class Data {
    // Game state
    public static Status status = Status.LOADING;
    // Minefield size
    public static int size = 16;
    // The number of thunder
    public static int numOfMine = 0;
    // Indicates whether there is thunder. 1: yes, 0: no
    public static int[][] maps = null;
    // Whether to access
    public static boolean[][] visited = null;
    // The number of surrounding mines
    public static int[][] nums = null;
    // Whether it is marked
    public static boolean[][] flags = null;
    // The coordinates of the last block accessed
    public static Point lastVisitedPoint = null;
    // Hard mode
    private staticDifficultModeEnum mode; . }Copy the code

The following data needs to be maintained:

  • Game state: start, end, success, failure, etc
  • Mode: easy, medium, or difficult, which affects the number of mines automatically generated
  • Size of minefield: 16 x 16 squares
  • Number of thunder: is related to mode selection and is a random number
  • Identify if each block has thunder: the most basic data that needs to be updated synchronously after it is generated
  • Identifies whether each square is swept: Default is not swept
  • The number of mines around each block: this result is calculated synchronously when generated, not after each click, after all, it is not updated data, once and for all
  • Mark blocks if they are marked: when minesweeper we mark blocks with flags to indicate that they are mines, and when all mines are marked, success
  • Block coordinates from last visit: this is actually not recorded, but recorded to show the explosion effect, unlike other thunder displays

Views are separated from data

Try to follow a principle of keeping views separate from data or data changes for easy maintenance. We know that in Java, we use Swing to draw graphical interfaces, and it’s really hard to draw things, you write complicated views but you don’t draw anything.

The separation of views and data is also a great feature of almost all frameworks, mainly because it’s easy to maintain. If views and data are mixed together, update data, and manipulate views, it’s messy. (Of course, I wrote the rough version, just a quick distinction.)

In this minesweeper program are basically click events, triggered data change, data change, call view refresh, view rendering logic and data change logic maintained separately.

Data. Visit (x, y) is a refresh view, and repaintBlocks() is a refresh view.

new MouseListener() {
                    @Override
                    public void mouseClicked(MouseEvent e) {
                        if (Data.status == Status.GOING) {
                            int c = e.getButton(); // Get the mouse button pressed
                            Block block = (Block) e.getComponent();
                            int x = block.getPoint_x();
                            int y = block.getPoint_y();
                            if (c == MouseEvent.BUTTON1) {
                                Data.visit(x, y);
                            } else if (c == MouseEvent.BUTTON3) {// The inference is that the right mouse button is pressed
                                if(! Data.visited[x][y]) { Data.flags[x][y] = ! Data.flags[x][y]; } } } repaintBlocks(); }}Copy the code

It is a pity that there is still a background URL in each square that is not extracted. This is changing data and should not be placed in the view:

public class Block extends JPanel {
    private int point_x;
    private int point_y;

    private String backgroundPath = ImgPath.DEFAULT;

    public Block(int x, int y) {
        this.point_x = x;
        this.point_y = y; setBorder(BorderFactory.createEtchedBorder()); }}Copy the code

To recenter the box background, redraw the void paintComponent(Graphics G) method:

    @Override
    protected void paintComponent(Graphics g) {
        refreshBackground();
        URL url = getClass().getClassLoader().getResource(backgroundPath);
        ImageIcon icon = new ImageIcon(url);
        if (backgroundPath.equals(ImgPath.DEFAULT) || backgroundPath.equals(ImgPath.FLAG)
                || backgroundPath.equals(String.format(ImgPath.NUM, 0))) {
            g.drawImage(icon.getImage(), 0.0, getWidth(), getHeight(), this);
        } else {
            int x = (int) (getWidth() * 0.1);
            int y = (int) (getHeight() * 0.15);
            g.drawImage(icon.getImage(), x, y, getWidth() - 2 * x, getHeight() - 2 * y, this); }}Copy the code

BFS scanning

BFS, also known as the breadth-first search, this is mine inside the core of knowledge points, that is, when the click, if the current square is empty, it can trigger scanning the perimeter of the square, at the same time around the square if is empty, and will continue to be recursive, I used the breadth-first search, also is the first to put them in the queue, and then determine whether is empty, Then the surrounding square is added, one by one processing.

Breadth-first search is not going to be done here, but essentially it’s going to take precedence over the data that’s directly associated with it, which is the point around the square, and that’s why we need queues, we need queues to keep the order of the traversal.

    public static void visit(int x, int y) {
        lastVisitedPoint.x = x;
        lastVisitedPoint.y = y;
        if (maps[x][y] == 1) {
            status = Status.FAILED;
            // Game over, expose all thunder
        } else {
            // Click not thunder
            Queue<Point> points = new LinkedList<>();
            points.add(new Point(x, y));
            while(! points.isEmpty()) { Point point = points.poll(); visited[point.x][point.y] =true;
                if (nums[point.x][point.y] == 0) { addToVisited(points, point.x, point.y); }}}}public static void addToVisited(Queue<Point> points, int i, int j) {
        int x = i - 1;
        while (x <= i + 1) {
            if (x >= 0 && x < size) {
                int y = j - 1;
                while (y <= j + 1) {
                    if (y >= 0 && y < size) {
                        if(! (x == i && j == y)) {// Not visited and not thunder
                            if(! visited[x][y] && maps[x][y] ==0) {
                                points.add(newPoint(x, y)); } } } y++; } } x++; }}Copy the code

Note that the surrounding point, if it is not surrounded by lightning, will continue to expand, but as long as it is surrounded by lightning, it will stop expanding, and only the number will be displayed.

Judge success and failure

When digging for thunder, it fails and exposes all the thunder. To show the current point we dug, which has an explosion effect, we record the point of the previous operation. After refreshing the view, the popup window prompts:

Success is determined by traversing all the mines once to see if they are marked. This is the rule I simply thought of, forgetting whether minesweeper is like this or if it can be achieved by hollowing out all the other non-minefields. Success is also ok.

conclusion

Minesweeper, a simple game, boring when you can try, but Java Swing is really difficult to use, want to find a data-driven view modification framework, but there seems to be no, that simple implementation. In fact, most of the time looking for ICONS, testing UI, the core code is not much.

Here recommend icon website: https://www.iconfont.cn/, even if there is no technical content of demining, write down or interesting.

[Author profile] : Qin Huai, public number [Qin Huai grocery store] author, personal website: aphysia.cn, the road of technology is not at that time, mountain high water long, even if slow, chi and not stop.

Offer all questions in PDF

Open Source Programming Notes