Java—— IO流的应用

带权重的点名系统

案例要求

文件中有学生的信息,每个学生的信息独占一行。包括学生的姓名,性别,权重
要求每次被抽中的学生,再次被抽中的概率在原先的基础上降低一半。
本题的核心就是带权重的随机

分析 

权重,权重和,权重占比

如何将概率降低为原先的一半

假设总共10个人,一开始设定每个人的权重都是1,权重和是10,权重占比=权重/权重和,那么每个人的权重占比是0.1,说明每个人一开始被抽中的概率都是0.1,抽中后再次被抽中的概率在原先的基础上降低一半,需要将其权重降低为原来的一半。修改完权重要将其写回文件,下次再抽人时权重就是0.5了。

细节:

权重降低为原来的一半,权重和也会改变,但是改变很小(由10变为9.5),人数越多改变越小(假如一共100人时,权重和为100,抽到一人,这人权重降低为原来的一半,权重和由100变为99.5),可以视作不变,而这个人权重降低为原来的一半,权重和又视作不变,则权重占比就是原来的一半。被抽中的概率就是原先的一半

权重占比的区间范围 

如何确定抽到哪个人

 一开始每个人的权重占比是0.1,说明可以将长度为1的数轴分为10等份,每个人占其中一份

这就是权重占比的区间范围,例如:

        于沧浪-男-1 (0.0~0.1] 
        双文楠-男-1 (0.1~0.2]
        鞠弘杰-男-1 (0.2~0.3]
        乐弘雪-男-1 (0.3~0.4]
        贝泽瀚-男-1 (0.4~0.5]
        孙秀逸-女-1 (0.5~0.6]
        蔺文思-女-1 (0.6~0.7]
        燕芷灵-女-1 (0.7~0.8]
        酆若环-女-1 (0.8~0.9]
        广飞瑶-女-1 (0.9~1.0]

随机一个0~1之间的数,其在哪个范围就表示抽取到了哪个同学

代码实现

Student类用于封装文件中的数据

public class Student {private String name;private String sex;private double weight;public Student() {}public Student(String name, String sex, double weight) {this.name = name;this.sex = sex;this.weight = weight;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}public double getWeight() {return weight;}public void setWeight(double weight) {this.weight = weight;}//toString方法数据格式与文件中相同//这样直接传递学生对象的toString方法就能写出相同格式的数据,public String toString() {return name + "-" + sex + "-" + weight;}
}

测试类 

