AI结合GUI开发一个石头迷阵的游戏

![image-20240711153717883](E:\JAVA\黑马javFATAL Something’s wrong. Maybe you can find the solution here: https://hexo.io/docs/troubleshooting.html Error: Spawn failed at ChildProcess. (E:\Hexo-Blog\node_modules\hexo-deployer-git\node_modules\hexo-util\lib\spawn.js:51:21) at ChildProcess.emit (node:events:519:28) at cp.emit (E:\Hexo-Blog\node_modules\cross-spawn\lib\enoent.js:34:29) at ChildProcess._handle.onexit (node:internal/child_process:294:12)aai\Java+AI(Java基础入门到大牛)\JavaSE基础\day09-综合项目实战\石头迷阵项目文档\AI结合GUI开发一个石头迷阵的游戏.assets\image-20240711153717883.png)

准备环节

  • 创建一个模块用于开发石头迷阵游戏,模块名称取名为:stone-maze
  • 导入项目需要的资源包到src目录下:主要是一些图片文件,在image文件夹下。
  • 创建项目包:com.itheima.

1、创建石头迷阵的界面

  • 定义主界面类,MainFrame继承JFrame. 自定义窗口。
  • 初始化窗口大小
  • 初始化界面图片
  • 初始化界面菜单:系统退出,重启游戏。
  • public class MainFrame extends JFrame {
        public static final String IMAGE_PATH = "stonemaze/image/";
        private int[][] data = new int[][]{
                {1, 2, 3, 4},
                {5, 6, 7, 8},
                {9, 10, 11, 12},
                {13, 14, 15, 0}
        };
    
        public MainFrame2() {
            // 1、初始化窗口大小等信息
            initFrame();
            // 3、添加操作按钮
            initMenu();
            // 2、初始化界面信息,展示图片,需要定义一个二维数组展示图片的位置,然后按照二位数组的图片名称依次在窗口上展示图片
            initImage();
    
            // 必须最后设置界面可见
            this.setVisible(true);
        }
    
        private void initMenu() {
            // 在主界面上方展示一个系统菜单,菜单下展示重启游戏和退出程序两个功能
            JMenuBar menuBar = new JMenuBar();
            JMenu menu = new JMenu("系统菜单");
            JMenuItem restartItem = new JMenuItem("重启游戏");
            restartItem.addActionListener(e -> {
                System.out.println("重启游戏!");
            });
            JMenuItem exitItem = new JMenuItem("退出程序");
            exitItem.addActionListener(e -> {
                // 退出程序,销毁窗口即可
                this.dispose();
            });
            menu.add(restartItem);
            menu.add(exitItem);
            menuBar.add(menu);
            this.setJMenuBar(menuBar);
        }
    
        // 在窗口上展示图片
        private void initImage() {
            for (int i = 0; i < data.length; i++) {
                for (int j = 0; j < data[i].length; j++) {
                    // 获取图片名称
                    String imageName = data[i][j] + ".png";
                    // 创建图片对象
                    ImageIcon imageIcon = new ImageIcon(IMAGE_PATH + imageName);
                    // 创建图片标签
                    JLabel jLabel = new JLabel(imageIcon);
                    // 设置图片标签的位置
                    jLabel.setBounds(20 + j * 100, 60 + i * 100, 100, 100);
                    this.add(jLabel);
               }
           }
    
            // 设置窗口的背景图片
            JLabel background = new JLabel(new ImageIcon(IMAGE_PATH + "background.png"));
            background.setBounds(0, 0, 450, 484);
            this.add(background);
        }
    
        private void initFrame() {
            // 设置窗口的标题
            this.setTitle("石子迷阵 v1.0");
            // 设置窗口的大小
            this.setSize(465, 580);
            // 设置窗口的位置
            this.setLocationRelativeTo(null);
            // 设置窗口的关闭方式
            this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            // 设置布局方式为绝对位置定位
            this.setLayout(null);
    
        }
    
        public static void main(String[] args) {
            new MainFrame();
        }
    }
    
    1
    2
    3
    4
    5
    6
    7

    ### 2、打乱顺序

    * 打乱界面的图片顺序,让游戏具备可玩性: 使用方法如下

    ```java
    打乱二维数组中的元素顺序:initRandomArray();
    **完成代码如下:**
  • package com.itheima;
    
    import javax.swing.*;
    
    public class MainFrame extends JFrame {
        public static final String IMAGE_PATH = "stonemaze/image/";
        private int[][] data = new int[][]{
                {1, 2, 3, 4},
                {5, 6, 7, 8},
                {9, 10, 11, 12},
                {13, 14, 15, 0}
        };
    
        public MainFrame2() {
            // 1、初始化窗口大小等信息
            initFrame();
            // 3、添加操作按钮
            initMenu();
    
            // 4、打乱二维数组中的元素顺序。
            initRandomArray();
    
            // 2、初始化界面信息,展示图片,需要定义一个二维数组展示图片的位置,然后按照二位数组的图片名称依次在窗口上展示图片
            initImage();
    
            // 必须最后设置界面可见
            this.setVisible(true);
        }
    
       private void initRandomArray() {
            // 打乱二维数组中的元素顺序
            for (int i = 0; i < imageData.length; i++) {
                for (int j = 0; j < imageData[i].length; j++) {
                    // 随机两个行列位置,让这两个位置交换。
                    int i1 = (int) (Math.random() * imageData.length);
                    int j1 = (int) (Math.random() * imageData.length);
    
                    int i2 = (int) (Math.random() * imageData.length);
                    int j2 = (int) (Math.random() * imageData.length);
    
                    int temp = imageData[i1][j1];
                    imageData[i1][j1] = imageData[i2][j2];
                    imageData[i2][j2] = temp;
                }
            }
        }
    
        private void initMenu() {
            // 在主界面上方展示一个系统菜单,菜单下展示重启游戏和退出程序两个功能
            JMenuBar menuBar = new JMenuBar();
            JMenu menu = new JMenu("系统菜单");
            JMenuItem restartItem = new JMenuItem("重启游戏");
            restartItem.addActionListener(e -> {
                System.out.println("重启游戏!");
            });
            JMenuItem exitItem = new JMenuItem("退出程序");
            exitItem.addActionListener(e -> {
                // 退出程序,销毁窗口即可
                this.dispose();
            });
            menu.add(restartItem);
            menu.add(exitItem);
            menuBar.add(menu);
            this.setJMenuBar(menuBar);
        }
    
        // 在窗口上展示图片
        private void initImage() {
            for (int i = 0; i < data.length; i++) {
                for (int j = 0; j < data[i].length; j++) {
                    // 获取图片名称
                    String imageName = data[i][j] + ".png";
                    // 创建图片对象
                    ImageIcon imageIcon = new ImageIcon(IMAGE_PATH + imageName);
                    // 创建图片标签
                    JLabel jLabel = new JLabel(imageIcon);
                    // 设置图片标签的位置
                    jLabel.setBounds(20 + j * 100, 60 + i * 100, 100, 100);
                    this.add(jLabel);
               }
           }
    
            // 设置窗口的背景图片
            JLabel background = new JLabel(new ImageIcon(IMAGE_PATH + "background.png"));
            background.setBounds(0, 0, 450, 484);
            this.add(background);
        }
    
        private void initFrame() {
            // 设置窗口的标题
            this.setTitle("石子迷阵 v1.0");
            // 设置窗口的大小
            this.setSize(465, 580);
            // 设置窗口的位置
            this.setLocationRelativeTo(null);
            // 设置窗口的关闭方式
            this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            // 设置布局方式为绝对位置定位
            this.setLayout(null);
    
        }
    
        public static void main(String[] args) {
            new MainFrame();
        }
    }
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38

    原代码打乱图片顺序会有bug,导致游戏无解。可以换种思路打乱,以空白块为中心向四周随机交换,每次更新空白块的位置,以下是我的代码:

    ```java
    private void initRandomArray() {
    //随机打乱数组,以空白色块位置为中心,与周围色块进行随机交换,可以设置交换次数为100次到200次随机
    int count = (int) (Math.random() * 300) + 300;
    for (int i = 0; i < count; i++) {
    switch ((int) (Math.random() * 4)) {
    case 0:
    switchmove(Direction.UP);
    break;
    case 1:
    switchmove(Direction.DOWN);
    break;
    case 2:
    switchmove(Direction.LEFT);
    break;
    case 3:
    switchmove(Direction.RIGHT);
    break;
    }
    }
    // OUT:
    // for (int i = 0; i < imageData.length; i++) {
    // for (int j = 0; j < imageData[i].length; j++) {
    // if (imageData[i][j] == 0) {
    // //记录空白色块的行列位置
    // blankRow = i;
    // blankCol = j;
    // break OUT;//跳出循环
    // }
    // }
    //
    // }
    //重置步数
    step = 0;
    }

3、控制上下左右移动

  • 给窗口绑定上下左右按键事件

  • 控制位置的交换。

    **---  定位当前空白色块的位置。**
    
    **--- 根据用户点击的方位确定交换哪个数据,到数组中交换。**
    
  • 重新绘制主界面的内容

    **---  让主界面按照二维数组的最新内容刷新界面**
    
  • public enum Direction {
        UP, DOWN, LEFT, RIGHT;
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217

    ```java
    package com.itheima;

    import javax.swing.*;
    import java.awt.event.KeyAdapter;
    import java.awt.event.KeyEvent;

    // 自定义窗口类,创建对象,展示一个主窗口。
    public class MainFrame extends JFrame {
    // 设置图片位置
    private static final String imagePath = "stone-maze/src/image/";
    // 准备一个数组,用户存储数字色块的行列位置: 4行4列
    private int[][] imageData = {
    {1,2,3,4},
    {5,6,7,8},
    {9,10,11,12},
    {13,14,15,0}
    };
    // 定义两个整数变量记录当前空白色块的位置。
    private int row; // 行索引
    private int col; // 列索引

    public MainFrame() {
    // 1、调用一个初始化方法:初始化窗口大小等信息。
    initFrame();
    // 4、打乱数组色块的顺序,再展示图片
    initRandomArray();
    // 2、初始化界面:展示数字色块。
    initImage();
    // 3、初始化系统菜单:点击弹出菜单信息是系统退出,重启游戏
    initMenu();
    // 5、给当前窗口绑定上下左右按键事件。
    initKeyPressEvent();
    // 设置窗口的显示
    this.setVisible(true);
    }

    private void initKeyPressEvent() {
    // 给当前窗口绑定上下左右按键事件。
    this.addKeyListener(new KeyAdapter() {
    @Override
    public void keyPressed(KeyEvent e) {
    // 获取当前按钮的编号
    int keyCode = e.getKeyCode();
    // 判断这个编号是否是上下左右的按键
    switch (keyCode) {
    case KeyEvent.VK_UP:
    // 用户按了上键,让图片向上移动。
    switchAndMove(Direction.UP);
    break;
    case KeyEvent.VK_DOWN:
    // 用户按了下键,让图片向下移动。
    switchAndMove(Direction.DOWN);
    break;
    case KeyEvent.VK_LEFT:
    // 用户按了左键,让图片向左移动。
    switchAndMove(Direction.LEFT);
    break;
    case KeyEvent.VK_RIGHT:
    // 用户按了右键,让图片向右移动。
    switchAndMove(Direction.RIGHT);
    break;
    }
    }
    });
    }

    // 控制数据交换,和图片移动。
    private void switchAndMove(Direction r){
    // 判断图片的方向,再控制图片移动
    switch (r) {
    case UP:
    // 上交换的条件是行必须 < 3,然后才开始交换.
    if(row < imageData.length - 1){
    // 当前空白色块位置:rol col
    // 需要被交换的位置:row + 1 col
    int temp = imageData[row][col];
    imageData[row][col] = imageData[row + 1][col];
    imageData[row + 1][col] = temp;
    // 更新当前空白色块的位置了。
    row++;
    }
    break;
    case DOWN:
    if(row > 0){
    // 当前空白色块位置:rol col
    // 需要被交换的位置:row - 1 col
    int temp = imageData[row][col];
    imageData[row][col] = imageData[row - 1][col];
    imageData[row - 1][col] = temp;
    // 更新当前空白色块的位置了。
    row--;
    }
    break;
    case LEFT:
    // 左交换的条件是空白色块的列必须小于3
    if(col < imageData.length - 1){
    // 当前空白色块位置:rol col
    // 需要被交换的位置:row col + 1
    int temp = imageData[row][col];
    imageData[row][col] = imageData[row][col + 1];
    imageData[row][col + 1] = temp;
    // 更新当前空白色块的位置了。
    col++;
    }
    break;
    case RIGHT:
    if(col > 0){
    // 当前空白色块位置:rol col
    // 需要被交换的位置:row col - 1
    int temp = imageData[row][col];
    imageData[row][col] = imageData[row][col - 1];
    imageData[row][col - 1] = temp;
    // 更新当前空白色块的位置了。
    col--;
    }
    break;
    }
    // 重新刷新界面!!!
    initImage();
    }

    private void initRandomArray() {
    // 打乱二维数组中的元素顺序
    for (int i = 0; i < imageData.length; i++) {
    for (int j = 0; j < imageData[i].length; j++) {
    // 随机两个行列位置,让这两个位置交换。
    int i1 = (int) (Math.random() * imageData.length);
    int j1 = (int) (Math.random() * imageData.length);

    int i2 = (int) (Math.random() * imageData.length);
    int j2 = (int) (Math.random() * imageData.length);

    int temp = imageData[i1][j1];
    imageData[i1][j1] = imageData[i2][j2];
    imageData[i2][j2] = temp;
    }
    }

    // 定位空白色块的位置。
    // 去二维数组中遍历每个数据,只要发现这个数据等于0,这个位置就是当前空白色块的位置。
    OUT:
    for (int i = 0; i < imageData.length; i++) {
    for (int j = 0; j < imageData[i].length; j++) {
    if (imageData[i][j] == 0) {
    // 定位到空白色块的位置。
    row = i;
    col = j;
    break OUT; // 跳出循环。
    }
    }
    }
    }

    private void initMenu() {
    JMenuBar menuBar = new JMenuBar(); // 创建一个菜单条
    JMenu menu = new JMenu("系统"); // 创建一个菜单
    JMenuItem exitJi = new JMenuItem("退出");
    menu.add(exitJi); // 添加一个菜单项
    exitJi.addActionListener(e -> {
    dispose(); // 销毁!
    });
    // 添加一个菜单,重启
    JMenuItem restartJi = new JMenuItem("重启");
    menu.add(restartJi);
    restartJi.addActionListener(e -> {
    // 重启游戏。
    });
    menuBar.add(menu); // 添加到菜单条中
    this.setJMenuBar(menuBar);
    }

    private void initImage() {
    // 先清空窗口上的全部图层
    this.getContentPane().removeAll();


    // 1、展示一个行列矩阵的图片色块依次铺满窗口(4 * 4)
    for (int i = 0; i < imageData.length; i++) {
    for (int j = 0; j < imageData[i].length; j++) {
    // 拿到图片的名称
    String imageName = imageData[i][j] + ".png";
    // 2、创建一个JLabel对象,设置图片给他展示。
    JLabel label = new JLabel();
    // 3、设置图片到label对象中去。
    label.setIcon(new ImageIcon( imagePath + imageName));
    // 4、设置图片位置展示出来
    label.setBounds(20 + j * 100,60 + i * 100, 100, 100);
    // 5、把这个图片展示到窗口上去
    this.add(label);
    }
    }

    // 设置窗口的背景图片
    JLabel background = new JLabel(new ImageIcon(imagePath + "background.png"));
    background.setBounds(0, 0, 450, 484);
    this.add(background);

    // 刷新新图层,重新绘制
    this.repaint();
    }

    private void initFrame() {
    // 设置窗口的标题
    this.setTitle("石子迷宫 V 1.0 dlei");
    // 设置窗口的宽高
    this.setSize(465,575);
    // 设置窗口的关闭方式
    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    // 设置窗口的居中显示
    this.setLocationRelativeTo(null);
    // 设置布局方式为绝对位置定位
    this.setLayout(null);
    }
    }

4、判断是否通关

  • 用户每操作一步,需要立即判断是否已经通关,如果通过,需要显示胜利的标记。
  • image-20240711162511773
  • private int[][] winData = new int[][]{
            {1, 2, 3, 4},
            {5, 6, 7, 8},
            {9, 10, 11, 12},
            {13, 14, 15, 0}
    };
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12

    ```java
    private boolean isWin() {
    for (int i = 0; i < data.length; i++) {
    for (int j = 0; j < data[i].length; j++) {
    if(data[i][j] != winData[i][j]){
    return false;
    }
    }
    }
    return true;
    }
    1
    2
    3
    4
    5
    if(isWin()){
    JLabel winLabel = new JLabel(new ImageIcon(IMAGE_PATH + "win.png"));
    winLabel.setBounds(124, 230, 266, 88);
    this.add(winLabel);
    }

5、统计移动步骤、重启游戏

  • 每成功移动一步,都需要累加一次步数。
  • 定义一个变量用于累加步数,并实时展示到界面上。

6、完整代码:

MainFrame.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
package com.itheima;

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

//自定义窗口类
public class MainFrame extends JFrame {
//设置图片位置为常量
private static final String IMAGE_PATH = "stone-maze\\src\\image\\";
//统计移动步数
private int step = 0;
//准备一个数组,用于存储数字色块的行列信息,4行4列
private int[][] imageData = new int[][]{
{1,2,3,4},
{5,6,7,8},
{9,10,11,12},
{13,14,15,0}
};

//定义两个整数变量记录当前空白色块位置
private int blankRow = 3;//行
private int blankCol = 3;//列

//胜利时的数组
private int[][] winData = new int[][]{
{1,2,3,4},
{5,6,7,8},
{9,10,11,12},
{13,14,15,0}
};

public MainFrame() {
//1、调用一个初始化方法:初始化窗口
initFrame();
//4、打乱数组色块顺序,在展示图片
initRandomArray();
//2、初始化窗口的界面:展示数字色块
initImage();
//3、初始化系统菜单:展示点击弹出菜单信息是系统退出、重启游戏
initMenu();

//4、给当前窗口绑定上下左右按键事件
initKeyPressEvent();

//设置窗口显示
this.setVisible(true);

}

private void initKeyPressEvent() {
//给当前窗口绑定上下左右按键事件
this.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
//获取键盘按下的键值
int keyCode = e.getKeyCode();
//判断按下的键值
switch (keyCode){
case KeyEvent.VK_UP:
//上
switchmove(Direction.UP);
break;
case KeyEvent.VK_DOWN:
//下
switchmove(Direction.DOWN);
break;
case KeyEvent.VK_LEFT:
//左
switchmove(Direction.LEFT);
break;
case KeyEvent.VK_RIGHT:
//右
switchmove(Direction.RIGHT);
break;
}
}
});
}

