1. 成员变量扩展
// 统计移动步数
int step = 0;
// 胜利时的目标数组(每个方块的"正确位置")
int[][] win = new int[][]{{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}, {13, 14, 15, 0}};
// 图片资源主路径(后续可切换动物、风景等主题)
String path = "image/animal/animal1/";
// 空白方块在二维数组中的坐标(x行y列)
int x = 0, y = 0;
// 记录当前拼图方块的位置(动态变化)
int[][] arr = new int[4][4];
// 菜单栏的菜单项(用于绑定点击事件)
JMenuItem rePlayItem = new JMenuItem("重置游戏");
JMenuItem reLogo = new JMenuItem("重新登录");
JMenuItem closeGame = new JMenuItem("关闭游戏");
JMenuItem gongZhongHao = new JMenuItem("公众号");(1)胜利判定:win1()
判断当前拼图数组arr是否与 "目标数组win" 完全一致
private boolean win1() {
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4; j++) {
            if (arr[i][j] != win[i][j]) {
                return false; // 有一个位置不一致,未胜利
            }
        }
    }
    return true; // 所有位置一致,判定胜利
}(2)随机打乱图片:randomPicture(int[][] arr)
用 "洗牌算法" 随机交换数组元素,实现拼图打乱
private void randomPicture(int[][] arr) {
    int[] temp = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0};
    Random r = new Random();
    // 第一步:数组元素"洗牌"(随机交换)
    for (int i = 0; i < temp.length; i++) {
        int index = r.nextInt(arr.length * arr[0].length); // 生成随机下标
        int t = temp[i];
        temp[i] = temp[index];
        temp[index] = t;
    }
    // 第二步:将一维数组转二维,并记录空白方块位置
    for (int i = 0; i < temp.length; i++) {
        if (temp[i] == 0) { // 找到空白方块(值为0)
            x = i / 4; // 计算所在行
            y = i % 4; // 计算所在列
        }
        arr[i / 4][i % 4] = temp[i];
    }
}(3)初始化 / 刷新拼图:initPicture(int[][] arr)
根据数组arr的状态,刷新界面上的拼图图
private void initPicture(int[][] arr) {
    this.getContentPane().removeAll(); // 清空原有组件
    
    // 显示步数
    JLabel stepCount = new JLabel("步数:" + step);
    stepCount.setBounds(20, 20, 60, 20);
    this.getContentPane().add(stepCount);
    
    // 胜利判定:若拼图完成,显示胜利图片
    if (win1()) {
        ImageIcon winPicture = new ImageIcon("image/win.png");
        JLabel label = new JLabel(winPicture);
        label.setBounds(100, 100, winPicture.getIconWidth(), winPicture.getIconHeight());
        this.getContentPane().add(label);
    }
    
    // 绘制拼图方块(根据arr数组)
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4; j++) {
            ImageIcon icon = new ImageIcon(path + arr[i][j] + ".jpg");
            JLabel label = new JLabel(icon);
            label.setBounds(105 * j + 100, 105 * i + 100, icon.getIconWidth(), icon.getIconHeight());
            this.getContentPane().add(label);
        }
    }
    
    // 绘制背景图
    ImageIcon background = new ImageIcon("image/background.png");
    JLabel label2 = new JLabel(background);
    label2.setBounds(56, 8, background.getIconWidth(), background.getIconHeight());
    this.getContentPane().add(label2);
    
    this.getContentPane().repaint(); // 刷新界面
}(4)键盘事件监听:控制方块移动
通过 方向键(←↑→↓)控制空白方块移动,A键显示全图,W键直接通关
@Override
public void keyPressed(KeyEvent e) {
    int code = e.getKeyCode();
    // 按A键:显示完整图片(方便参考拼图)
    if (code == 65) { 
        this.getContentPane().removeAll();
        ImageIcon all = new ImageIcon(path + "all.jpg");
        JLabel label = new JLabel(all);
        label.setBounds(100, 102, all.getIconWidth(), all.getIconHeight());
        this.add(label);
        ImageIcon background = new ImageIcon("image/background.png");
        JLabel label2 = new JLabel(background);
        label2.setBounds(56, 8, background.getIconWidth(), background.getIconHeight());
        this.add(label2);
        this.getContentPane().repaint();
    }
}
@Override
public void keyReleased(KeyEvent e) {
    if (win1()) return; // 胜利后,键盘操作无效
    
    int code = e.getKeyCode();
    // ←键:空白方块左移(交换右侧方块)
    if (code == 37) {
        if (y == 0) return; // 最左侧,无法左移
        arr[x][y] = arr[x][y - 1];
        arr[x][y - 1] = 0;
        y--;
        step++; // 步数+1
        initPicture(arr); // 刷新拼图
    } 
    // ↑键:空白方块上移(交换下方方块)
    else if (code == 38) {
        if (x == 0) return; // 最上方,无法上移
        arr[x][y] = arr[x - 1][y];
        arr[x - 1][y] = 0;
        x--;
        step++;
        initPicture(arr);
    } 
    // →键:空白方块右移(交换左侧方块)
    else if (code == 39) {
        if (y == 3) return; // 最右侧,无法右移
        arr[x][y] = arr[x][y + 1];
        arr[x][y + 1] = 0;
        y++;
        step++;
        initPicture(arr);
    } 
    // ↓键:空白方块下移(交换上方方块)
    else if (code == 40) {
        if (x == 3) return; // 最下方,无法下移
        arr[x][y] = arr[x + 1][y];
        arr[x + 1][y] = 0;
        x++;
        step++;
        initPicture(arr);
    } 
    // W键:直接胜利(测试用,后续可移除)
    else if (code == 87) {
        arr = new int[][]{{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}, {13, 14, 15, 0}};
        initPicture(arr);
    }
}5)菜单栏点击事件:actionPerformed
为 "重置游戏""重新登录""关闭游戏""公众号" 添加具体逻辑
@Override
public void actionPerformed(ActionEvent e) {
    Object source = e.getSource();
    // 重置游戏:步数清零 + 重新打乱图片
    if (source == rePlayItem) {
        step = 0;
        randomPicture(arr);
        initPicture(arr);
    } 
    // 重新登录:隐藏当前窗口,打开启动页
    else if (source == reLogo) {
        this.setVisible(false);
        new LogoJframe();
    } 
    // 关闭游戏:退出程序
    else if (source == closeGame) {
        System.exit(0);
    } 
    // 公众号:弹出包含公众号图片的对话框
    else if (source == gongZhongHao) {
        JDialog jd = new JDialog();
        ImageIcon gongZhongPicture = new ImageIcon("image/小韦(小).png");
        JLabel label = new JLabel(gongZhongPicture);
        label.setBounds(0, 0, 1800, 1800);
        jd.getContentPane().add(label);
        jd.setAlwaysOnTop(true);
        jd.setSize(600, 600);
        jd.setLocationRelativeTo(null);
        jd.setModal(true); // 模态窗口(阻止父窗口交互)
        jd.setVisible(true);
    }
}