import java.io.*;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;public class Test2 {public static void main(String[] args) throws IOException {//定义集合存储学生对象ArrayList<Student> list = new ArrayList<>();//将文件中的数据读出,交给Student对象进行封装BufferedReader br = new BufferedReader(new FileReader("day05\\names.txt"));String line;while ((line = br.readLine()) != null) {String[] arr = line.split("-");Student stu = new Student(arr[0], arr[1], Double.parseDouble(arr[2]));//将该Student添加到集合中list.add(stu);}br.close();//获取总权重double weightSum = 0;for (Student stu : list) {weightSum = weightSum + stu.getWeight();}//计算每个人的权重占比,保存到一个数组中double[] arr = new double[list.size()];int index = 0;for (Student stu : list) {arr[index] = stu.getWeight() / weightSum;index++;}System.out.println(Arrays.toString(arr));//计算每个人权重占比的区间范围//例如第一个人权重占比是0.1,那么就规定0~0.1是他的权重占比的区间范围,记为0.1//0~0.1是第一个人的,那么第二个人的权重占比的区间范围就从0.1开始//所以第二个人的权重占比的区间范围是 第一个人权重占比~第一个人权重占比+自己的权重占比//依次往后//随机一个0~1之间的数,若该数处于0~0.1,就表示随机到了第一个人for (int i = 1; i < arr.length; i++) {//利用BigDecimal精确运算BigDecimal bd1 = BigDecimal.valueOf(arr[i - 1]);BigDecimal bd2 = BigDecimal.valueOf(arr[i]);arr[i] = bd1.add(bd2).doubleValue();}System.out.println(Arrays.toString(arr));//随机0~1之间的数double random = Math.random();System.out.println(random);//判断random在数组中的位置//数组中元素是有序的利用二分查找法//如果要查找的元素在数组中,返回该元素的索引//如果要查找的元素不在数组中,返回值 = -索引 -1//通过加法交换率得           索引= -(返回值 +1)int i = Arrays.binarySearch(arr, random);if (i >= 0) {System.out.println(i);} else {i = -i - 1;System.out.println(i);}//索引i表示抽到的人Student stu = list.get(i);System.out.println(stu);//修改这个人的权重为原来的一半stu.setWeight(stu.getWeight() / 2);//将修改后的数据写回文件BufferedWriter bw = new BufferedWriter(new FileWriter("day05\\names.txt"));for (Student s : list) {bw.write(s.toString());bw.newLine();}bw.close();}
}

一开始文件中的数据         第一次抽取                 第二次抽取                 第三次抽取   

游戏注册功能以及存档功能

可以将用户信息和游戏进度写到一个文件中永久保存,这样结束程序重新启动时,数据不会丢失,借助IO将前面介绍的拼图游戏完善

程序启动类 

import java.io.IOException;public class App {public static void main(String[] args) throws IOException {//创建登录界面,在登录界面中成功登录后创建游戏界面new LoginJFrame();}
}

登录界面 

import javax.swing.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;public class LoginJFrame extends JFrame implements MouseListener {//不止一个方法使用的变量定义在成员变量位置JButton login;JButton register;JTextField username;JTextField password;JTextField code;String codeStr;JLabel showCode;JDialog jDialog;//记录所有用户ArrayList<User> list = new ArrayList();//空参构造初始化登录public LoginJFrame() throws IOException {//调用方法获取文件中记录的用户信息,存储在集合中UserInfo();//调用方法初始化登录界面initFrame();//调用方法加载登录界面图式loadImages();//添加事件监听,鼠标监听事件MouseListenerlogin.addMouseListener(this);register.addMouseListener(this);showCode.addMouseListener(this);//设置界面可视,建议放在最后this.setVisible(true);}//定义方法获取文件中记录的用户信息,存储在集合中private void UserInfo() throws IOException {BufferedReader br = new BufferedReader(new FileReader("PuzzleGame\\UserInfo.txt"));String line;while ((line = br.readLine()) != null) {String[] arr = line.split("&");String username = arr[0].split("=")[1];String password = arr[1].split("=")[1];User u = new User(username, password);list.add(u);}br.close();}//定义方法加载登录界面图式private void loadImages() {//1. 添加用户名文字JLabel usernameText = new JLabel(new ImageIcon("puzzlegame\\image\\login\\用户名.png"));usernameText.setBounds(116, 135, 47, 17);this.getContentPane().add(usernameText);//2.添加用户名输入框username = new JTextField();username.setBounds(195, 134, 200, 30);this.getContentPane().add(username);//3.添加密码文字JLabel passwordText = new JLabel(new ImageIcon("puzzlegame\\image\\login\\密码.png"));passwordText.setBounds(130, 195, 32, 16);this.getContentPane().add(passwordText);//4.密码输入框password = new JTextField();password.setBounds(195, 195, 200, 30);this.getContentPane().add(password);//验证码提示JLabel codeText = new JLabel(new ImageIcon("puzzlegame\\image\\login\\验证码.png"));codeText.setBounds(133, 256, 50, 30);this.getContentPane().add(codeText);//验证码的输入框code = new JTextField();code.setBounds(195, 256, 100, 30);this.getContentPane().add(code);//调用工具类生成验证码codeStr = CodeUtil.getCode();//显示生成的验证码showCode = new JLabel();//设置内容showCode.setText(codeStr);//位置和宽高showCode.setBounds(300, 256, 50, 30);//添加到界面this.getContentPane().add(showCode);//5.添加登录按钮login = new JButton();login.setBounds(123, 310, 128, 47);//设置按钮背景图login.setIcon(new ImageIcon("puzzlegame\\image\\login\\登录按钮.png"));//去除按钮的默认边框login.setBorderPainted(false);//去除按钮的默认背景login.setContentAreaFilled(false);this.getContentPane().add(login);//6.添加注册按钮register = new JButton();register.setBounds(256, 310, 128, 47);//设置按钮背景图register.setIcon(new ImageIcon("puzzlegame\\image\\login\\注册按钮.png"));//去除按钮的默认边框register.setBorderPainted(false);//去除按钮的默认背景register.setContentAreaFilled(false);this.getContentPane().add(register);//7.添加界面背景图片JLabel background = new JLabel(new ImageIcon("puzzlegame\\image\\login\\background.png"));background.setBounds(0, 0, 470, 390);this.getContentPane().add(background);}//定义方法初始化登录界面private void initFrame() {this.setSize(488, 430);this.setTitle("拼图游戏登录");this.setAlwaysOnTop(true);this.setLocationRelativeTo(null);this.setDefaultCloseOperation(3);this.setLayout(null);}//定义方法判断用户名密码是否正确private boolean checkUser(ArrayList<User> list, User u) {//查询用户名是否在集合中存在int index = checkUserName(list, u);if (index == -1) {//System.out.println("用户名和密码错误");return false;}//到这步,证明用户名存在,判断对应的密码是否相同if (list.get(index).getPassWord().equals(u.getPassWord())) {//相同返回truereturn true;}//不同返回falsereturn false;}//定义方法查询用户名是否在集合中存在,存在返回索引,不存在返回-1private int checkUserName(ArrayList<User> list, User u) {for (int i = 0; i < list.size(); i++) {if (list.get(i).getUserName().equals(u.getUserName())) {return i;}}return -1;}//定义方法展示弹窗private void showDialog(String s) {jDialog = new JDialog();//设置弹框的宽和高:100,100jDialog.setSize(100, 100);//设置弹框居中jDialog.setLocationRelativeTo(null);//设置弹框置顶jDialog.setAlwaysOnTop(true);//设置关闭后进行其他操作jDialog.setModal(true);//创建一个JLabel去编写文本内容JLabel textJlabel = new JLabel(s);textJlabel.setBounds(20, 50, 120, 60);//把文本JLabel添加到弹框当中jDialog.getContentPane().add(textJlabel);//把弹框展示出来jDialog.setVisible(true);}//鼠标监听事件MouseListener//鼠标单击调用该方法@Overridepublic void mouseClicked(MouseEvent e) {Object source = e.getSource();if (source == login) {//如果是登录按钮,获取输入框中的用户名,密码,验证码String myUserName = username.getText();String myPassWord = password.getText();String myCode = code.getText();//判断是否为空,如果为空,提示:用户名或密码为空if (myUserName.equals("") || myPassWord.equals("")) {//展示弹框:用户名或密码为空//调用方法展示弹框,参数为需要展示的文字showDialog("用户名或密码为空");//换一个验证码codeStr = CodeUtil.getCode();showCode.setText(codeStr);return;}//判断验证码是否正确if (!(myCode.equalsIgnoreCase(codeStr))) {//展示弹框:验证码错误showDialog("验证码错误");System.out.println("验证码错误");//换一个验证码codeStr = CodeUtil.getCode();showCode.setText(codeStr);return;}//判断用户名和密码是否为正确,如果正确隐藏登录界面,进入游戏界面。//调用方法判断User myUser = new User(myUserName, myPassWord);boolean flag = checkUser(list, myUser);if (!flag) {//展示弹框:用户名或密码错误showDialog("用户名或密码错误");System.out.println("用户名或密码错误");//换一个验证码codeStr = CodeUtil.getCode();showCode.setText(codeStr);return;}//到这步,证明用户名和密码正确//隐藏登录界面,进入游戏界面this.setVisible(false);new GameJFrame();} else if (source == showCode) {//重新生成验证码codeStr = CodeUtil.getCode();showCode.setText(codeStr);} else if (source == register) {//进行注册//关闭登录界面this.setVisible(false);//创建注册界面//把存储用户信息的集合传递过去,注册时用户名不能与集合中的重复new RegisterJFrame(list);}}//鼠标按下调用该方法@Overridepublic void mousePressed(MouseEvent e) {Object source = e.getSource();if (source == login) {//登录按钮//按下不松的时候利用setIcon方法,修改登录按钮的背景色login.setIcon(new ImageIcon("PuzzleGame\\image\\login\\登录按下.png"));} else if (source == register) {//注册按钮//按下不松的时候利用setIcon方法,修改注册按钮的背景色register.setIcon(new ImageIcon("PuzzleGame\\image\\login\\注册按下.png"));}}//鼠标释放调用该方法@Overridepublic void mouseReleased(MouseEvent e) {Object source = e.getSource();//登录按钮//释放的时候利用setIcon方法,恢复登录按钮的背景色if (source == login) {login.setIcon(new ImageIcon("PuzzleGame\\image\\login\\登录按钮.png"));} else if (source == register) {//注册按钮//释放的时候利用setIcon方法,恢复注册按钮的背景色register.setIcon(new ImageIcon("PuzzleGame\\image\\login\\注册按钮.png"));}}//鼠标划入调用该方法@Overridepublic void mouseEntered(MouseEvent e) {}//鼠标划出调用该方法@Overridepublic void mouseExited(MouseEvent e) {}}

注册界面

import javax.swing.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;public class RegisterJFrame extends JFrame implements MouseListener {//存储用户集合ArrayList<User> list;//提升三个输入框的变量的作用范围,让这三个变量可以在本类中所有方法里面可以使用。JTextField username = new JTextField();JTextField password = new JTextField();JTextField rePassword = new JTextField();//提升两个按钮变量的作用范围,让这两个变量可以在本类中所有方法里面可以使用。JButton submit = new JButton();JButton reset = new JButton();//弹窗JDialog jDialog;public RegisterJFrame(ArrayList<User> list) {//接收传递过来的用户集合this.list = list;//初始化界面initFrame();//调用方法加载登录界面图式initView();//添加事件监听,鼠标监听事件MouseListenersubmit.addMouseListener(this);reset.addMouseListener(this);//设置界面可视,建议放在最后this.setVisible(true);}//初始化界面private void initFrame() {//对自己的界面做一些设置。//设置宽高this.setSize(488, 430);//设置标题this.setTitle("拼图游戏 V1.0注册");//取消内部默认布局this.setLayout(null);//设置关闭模式this.setDefaultCloseOperation(3);//设置居中this.setLocationRelativeTo(null);//设置置顶this.setAlwaysOnTop(true);}//加载登录界面图式private void initView() {//添加注册用户名的文本JLabel usernameText = new JLabel(new ImageIcon("puzzlegame\\image\\register\\注册用户名.png"));usernameText.setBounds(85, 135, 80, 20);//添加注册用户名的输入框username.setBounds(195, 134, 200, 30);//添加注册密码的文本JLabel passwordText = new JLabel(new ImageIcon("puzzlegame\\image\\register\\注册密码.png"));passwordText.setBounds(97, 193, 70, 20);//添加密码输入框password.setBounds(195, 195, 200, 30);//添加再次输入密码的文本JLabel rePasswordText = new JLabel(new ImageIcon("puzzlegame\\image\\register\\再次输入密码.png"));rePasswordText.setBounds(64, 255, 95, 20);//添加再次输入密码的输入框rePassword.setBounds(195, 255, 200, 30);//注册的按钮submit.setIcon(new ImageIcon("puzzlegame\\image\\register\\注册按钮.png"));submit.setBounds(123, 310, 128, 47);submit.setBorderPainted(false);submit.setContentAreaFilled(false);//重置的按钮reset.setIcon(new ImageIcon("puzzlegame\\image\\register\\重置按钮.png"));reset.setBounds(256, 310, 128, 47);reset.setBorderPainted(false);reset.setContentAreaFilled(false);//背景图片JLabel background = new JLabel(new ImageIcon("puzzlegame\\image\\register\\background.png"));background.setBounds(0, 0, 470, 390);this.getContentPane().add(usernameText);this.getContentPane().add(passwordText);this.getContentPane().add(rePasswordText);this.getContentPane().add(username);this.getContentPane().add(password);this.getContentPane().add(rePassword);this.getContentPane().add(submit);this.getContentPane().add(reset);this.getContentPane().add(background);}//定义方法展示弹窗private void showDialog(String s) {jDialog = new JDialog();//设置弹框的宽和高:100,100jDialog.setSize(100, 100);//设置弹框居中jDialog.setLocationRelativeTo(null);//设置弹框置顶jDialog.setAlwaysOnTop(true);//设置关闭后进行其他操作jDialog.setModal(true);//创建一个JLabel去编写文本内容JLabel textJlabel = new JLabel(s);textJlabel.setBounds(20, 50, 120, 60);//把文本JLabel添加到弹框当中jDialog.getContentPane().add(textJlabel);//把弹框展示出来jDialog.setVisible(true);}//鼠标单击事件@Overridepublic void mouseClicked(MouseEvent e) {Object source = e.getSource();if (source == submit) {//注册按钮//得到三个输入框中的数据String myUsername = username.getText();String myPassword = password.getText();String myRePassword = rePassword.getText();//三个输入框中的数据不能为空if (myUsername.length() == 0 || myPassword.length() == 0 || myRePassword.length() == 0) {//弹窗提醒showDialog("输入框不能为空");//结束方法return;}//密码和再次输入的密码要相同if (!myPassword.equals(myRePassword)) {//弹窗提醒showDialog("两次输入的密码不同");//结束方法return;}//用户名要符合规定,4-16位大小写字母和数字if (!myUsername.matches("[a-zA-Z0-9]{4,16}")) {//弹窗提醒showDialog("用户名要4-16位大小写字母和数字");//结束方法return;}//密码要符合规定,至少6位大小写字母和数字if (!myPassword.matches("[a-zA-Z0-9]{6,}")) {//弹窗提醒showDialog("密码要至少6位大小写字母和数字");//结束方法return;}//用户名不能与集合中的重复//调用方法判断if (containsUsername(myUsername)) {//弹窗提醒showDialog("用户名已存在");//结束方法return;}//到这一步,说明用户名和密码符合条件//将其添加到用户集合中,并写到文件中永久存储User u = new User(myUsername, myPassword);list.add(u);try {BufferedWriter bw = new BufferedWriter(new FileWriter("PuzzleGame\\UserInfo.txt"));for (User user : list) {bw.write(user.toString());bw.newLine();}bw.close();//开启登录界面this.setVisible(false);new LoginJFrame();} catch (IOException ex) {throw new RuntimeException(ex);}} else if (source == reset) {//重置按钮//清空三个输入框中的内容username.setText("");password.setText("");rePassword.setText("");}}//判断自定义用户名是否与集合中的用户名重复private boolean containsUsername(String myUsername) {for (User u : list) {if (u.getUserName().equals(myUsername)) {return true;}}return false;}//鼠标按下事件@Overridepublic void mousePressed(MouseEvent e) {Object source = e.getSource();//切换按钮深色背景if (source == submit) {submit.setIcon(new ImageIcon("PuzzleGame\\image\\register\\注册按下.png"));} else if (source == reset) {reset.setIcon(new ImageIcon("PuzzleGame\\image\\register\\重置按下.png"));}}//鼠标释放事件@Overridepublic void mouseReleased(MouseEvent e) {Object source = e.getSource();//切换按钮正常背景if (source == submit) {submit.setIcon(new ImageIcon("PuzzleGame\\image\\register\\注册按钮.png"));} else if (source == reset) {reset.setIcon(new ImageIcon("PuzzleGame\\image\\register\\重置按钮.png"));}}@Overridepublic void mouseEntered(MouseEvent e) {}@Overridepublic void mouseExited(MouseEvent e) {}
}

游戏界面

import javax.swing.*;
import javax.swing.border.BevelBorder;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.*;
import java.util.Random;//游戏界面类继承界面类,实现键盘监听和动作监听
public class GameJFrame extends JFrame implements KeyListener, ActionListener {//多个方法需要用到的变量,记录在成员变量的位置//定义二维数组记录打乱后的0~15,每一个数字对应一张拼图int[][] data = new int[4][4];//定义胜利时的数据数组int[][] winArr = {{1, 2, 3, 4},{5, 6, 7, 8},{9, 10, 11, 12},{13, 14, 15, 0}};//定义坐标记录0的位置int x = 0;int y = 0;//定义计数器记录移动步数int stepCount = 0;//创建菜单选项里下面的条目JMenuItem restartItem = new JMenuItem("重新开始");JMenuItem reLoginItem = new JMenuItem("重新登录");JMenuItem exitItem = new JMenuItem("退出游戏");JMenuItem animalItem = new JMenuItem("动物");JMenuItem girllItem = new JMenuItem("美女");JMenuItem sportItem = new JMenuItem("运动");JMenuItem AccountItem = new JMenuItem("公众号");JMenu saveJmenu = new JMenu("存档");JMenuItem saveItem0 = new JMenuItem("存档0(空)");JMenuItem saveItem1 = new JMenuItem("存档1(空)");JMenuItem saveItem2 = new JMenuItem("存档2(空)");JMenu loadJmenu = new JMenu("读档");JMenuItem loadItem0 = new JMenuItem("读档0(空)");JMenuItem loadItem1 = new JMenuItem("读档1(空)");JMenuItem loadItem2 = new JMenuItem("读档2(空)");//定义图片路径,方便后面修改String path = "PuzzleGame\\image\\animal\\animal1\\";Random r = new Random();//空参构造初始化游戏public GameJFrame() {//调用方法初始化界面initFrame();//给界面添加事件监听,键盘监听KeyListenerthis.addKeyListener(this);//调用方法添加菜单initMenu();//给菜单里的条目添加事件监听,动作监听ActionListenerrestartItem.addActionListener(this);reLoginItem.addActionListener(this);exitItem.addActionListener(this);AccountItem.addActionListener(this);animalItem.addActionListener(this);girllItem.addActionListener(this);sportItem.addActionListener(this);saveItem0.addActionListener(this);saveItem1.addActionListener(this);saveItem2.addActionListener(this);loadItem0.addActionListener(this);loadItem1.addActionListener(this);loadItem2.addActionListener(this);//调用方法初始化数据initData();//调用方法根据初始化后的数据加载图片loadImages();//设置界面可视,建议放在最后this.setVisible(true);}//定义方法判断游戏是否胜利private boolean victoty() {for (int i = 0; i < data.length; i++) {for (int j = 0; j < data[i].length; j++) {if (data[i][j] != winArr[i][j]) {//data中的数据有一个与胜利数组中的数据不同,就说明没有胜利return false;}}}return true;}//定义方法根据初始化后的数据加载图片private void loadImages() {//清空所有图片this.getContentPane().removeAll();//如果胜利,加载胜利图标if (victoty()) {JLabel vicJLabel = new JLabel(new ImageIcon("PuzzleGame\\image\\win.png"));vicJLabel.setBounds(203, 283, 197, 73);this.getContentPane().add(vicJLabel);}//加载计数器JLabel countJLabel = new JLabel("步数:" + stepCount);countJLabel.setBounds(50, 30, 100, 20);this.getContentPane().add(countJLabel);//利用循环加载拼图图片for (int i = 0; i < data.length; i++) {for (int j = 0; j < data[i].length; j++) {//获得data数组里的数据int number = data[i][j];//根据数据创建图片对象ImageIcon icon = new ImageIcon(path + number + ".jpg");//创建管理容器,将图片交给管理容器JLabel jLabel = new JLabel(icon);//设置管理容器位置,大小jLabel.setBounds(105 * j + 83, 105 * i + 134, 105, 105);//设置边框jLabel.setBorder(new BevelBorder(0));//将管理容器添加到界面中this.getContentPane().add(jLabel);}}//添加背景图片JLabel bgJLabel = new JLabel(new ImageIcon("PuzzleGame\\image\\background.png"));bgJLabel.setBounds(40, 40, 508, 560);this.getContentPane().add(bgJLabel);//刷新一下this.getContentPane().repaint();}//定义方法初始化数据private void initData() {int[] tempArr = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};//打乱数据,根据打乱后的数据就能实现打乱拼图for (int i = 0; i < tempArr.length; i++) {int index = r.nextInt(tempArr.length);int temp = tempArr[i];tempArr[i] = tempArr[index];tempArr[index] = temp;}//将打乱后的数据记录在二维数组data中for (int i = 0; i < tempArr.length; i++) {//如果是0,记录0的位置if (tempArr[i] == 0) {x = i / 4;y = i % 4;}data[i / 4][i % 4] = tempArr[i];}}//定义方法添加菜单private void initMenu() {//创建菜单JMenuBar jMenuBar = new JMenuBar();//创建菜单的选项JMenu functionJmenu = new JMenu("功能");JMenu aboutJmenu = new JMenu("关于我们");//嵌套二级菜单,JMenu里面是可以再次添加其他的JMenuJMenu updateJmenu = new JMenu("更换图片");updateJmenu.add(animalItem);updateJmenu.add(girllItem);updateJmenu.add(sportItem);//存档saveJmenu.add(saveItem0);saveJmenu.add(saveItem1);saveJmenu.add(saveItem2);//读档loadJmenu.add(loadItem0);loadJmenu.add(loadItem1);loadJmenu.add(loadItem2);//将条目添加到选项中functionJmenu.add(updateJmenu);functionJmenu.add(restartItem);functionJmenu.add(reLoginItem);functionJmenu.add(exitItem);functionJmenu.add(saveJmenu);functionJmenu.add(loadJmenu);aboutJmenu.add(AccountItem);//将选项添加到菜单中jMenuBar.add(functionJmenu);jMenuBar.add(aboutJmenu);//将菜单添加到界面中this.setJMenuBar(jMenuBar);//游戏开始时获取游戏数据信息修改菜单提示getGameInfo();}//游戏开始时获取游戏数据信息修改菜单提示private void getGameInfo() {//遍历存档文件夹File f = new File("PuzzleGame\\save");File[] files = f.listFiles();if (files == null) {return;}for (File file : files) {//读取每一个文件信息GameInfo gi = null;try {ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));gi = (GameInfo) ois.readObject();ois.close();} catch (IOException e) {throw new RuntimeException(e);} catch (ClassNotFoundException e) {throw new RuntimeException(e);}//获取要体现在菜单上的步数信息int step = gi.getStepCount();//获取要修改的条目索引String name = file.getName();//save0/1/2.dataint index = name.charAt(4) - '0';//进行修改JMenuItem item1 = saveJmenu.getItem(index);item1.setText("存档" + index + "(" + step + "步)");JMenuItem item2 = loadJmenu.getItem(index);item2.setText("读档" + index + "(" + step + "步)");}}//定义方法初始化界面private void initFrame() {//设置大小this.setSize(603, 680);//设置标题this.setTitle("拼图游戏");//设置居中this.setLocationRelativeTo(null);//设置置顶this.setAlwaysOnTop(true);//设置关闭模式this.setDefaultCloseOperation(3);//设置解除默认居中放置,只有解除了,才能根据xy轴的方式添加主件this.setLayout(null);}//动作监听ActionListener,鼠标单击或按空格调用该方法@Overridepublic void actionPerformed(ActionEvent e) {Object source = e.getSource();if (source == restartItem) {//重新开始//重新初始化数据initData();//计数器归0stepCount = 0;//重新根据初始化后的数据加载图片loadImages();} else if (source == reLoginItem) {//重新登录//关闭本类(游戏类)this.setVisible(false);//创建登录界面try {new LoginJFrame();} catch (IOException ex) {throw new RuntimeException(ex);}} else if (source == exitItem) {//退出游戏System.exit(0);} else if (source == AccountItem) {//显示公众号//创建弹窗JDialog accJDialog = new JDialog();//加载弹窗中的图片JLabel aboutJLabel = new JLabel(new ImageIcon("PuzzleGame\\image\\about.png"));aboutJLabel.setBounds(0, 0, 258, 258);//将图片添加到弹窗中accJDialog.getContentPane().add(aboutJLabel);//设置弹窗的大小accJDialog.setSize(344, 344);//设置弹窗置顶accJDialog.setAlwaysOnTop(true);//设置弹窗居中放置accJDialog.setLocationRelativeTo(null);//设置关闭后进行其他操作accJDialog.setModal(true);//设置弹窗可视accJDialog.setVisible(true);} else if (source == animalItem) {//随机更换动物图片int rAnimalNum = r.nextInt(8) + 1;path = "PuzzleGame\\image\\animal\\animal" + rAnimalNum + "\\";//重新初始化数据initData();//计数器归0stepCount = 0;//重新根据初始化后的数据加载图片loadImages();} else if (source == girllItem) {//随机更换美女图片int rGirlNum = r.nextInt(13) + 1;path = "PuzzleGame\\image\\girl\\girl" + rGirlNum + "\\";//重新初始化数据initData();//计数器归0stepCount = 0;//重新根据初始化后的数据加载图片loadImages();} else if (source == sportItem) {//随机更换运动图片int rSportlNum = r.nextInt(10) + 1;path = "PuzzleGame\\image\\sport\\sport" + rSportlNum + "\\";//重新初始化数据initData();//计数器归0stepCount = 0;//重新根据初始化后的数据加载图片loadImages();} else if (source == saveItem0 || source == saveItem1 || source == saveItem2) {//进行存档//得到点击的存档序号JMenuItem item = (JMenuItem) source;String text = item.getText();//存档0/1/2(空)int index = text.charAt(2) - '0';//封装要保存的游戏数据//包括:对应拼图的data数组,记录0位置的坐标x,y,图片路径path,步数stepCountGameInfo gi = new GameInfo(data, x, y, stepCount, path);//将游戏信息对象以序列化流写入对应文件中,防止篡改数据try {ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("PuzzleGame\\save\\save" + index + ".data"));oos.writeObject(gi);oos.close();} catch (IOException ex) {throw new RuntimeException(ex);}//修改菜单上的提示信息item.setText("存档" + index + "(" + stepCount + "步)");//获取与存档对应的读档菜单JMenuItem item1 = loadJmenu.getItem(index);item1.setText("读档" + index + "(" + stepCount + "步)");} else if (source == loadItem0 || source == loadItem1 || source == loadItem2) {//进行读档//得到点击的读档序号JMenuItem item = (JMenuItem) source;String text = item.getText();//读档0/1/2(空)int index = text.charAt(2) - '0';//利用反序列化流读取文件中的游戏数据GameInfo gi = null;try {ObjectInputStream ois = new ObjectInputStream(new FileInputStream("PuzzleGame\\save\\save" + index + ".data"));gi = (GameInfo) ois.readObject();ois.close();} catch (IOException ex) {throw new RuntimeException(ex);} catch (ClassNotFoundException ex) {throw new RuntimeException(ex);}//将游戏数据更新为存档的游戏数据data = gi.getData();x = gi.getX();y = gi.getY();path = gi.getPath();stepCount = gi.getStepCount();//重新加载游戏loadImages();}}//键盘监听KeyListener//该方法基本不使用@Overridepublic void keyTyped(KeyEvent e) {}//长按键盘时调用该方法@Overridepublic void keyPressed(KeyEvent e) {//判断是否胜利if (victoty()) {//如果胜利,禁止进行显示全图操作,直接结束方法return;}//长按w显示全图int keyCode = e.getKeyCode();if (keyCode == 87) {//清空所有图片this.getContentPane().removeAll();//加载计数器JLabel countJLabel = new JLabel("步数:" + stepCount);countJLabel.setBounds(50, 30, 100, 20);this.getContentPane().add(countJLabel);//加载全图JLabel picJLabel = new JLabel(new ImageIcon(path + "all.jpg"));picJLabel.setBounds(83, 134, 420, 420);this.getContentPane().add(picJLabel);//添加背景图片JLabel bgJLabel = new JLabel(new ImageIcon("PuzzleGame\\image\\background.png"));bgJLabel.setBounds(40, 40, 508, 560);this.getContentPane().add(bgJLabel);//刷新一下this.getContentPane().repaint();}}//按下并松开键盘时调用该方法@Overridepublic void keyReleased(KeyEvent e) {//判断是否胜利if (victoty()) {//如果胜利,禁止进行移动操作,直接结束方法return;}int keyCode = e.getKeyCode();if (keyCode == 37) {//判断是否到了最左边if (y == 0) {//如果到了最左边,不能进行向左,直接结束方法return;}//没到最左边,进行下面的操作System.out.println("向左");//更改data数组里的数据data[x][y] = data[x][y - 1];data[x][y - 1] = 0;//更改0的坐标y--;//步数加1stepCount++;//按照此数据重新加载图片loadImages();} else if (keyCode == 38) {//判断是否到了最上边if (x == 0) {//如果到了最上边,不能进行向上,直接结束方法return;}//没到最上边,进行下面的操作System.out.println("向上");//更改data数组里的数据data[x][y] = data[x - 1][y];data[x - 1][y] = 0;//更改0的坐标x--;//步数加1stepCount++;//按照此数据重新加载图片loadImages();} else if (keyCode == 39) {//判断是否到了最右边if (y == 3) {//如果到了最右边,不能进行向右,直接结束方法return;}//没到最右边,进行下面的操作System.out.println("向右");//更改data数组里的数据data[x][y] = data[x][y + 1];data[x][y + 1] = 0;//更改0的坐标y++;//步数加1stepCount++;//按照此数据重新加载图片loadImages();} else if (keyCode == 40) {//判断是否到了最下边if (x == 3) {//如果到了最下边,不能进行向下,直接结束方法return;}//没到最下边,进行下面的操作System.out.println("向下");//更改data数组里的数据data[x][y] = data[x + 1][y];data[x + 1][y] = 0;//更改0的坐标x++;//步数加1stepCount++;//按照此数据重新加载图片loadImages();} else if (keyCode == 87) {//松开w恢复原状loadImages();} else if (keyCode == 65) {//一键通过for (int i = 0; i < data.length; i++) {for (int j = 0; j < data[i].length; j++) {data[i][j] = winArr[i][j];}}loadImages();}}}

 封装用户信息

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;}@Overridepublic String toString() {return "uesrname="+userName+"&password="+passWord;}
}

封装游戏信息

import java.io.Serial;
import java.io.Serializable;public class GameInfo implements Serializable {@Serialprivate static final long serialVersionUID = 3545018877843048289L;private int[][] data;private int x;private int y;private int stepCount;private String path;public GameInfo() {}public GameInfo(int[][] data, int x, int y, int stepCount, String path) {this.data = data;this.x = x;this.y = y;this.stepCount = stepCount;this.path = path;}public int[][] getData() {return data;}public void setData(int[][] data) {this.data = data;}public int getX() {return x;}public void setX(int x) {this.x = x;}public int getY() {return y;}public void setY(int y) {this.y = y;}public int getStepCount() {return stepCount;}public void setStepCount(int stepCount) {this.stepCount = stepCount;}public String getPath() {return path;}public void setPath(String path) {this.path = path;}public String toString() {return "GameInfo{data = " + data + ", x = " + x + ", y = " + y + ", stepCount = " + stepCount + ", path = " + path + "}";}
}

生成验证码工具类

import java.util.Random;public class CodeUtil {private CodeUtil(){}public static String getCode(){//定义StringBuilder方便拼接字符串StringBuilder sb = new StringBuilder();//记录a~z,A~Zchar[] ch = new char[52];for (int i = 0; i < ch.length; i++) {if (i < 26) {ch[i] = (char) ('a' + i);} else {ch[i] = (char) ('A' + i - 26);}}Random r = new Random();//随机抽取4个字母for (int i = 0; i < 4; i++) {int index = r.nextInt(ch.length);char randomCh = ch[index];//拼接sb.append(randomCh);}//随机抽取1个字母int randomNum = r.nextInt(10);//拼接sb.append(randomNum);//数字可以位于随机位置,因此最后一位需要与随机位置交换char[] chars = sb.toString().toCharArray();int index = r.nextInt(chars.length);char temp = chars[chars.length-1];chars[chars.length-1] = chars[index];chars[index] = temp;return new String(chars);}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/pingmian/82051.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Docker中部署Alertmanager

在 Docker 中部署 Alertmanager&#xff08;通常与 Prometheus 告警系统配合使用&#xff09;的步骤如下&#xff1a; 一、拉取镜像prom/alertmanager docker pull prom/alertmanager二、 创建 Alertmanager 配置文件 首先准备Alertmanager的配置文件 alertmanager.yml(如存…

【大模型面试每日一题】Day 27:自注意力机制中Q/K/V矩阵的作用与缩放因子原理

【大模型面试每日一题】Day 27&#xff1a;自注意力机制中Q/K/V矩阵的作用与缩放因子原理 &#x1f4cc; 题目重现 &#x1f31f;&#x1f31f; 面试官&#xff1a;请解释Transformer自注意力机制中Query、Key、Value矩阵的核心作用&#xff0c;并分析为何在计算注意力分数时…

AI+能碳管理系统:全生命周期碳管理

在"双碳"目标的时代背景下&#xff0c;AI赋能的能碳管理系统正在重新定义企业碳管理的边界与深度。这套系统犹如一位不知疲倦的碳管家&#xff0c;从原材料采购到产品报废&#xff0c;在每一个价值环节编织起精密的碳管理网络&#xff0c;实现从微观设备到宏观战略的…

k8s1.27版本集群部署minio分布式

需求&#xff1a; 1.创建4个pv&#xff0c;一个pv一个minio-pod。使用sts动态分配pvc(根据存储类找到pv)。----持久化 2.暴露minio的9001端口。&#xff08;nodeport&#xff09;----管理界面 镜像&#xff1a;minio/minio:RELEASE.2023-03-20T20-16-18Z--->换国内源 说明…

使用 OpenCV 实现 ArUco 码识别与坐标轴绘制

&#x1f3af; 使用 OpenCV 实现 ArUco 码识别与坐标轴绘制&#xff08;含Python源码&#xff09; Aruco 是一种广泛用于机器人、增强现实&#xff08;AR&#xff09;和相机标定的方形标记系统。本文将带你一步一步使用 Python OpenCV 实现图像中多个 ArUco 码的检测与坐标轴…

Qt 控件发展历程 + 目标(1)

文章目录 声明简述控件的发展历程学习目标QWidget属性 简介&#xff1a;这篇文章只是一个引子&#xff0c;介绍一点与控件相关的但不重要的内容&#xff08;浏览浏览即可&#xff09;&#xff0c;这一章节最为重要的还是要把之后常用且重要的控件属性和作用给学透&#xff0c;学…

socc 19 echash论文部分解读

前言&#xff1a;论文还是得吃透才行&#xff0c;不然很多细节有问题 q1 object和data chunck哪一个大 根据论文&#xff0c;一个 data chunk 通常比一个 object 大&#xff0c;因为它是由多个 object 组合而成的 。 论文中提到&#xff0c;cross-coding 会将多个 object 组合…

w~自动驾驶~合集1

我自己的原文哦~ https://blog.51cto.com/whaosoft/12371169 #世界模型和DriveGPT这类大模型到底能给自动驾驶带来什么ne 以下分享大模型与自动驾驶结合的相关工作9篇论 1、ADAPT ADAPT: Action-aware Driving Caption Transformer&#xff08;ICRA2023&#xff09; A…

【paddle】常见的数学运算

根据提供的 PaddlePaddle 函数列表&#xff0c;我们可以将它们按照数学运算、逻辑运算、三角函数、特殊函数、统计函数、张量操作和其他操作等类型进行分类。以下是根据函数功能进行的分类&#xff1a; 取整运算 Rounding functions 代码描述round(x)距离 x 最近的整数floor(…

绘制音频信号的各种频谱图,包括Mel频谱图、STFT频谱图等。它不仅能够绘制频谱图librosa.display.specshow

librosa.display.specshow 是一个非常方便的函数&#xff0c;用于绘制音频信号的各种频谱图&#xff0c;包括Mel频谱图、STFT频谱图等。它不仅能够绘制频谱图&#xff0c;还能自动设置轴标签和刻度&#xff0c;使得生成的图像更加直观和易于理解。 ### 函数签名 python libros…

DDR DFI 5.2 协议接口学习梳理笔记01

备注:本文新增对各种时钟含义做了明确定义区分,避免大家产生误解,这也是5.2版本新引入的。 1. 前言 截止2025年5月,DFI协议最新版本为 5.2,我们首先看一下过去几代的演进: DFI全称DDR PHY Interface,是一种接口协议,定义了 Controller 和 PHY 之间接口的信号、时序以…

windows篡改脚本提醒

✅ 功能简介 该监控系统具备如下主要功能&#xff1a; &#x1f4c1; 目录监控 实时监听指定主目录及其所有子目录内文件的变动情况。 &#x1f512; 文件哈希校验 对文件内容生成 SHA256 哈希&#xff0c;确保变更检测基于内容而非时间戳。 &#x1f6ab; 排除机制 支…

文章记单词 | 第102篇(六级)

一&#xff0c;单词释义 apologize /əˈpɒlədʒaɪz/ v. 道歉&#xff1b;认错discharge /dɪsˈtʃɑːrdʒ/ v./n. 排出&#xff1b;释放&#xff1b;解雇&#xff1b; dischargequiver /ˈkwɪvər/ v./n. 颤抖&#xff1b;抖动&#xff1b;箭筒plantation /plnˈteɪʃ…

【DCGMI专题1】---DCGMI 在 Ubuntu 22.04 上的深度安装指南与原理分析(含架构图解)

目录 一、DCGMI 概述与应用场景 二、Ubuntu 22.04 系统准备 2.1 系统要求 2.2 环境清理(可选) 三、DCGMI 安装步骤(详细图解) 3.1 安装流程总览 3.2 分步操作指南 3.2.1 系统更新与依赖安装 3.2.2 添加 NVIDIA 官方仓库 3.2.3 安装数据中心驱动与 DCGM 3.2.4 服务…

主成分分析(PCA)法例题——给定协方差矩阵

已知样本集合的协方差矩阵为 C x 1 10 [ 3 1 1 1 3 − 1 1 − 1 3 ] {\bm C}_x \frac{1}{10} \begin{bmatrix} 3 & 1 & 1 \\ 1 & 3 & -1 \\ 1 & -1 & 3 \end{bmatrix} Cx​101​ ​311​13−1​1−13​ ​ 使用PCA方法将样本向量降到二维 。 求解 计…

uni-app(4):js语法、css语法

1 js语法 uni-app的js API由标准ECMAScript的js API 和 uni 扩展 API 这两部分组成。标准ECMAScript的js仅是最基础的js。浏览器基于它扩展了window、document、navigator等对象。小程序也基于标准js扩展了各种wx.xx、my.xx、swan.xx的API。node也扩展了fs等模块。uni-app基于E…

Idea 配合 devtools 依赖 实现热部署

核心依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional></dependency> yaml配置 spring: #…

leetcode513.找树左下角的值:递归深度优先搜索中的最左节点追踪之道

一、题目本质与核心诉求解析 在二叉树算法问题中&#xff0c;"找树左下角的值"是一个典型的结合深度与位置判断的问题。题目要求我们找到二叉树中最深层最左边的节点值&#xff0c;这里的"左下角"有两个关键限定&#xff1a; 深度优先&#xff1a;必须是…

Python入门手册:Python基础语法

Python是一种简洁、易读且功能强大的编程语言&#xff0c;非常适合初学者入门。无论你是编程新手&#xff0c;还是有一定编程基础但想学习Python的开发者&#xff0c;掌握Python的基础语法都是迈向高效编程的第一步。本文将详细介绍Python的基本语法&#xff0c;包括变量和数据…

postgresql 常用参数配置

#01 - Connection-Authentication 优化点&#xff1a; listen_addresses 0.0.0.0 建议&#xff1a;生产环境应限制为具体IP&#xff08;如 192.168.1.0/24,127.0.0.1&#xff09;&#xff0c;避免暴露到公网。 ssl off 建议&#xff1a;启用SSL&#xff08;ssl on&#xf…