//移动图片
private void switchmove(Direction direction){
//判断图片方向,再控制图片移动
switch (direction){
case UP:
//上交换的前提:行小于3
if(blankRow < imageData.length-1){
//交换
int temp = imageData[blankRow][blankCol];
imageData[blankRow][blankCol] = imageData[blankRow+1][blankCol];
imageData[blankRow+1][blankCol] = temp;
//记录空白色块的位置
blankRow++;
step++;
}
break;
case DOWN:
//下交换的前提:行大于0
if(blankRow > 0){
//交换
int temp = imageData[blankRow][blankCol];
imageData[blankRow][blankCol] = imageData[blankRow-1][blankCol];
imageData[blankRow-1][blankCol] = temp;
//记录空白色块的位置
blankRow--;
step++;
}
break;
case LEFT:
//左交换的前提:列小于3
if(blankCol < imageData[blankRow].length-1){
//交换
int temp = imageData[blankRow][blankCol];
imageData[blankRow][blankCol] = imageData[blankRow][blankCol+1];
imageData[blankRow][blankCol+1] = temp;
//记录空白色块的位置
blankCol++;
step++;
}
break;
case RIGHT:
//右交换的前提:列大于0
if(blankCol > 0){
//交换
int temp = imageData[blankRow][blankCol];
imageData[blankRow][blankCol] = imageData[blankRow][blankCol-1];
imageData[blankRow][blankCol-1] = temp;
//记录空白色块的位置
blankCol--;
step++;
}
break;
}
//刷新界面
initImage();

}


