验证码获取:

public class CodeUtil {
    public static String getCode(){
        ArrayList<Character> list=new ArrayList<>();
        for (int i = 0; i < 26; i++) {
            list.add((char)('a'+i));
            list.add((char)('A'+i));
        }
        for(int i=0;i<10;i++){
            list.add((char)('0'+i));
        }
        Random r=new Random();
        int index;
        StringBuilder code=new StringBuilder();
        for(int i=0;i<4;i++){
            index=r.nextInt(52);
            code.append(list.get(index));
        }
        index=r.nextInt(10)+52;
        code.append(list.get(index));
        for(int i=0;i<5;i++){
            index=r.nextInt(4);
            char temp=code.charAt(i);
            code.setCharAt(i,code.charAt(index));
            code.setCharAt(index,temp);
        }
        return code.toString();
    }
}
-------------------------
游戏类:
```java
public class GameJFrame extends JFrame implements KeyListener, ActionListener {
    //步数器
    int step=0;
    //定义一个二维数组,用于存储正确图片的编号
    int [][]win=new int[][]{{3,2},{1,0}};
    int[][] map = new int[2][2];
    //定义一个变量,记录空白图片的位置
    int x = 0, y = 0;
String path="C:\\Users\\喻响\\IdeaProjects\\day19-exercise\\image1\\";
    JMenuItem replayItem;
    JMenuItem reLoginItem;
    JMenuItem closeItem;
    JMenuItem aboutItem;
    public GameJFrame() {
        //初始化界面
        InitJFrame();
        //初始化菜单
        InitJMenuBar();
        //初始化图片顺序
        initData();
        //初始化图片
        InitImage();
        //设置界面可见,建议写在最后
        this.setVisible(true);
    }

    private void initData() {
        int[] temp = {0, 1, 2, 3};
        Random r = new Random();
        int index;
        for (int i = 0; i < temp.length; i++) {
            index = r.nextInt(4);
            int t = temp[i];
            temp[i] = temp[index];
            temp[index] = t;
        }
        //给二维数组添加数据
        for (int i = 0; i < temp.length; i++) {
            if (temp[i] == 0) {
                x = i / 2;
                y = i % 2;
            }
            map[i / 2][i % 2] = temp[i];

        }
    }

    private void InitImage() {
        //清空原本的图片
        this.getContentPane().removeAll();
        //判断胜利
        if(isWin()){
            JLabel winJLabel=new JLabel(new ImageIcon(path+"win.jpg"));
            winJLabel.setBounds(100,100,760,780);
            this.getContentPane().add(winJLabel);
            //this.getContentPane().repaint();
        }
        //重新添加图片
        for (int i = 0; i < 2; i++) {
            for (int j = 0; j < 2; j++) {
                int number = map[i][j];
                //创建一个imageIcon对象
                ImageIcon imageIcon = new ImageIcon(path + number + ".jpg");
                //创建一个JLable对象(管理容器)
                JLabel imageJLabel = new JLabel(imageIcon);
                //指定图片位置
                imageJLabel.setBounds(j * 380 + 100, i * 380 + 100, 380, 380);
                //给图片添加边框
                //0-外边框(凸),1-内边框(凹)
                imageJLabel.setBorder(new BevelBorder(1));//BorderFactory.createLineBorder(java.awt.Color.BLACK)
                //把管理容器添加到界面中
                //this.add(imageJLabel);
                this.getContentPane().add(imageJLabel);
            }
        }
        //如果要添加背景图片需要添加在最后
        //例如:
        /*ImageIcon bgImageIcon = new ImageIcon("C:\\Users\\喻响\\IdeaProjects\\day19-exercise\\image1\\bg.jpg");
        JLabel bgImageJLabel = new JLabel(bgImageIcon);
        bgImageJLabel.setBounds(0,0,983,1000);
        this.getContentPane().add(bgImageJLabel);*/
        //添加步数计数器
        JLabel stepJLabel=new JLabel("步数:"+step);
        stepJLabel.setBounds(10,10,100,50);
        this.getContentPane().add(stepJLabel);
        //刷新界面
        this.getContentPane().repaint();
    }

    private void InitJMenuBar() {
        //创建整个菜单对象
        JMenuBar jMenuBar = new JMenuBar();
        //创建菜单上的功能菜单
        JMenu functionJMenu = new JMenu("功能");
        JMenu aboutJMenu = new JMenu("关于游戏");
        //创建菜单下的条目
         replayItem = new JMenuItem("重新游戏");
         reLoginItem = new JMenuItem("重新登录");
         closeItem = new JMenuItem("关闭游戏");

         aboutItem = new JMenuItem("看啥,啥也没有");
        //将条目添加到功能菜单上
        functionJMenu.add(replayItem);
        functionJMenu.add(reLoginItem);
        functionJMenu.add(closeItem);
        aboutJMenu.add(aboutItem);
        //给条目绑定时间
        replayItem.addActionListener(this);
        reLoginItem.addActionListener(this);
        closeItem.addActionListener(this);
        aboutItem.addActionListener(this);
        //将功能菜单添加到菜单上
        jMenuBar.add(functionJMenu);
        jMenuBar.add(aboutJMenu);
        //给整个界面设置菜单
        this.setJMenuBar(jMenuBar);
    }

    private void InitJFrame() {
        //设置大小
        this.setSize(983, 1000);
        //设置界面标题
        this.setTitle("拼图游戏单机版1.0");
        //设置界面置顶
        this.setAlwaysOnTop(true);
        //设置界面居中
        this.setLocationRelativeTo(null);
        //设置关闭模式,0-3代表不同关闭模式
        //0-正常退出,1-隐藏当前界面(关闭当前界面),2-所有界面全部隐藏(),3-退出虚拟机(关闭界面直接关闭所有界面并退出虚拟机)
        this.setDefaultCloseOperation(3);
        //取消默认居中放置,由坐标决定
        this.setLayout(null);
        //给整个界面添加键盘监听
        this.addKeyListener(this);
    }

    @Override
    public void keyTyped(KeyEvent e) {

    }

    //按下不松时调用
    @Override
    public void keyPressed(KeyEvent e) {
        int code = e.getKeyCode();
        if (code == 65) {//a键
            //清空原本的图片
            this.getContentPane().removeAll();
            //创建一个imageIcon对象
            ImageIcon imageIcon1 = new ImageIcon(path+"all.jpg");
            //创建一个JLable对象(管理容器)
            JLabel imageJLabel1 = new JLabel(imageIcon1);
            //指定图片位置
            imageJLabel1.setBounds(100, 100, 760, 780);
            //把管理容器添加到界面中
            this.getContentPane().add(imageJLabel1);
            //刷新界面
            this.getContentPane().repaint();
        }
    }

    @Override
    public void keyReleased(KeyEvent e) {
        //判断是否胜利
        if(isWin()){
            //1.返回结果 2.结束方法
            return;
        }
        //对上下左右判断
        //上下左右的键值分别为38,40,37,39
        int code = e.getKeyCode();
        if (code == 37) {
            System.out.println("向左移动");
            if (y == 1) {
                return;
            }
            map[x][y] = map[x][y + 1];
            map[x][y + 1] = 0;
            y = y + 1;
            //步数加一
            step++;
            //调用方法,重新初始化图片
            InitImage();//此方法中包含了map数组的重新赋值,但是要先删掉原先的图片,会产生重叠现象

        } else if (code == 38) {
            System.out.println("向上移动");
            if (x == 1) {
                return;
            }
            //x,y表示空白图片的位置
            //x+1,y表示空白图片的下方图片的位置
            //把空白方块下方的数字赋值给空白方块
            map[x][y] = map[x + 1][y];
            map[x + 1][y] = 0;
            x = x + 1;
            //步数加一
            step++;
            //调用方法,重新初始化图片
            InitImage();//此方法中包含了map数组的重新赋值,但是要先删掉原先的图片,会产生重叠现象


        } else if (code == 39) {
            System.out.println("向右移动");
            if (y == 0) {
                return;
            }
            map[x][y] = map[x][y - 1];
            map[x][y - 1] = 0;
            y = y - 1;
            //步数加一
            step++;
            //调用方法,重新初始化图片
            InitImage();//此方法中包含了map数组的重新赋值,但是要先删掉原先的图片,会产生重叠现象
        } else if (code == 40) {
            System.out.println("向下移动");
            if (x == 0) {
                return;
            }
            map[x][y] = map[x - 1][y];
            map[x - 1][y] = 0;
            x = x - 1;
            //步数加一
            step++;
            //调用方法,重新初始化图片
            InitImage();//此方法中包含了map数组的重新赋值,但是要先删掉原先的图片,会产生重叠现象
        }else if(code==65){//a键,一键还原
            InitImage();
        }else if(code==87){//w键,一键完成
            map=new int[][]{
                    {3,2},
                    {1,0}
            };
            InitImage();
        }
    }
    public boolean isWin(){
        for (int i = 0; i < map.length; i++) {
            for(int j=0;j<map[i].length;j++){
                if(map[i][j]!=win[i][j]){
                    return false;
                }
            }
        }
        return true;
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        Object source=e.getSource();
        if(source==replayItem){
            System.out.println("重新游戏");
            //重置步数
            step=0;
            //重新初始化数据
            initData();
            //重新初始化图片
            InitImage();
        }else if(source==reLoginItem){
            System.out.println("重新登录");
            //关闭当前界面
            this.setVisible(false);
            //创建一个新的登陆界面
            new LoginJFrame();
        }else if(source==closeItem){
            System.out.println("关闭游戏");
            System.exit(0);
        }else if(source==aboutItem){
            System.out.println("看啥,真啥也没有");
            //创建一个弹窗
            JDialog jd=new JDialog();
            JLabel jl=new JLabel("啥也没有");
            jl.setBounds(0,0,200,200);
            jd.getContentPane().add(jl);
            jd.setSize(200,200);
            //设置弹窗置顶
            jd.setAlwaysOnTop(true);
            //设置弹窗居中
            jd.setLocationRelativeTo(null);
            //设置弹框可见
            jd.setVisible(true);
        }
    }
}
--------------------------------------------------
登录类:
```java
public class LoginJFrame extends JFrame implements ActionListener {
    //创建一个用户集合
    static ArrayList<User> list=new ArrayList<>();
    static{
        list.add(new User("haha","123"));
        list.add(new User("xiangxiang","456"));
    }
    JButton login;
    JButton register;
    JTextField code;
    String codeStr;
    JTextField  username;
    JPasswordField password;