// private void initRandomArray() {
// //打乱二维数组中的元素位置
// for (int i = 0; i < imageData.length; i++) {
// for (int j = 0; j < imageData[i].length; j++) {
// //随机两个行列位置,让这两个位置交换
// int i1 = (int)(Math.random()*imageData.length);
// int j1 = (int)(Math.random()*imageData[i].length);
//
// int i2 = (int)(Math.random()*imageData.length);
// int j2 = (int)(Math.random()*imageData[i].length);
//
// int temp = imageData[i1][j1];
// imageData[i1][j1] = imageData[i2][j2];
// imageData[i2][j2] = temp;
//
// }
// }
// //定位空白色块位置
// //二维数组中遍历找出
// OUT:
// for (int i = 0; i < imageData.length; i++) {
// for (int j = 0; j < imageData[i].length; j++) {
// if(imageData[i][j] == 0){
// //记录空白色块的行列位置
// blankRow = i;
// blankCol = j;
// break OUT;//跳出循环
// }
// }
// }
// }

private void initRandomArray() {
//随机打乱数组,以空白色块位置为中心,与周围色块进行随机交换,可以设置交换次数为100次到200次随机
int count = (int) (Math.random() * 300) + 300;
for (int i = 0; i < count; i++) {
switch ((int) (Math.random() * 4)) {
case 0:
switchmove(Direction.UP);
break;
case 1:
switchmove(Direction.DOWN);
break;
case 2:
switchmove(Direction.LEFT);
break;
case 3:
switchmove(Direction.RIGHT);
break;
}
}
// OUT:
// for (int i = 0; i < imageData.length; i++) {
// for (int j = 0; j < imageData[i].length; j++) {
// if (imageData[i][j] == 0) {
// //记录空白色块的行列位置
// blankRow = i;
// blankCol = j;
// break OUT;//跳出循环
// }
// }
//
// }
//重置步数
step = 0;
}

private void initMenu() {
JMenuBar menuBar = new JMenuBar();//创建菜单栏
JMenu menu = new JMenu("系统");//创建菜单
JMenuItem exit = new JMenuItem("退出");//创建菜单项
JMenuItem restart = new JMenuItem("重启游戏");
menu.add(exit);
menu.add(restart);

exit.addActionListener(e -> {
dispose();//关闭窗口
});
restart.addActionListener(e -> {
//重启游戏
step = 0;//重置步数
initRandomArray();
initImage();
});

menuBar.add(menu);
this.setJMenuBar(menuBar);
}



private void initImage() {
//先清空窗口上的全部图层
this.getContentPane().removeAll();

//刷新界面时,展示移动步数
JLabel stepLabel = new JLabel("步数:"+step);
stepLabel.setBounds(20,20,100,20);
stepLabel.setFont(new Font("宋体", Font.BOLD,18));
//展示步数的字体加粗,设置为红色
stepLabel.setForeground(Color.RED);
this.getContentPane().setLayout(null);

this.add(stepLabel);

//判断是否胜利
if(iswin()){
//展示胜利时图片
JLabel winLabel = new JLabel(new ImageIcon(IMAGE_PATH+"win.png"));
winLabel.setBounds(124,230,266,88);
this.add(winLabel);

}

//1、展示一个行列矩阵的图片色块依次铺满窗口(4*4)
for (int i = 0; i < imageData.length; i++) {
for (int j = 0; j < imageData[i].length; j++) {
//1、获取图片名称
String imageName = imageData[i][j]+".png";
//2、创建一个JLable对象,设置图片给它展示
JLabel lable = new JLabel();
//3、设置图片到JLable对象中
lable.setIcon(new ImageIcon(IMAGE_PATH+imageName));
//4、设置坐标
lable.setBounds(20+j*100,60+i*100,100,100);
//5、添加到窗口中
this.add(lable);
}
}

//设置窗口背景图片
JLabel bgLabel = new JLabel(new ImageIcon(IMAGE_PATH+"background.png"));
bgLabel.setBounds(0,0,450,484);
this.add(bgLabel);

//刷新界面,重新绘制
this.repaint();

}

private boolean iswin() {
//判断游戏内的二维数组和胜利的二维数组是否一致
for (int i = 0; i < imageData.length; i++) {
for (int j = 0; j < imageData[i].length; j++) {
if(imageData[i][j] != winData[i][j]){
return false;
}
}
}
return true;
}

private void initFrame() {
//设置窗口标题
this.setTitle("石头迷阵 V1.1 cchao");
//设置窗口大小
this.setSize(465, 575);
//设置窗口居中
this.setLocationRelativeTo(null);
//设置窗口关闭按钮的默认操作
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//设置布局方式为绝对位置布局
this.setLayout(null);


}

}

Direction.java:

1
2
3
4
5
package com.itheima;

public enum Direction {
UP,DOWN,LEFT,RIGHT;
}

APP.java:

1
2
3
4
5
6
7
package com.itheima;

public class App {
public static void main(String[] args) {
new MainFrame();
}
}