    public LoginJFrame() {
        //初始化界面
       InitJFrame();
       //在界面上添加内容
        InitView();
        //让当前界面显示出来
        this.setVisible(true);
    }

    private void InitView() {
        //添加用户名输入框
        username=new JTextField();
        username.setBounds(195,134,200,30);
        this.add(username);
        //添加密码输入框
        password=new JPasswordField();
        password.setBounds(195,190,200,30);
        this.add(password);
        //验证码输入框
        code=new JTextField();
        code.setBounds(195,256,100,30);
        this.add(code);

        codeStr=CodeUtil.getCode();
        JLabel rightCode=new JLabel();
        //设置内容
        rightCode.setText(codeStr);
        //位置
        rightCode.setBounds(300,256,50,30);
        //添加到界面上
        this.add(rightCode);//展示正确的验证码
        //添加登录按钮
        login=new JButton("登录");
        login.setBounds(123,312,128,40);
        this.getContentPane().add(login);
        login.addActionListener(this);
        //添加注册按钮
        register=new JButton("注册");
        register.setBounds(256,312,128,40);
        this.getContentPane().add(register);
        register.addActionListener(this);

    }
    public void shoeJDialog(String content){
        //登录错误时弹出的弹框
        //创建一个对话框
        JDialog jd=new JDialog();
        //给弹框设置大小
        jd.setSize(200,150);
        //让弹框置顶
        jd.setAlwaysOnTop(true);
        //让弹框居中
        jd.setLocationRelativeTo(null);
        //弹框不关闭无法操作下面的界面
        jd.setModal(true);

        //创建Jlabel对象管理文字并添加到弹框上
        JLabel jl=new JLabel(content);
        jl.setBounds(0,0,200,150);
        jd.getContentPane().add(jl);
        //让弹框显示出来
        jd.setVisible(true);
    }

    private void InitJFrame(){
        this.setSize(488,430);
        this.setTitle("拼图 登录");
        //设置界面置顶
        this.setAlwaysOnTop(true);
        //设置界面居中
        this.setLocationRelativeTo(null);
        //设置关闭模式,0-3代表不同关闭模式
        //0-正常退出,1-隐藏当前界面(关闭当前界面),2-所有界面全部隐藏(),3-退出虚拟机(关闭界面直接关闭所有界面并退出虚拟机)
        this.setDefaultCloseOperation(3);
        //取消默认居中放置,改为绝对定位
        this.setLayout(null);
    }
    public boolean compare(String code,String rightCode){
        return code.equalsIgnoreCase(rightCode);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        Object source=e.getSource();
        if(source==login){
            String inputCode=code.getText();
            String inputUsername=username.getText();
            String inputPassword=password.getText();
            boolean flag=compare(inputCode,codeStr);
            if(!flag){
                System.out.println("验证码错误");
            }else{
                if((inputUsername.equals("haha")&&inputPassword.equals("123"))||(inputUsername.equals("xiangxiang")&&inputPassword.equals("456"))){
                    System.out.println("登录成功");
                    new GameJFrame();
                }else{
                    System.out.println("登录失败");
                    shoeJDialog("用户名或密码错误");
                }
            }
        }else if(source==register){
            System.out.println("还未开发,请使用默认人员登录");
            shoeJDialog("还未开发,请使用默认人员登录");
            //new RegisterJFrame();
        }
    }
}
-----------------------------------
注册类(未开发):
```java
public class RegisterJFrame extends JFrame {
    public RegisterJFrame() {

        this.setSize(488,500);
        this.setTitle("拼图 注册");
        //设置界面置顶
        this.setAlwaysOnTop(true);
        //设置界面居中
        this.setLocationRelativeTo(null);
        //设置关闭模式,0-3代表不同关闭模式
        //0-正常退出,1-隐藏当前界面(关闭当前界面),2-所有界面全部隐藏(),3-退出虚拟机(关闭界面直接关闭所有界面并退出虚拟机)
        this.setDefaultCloseOperation(3);
        this.setVisible(true);
    }
}
-----------------------------------------
用户类:
```java
public class User {
    private String username;
    private String password;

    public User() {
    }

    public User(String username, String password) {
        this.username = username;
        this.password = password;

    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

}
-------------------------------------------
测试:
```java
public class App {
    public static void main(String[] args) {
        //new GameJFrame();
        new LoginJFrame();
        //new RegisterJFrame();
    }
}